winspool: Add a helper to duplicate a devmode.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob7fbede27905ff934563f753f48bfd53690d6eae9
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-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stddef.h>
36 #include <errno.h>
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 #include <signal.h>
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
46 #endif
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
51 #include "windef.h"
52 #include "winbase.h"
53 #include "winuser.h"
54 #include "winerror.h"
55 #include "winreg.h"
56 #include "wingdi.h"
57 #include "winspool.h"
58 #include "winternl.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
63 #include "winnls.h"
65 #include "ddk/winsplp.h"
66 #include "wspool.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
75 0, 0, &printer_handles_cs,
76 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
81 /* ############################### */
83 typedef struct {
84 DWORD job_id;
85 HANDLE hf;
86 } started_doc_t;
88 typedef struct {
89 struct list jobs;
90 LONG ref;
91 } jobqueue_t;
93 typedef struct {
94 LPWSTR name;
95 LPWSTR printername;
96 HANDLE backend_printer;
97 jobqueue_t *queue;
98 started_doc_t *doc;
99 } opened_printer_t;
101 typedef struct {
102 struct list entry;
103 DWORD job_id;
104 WCHAR *filename;
105 WCHAR *portname;
106 WCHAR *document_title;
107 WCHAR *printer_name;
108 LPDEVMODEW devmode;
109 } job_t;
112 typedef struct {
113 LPCWSTR envname;
114 LPCWSTR subdir;
115 DWORD driverversion;
116 LPCWSTR versionregpath;
117 LPCWSTR versionsubdir;
118 } printenv_t;
120 /* ############################### */
122 static opened_printer_t **printer_handles;
123 static UINT nb_printer_handles;
124 static LONG next_job_id = 1;
126 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
127 WORD fwCapability, LPSTR lpszOutput,
128 LPDEVMODEA lpdm );
129 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
130 LPSTR lpszDevice, LPSTR lpszPort,
131 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
132 DWORD fwMode );
134 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
135 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
136 'c','o','n','t','r','o','l','\\',
137 'P','r','i','n','t','\\',
138 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
139 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
141 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
142 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
143 'C','o','n','t','r','o','l','\\',
144 'P','r','i','n','t','\\',
145 'P','r','i','n','t','e','r','s',0};
147 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
149 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
150 'M','i','c','r','o','s','o','f','t','\\',
151 'W','i','n','d','o','w','s',' ','N','T','\\',
152 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
153 'W','i','n','d','o','w','s',0};
155 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
156 'M','i','c','r','o','s','o','f','t','\\',
157 'W','i','n','d','o','w','s',' ','N','T','\\',
158 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
159 'D','e','v','i','c','e','s',0};
161 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
162 'M','i','c','r','o','s','o','f','t','\\',
163 'W','i','n','d','o','w','s',' ','N','T','\\',
164 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
165 'P','o','r','t','s',0};
167 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
168 'M','i','c','r','o','s','o','f','t','\\',
169 'W','i','n','d','o','w','s',' ','N','T','\\',
170 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
171 'P','r','i','n','t','e','r','P','o','r','t','s',0};
173 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
174 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
175 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
176 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
177 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
178 static const WCHAR subdir_x64W[] = {'x','6','4',0};
179 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
180 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
181 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
182 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
183 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
185 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
186 static const WCHAR backslashW[] = {'\\',0};
187 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
188 'i','o','n',' ','F','i','l','e',0};
189 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
190 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
191 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
192 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
193 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
194 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
195 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
196 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
197 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
198 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
199 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
200 static const WCHAR NameW[] = {'N','a','m','e',0};
201 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
202 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
203 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
204 static const WCHAR PortW[] = {'P','o','r','t',0};
205 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
206 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
207 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
208 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
209 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
210 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
211 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
212 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
213 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
214 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
215 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
216 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
217 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
218 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
219 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
220 static WCHAR rawW[] = {'R','A','W',0};
221 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
222 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
223 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
224 static const WCHAR commaW[] = {',',0};
225 static WCHAR emptyStringW[] = {0};
227 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
229 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
230 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
231 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
233 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
234 'D','o','c','u','m','e','n','t',0};
236 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
237 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
238 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
239 0, sizeof(DRIVER_INFO_8W)};
242 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
243 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
244 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
245 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
246 sizeof(PRINTER_INFO_9W)};
248 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
249 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
250 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
252 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
254 /******************************************************************
255 * validate the user-supplied printing-environment [internal]
257 * PARAMS
258 * env [I] PTR to Environment-String or NULL
260 * RETURNS
261 * Failure: NULL
262 * Success: PTR to printenv_t
264 * NOTES
265 * An empty string is handled the same way as NULL.
266 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
270 static const printenv_t * validate_envW(LPCWSTR env)
272 const printenv_t *result = NULL;
273 unsigned int i;
275 TRACE("testing %s\n", debugstr_w(env));
276 if (env && env[0])
278 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
280 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
282 result = all_printenv[i];
283 break;
287 if (result == NULL) {
288 FIXME("unsupported Environment: %s\n", debugstr_w(env));
289 SetLastError(ERROR_INVALID_ENVIRONMENT);
291 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
293 else
295 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
297 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
299 return result;
303 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
304 if passed a NULL string. This returns NULLs to the result.
306 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
308 if ( (src) )
310 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
311 return usBufferPtr->Buffer;
313 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
314 return NULL;
317 static LPWSTR strdupW(LPCWSTR p)
319 LPWSTR ret;
320 DWORD len;
322 if(!p) return NULL;
323 len = (strlenW(p) + 1) * sizeof(WCHAR);
324 ret = HeapAlloc(GetProcessHeap(), 0, len);
325 memcpy(ret, p, len);
326 return ret;
329 static LPSTR strdupWtoA( LPCWSTR str )
331 LPSTR ret;
332 INT len;
334 if (!str) return NULL;
335 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
336 ret = HeapAlloc( GetProcessHeap(), 0, len );
337 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
338 return ret;
341 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
343 DEVMODEW *ret;
345 if (!dm) return NULL;
346 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
347 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
348 return ret;
351 /******************************************************************
352 * verify, that the filename is a local file
355 static inline BOOL is_local_file(LPWSTR name)
357 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
360 /* ################################ */
362 static int multi_sz_lenA(const char *str)
364 const char *ptr = str;
365 if(!str) return 0;
368 ptr += lstrlenA(ptr) + 1;
369 } while(*ptr);
371 return ptr - str + 1;
374 static void
375 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
376 char qbuf[200];
378 /* If forcing, or no profile string entry for device yet, set the entry
380 * The always change entry if not WINEPS yet is discussable.
382 if (force ||
383 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
384 !strcmp(qbuf,"*") ||
385 !strstr(qbuf,"WINEPS.DRV")
387 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
388 HKEY hkey;
390 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
391 WriteProfileStringA("windows","device",buf);
392 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
393 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
394 RegCloseKey(hkey);
396 HeapFree(GetProcessHeap(),0,buf);
400 static BOOL add_printer_driver(WCHAR *name)
402 DRIVER_INFO_3W di3;
404 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
405 di3.cVersion = 3;
406 di3.pName = name;
407 di3.pEnvironment = envname_x86W;
408 di3.pDriverPath = driver_nt;
409 di3.pDataFile = generic_ppdW;
410 di3.pConfigFile = driver_nt;
411 di3.pDefaultDataType = rawW;
413 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
414 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
416 di3.cVersion = 0;
417 di3.pEnvironment = envname_win40W;
418 di3.pDriverPath = driver_9x;
419 di3.pConfigFile = driver_9x;
420 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
421 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
423 return TRUE;
426 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
427 return FALSE;
430 #ifdef SONAME_LIBCUPS
431 static typeof(cupsFreeDests) *pcupsFreeDests;
432 static typeof(cupsGetDests) *pcupsGetDests;
433 static typeof(cupsGetPPD) *pcupsGetPPD;
434 static typeof(cupsPrintFile) *pcupsPrintFile;
435 static void *cupshandle;
437 static BOOL CUPS_LoadPrinters(void)
439 int i, nrofdests;
440 BOOL hadprinter = FALSE, haddefault = FALSE;
441 cups_dest_t *dests;
442 PRINTER_INFO_2W pi2;
443 WCHAR *port;
444 HKEY hkeyPrinter, hkeyPrinters;
445 char loaderror[256];
446 WCHAR nameW[MAX_PATH];
448 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
449 if (!cupshandle) {
450 TRACE("%s\n", loaderror);
451 return FALSE;
453 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
455 #define DYNCUPS(x) \
456 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
457 if (!p##x) return FALSE;
459 DYNCUPS(cupsFreeDests);
460 DYNCUPS(cupsGetPPD);
461 DYNCUPS(cupsGetDests);
462 DYNCUPS(cupsPrintFile);
463 #undef DYNCUPS
465 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
466 ERROR_SUCCESS) {
467 ERR("Can't create Printers key\n");
468 return FALSE;
471 nrofdests = pcupsGetDests(&dests);
472 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
473 for (i=0;i<nrofdests;i++) {
474 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
476 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
477 lstrcpyW(port, CUPS_Port);
478 lstrcatW(port, nameW);
480 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
481 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
482 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
483 and continue */
484 TRACE("Printer already exists\n");
485 /* overwrite old LPR:* port */
486 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
487 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
488 RegCloseKey(hkeyPrinter);
489 } else {
490 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
491 ' ','u','s','i','n','g',' ','C','U','P','S',0};
493 add_printer_driver(nameW);
495 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
496 pi2.pPrinterName = nameW;
497 pi2.pDatatype = rawW;
498 pi2.pPrintProcessor = WinPrintW;
499 pi2.pDriverName = nameW;
500 pi2.pComment = comment_cups;
501 pi2.pLocation = emptyStringW;
502 pi2.pPortName = port;
503 pi2.pParameters = emptyStringW;
504 pi2.pShareName = emptyStringW;
505 pi2.pSepFile = emptyStringW;
507 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
508 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
509 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
512 HeapFree(GetProcessHeap(),0,port);
514 hadprinter = TRUE;
515 if (dests[i].is_default) {
516 SetDefaultPrinterW(nameW);
517 haddefault = TRUE;
520 if (hadprinter && !haddefault) {
521 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
522 SetDefaultPrinterW(nameW);
524 pcupsFreeDests(nrofdests, dests);
525 RegCloseKey(hkeyPrinters);
526 return hadprinter;
528 #endif
530 static BOOL
531 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
532 PRINTER_INFO_2A pinfo2a;
533 const char *r;
534 size_t name_len;
535 char *e,*s,*name,*prettyname,*devname;
536 BOOL ret = FALSE, set_default = FALSE;
537 char *port = NULL, *env_default;
538 HKEY hkeyPrinter, hkeyPrinters;
539 WCHAR devnameW[MAX_PATH];
541 while (isspace(*pent)) pent++;
542 r = strchr(pent,':');
543 if (r)
544 name_len = r - pent;
545 else
546 name_len = strlen(pent);
547 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
548 memcpy(name, pent, name_len);
549 name[name_len] = '\0';
550 if (r)
551 pent = r;
552 else
553 pent = "";
555 TRACE("name=%s entry=%s\n",name, pent);
557 if(ispunct(*name)) { /* a tc entry, not a real printer */
558 TRACE("skipping tc entry\n");
559 goto end;
562 if(strstr(pent,":server")) { /* server only version so skip */
563 TRACE("skipping server entry\n");
564 goto end;
567 /* Determine whether this is a postscript printer. */
569 ret = TRUE;
570 env_default = getenv("PRINTER");
571 prettyname = name;
572 /* Get longest name, usually the one at the right for later display. */
573 while((s=strchr(prettyname,'|'))) {
574 *s = '\0';
575 e = s;
576 while(isspace(*--e)) *e = '\0';
577 TRACE("\t%s\n", debugstr_a(prettyname));
578 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
579 for(prettyname = s+1; isspace(*prettyname); prettyname++)
582 e = prettyname + strlen(prettyname);
583 while(isspace(*--e)) *e = '\0';
584 TRACE("\t%s\n", debugstr_a(prettyname));
585 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
587 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
588 * if it is too long, we use it as comment below. */
589 devname = prettyname;
590 if (strlen(devname)>=CCHDEVICENAME-1)
591 devname = name;
592 if (strlen(devname)>=CCHDEVICENAME-1) {
593 ret = FALSE;
594 goto end;
597 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
598 sprintf(port,"LPR:%s",name);
600 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
601 ERROR_SUCCESS) {
602 ERR("Can't create Printers key\n");
603 ret = FALSE;
604 goto end;
607 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
609 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
610 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
611 and continue */
612 TRACE("Printer already exists\n");
613 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
614 RegCloseKey(hkeyPrinter);
615 } else {
616 static CHAR data_type[] = "RAW",
617 print_proc[] = "WinPrint",
618 comment[] = "WINEPS Printer using LPR",
619 params[] = "<parameters?>",
620 share_name[] = "<share name?>",
621 sep_file[] = "<sep file?>";
623 add_printer_driver(devnameW);
625 memset(&pinfo2a,0,sizeof(pinfo2a));
626 pinfo2a.pPrinterName = devname;
627 pinfo2a.pDatatype = data_type;
628 pinfo2a.pPrintProcessor = print_proc;
629 pinfo2a.pDriverName = devname;
630 pinfo2a.pComment = comment;
631 pinfo2a.pLocation = prettyname;
632 pinfo2a.pPortName = port;
633 pinfo2a.pParameters = params;
634 pinfo2a.pShareName = share_name;
635 pinfo2a.pSepFile = sep_file;
637 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
638 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
639 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
642 RegCloseKey(hkeyPrinters);
644 if (isfirst || set_default)
645 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
647 end:
648 HeapFree(GetProcessHeap(), 0, port);
649 HeapFree(GetProcessHeap(), 0, name);
650 return ret;
653 static BOOL
654 PRINTCAP_LoadPrinters(void) {
655 BOOL hadprinter = FALSE;
656 char buf[200];
657 FILE *f;
658 char *pent = NULL;
659 BOOL had_bash = FALSE;
661 f = fopen("/etc/printcap","r");
662 if (!f)
663 return FALSE;
665 while(fgets(buf,sizeof(buf),f)) {
666 char *start, *end;
668 end=strchr(buf,'\n');
669 if (end) *end='\0';
671 start = buf;
672 while(isspace(*start)) start++;
673 if(*start == '#' || *start == '\0')
674 continue;
676 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
677 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
678 HeapFree(GetProcessHeap(),0,pent);
679 pent = NULL;
682 if (end && *--end == '\\') {
683 *end = '\0';
684 had_bash = TRUE;
685 } else
686 had_bash = FALSE;
688 if (pent) {
689 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
690 strcat(pent,start);
691 } else {
692 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
693 strcpy(pent,start);
697 if(pent) {
698 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
699 HeapFree(GetProcessHeap(),0,pent);
701 fclose(f);
702 return hadprinter;
705 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
707 if (value)
708 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
709 (lstrlenW(value) + 1) * sizeof(WCHAR));
710 else
711 return ERROR_FILE_NOT_FOUND;
714 /******************************************************************
715 * get_servername_from_name (internal)
717 * for an external server, a copy of the serverpart from the full name is returned
720 static LPWSTR get_servername_from_name(LPCWSTR name)
722 LPWSTR server;
723 LPWSTR ptr;
724 WCHAR buffer[MAX_PATH];
725 DWORD len;
727 if (name == NULL) return NULL;
728 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
730 server = strdupW(&name[2]); /* skip over both backslash */
731 if (server == NULL) return NULL;
733 /* strip '\' and the printername */
734 ptr = strchrW(server, '\\');
735 if (ptr) ptr[0] = '\0';
737 TRACE("found %s\n", debugstr_w(server));
739 len = sizeof(buffer)/sizeof(buffer[0]);
740 if (GetComputerNameW(buffer, &len)) {
741 if (lstrcmpW(buffer, server) == 0) {
742 /* The requested Servername is our computername */
743 HeapFree(GetProcessHeap(), 0, server);
744 return NULL;
747 return server;
750 /******************************************************************
751 * get_basename_from_name (internal)
753 * skip over the serverpart from the full name
756 static LPCWSTR get_basename_from_name(LPCWSTR name)
758 if (name == NULL) return NULL;
759 if ((name[0] == '\\') && (name[1] == '\\')) {
760 /* skip over the servername and search for the following '\' */
761 name = strchrW(&name[2], '\\');
762 if ((name) && (name[1])) {
763 /* found a separator ('\') followed by a name:
764 skip over the separator and return the rest */
765 name++;
767 else
769 /* no basename present (we found only a servername) */
770 return NULL;
773 return name;
776 /******************************************************************
777 * get_opened_printer_entry
778 * Get the first place empty in the opened printer table
780 * ToDo:
781 * - pDefault is ignored
783 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
785 UINT_PTR handle = nb_printer_handles, i;
786 jobqueue_t *queue = NULL;
787 opened_printer_t *printer = NULL;
788 LPWSTR servername;
789 LPCWSTR printername;
791 if ((backend == NULL) && !load_backend()) return NULL;
793 servername = get_servername_from_name(name);
794 if (servername) {
795 FIXME("server %s not supported\n", debugstr_w(servername));
796 HeapFree(GetProcessHeap(), 0, servername);
797 SetLastError(ERROR_INVALID_PRINTER_NAME);
798 return NULL;
801 printername = get_basename_from_name(name);
802 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
804 /* an empty printername is invalid */
805 if (printername && (!printername[0])) {
806 SetLastError(ERROR_INVALID_PARAMETER);
807 return NULL;
810 EnterCriticalSection(&printer_handles_cs);
812 for (i = 0; i < nb_printer_handles; i++)
814 if (!printer_handles[i])
816 if(handle == nb_printer_handles)
817 handle = i;
819 else
821 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
822 queue = printer_handles[i]->queue;
826 if (handle >= nb_printer_handles)
828 opened_printer_t **new_array;
829 if (printer_handles)
830 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
831 (nb_printer_handles + 16) * sizeof(*new_array) );
832 else
833 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
834 (nb_printer_handles + 16) * sizeof(*new_array) );
836 if (!new_array)
838 handle = 0;
839 goto end;
841 printer_handles = new_array;
842 nb_printer_handles += 16;
845 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
847 handle = 0;
848 goto end;
851 /* get a printer handle from the backend */
852 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
853 handle = 0;
854 goto end;
857 /* clone the base name. This is NULL for the printserver */
858 printer->printername = strdupW(printername);
860 /* clone the full name */
861 printer->name = strdupW(name);
862 if (name && (!printer->name)) {
863 handle = 0;
864 goto end;
867 if(queue)
868 printer->queue = queue;
869 else
871 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
872 if (!printer->queue) {
873 handle = 0;
874 goto end;
876 list_init(&printer->queue->jobs);
877 printer->queue->ref = 0;
879 InterlockedIncrement(&printer->queue->ref);
881 printer_handles[handle] = printer;
882 handle++;
883 end:
884 LeaveCriticalSection(&printer_handles_cs);
885 if (!handle && printer) {
886 /* Something failed: Free all resources */
887 HeapFree(GetProcessHeap(), 0, printer->printername);
888 HeapFree(GetProcessHeap(), 0, printer->name);
889 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
890 HeapFree(GetProcessHeap(), 0, printer);
893 return (HANDLE)handle;
896 /******************************************************************
897 * get_opened_printer
898 * Get the pointer to the opened printer referred by the handle
900 static opened_printer_t *get_opened_printer(HANDLE hprn)
902 UINT_PTR idx = (UINT_PTR)hprn;
903 opened_printer_t *ret = NULL;
905 EnterCriticalSection(&printer_handles_cs);
907 if ((idx > 0) && (idx <= nb_printer_handles)) {
908 ret = printer_handles[idx - 1];
910 LeaveCriticalSection(&printer_handles_cs);
911 return ret;
914 /******************************************************************
915 * get_opened_printer_name
916 * Get the pointer to the opened printer name referred by the handle
918 static LPCWSTR get_opened_printer_name(HANDLE hprn)
920 opened_printer_t *printer = get_opened_printer(hprn);
921 if(!printer) return NULL;
922 return printer->name;
925 /******************************************************************
926 * WINSPOOL_GetOpenedPrinterRegKey
929 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
931 LPCWSTR name = get_opened_printer_name(hPrinter);
932 DWORD ret;
933 HKEY hkeyPrinters;
935 if(!name) return ERROR_INVALID_HANDLE;
937 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
938 ERROR_SUCCESS)
939 return ret;
941 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
943 ERR("Can't find opened printer %s in registry\n",
944 debugstr_w(name));
945 RegCloseKey(hkeyPrinters);
946 return ERROR_INVALID_PRINTER_NAME; /* ? */
948 RegCloseKey(hkeyPrinters);
949 return ERROR_SUCCESS;
952 void WINSPOOL_LoadSystemPrinters(void)
954 HKEY hkey, hkeyPrinters;
955 HANDLE hprn;
956 DWORD needed, num, i;
957 WCHAR PrinterName[256];
958 BOOL done = FALSE;
960 /* This ensures that all printer entries have a valid Name value. If causes
961 problems later if they don't. If one is found to be missed we create one
962 and set it equal to the name of the key */
963 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
964 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
965 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
966 for(i = 0; i < num; i++) {
967 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
968 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
969 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
970 set_reg_szW(hkey, NameW, PrinterName);
972 RegCloseKey(hkey);
977 RegCloseKey(hkeyPrinters);
980 /* We want to avoid calling AddPrinter on printers as much as
981 possible, because on cups printers this will (eventually) lead
982 to a call to cupsGetPPD which takes forever, even with non-cups
983 printers AddPrinter takes a while. So we'll tag all printers that
984 were automatically added last time around, if they still exist
985 we'll leave them be otherwise we'll delete them. */
986 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
987 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
988 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
989 for(i = 0; i < num; i++) {
990 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
991 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
992 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
993 DWORD dw = 1;
994 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
995 RegCloseKey(hkey);
997 ClosePrinter(hprn);
1002 HeapFree(GetProcessHeap(), 0, pi);
1006 #ifdef SONAME_LIBCUPS
1007 done = CUPS_LoadPrinters();
1008 #endif
1010 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1011 PRINTCAP_LoadPrinters();
1013 /* Now enumerate the list again and delete any printers that are still tagged */
1014 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1015 if(needed) {
1016 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1017 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1018 for(i = 0; i < num; i++) {
1019 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1020 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1021 BOOL delete_driver = FALSE;
1022 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1023 DWORD dw, type, size = sizeof(dw);
1024 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1025 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1026 DeletePrinter(hprn);
1027 delete_driver = TRUE;
1029 RegCloseKey(hkey);
1031 ClosePrinter(hprn);
1032 if(delete_driver)
1033 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1038 HeapFree(GetProcessHeap(), 0, pi);
1041 return;
1045 /******************************************************************
1046 * get_job
1048 * Get the pointer to the specified job.
1049 * Should hold the printer_handles_cs before calling.
1051 static job_t *get_job(HANDLE hprn, DWORD JobId)
1053 opened_printer_t *printer = get_opened_printer(hprn);
1054 job_t *job;
1056 if(!printer) return NULL;
1057 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1059 if(job->job_id == JobId)
1060 return job;
1062 return NULL;
1065 /***********************************************************
1066 * DEVMODEcpyAtoW
1068 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1070 BOOL Formname;
1071 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1072 DWORD size;
1074 Formname = (dmA->dmSize > off_formname);
1075 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1076 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1077 dmW->dmDeviceName, CCHDEVICENAME);
1078 if(!Formname) {
1079 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1080 dmA->dmSize - CCHDEVICENAME);
1081 } else {
1082 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1083 off_formname - CCHDEVICENAME);
1084 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1085 dmW->dmFormName, CCHFORMNAME);
1086 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1087 (off_formname + CCHFORMNAME));
1089 dmW->dmSize = size;
1090 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1091 dmA->dmDriverExtra);
1092 return dmW;
1095 /***********************************************************
1096 * DEVMODEdupWtoA
1097 * Creates an ansi copy of supplied devmode
1099 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1101 LPDEVMODEA dmA;
1102 DWORD size;
1104 if (!dmW) return NULL;
1105 size = dmW->dmSize - CCHDEVICENAME -
1106 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1108 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1109 if (!dmA) return NULL;
1111 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1112 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1114 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1115 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1116 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1118 else
1120 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1121 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1122 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1123 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1125 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1128 dmA->dmSize = size;
1129 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1130 return dmA;
1133 /******************************************************************
1134 * convert_printerinfo_W_to_A [internal]
1137 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1138 DWORD level, DWORD outlen, DWORD numentries)
1140 DWORD id = 0;
1141 LPSTR ptr;
1142 INT len;
1144 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1146 len = pi_sizeof[level] * numentries;
1147 ptr = (LPSTR) out + len;
1148 outlen -= len;
1150 /* copy the numbers of all PRINTER_INFO_* first */
1151 memcpy(out, pPrintersW, len);
1153 while (id < numentries) {
1154 switch (level) {
1155 case 1:
1157 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1158 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1160 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1161 if (piW->pDescription) {
1162 piA->pDescription = ptr;
1163 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1164 ptr, outlen, NULL, NULL);
1165 ptr += len;
1166 outlen -= len;
1168 if (piW->pName) {
1169 piA->pName = ptr;
1170 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1171 ptr, outlen, NULL, NULL);
1172 ptr += len;
1173 outlen -= len;
1175 if (piW->pComment) {
1176 piA->pComment = ptr;
1177 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1178 ptr, outlen, NULL, NULL);
1179 ptr += len;
1180 outlen -= len;
1182 break;
1185 case 2:
1187 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1188 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1189 LPDEVMODEA dmA;
1191 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1192 if (piW->pServerName) {
1193 piA->pServerName = ptr;
1194 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1195 ptr, outlen, NULL, NULL);
1196 ptr += len;
1197 outlen -= len;
1199 if (piW->pPrinterName) {
1200 piA->pPrinterName = ptr;
1201 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1202 ptr, outlen, NULL, NULL);
1203 ptr += len;
1204 outlen -= len;
1206 if (piW->pShareName) {
1207 piA->pShareName = ptr;
1208 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1209 ptr, outlen, NULL, NULL);
1210 ptr += len;
1211 outlen -= len;
1213 if (piW->pPortName) {
1214 piA->pPortName = ptr;
1215 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1216 ptr, outlen, NULL, NULL);
1217 ptr += len;
1218 outlen -= len;
1220 if (piW->pDriverName) {
1221 piA->pDriverName = ptr;
1222 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1223 ptr, outlen, NULL, NULL);
1224 ptr += len;
1225 outlen -= len;
1227 if (piW->pComment) {
1228 piA->pComment = ptr;
1229 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1230 ptr, outlen, NULL, NULL);
1231 ptr += len;
1232 outlen -= len;
1234 if (piW->pLocation) {
1235 piA->pLocation = ptr;
1236 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1237 ptr, outlen, NULL, NULL);
1238 ptr += len;
1239 outlen -= len;
1242 dmA = DEVMODEdupWtoA(piW->pDevMode);
1243 if (dmA) {
1244 /* align DEVMODEA to a DWORD boundary */
1245 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1246 ptr += len;
1247 outlen -= len;
1249 piA->pDevMode = (LPDEVMODEA) ptr;
1250 len = dmA->dmSize + dmA->dmDriverExtra;
1251 memcpy(ptr, dmA, len);
1252 HeapFree(GetProcessHeap(), 0, dmA);
1254 ptr += len;
1255 outlen -= len;
1258 if (piW->pSepFile) {
1259 piA->pSepFile = ptr;
1260 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1261 ptr, outlen, NULL, NULL);
1262 ptr += len;
1263 outlen -= len;
1265 if (piW->pPrintProcessor) {
1266 piA->pPrintProcessor = ptr;
1267 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1268 ptr, outlen, NULL, NULL);
1269 ptr += len;
1270 outlen -= len;
1272 if (piW->pDatatype) {
1273 piA->pDatatype = ptr;
1274 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1275 ptr, outlen, NULL, NULL);
1276 ptr += len;
1277 outlen -= len;
1279 if (piW->pParameters) {
1280 piA->pParameters = ptr;
1281 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1282 ptr, outlen, NULL, NULL);
1283 ptr += len;
1284 outlen -= len;
1286 if (piW->pSecurityDescriptor) {
1287 piA->pSecurityDescriptor = NULL;
1288 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1290 break;
1293 case 4:
1295 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1296 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1298 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1300 if (piW->pPrinterName) {
1301 piA->pPrinterName = ptr;
1302 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1303 ptr, outlen, NULL, NULL);
1304 ptr += len;
1305 outlen -= len;
1307 if (piW->pServerName) {
1308 piA->pServerName = ptr;
1309 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1310 ptr, outlen, NULL, NULL);
1311 ptr += len;
1312 outlen -= len;
1314 break;
1317 case 5:
1319 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1320 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1322 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1324 if (piW->pPrinterName) {
1325 piA->pPrinterName = ptr;
1326 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1327 ptr, outlen, NULL, NULL);
1328 ptr += len;
1329 outlen -= len;
1331 if (piW->pPortName) {
1332 piA->pPortName = ptr;
1333 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1334 ptr, outlen, NULL, NULL);
1335 ptr += len;
1336 outlen -= len;
1338 break;
1341 case 6: /* 6A and 6W are the same structure */
1342 break;
1344 case 7:
1346 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1347 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1349 TRACE("(%u) #%u\n", level, id);
1350 if (piW->pszObjectGUID) {
1351 piA->pszObjectGUID = ptr;
1352 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1353 ptr, outlen, NULL, NULL);
1354 ptr += len;
1355 outlen -= len;
1357 break;
1360 case 9:
1362 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1363 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1364 LPDEVMODEA dmA;
1366 TRACE("(%u) #%u\n", level, id);
1367 dmA = DEVMODEdupWtoA(piW->pDevMode);
1368 if (dmA) {
1369 /* align DEVMODEA to a DWORD boundary */
1370 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1371 ptr += len;
1372 outlen -= len;
1374 piA->pDevMode = (LPDEVMODEA) ptr;
1375 len = dmA->dmSize + dmA->dmDriverExtra;
1376 memcpy(ptr, dmA, len);
1377 HeapFree(GetProcessHeap(), 0, dmA);
1379 ptr += len;
1380 outlen -= len;
1383 break;
1386 default:
1387 FIXME("for level %u\n", level);
1389 pPrintersW += pi_sizeof[level];
1390 out += pi_sizeof[level];
1391 id++;
1395 /******************************************************************
1396 * convert_driverinfo_W_to_A [internal]
1399 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1400 DWORD level, DWORD outlen, DWORD numentries)
1402 DWORD id = 0;
1403 LPSTR ptr;
1404 INT len;
1406 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1408 len = di_sizeof[level] * numentries;
1409 ptr = (LPSTR) out + len;
1410 outlen -= len;
1412 /* copy the numbers of all PRINTER_INFO_* first */
1413 memcpy(out, pDriversW, len);
1415 #define COPY_STRING(fld) \
1416 { if (diW->fld){ \
1417 diA->fld = ptr; \
1418 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1419 ptr += len; outlen -= len;\
1421 #define COPY_MULTIZ_STRING(fld) \
1422 { LPWSTR p = diW->fld; if (p){ \
1423 diA->fld = ptr; \
1424 do {\
1425 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1426 ptr += len; outlen -= len; p += len;\
1428 while(len > 1 && outlen > 0); \
1431 while (id < numentries)
1433 switch (level)
1435 case 1:
1437 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1438 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1440 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1442 COPY_STRING(pName);
1443 break;
1445 case 2:
1447 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1448 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1450 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1452 COPY_STRING(pName);
1453 COPY_STRING(pEnvironment);
1454 COPY_STRING(pDriverPath);
1455 COPY_STRING(pDataFile);
1456 COPY_STRING(pConfigFile);
1457 break;
1459 case 3:
1461 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1462 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1464 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1466 COPY_STRING(pName);
1467 COPY_STRING(pEnvironment);
1468 COPY_STRING(pDriverPath);
1469 COPY_STRING(pDataFile);
1470 COPY_STRING(pConfigFile);
1471 COPY_STRING(pHelpFile);
1472 COPY_MULTIZ_STRING(pDependentFiles);
1473 COPY_STRING(pMonitorName);
1474 COPY_STRING(pDefaultDataType);
1475 break;
1477 case 4:
1479 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1480 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1482 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1484 COPY_STRING(pName);
1485 COPY_STRING(pEnvironment);
1486 COPY_STRING(pDriverPath);
1487 COPY_STRING(pDataFile);
1488 COPY_STRING(pConfigFile);
1489 COPY_STRING(pHelpFile);
1490 COPY_MULTIZ_STRING(pDependentFiles);
1491 COPY_STRING(pMonitorName);
1492 COPY_STRING(pDefaultDataType);
1493 COPY_MULTIZ_STRING(pszzPreviousNames);
1494 break;
1496 case 5:
1498 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1499 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1501 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1503 COPY_STRING(pName);
1504 COPY_STRING(pEnvironment);
1505 COPY_STRING(pDriverPath);
1506 COPY_STRING(pDataFile);
1507 COPY_STRING(pConfigFile);
1508 break;
1510 case 6:
1512 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1513 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1515 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1517 COPY_STRING(pName);
1518 COPY_STRING(pEnvironment);
1519 COPY_STRING(pDriverPath);
1520 COPY_STRING(pDataFile);
1521 COPY_STRING(pConfigFile);
1522 COPY_STRING(pHelpFile);
1523 COPY_MULTIZ_STRING(pDependentFiles);
1524 COPY_STRING(pMonitorName);
1525 COPY_STRING(pDefaultDataType);
1526 COPY_MULTIZ_STRING(pszzPreviousNames);
1527 COPY_STRING(pszMfgName);
1528 COPY_STRING(pszOEMUrl);
1529 COPY_STRING(pszHardwareID);
1530 COPY_STRING(pszProvider);
1531 break;
1533 case 8:
1535 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1536 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1538 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1540 COPY_STRING(pName);
1541 COPY_STRING(pEnvironment);
1542 COPY_STRING(pDriverPath);
1543 COPY_STRING(pDataFile);
1544 COPY_STRING(pConfigFile);
1545 COPY_STRING(pHelpFile);
1546 COPY_MULTIZ_STRING(pDependentFiles);
1547 COPY_STRING(pMonitorName);
1548 COPY_STRING(pDefaultDataType);
1549 COPY_MULTIZ_STRING(pszzPreviousNames);
1550 COPY_STRING(pszMfgName);
1551 COPY_STRING(pszOEMUrl);
1552 COPY_STRING(pszHardwareID);
1553 COPY_STRING(pszProvider);
1554 COPY_STRING(pszPrintProcessor);
1555 COPY_STRING(pszVendorSetup);
1556 COPY_MULTIZ_STRING(pszzColorProfiles);
1557 COPY_STRING(pszInfPath);
1558 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1559 break;
1563 default:
1564 FIXME("for level %u\n", level);
1567 pDriversW += di_sizeof[level];
1568 out += di_sizeof[level];
1569 id++;
1572 #undef COPY_STRING
1573 #undef COPY_MULTIZ_STRING
1577 /***********************************************************
1578 * PRINTER_INFO_2AtoW
1579 * Creates a unicode copy of PRINTER_INFO_2A on heap
1581 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1583 LPPRINTER_INFO_2W piW;
1584 UNICODE_STRING usBuffer;
1586 if(!piA) return NULL;
1587 piW = HeapAlloc(heap, 0, sizeof(*piW));
1588 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1590 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1591 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1592 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1593 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1594 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1595 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1596 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1597 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1598 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1599 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1600 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1601 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1602 return piW;
1605 /***********************************************************
1606 * FREE_PRINTER_INFO_2W
1607 * Free PRINTER_INFO_2W and all strings
1609 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1611 if(!piW) return;
1613 HeapFree(heap,0,piW->pServerName);
1614 HeapFree(heap,0,piW->pPrinterName);
1615 HeapFree(heap,0,piW->pShareName);
1616 HeapFree(heap,0,piW->pPortName);
1617 HeapFree(heap,0,piW->pDriverName);
1618 HeapFree(heap,0,piW->pComment);
1619 HeapFree(heap,0,piW->pLocation);
1620 HeapFree(heap,0,piW->pDevMode);
1621 HeapFree(heap,0,piW->pSepFile);
1622 HeapFree(heap,0,piW->pPrintProcessor);
1623 HeapFree(heap,0,piW->pDatatype);
1624 HeapFree(heap,0,piW->pParameters);
1625 HeapFree(heap,0,piW);
1626 return;
1629 /******************************************************************
1630 * DeviceCapabilities [WINSPOOL.@]
1631 * DeviceCapabilitiesA [WINSPOOL.@]
1634 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1635 LPSTR pOutput, LPDEVMODEA lpdm)
1637 INT ret;
1639 if (!GDI_CallDeviceCapabilities16)
1641 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1642 (LPCSTR)104 );
1643 if (!GDI_CallDeviceCapabilities16) return -1;
1645 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1647 /* If DC_PAPERSIZE map POINT16s to POINTs */
1648 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1649 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1650 POINT *pt = (POINT *)pOutput;
1651 INT i;
1652 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1653 for(i = 0; i < ret; i++, pt++)
1655 pt->x = tmp[i].x;
1656 pt->y = tmp[i].y;
1658 HeapFree( GetProcessHeap(), 0, tmp );
1660 return ret;
1664 /*****************************************************************************
1665 * DeviceCapabilitiesW [WINSPOOL.@]
1667 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1670 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1671 WORD fwCapability, LPWSTR pOutput,
1672 const DEVMODEW *pDevMode)
1674 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1675 LPSTR pDeviceA = strdupWtoA(pDevice);
1676 LPSTR pPortA = strdupWtoA(pPort);
1677 INT ret;
1679 if(pOutput && (fwCapability == DC_BINNAMES ||
1680 fwCapability == DC_FILEDEPENDENCIES ||
1681 fwCapability == DC_PAPERNAMES)) {
1682 /* These need A -> W translation */
1683 INT size = 0, i;
1684 LPSTR pOutputA;
1685 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1686 dmA);
1687 if(ret == -1)
1688 return ret;
1689 switch(fwCapability) {
1690 case DC_BINNAMES:
1691 size = 24;
1692 break;
1693 case DC_PAPERNAMES:
1694 case DC_FILEDEPENDENCIES:
1695 size = 64;
1696 break;
1698 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1699 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1700 dmA);
1701 for(i = 0; i < ret; i++)
1702 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1703 pOutput + (i * size), size);
1704 HeapFree(GetProcessHeap(), 0, pOutputA);
1705 } else {
1706 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1707 (LPSTR)pOutput, dmA);
1709 HeapFree(GetProcessHeap(),0,pPortA);
1710 HeapFree(GetProcessHeap(),0,pDeviceA);
1711 HeapFree(GetProcessHeap(),0,dmA);
1712 return ret;
1715 /******************************************************************
1716 * DocumentPropertiesA [WINSPOOL.@]
1718 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1720 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1721 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1722 LPDEVMODEA pDevModeInput,DWORD fMode )
1724 LPSTR lpName = pDeviceName;
1725 static CHAR port[] = "LPT1:";
1726 LONG ret;
1728 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1729 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1732 if(!pDeviceName) {
1733 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1734 if(!lpNameW) {
1735 ERR("no name from hPrinter?\n");
1736 SetLastError(ERROR_INVALID_HANDLE);
1737 return -1;
1739 lpName = strdupWtoA(lpNameW);
1742 if (!GDI_CallExtDeviceMode16)
1744 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1745 (LPCSTR)102 );
1746 if (!GDI_CallExtDeviceMode16) {
1747 ERR("No CallExtDeviceMode16?\n");
1748 return -1;
1751 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1752 pDevModeInput, NULL, fMode);
1754 if(!pDeviceName)
1755 HeapFree(GetProcessHeap(),0,lpName);
1756 return ret;
1760 /*****************************************************************************
1761 * DocumentPropertiesW (WINSPOOL.@)
1763 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1765 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1766 LPWSTR pDeviceName,
1767 LPDEVMODEW pDevModeOutput,
1768 LPDEVMODEW pDevModeInput, DWORD fMode)
1771 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1772 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1773 LPDEVMODEA pDevModeOutputA = NULL;
1774 LONG ret;
1776 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1777 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1778 fMode);
1779 if(pDevModeOutput) {
1780 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1781 if(ret < 0) return ret;
1782 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1784 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1785 pDevModeInputA, fMode);
1786 if(pDevModeOutput) {
1787 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1788 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1790 if(fMode == 0 && ret > 0)
1791 ret += (CCHDEVICENAME + CCHFORMNAME);
1792 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1793 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1794 return ret;
1797 /*****************************************************************************
1798 * IsValidDevmodeA [WINSPOOL.@]
1800 * Validate a DEVMODE structure and fix errors if possible.
1803 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1805 FIXME("(%p,%ld): stub\n", pDevMode, size);
1807 if(!pDevMode)
1808 return FALSE;
1810 return TRUE;
1813 /*****************************************************************************
1814 * IsValidDevmodeW [WINSPOOL.@]
1816 * Validate a DEVMODE structure and fix errors if possible.
1819 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1821 FIXME("(%p,%ld): stub\n", pDevMode, size);
1823 if(!pDevMode)
1824 return FALSE;
1826 return TRUE;
1829 /******************************************************************
1830 * OpenPrinterA [WINSPOOL.@]
1832 * See OpenPrinterW.
1835 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1836 LPPRINTER_DEFAULTSA pDefault)
1838 UNICODE_STRING lpPrinterNameW;
1839 UNICODE_STRING usBuffer;
1840 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1841 PWSTR pwstrPrinterNameW;
1842 BOOL ret;
1844 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1846 if(pDefault) {
1847 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1848 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1849 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1850 pDefaultW = &DefaultW;
1852 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1853 if(pDefault) {
1854 RtlFreeUnicodeString(&usBuffer);
1855 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1857 RtlFreeUnicodeString(&lpPrinterNameW);
1858 return ret;
1861 /******************************************************************
1862 * OpenPrinterW [WINSPOOL.@]
1864 * Open a Printer / Printserver or a Printer-Object
1866 * PARAMS
1867 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1868 * phPrinter [O] The resulting Handle is stored here
1869 * pDefault [I] PTR to Default Printer Settings or NULL
1871 * RETURNS
1872 * Success: TRUE
1873 * Failure: FALSE
1875 * NOTES
1876 * lpPrinterName is one of:
1877 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1878 *| Printer: "PrinterName"
1879 *| Printer-Object: "PrinterName,Job xxx"
1880 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1881 *| XcvPort: "Servername,XcvPort PortName"
1883 * BUGS
1884 *| Printer-Object not supported
1885 *| pDefaults is ignored
1888 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1891 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1892 if (pDefault) {
1893 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1894 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1897 if(!phPrinter) {
1898 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1899 SetLastError(ERROR_INVALID_PARAMETER);
1900 return FALSE;
1903 /* Get the unique handle of the printer or Printserver */
1904 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1905 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1906 return (*phPrinter != 0);
1909 /******************************************************************
1910 * AddMonitorA [WINSPOOL.@]
1912 * See AddMonitorW.
1915 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1917 LPWSTR nameW = NULL;
1918 INT len;
1919 BOOL res;
1920 LPMONITOR_INFO_2A mi2a;
1921 MONITOR_INFO_2W mi2w;
1923 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1924 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1925 debugstr_a(mi2a ? mi2a->pName : NULL),
1926 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1927 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1929 if (Level != 2) {
1930 SetLastError(ERROR_INVALID_LEVEL);
1931 return FALSE;
1934 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1935 if (mi2a == NULL) {
1936 return FALSE;
1939 if (pName) {
1940 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1941 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1942 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1945 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1946 if (mi2a->pName) {
1947 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1948 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1949 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1951 if (mi2a->pEnvironment) {
1952 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1953 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1954 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1956 if (mi2a->pDLLName) {
1957 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1958 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1959 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1962 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1964 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1965 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1966 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1968 HeapFree(GetProcessHeap(), 0, nameW);
1969 return (res);
1972 /******************************************************************************
1973 * AddMonitorW [WINSPOOL.@]
1975 * Install a Printmonitor
1977 * PARAMS
1978 * pName [I] Servername or NULL (local Computer)
1979 * Level [I] Structure-Level (Must be 2)
1980 * pMonitors [I] PTR to MONITOR_INFO_2
1982 * RETURNS
1983 * Success: TRUE
1984 * Failure: FALSE
1986 * NOTES
1987 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1990 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1992 LPMONITOR_INFO_2W mi2w;
1994 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1995 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1996 debugstr_w(mi2w ? mi2w->pName : NULL),
1997 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1998 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2000 if ((backend == NULL) && !load_backend()) return FALSE;
2002 if (Level != 2) {
2003 SetLastError(ERROR_INVALID_LEVEL);
2004 return FALSE;
2007 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2008 if (mi2w == NULL) {
2009 return FALSE;
2012 return backend->fpAddMonitor(pName, Level, pMonitors);
2015 /******************************************************************
2016 * DeletePrinterDriverA [WINSPOOL.@]
2019 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2021 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2024 /******************************************************************
2025 * DeletePrinterDriverW [WINSPOOL.@]
2028 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2030 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2033 /******************************************************************
2034 * DeleteMonitorA [WINSPOOL.@]
2036 * See DeleteMonitorW.
2039 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2041 LPWSTR nameW = NULL;
2042 LPWSTR EnvironmentW = NULL;
2043 LPWSTR MonitorNameW = NULL;
2044 BOOL res;
2045 INT len;
2047 if (pName) {
2048 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2049 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2050 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2053 if (pEnvironment) {
2054 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2055 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2056 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2058 if (pMonitorName) {
2059 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2060 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2061 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2064 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2066 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2067 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2068 HeapFree(GetProcessHeap(), 0, nameW);
2069 return (res);
2072 /******************************************************************
2073 * DeleteMonitorW [WINSPOOL.@]
2075 * Delete a specific Printmonitor from a Printing-Environment
2077 * PARAMS
2078 * pName [I] Servername or NULL (local Computer)
2079 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2080 * pMonitorName [I] Name of the Monitor, that should be deleted
2082 * RETURNS
2083 * Success: TRUE
2084 * Failure: FALSE
2086 * NOTES
2087 * pEnvironment is ignored in Windows for the local Computer.
2090 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2093 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2094 debugstr_w(pMonitorName));
2096 if ((backend == NULL) && !load_backend()) return FALSE;
2098 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2102 /******************************************************************
2103 * DeletePortA [WINSPOOL.@]
2105 * See DeletePortW.
2108 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2110 LPWSTR nameW = NULL;
2111 LPWSTR portW = NULL;
2112 INT len;
2113 DWORD res;
2115 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2117 /* convert servername to unicode */
2118 if (pName) {
2119 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2120 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2121 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2124 /* convert portname to unicode */
2125 if (pPortName) {
2126 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2127 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2128 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2131 res = DeletePortW(nameW, hWnd, portW);
2132 HeapFree(GetProcessHeap(), 0, nameW);
2133 HeapFree(GetProcessHeap(), 0, portW);
2134 return res;
2137 /******************************************************************
2138 * DeletePortW [WINSPOOL.@]
2140 * Delete a specific Port
2142 * PARAMS
2143 * pName [I] Servername or NULL (local Computer)
2144 * hWnd [I] Handle to parent Window for the Dialog-Box
2145 * pPortName [I] Name of the Port, that should be deleted
2147 * RETURNS
2148 * Success: TRUE
2149 * Failure: FALSE
2152 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2154 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2156 if ((backend == NULL) && !load_backend()) return FALSE;
2158 if (!pPortName) {
2159 SetLastError(RPC_X_NULL_REF_POINTER);
2160 return FALSE;
2163 return backend->fpDeletePort(pName, hWnd, pPortName);
2166 /******************************************************************************
2167 * SetPrinterW [WINSPOOL.@]
2169 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2171 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2172 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2173 return FALSE;
2176 /******************************************************************************
2177 * WritePrinter [WINSPOOL.@]
2179 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2181 opened_printer_t *printer;
2182 BOOL ret = FALSE;
2184 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2186 EnterCriticalSection(&printer_handles_cs);
2187 printer = get_opened_printer(hPrinter);
2188 if(!printer)
2190 SetLastError(ERROR_INVALID_HANDLE);
2191 goto end;
2194 if(!printer->doc)
2196 SetLastError(ERROR_SPL_NO_STARTDOC);
2197 goto end;
2200 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2201 end:
2202 LeaveCriticalSection(&printer_handles_cs);
2203 return ret;
2206 /*****************************************************************************
2207 * AddFormA [WINSPOOL.@]
2209 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2211 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2212 return 1;
2215 /*****************************************************************************
2216 * AddFormW [WINSPOOL.@]
2218 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2220 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2221 return 1;
2224 /*****************************************************************************
2225 * AddJobA [WINSPOOL.@]
2227 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2229 BOOL ret;
2230 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2231 DWORD needed;
2233 if(Level != 1) {
2234 SetLastError(ERROR_INVALID_LEVEL);
2235 return FALSE;
2238 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2240 if(ret) {
2241 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2242 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2243 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2244 if(*pcbNeeded > cbBuf) {
2245 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2246 ret = FALSE;
2247 } else {
2248 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2249 addjobA->JobId = addjobW->JobId;
2250 addjobA->Path = (char *)(addjobA + 1);
2251 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2254 return ret;
2257 /*****************************************************************************
2258 * AddJobW [WINSPOOL.@]
2260 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2262 opened_printer_t *printer;
2263 job_t *job;
2264 BOOL ret = FALSE;
2265 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2266 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2267 WCHAR path[MAX_PATH], filename[MAX_PATH];
2268 DWORD len;
2269 ADDJOB_INFO_1W *addjob;
2271 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2273 EnterCriticalSection(&printer_handles_cs);
2275 printer = get_opened_printer(hPrinter);
2277 if(!printer) {
2278 SetLastError(ERROR_INVALID_HANDLE);
2279 goto end;
2282 if(Level != 1) {
2283 SetLastError(ERROR_INVALID_LEVEL);
2284 goto end;
2287 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2288 if(!job)
2289 goto end;
2291 job->job_id = InterlockedIncrement(&next_job_id);
2293 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2294 if(path[len - 1] != '\\')
2295 path[len++] = '\\';
2296 memcpy(path + len, spool_path, sizeof(spool_path));
2297 sprintfW(filename, fmtW, path, job->job_id);
2299 len = strlenW(filename);
2300 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2301 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2302 job->document_title = strdupW(default_doc_title);
2303 job->printer_name = strdupW(printer->name);
2304 job->devmode = NULL;
2305 list_add_tail(&printer->queue->jobs, &job->entry);
2307 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2308 if(*pcbNeeded <= cbBuf) {
2309 addjob = (ADDJOB_INFO_1W*)pData;
2310 addjob->JobId = job->job_id;
2311 addjob->Path = (WCHAR *)(addjob + 1);
2312 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2313 ret = TRUE;
2314 } else
2315 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2317 end:
2318 LeaveCriticalSection(&printer_handles_cs);
2319 return ret;
2322 /*****************************************************************************
2323 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2325 * Return the PATH for the Print-Processors
2327 * See GetPrintProcessorDirectoryW.
2331 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2332 DWORD level, LPBYTE Info,
2333 DWORD cbBuf, LPDWORD pcbNeeded)
2335 LPWSTR serverW = NULL;
2336 LPWSTR envW = NULL;
2337 BOOL ret;
2338 INT len;
2340 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2341 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2344 if (server) {
2345 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2346 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2347 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2350 if (env) {
2351 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2352 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2353 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2356 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2357 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2359 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2360 cbBuf, pcbNeeded);
2362 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2363 cbBuf, NULL, NULL) > 0;
2366 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2367 HeapFree(GetProcessHeap(), 0, envW);
2368 HeapFree(GetProcessHeap(), 0, serverW);
2369 return ret;
2372 /*****************************************************************************
2373 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2375 * Return the PATH for the Print-Processors
2377 * PARAMS
2378 * server [I] Servername (NT only) or NULL (local Computer)
2379 * env [I] Printing-Environment (see below) or NULL (Default)
2380 * level [I] Structure-Level (must be 1)
2381 * Info [O] PTR to Buffer that receives the Result
2382 * cbBuf [I] Size of Buffer at "Info"
2383 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2384 * required for the Buffer at "Info"
2386 * RETURNS
2387 * Success: TRUE and in pcbNeeded the Bytes used in Info
2388 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2389 * if cbBuf is too small
2391 * Native Values returned in Info on Success:
2392 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2393 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2394 *| win9x(Windows 4.0): "%winsysdir%"
2396 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2398 * BUGS
2399 * Only NULL or "" is supported for server
2402 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2403 DWORD level, LPBYTE Info,
2404 DWORD cbBuf, LPDWORD pcbNeeded)
2407 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2408 Info, cbBuf, pcbNeeded);
2410 if ((backend == NULL) && !load_backend()) return FALSE;
2412 if (level != 1) {
2413 /* (Level != 1) is ignored in win9x */
2414 SetLastError(ERROR_INVALID_LEVEL);
2415 return FALSE;
2418 if (pcbNeeded == NULL) {
2419 /* (pcbNeeded == NULL) is ignored in win9x */
2420 SetLastError(RPC_X_NULL_REF_POINTER);
2421 return FALSE;
2424 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2427 /*****************************************************************************
2428 * WINSPOOL_OpenDriverReg [internal]
2430 * opens the registry for the printer drivers depending on the given input
2431 * variable pEnvironment
2433 * RETURNS:
2434 * the opened hkey on success
2435 * NULL on error
2437 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2439 HKEY retval = NULL;
2440 LPWSTR buffer;
2441 const printenv_t * env;
2443 TRACE("(%s)\n", debugstr_w(pEnvironment));
2445 env = validate_envW(pEnvironment);
2446 if (!env) return NULL;
2448 buffer = HeapAlloc( GetProcessHeap(), 0,
2449 (strlenW(DriversW) + strlenW(env->envname) +
2450 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2451 if(buffer) {
2452 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2453 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2454 HeapFree(GetProcessHeap(), 0, buffer);
2456 return retval;
2459 /*****************************************************************************
2460 * set_devices_and_printerports [internal]
2462 * set the [Devices] and [PrinterPorts] entries for a printer.
2465 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2467 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2468 WCHAR *devline;
2469 HKEY hkey;
2471 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2473 /* FIXME: the driver must change to "winspool" */
2474 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2475 if (devline) {
2476 lstrcpyW(devline, driver_nt);
2477 lstrcatW(devline, commaW);
2478 lstrcatW(devline, pi->pPortName);
2480 TRACE("using %s\n", debugstr_w(devline));
2481 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2482 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2483 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2484 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2485 RegCloseKey(hkey);
2488 lstrcatW(devline, timeout_15_45);
2489 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2490 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2491 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2492 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2493 RegCloseKey(hkey);
2495 HeapFree(GetProcessHeap(), 0, devline);
2499 /*****************************************************************************
2500 * AddPrinterW [WINSPOOL.@]
2502 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2504 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2505 LPDEVMODEA dmA;
2506 LPDEVMODEW dmW;
2507 HANDLE retval;
2508 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2509 LONG size;
2510 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2511 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2512 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2513 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2514 statusW[] = {'S','t','a','t','u','s',0},
2515 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2517 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2519 if(pName != NULL) {
2520 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2521 SetLastError(ERROR_INVALID_PARAMETER);
2522 return 0;
2524 if(Level != 2) {
2525 ERR("Level = %d, unsupported!\n", Level);
2526 SetLastError(ERROR_INVALID_LEVEL);
2527 return 0;
2529 if(!pPrinter) {
2530 SetLastError(ERROR_INVALID_PARAMETER);
2531 return 0;
2533 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2534 ERROR_SUCCESS) {
2535 ERR("Can't create Printers key\n");
2536 return 0;
2538 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2539 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2540 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2541 RegCloseKey(hkeyPrinter);
2542 RegCloseKey(hkeyPrinters);
2543 return 0;
2545 RegCloseKey(hkeyPrinter);
2547 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2548 if(!hkeyDrivers) {
2549 ERR("Can't create Drivers key\n");
2550 RegCloseKey(hkeyPrinters);
2551 return 0;
2553 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2554 ERROR_SUCCESS) {
2555 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2556 RegCloseKey(hkeyPrinters);
2557 RegCloseKey(hkeyDrivers);
2558 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2559 return 0;
2561 RegCloseKey(hkeyDriver);
2562 RegCloseKey(hkeyDrivers);
2564 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2565 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2566 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2567 RegCloseKey(hkeyPrinters);
2568 return 0;
2571 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2572 ERROR_SUCCESS) {
2573 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2574 SetLastError(ERROR_INVALID_PRINTER_NAME);
2575 RegCloseKey(hkeyPrinters);
2576 return 0;
2579 set_devices_and_printerports(pi);
2580 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2581 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2582 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2584 /* See if we can load the driver. We may need the devmode structure anyway
2586 * FIXME:
2587 * Note that DocumentPropertiesW will briefly try to open the printer we
2588 * just create to find a DEVMODEA struct (it will use the WINEPS default
2589 * one in case it is not there, so we are ok).
2591 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2593 if(size < 0) {
2594 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2595 size = sizeof(DEVMODEW);
2597 if(pi->pDevMode)
2598 dmW = pi->pDevMode;
2599 else
2601 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2602 dmW->dmSize = size;
2603 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2605 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2606 HeapFree(GetProcessHeap(),0,dmW);
2607 dmW=NULL;
2609 else
2611 /* set devmode to printer name */
2612 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2616 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2617 and we support these drivers. NT writes DEVMODEW so somehow
2618 we'll need to distinguish between these when we support NT
2619 drivers */
2620 if (dmW)
2622 dmA = DEVMODEdupWtoA(dmW);
2623 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2624 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2625 HeapFree(GetProcessHeap(), 0, dmA);
2626 if(!pi->pDevMode)
2627 HeapFree(GetProcessHeap(), 0, dmW);
2629 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2630 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2631 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2632 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2634 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2635 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2636 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2637 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2638 (LPBYTE)&pi->Priority, sizeof(DWORD));
2639 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2640 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2641 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2642 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2643 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2644 (LPBYTE)&pi->Status, sizeof(DWORD));
2645 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2646 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2648 RegCloseKey(hkeyPrinter);
2649 RegCloseKey(hkeyPrinters);
2650 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2651 ERR("OpenPrinter failing\n");
2652 return 0;
2654 return retval;
2657 /*****************************************************************************
2658 * AddPrinterA [WINSPOOL.@]
2660 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2662 UNICODE_STRING pNameW;
2663 PWSTR pwstrNameW;
2664 PRINTER_INFO_2W *piW;
2665 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2666 HANDLE ret;
2668 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2669 if(Level != 2) {
2670 ERR("Level = %d, unsupported!\n", Level);
2671 SetLastError(ERROR_INVALID_LEVEL);
2672 return 0;
2674 pwstrNameW = asciitounicode(&pNameW,pName);
2675 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2677 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2679 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2680 RtlFreeUnicodeString(&pNameW);
2681 return ret;
2685 /*****************************************************************************
2686 * ClosePrinter [WINSPOOL.@]
2688 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2690 UINT_PTR i = (UINT_PTR)hPrinter;
2691 opened_printer_t *printer = NULL;
2692 BOOL ret = FALSE;
2694 TRACE("(%p)\n", hPrinter);
2696 EnterCriticalSection(&printer_handles_cs);
2698 if ((i > 0) && (i <= nb_printer_handles))
2699 printer = printer_handles[i - 1];
2702 if(printer)
2704 struct list *cursor, *cursor2;
2706 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2708 if (printer->backend_printer) {
2709 backend->fpClosePrinter(printer->backend_printer);
2712 if(printer->doc)
2713 EndDocPrinter(hPrinter);
2715 if(InterlockedDecrement(&printer->queue->ref) == 0)
2717 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2719 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2720 ScheduleJob(hPrinter, job->job_id);
2722 HeapFree(GetProcessHeap(), 0, printer->queue);
2725 HeapFree(GetProcessHeap(), 0, printer->printername);
2726 HeapFree(GetProcessHeap(), 0, printer->name);
2727 HeapFree(GetProcessHeap(), 0, printer);
2728 printer_handles[i - 1] = NULL;
2729 ret = TRUE;
2731 LeaveCriticalSection(&printer_handles_cs);
2732 return ret;
2735 /*****************************************************************************
2736 * DeleteFormA [WINSPOOL.@]
2738 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2740 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2741 return 1;
2744 /*****************************************************************************
2745 * DeleteFormW [WINSPOOL.@]
2747 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2749 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2750 return 1;
2753 /*****************************************************************************
2754 * DeletePrinter [WINSPOOL.@]
2756 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2758 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2759 HKEY hkeyPrinters, hkey;
2761 if(!lpNameW) {
2762 SetLastError(ERROR_INVALID_HANDLE);
2763 return FALSE;
2765 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2766 RegDeleteTreeW(hkeyPrinters, lpNameW);
2767 RegCloseKey(hkeyPrinters);
2769 WriteProfileStringW(devicesW, lpNameW, NULL);
2770 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2772 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2773 RegDeleteValueW(hkey, lpNameW);
2774 RegCloseKey(hkey);
2777 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2778 RegDeleteValueW(hkey, lpNameW);
2779 RegCloseKey(hkey);
2781 return TRUE;
2784 /*****************************************************************************
2785 * SetPrinterA [WINSPOOL.@]
2787 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2788 DWORD Command)
2790 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2791 return FALSE;
2794 /*****************************************************************************
2795 * SetJobA [WINSPOOL.@]
2797 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2798 LPBYTE pJob, DWORD Command)
2800 BOOL ret;
2801 LPBYTE JobW;
2802 UNICODE_STRING usBuffer;
2804 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2806 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2807 are all ignored by SetJob, so we don't bother copying them */
2808 switch(Level)
2810 case 0:
2811 JobW = NULL;
2812 break;
2813 case 1:
2815 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2816 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2818 JobW = (LPBYTE)info1W;
2819 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2820 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2821 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2822 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2823 info1W->Status = info1A->Status;
2824 info1W->Priority = info1A->Priority;
2825 info1W->Position = info1A->Position;
2826 info1W->PagesPrinted = info1A->PagesPrinted;
2827 break;
2829 case 2:
2831 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2832 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2834 JobW = (LPBYTE)info2W;
2835 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2836 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2837 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2838 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2839 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2840 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2841 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2842 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2843 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2844 info2W->Status = info2A->Status;
2845 info2W->Priority = info2A->Priority;
2846 info2W->Position = info2A->Position;
2847 info2W->StartTime = info2A->StartTime;
2848 info2W->UntilTime = info2A->UntilTime;
2849 info2W->PagesPrinted = info2A->PagesPrinted;
2850 break;
2852 case 3:
2853 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2854 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2855 break;
2856 default:
2857 SetLastError(ERROR_INVALID_LEVEL);
2858 return FALSE;
2861 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2863 switch(Level)
2865 case 1:
2867 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2868 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2869 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2870 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2871 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2872 break;
2874 case 2:
2876 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2877 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2878 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2879 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2880 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2881 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2882 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2883 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2884 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2885 break;
2888 HeapFree(GetProcessHeap(), 0, JobW);
2890 return ret;
2893 /*****************************************************************************
2894 * SetJobW [WINSPOOL.@]
2896 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2897 LPBYTE pJob, DWORD Command)
2899 BOOL ret = FALSE;
2900 job_t *job;
2902 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2903 FIXME("Ignoring everything other than document title\n");
2905 EnterCriticalSection(&printer_handles_cs);
2906 job = get_job(hPrinter, JobId);
2907 if(!job)
2908 goto end;
2910 switch(Level)
2912 case 0:
2913 break;
2914 case 1:
2916 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2917 HeapFree(GetProcessHeap(), 0, job->document_title);
2918 job->document_title = strdupW(info1->pDocument);
2919 break;
2921 case 2:
2923 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2924 HeapFree(GetProcessHeap(), 0, job->document_title);
2925 job->document_title = strdupW(info2->pDocument);
2926 HeapFree(GetProcessHeap(), 0, job->devmode);
2927 job->devmode = dup_devmode( info2->pDevMode );
2928 break;
2930 case 3:
2931 break;
2932 default:
2933 SetLastError(ERROR_INVALID_LEVEL);
2934 goto end;
2936 ret = TRUE;
2937 end:
2938 LeaveCriticalSection(&printer_handles_cs);
2939 return ret;
2942 /*****************************************************************************
2943 * EndDocPrinter [WINSPOOL.@]
2945 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2947 opened_printer_t *printer;
2948 BOOL ret = FALSE;
2949 TRACE("(%p)\n", hPrinter);
2951 EnterCriticalSection(&printer_handles_cs);
2953 printer = get_opened_printer(hPrinter);
2954 if(!printer)
2956 SetLastError(ERROR_INVALID_HANDLE);
2957 goto end;
2960 if(!printer->doc)
2962 SetLastError(ERROR_SPL_NO_STARTDOC);
2963 goto end;
2966 CloseHandle(printer->doc->hf);
2967 ScheduleJob(hPrinter, printer->doc->job_id);
2968 HeapFree(GetProcessHeap(), 0, printer->doc);
2969 printer->doc = NULL;
2970 ret = TRUE;
2971 end:
2972 LeaveCriticalSection(&printer_handles_cs);
2973 return ret;
2976 /*****************************************************************************
2977 * EndPagePrinter [WINSPOOL.@]
2979 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2981 FIXME("(%p): stub\n", hPrinter);
2982 return TRUE;
2985 /*****************************************************************************
2986 * StartDocPrinterA [WINSPOOL.@]
2988 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2990 UNICODE_STRING usBuffer;
2991 DOC_INFO_2W doc2W;
2992 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2993 DWORD ret;
2995 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2996 or one (DOC_INFO_3) extra DWORDs */
2998 switch(Level) {
2999 case 2:
3000 doc2W.JobId = doc2->JobId;
3001 /* fall through */
3002 case 3:
3003 doc2W.dwMode = doc2->dwMode;
3004 /* fall through */
3005 case 1:
3006 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3007 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3008 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3009 break;
3011 default:
3012 SetLastError(ERROR_INVALID_LEVEL);
3013 return FALSE;
3016 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3018 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3019 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3020 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3022 return ret;
3025 /*****************************************************************************
3026 * StartDocPrinterW [WINSPOOL.@]
3028 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3030 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3031 opened_printer_t *printer;
3032 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3033 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3034 JOB_INFO_1W job_info;
3035 DWORD needed, ret = 0;
3036 HANDLE hf;
3037 WCHAR *filename;
3038 job_t *job;
3040 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3041 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3042 debugstr_w(doc->pDatatype));
3044 if(Level < 1 || Level > 3)
3046 SetLastError(ERROR_INVALID_LEVEL);
3047 return 0;
3050 EnterCriticalSection(&printer_handles_cs);
3051 printer = get_opened_printer(hPrinter);
3052 if(!printer)
3054 SetLastError(ERROR_INVALID_HANDLE);
3055 goto end;
3058 if(printer->doc)
3060 SetLastError(ERROR_INVALID_PRINTER_STATE);
3061 goto end;
3064 /* Even if we're printing to a file we still add a print job, we'll
3065 just ignore the spool file name */
3067 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3069 ERR("AddJob failed gle %u\n", GetLastError());
3070 goto end;
3073 /* use pOutputFile only, when it is a real filename */
3074 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3075 filename = doc->pOutputFile;
3076 else
3077 filename = addjob->Path;
3079 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3080 if(hf == INVALID_HANDLE_VALUE)
3081 goto end;
3083 memset(&job_info, 0, sizeof(job_info));
3084 job_info.pDocument = doc->pDocName;
3085 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3087 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3088 printer->doc->hf = hf;
3089 ret = printer->doc->job_id = addjob->JobId;
3090 job = get_job(hPrinter, ret);
3091 job->portname = strdupW(doc->pOutputFile);
3093 end:
3094 LeaveCriticalSection(&printer_handles_cs);
3096 return ret;
3099 /*****************************************************************************
3100 * StartPagePrinter [WINSPOOL.@]
3102 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3104 FIXME("(%p): stub\n", hPrinter);
3105 return TRUE;
3108 /*****************************************************************************
3109 * GetFormA [WINSPOOL.@]
3111 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3112 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3114 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3115 Level,pForm,cbBuf,pcbNeeded);
3116 return FALSE;
3119 /*****************************************************************************
3120 * GetFormW [WINSPOOL.@]
3122 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3123 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3125 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3126 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3127 return FALSE;
3130 /*****************************************************************************
3131 * SetFormA [WINSPOOL.@]
3133 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3134 LPBYTE pForm)
3136 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3137 return FALSE;
3140 /*****************************************************************************
3141 * SetFormW [WINSPOOL.@]
3143 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3144 LPBYTE pForm)
3146 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3147 return FALSE;
3150 /*****************************************************************************
3151 * ReadPrinter [WINSPOOL.@]
3153 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3154 LPDWORD pNoBytesRead)
3156 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3157 return FALSE;
3160 /*****************************************************************************
3161 * ResetPrinterA [WINSPOOL.@]
3163 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3165 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3166 return FALSE;
3169 /*****************************************************************************
3170 * ResetPrinterW [WINSPOOL.@]
3172 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3174 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3175 return FALSE;
3178 /*****************************************************************************
3179 * WINSPOOL_GetDWORDFromReg
3181 * Return DWORD associated with ValueName from hkey.
3183 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3185 DWORD sz = sizeof(DWORD), type, value = 0;
3186 LONG ret;
3188 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3190 if(ret != ERROR_SUCCESS) {
3191 WARN("Got ret = %d on name %s\n", ret, ValueName);
3192 return 0;
3194 if(type != REG_DWORD) {
3195 ERR("Got type %d\n", type);
3196 return 0;
3198 return value;
3202 /*****************************************************************************
3203 * get_filename_from_reg [internal]
3205 * Get ValueName from hkey storing result in out
3206 * when the Value in the registry has only a filename, use driverdir as prefix
3207 * outlen is space left in out
3208 * String is stored either as unicode or ascii
3212 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3213 LPBYTE out, DWORD outlen, LPDWORD needed)
3215 WCHAR filename[MAX_PATH];
3216 DWORD size;
3217 DWORD type;
3218 LONG ret;
3219 LPWSTR buffer = filename;
3220 LPWSTR ptr;
3222 *needed = 0;
3223 size = sizeof(filename);
3224 buffer[0] = '\0';
3225 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3226 if (ret == ERROR_MORE_DATA) {
3227 TRACE("need dynamic buffer: %u\n", size);
3228 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3229 if (!buffer) {
3230 /* No Memory is bad */
3231 return FALSE;
3233 buffer[0] = '\0';
3234 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3237 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3238 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3239 return FALSE;
3242 ptr = buffer;
3243 while (ptr) {
3244 /* do we have a full path ? */
3245 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3246 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3248 if (!ret) {
3249 /* we must build the full Path */
3250 *needed += dirlen;
3251 if ((out) && (outlen > dirlen)) {
3252 lstrcpyW((LPWSTR)out, driverdir);
3253 out += dirlen;
3254 outlen -= dirlen;
3256 else
3257 out = NULL;
3260 /* write the filename */
3261 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3262 if ((out) && (outlen >= size)) {
3263 lstrcpyW((LPWSTR)out, ptr);
3264 out += size;
3265 outlen -= size;
3267 else
3268 out = NULL;
3269 *needed += size;
3270 ptr += lstrlenW(ptr)+1;
3271 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3274 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3276 /* write the multisz-termination */
3277 if (type == REG_MULTI_SZ) {
3278 size = sizeof(WCHAR);
3280 *needed += size;
3281 if (out && (outlen >= size)) {
3282 memset (out, 0, size);
3285 return TRUE;
3288 /*****************************************************************************
3289 * WINSPOOL_GetStringFromReg
3291 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3292 * String is stored as unicode.
3294 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3295 DWORD buflen, DWORD *needed)
3297 DWORD sz = buflen, type;
3298 LONG ret;
3300 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3301 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3302 WARN("Got ret = %d\n", ret);
3303 *needed = 0;
3304 return FALSE;
3306 /* add space for terminating '\0' */
3307 sz += sizeof(WCHAR);
3308 *needed = sz;
3310 if (ptr)
3311 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3313 return TRUE;
3316 /*****************************************************************************
3317 * WINSPOOL_GetDefaultDevMode
3319 * Get a default DevMode values for wineps.
3320 * FIXME - use ppd.
3323 static void WINSPOOL_GetDefaultDevMode(
3324 LPBYTE ptr,
3325 DWORD buflen, DWORD *needed)
3327 DEVMODEW dm;
3328 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3330 /* fill default DEVMODE - should be read from ppd... */
3331 ZeroMemory( &dm, sizeof(dm) );
3332 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3333 dm.dmSpecVersion = DM_SPECVERSION;
3334 dm.dmDriverVersion = 1;
3335 dm.dmSize = sizeof(DEVMODEW);
3336 dm.dmDriverExtra = 0;
3337 dm.dmFields =
3338 DM_ORIENTATION | DM_PAPERSIZE |
3339 DM_PAPERLENGTH | DM_PAPERWIDTH |
3340 DM_SCALE |
3341 DM_COPIES |
3342 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3343 DM_YRESOLUTION | DM_TTOPTION;
3345 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3346 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3347 dm.u1.s1.dmPaperLength = 2970;
3348 dm.u1.s1.dmPaperWidth = 2100;
3350 dm.u1.s1.dmScale = 100;
3351 dm.u1.s1.dmCopies = 1;
3352 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3353 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3354 /* dm.dmColor */
3355 /* dm.dmDuplex */
3356 dm.dmYResolution = 300; /* 300dpi */
3357 dm.dmTTOption = DMTT_BITMAP;
3358 /* dm.dmCollate */
3359 /* dm.dmFormName */
3360 /* dm.dmLogPixels */
3361 /* dm.dmBitsPerPel */
3362 /* dm.dmPelsWidth */
3363 /* dm.dmPelsHeight */
3364 /* dm.u2.dmDisplayFlags */
3365 /* dm.dmDisplayFrequency */
3366 /* dm.dmICMMethod */
3367 /* dm.dmICMIntent */
3368 /* dm.dmMediaType */
3369 /* dm.dmDitherType */
3370 /* dm.dmReserved1 */
3371 /* dm.dmReserved2 */
3372 /* dm.dmPanningWidth */
3373 /* dm.dmPanningHeight */
3375 if(buflen >= sizeof(DEVMODEW))
3376 memcpy(ptr, &dm, sizeof(DEVMODEW));
3377 *needed = sizeof(DEVMODEW);
3380 /*****************************************************************************
3381 * WINSPOOL_GetDevModeFromReg
3383 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3384 * DevMode is stored either as unicode or ascii.
3386 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3387 LPBYTE ptr,
3388 DWORD buflen, DWORD *needed)
3390 DWORD sz = buflen, type;
3391 LONG ret;
3393 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3394 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3395 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3396 if (sz < sizeof(DEVMODEA))
3398 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3399 return FALSE;
3401 /* ensures that dmSize is not erratically bogus if registry is invalid */
3402 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3403 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3404 sz += (CCHDEVICENAME + CCHFORMNAME);
3405 if (ptr && (buflen >= sz)) {
3406 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3407 memcpy(ptr, dmW, sz);
3408 HeapFree(GetProcessHeap(),0,dmW);
3410 *needed = sz;
3411 return TRUE;
3414 /*********************************************************************
3415 * WINSPOOL_GetPrinter_1
3417 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3419 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3420 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3422 DWORD size, left = cbBuf;
3423 BOOL space = (cbBuf > 0);
3424 LPBYTE ptr = buf;
3426 *pcbNeeded = 0;
3428 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3429 if(space && size <= left) {
3430 pi1->pName = (LPWSTR)ptr;
3431 ptr += size;
3432 left -= size;
3433 } else
3434 space = FALSE;
3435 *pcbNeeded += size;
3438 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3439 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3440 if(space && size <= left) {
3441 pi1->pDescription = (LPWSTR)ptr;
3442 ptr += size;
3443 left -= size;
3444 } else
3445 space = FALSE;
3446 *pcbNeeded += size;
3449 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3450 if(space && size <= left) {
3451 pi1->pComment = (LPWSTR)ptr;
3452 ptr += size;
3453 left -= size;
3454 } else
3455 space = FALSE;
3456 *pcbNeeded += size;
3459 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3461 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3462 memset(pi1, 0, sizeof(*pi1));
3464 return space;
3466 /*********************************************************************
3467 * WINSPOOL_GetPrinter_2
3469 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3471 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3472 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3474 DWORD size, left = cbBuf;
3475 BOOL space = (cbBuf > 0);
3476 LPBYTE ptr = buf;
3478 *pcbNeeded = 0;
3480 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3481 if(space && size <= left) {
3482 pi2->pPrinterName = (LPWSTR)ptr;
3483 ptr += size;
3484 left -= size;
3485 } else
3486 space = FALSE;
3487 *pcbNeeded += size;
3489 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3490 if(space && size <= left) {
3491 pi2->pShareName = (LPWSTR)ptr;
3492 ptr += size;
3493 left -= size;
3494 } else
3495 space = FALSE;
3496 *pcbNeeded += size;
3498 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3499 if(space && size <= left) {
3500 pi2->pPortName = (LPWSTR)ptr;
3501 ptr += size;
3502 left -= size;
3503 } else
3504 space = FALSE;
3505 *pcbNeeded += size;
3507 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3508 if(space && size <= left) {
3509 pi2->pDriverName = (LPWSTR)ptr;
3510 ptr += size;
3511 left -= size;
3512 } else
3513 space = FALSE;
3514 *pcbNeeded += size;
3516 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3517 if(space && size <= left) {
3518 pi2->pComment = (LPWSTR)ptr;
3519 ptr += size;
3520 left -= size;
3521 } else
3522 space = FALSE;
3523 *pcbNeeded += size;
3525 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3526 if(space && size <= left) {
3527 pi2->pLocation = (LPWSTR)ptr;
3528 ptr += size;
3529 left -= size;
3530 } else
3531 space = FALSE;
3532 *pcbNeeded += size;
3534 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3535 if(space && size <= left) {
3536 pi2->pDevMode = (LPDEVMODEW)ptr;
3537 ptr += size;
3538 left -= size;
3539 } else
3540 space = FALSE;
3541 *pcbNeeded += size;
3543 else
3545 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3546 if(space && size <= left) {
3547 pi2->pDevMode = (LPDEVMODEW)ptr;
3548 ptr += size;
3549 left -= size;
3550 } else
3551 space = FALSE;
3552 *pcbNeeded += size;
3554 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3555 if(space && size <= left) {
3556 pi2->pSepFile = (LPWSTR)ptr;
3557 ptr += size;
3558 left -= size;
3559 } else
3560 space = FALSE;
3561 *pcbNeeded += size;
3563 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3564 if(space && size <= left) {
3565 pi2->pPrintProcessor = (LPWSTR)ptr;
3566 ptr += size;
3567 left -= size;
3568 } else
3569 space = FALSE;
3570 *pcbNeeded += size;
3572 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3573 if(space && size <= left) {
3574 pi2->pDatatype = (LPWSTR)ptr;
3575 ptr += size;
3576 left -= size;
3577 } else
3578 space = FALSE;
3579 *pcbNeeded += size;
3581 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3582 if(space && size <= left) {
3583 pi2->pParameters = (LPWSTR)ptr;
3584 ptr += size;
3585 left -= size;
3586 } else
3587 space = FALSE;
3588 *pcbNeeded += size;
3590 if(pi2) {
3591 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3592 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3593 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3594 "Default Priority");
3595 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3596 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3599 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3600 memset(pi2, 0, sizeof(*pi2));
3602 return space;
3605 /*********************************************************************
3606 * WINSPOOL_GetPrinter_4
3608 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3610 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3611 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3613 DWORD size, left = cbBuf;
3614 BOOL space = (cbBuf > 0);
3615 LPBYTE ptr = buf;
3617 *pcbNeeded = 0;
3619 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3620 if(space && size <= left) {
3621 pi4->pPrinterName = (LPWSTR)ptr;
3622 ptr += size;
3623 left -= size;
3624 } else
3625 space = FALSE;
3626 *pcbNeeded += size;
3628 if(pi4) {
3629 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3632 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3633 memset(pi4, 0, sizeof(*pi4));
3635 return space;
3638 /*********************************************************************
3639 * WINSPOOL_GetPrinter_5
3641 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3643 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3644 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
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 if(space && size <= left) {
3654 pi5->pPrinterName = (LPWSTR)ptr;
3655 ptr += size;
3656 left -= size;
3657 } else
3658 space = FALSE;
3659 *pcbNeeded += size;
3661 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3662 if(space && size <= left) {
3663 pi5->pPortName = (LPWSTR)ptr;
3664 ptr += size;
3665 left -= size;
3666 } else
3667 space = FALSE;
3668 *pcbNeeded += size;
3670 if(pi5) {
3671 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3672 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3673 "dnsTimeout");
3674 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3675 "txTimeout");
3678 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3679 memset(pi5, 0, sizeof(*pi5));
3681 return space;
3684 /*********************************************************************
3685 * WINSPOOL_GetPrinter_7
3687 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3689 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3690 DWORD cbBuf, LPDWORD pcbNeeded)
3692 DWORD size, left = cbBuf;
3693 BOOL space = (cbBuf > 0);
3694 LPBYTE ptr = buf;
3696 *pcbNeeded = 0;
3698 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3700 ptr = NULL;
3701 size = sizeof(pi7->pszObjectGUID);
3703 if (space && size <= left) {
3704 pi7->pszObjectGUID = (LPWSTR)ptr;
3705 ptr += size;
3706 left -= size;
3707 } else
3708 space = FALSE;
3709 *pcbNeeded += size;
3710 if (pi7) {
3711 /* We do not have a Directory Service */
3712 pi7->dwAction = DSPRINT_UNPUBLISH;
3715 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3716 memset(pi7, 0, sizeof(*pi7));
3718 return space;
3721 /*********************************************************************
3722 * WINSPOOL_GetPrinter_9
3724 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3726 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3727 DWORD cbBuf, LPDWORD pcbNeeded)
3729 DWORD size;
3730 BOOL space = (cbBuf > 0);
3732 *pcbNeeded = 0;
3734 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3735 if(space && size <= cbBuf) {
3736 pi9->pDevMode = (LPDEVMODEW)buf;
3737 } else
3738 space = FALSE;
3739 *pcbNeeded += size;
3741 else
3743 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3744 if(space && size <= cbBuf) {
3745 pi9->pDevMode = (LPDEVMODEW)buf;
3746 } else
3747 space = FALSE;
3748 *pcbNeeded += size;
3751 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3752 memset(pi9, 0, sizeof(*pi9));
3754 return space;
3757 /*****************************************************************************
3758 * GetPrinterW [WINSPOOL.@]
3760 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3761 DWORD cbBuf, LPDWORD pcbNeeded)
3763 LPCWSTR name;
3764 DWORD size, needed = 0;
3765 LPBYTE ptr = NULL;
3766 HKEY hkeyPrinter, hkeyPrinters;
3767 BOOL ret;
3769 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3771 if (!(name = get_opened_printer_name(hPrinter))) {
3772 SetLastError(ERROR_INVALID_HANDLE);
3773 return FALSE;
3776 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3777 ERROR_SUCCESS) {
3778 ERR("Can't create Printers key\n");
3779 return FALSE;
3781 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3783 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3784 RegCloseKey(hkeyPrinters);
3785 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3786 return FALSE;
3789 switch(Level) {
3790 case 2:
3792 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3794 size = sizeof(PRINTER_INFO_2W);
3795 if(size <= cbBuf) {
3796 ptr = pPrinter + size;
3797 cbBuf -= size;
3798 memset(pPrinter, 0, size);
3799 } else {
3800 pi2 = NULL;
3801 cbBuf = 0;
3803 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3804 needed += size;
3805 break;
3808 case 4:
3810 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3812 size = sizeof(PRINTER_INFO_4W);
3813 if(size <= cbBuf) {
3814 ptr = pPrinter + size;
3815 cbBuf -= size;
3816 memset(pPrinter, 0, size);
3817 } else {
3818 pi4 = NULL;
3819 cbBuf = 0;
3821 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3822 needed += size;
3823 break;
3827 case 5:
3829 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3831 size = sizeof(PRINTER_INFO_5W);
3832 if(size <= cbBuf) {
3833 ptr = pPrinter + size;
3834 cbBuf -= size;
3835 memset(pPrinter, 0, size);
3836 } else {
3837 pi5 = NULL;
3838 cbBuf = 0;
3841 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3842 needed += size;
3843 break;
3847 case 6:
3849 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3851 size = sizeof(PRINTER_INFO_6);
3852 if (size <= cbBuf) {
3853 /* FIXME: We do not update the status yet */
3854 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3855 ret = TRUE;
3856 } else {
3857 ret = FALSE;
3860 needed += size;
3861 break;
3864 case 7:
3866 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3868 size = sizeof(PRINTER_INFO_7W);
3869 if (size <= cbBuf) {
3870 ptr = pPrinter + size;
3871 cbBuf -= size;
3872 memset(pPrinter, 0, size);
3873 } else {
3874 pi7 = NULL;
3875 cbBuf = 0;
3878 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3879 needed += size;
3880 break;
3884 case 9:
3886 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3888 size = sizeof(PRINTER_INFO_9W);
3889 if(size <= cbBuf) {
3890 ptr = pPrinter + size;
3891 cbBuf -= size;
3892 memset(pPrinter, 0, size);
3893 } else {
3894 pi9 = NULL;
3895 cbBuf = 0;
3898 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3899 needed += size;
3900 break;
3904 default:
3905 FIXME("Unimplemented level %d\n", Level);
3906 SetLastError(ERROR_INVALID_LEVEL);
3907 RegCloseKey(hkeyPrinters);
3908 RegCloseKey(hkeyPrinter);
3909 return FALSE;
3912 RegCloseKey(hkeyPrinter);
3913 RegCloseKey(hkeyPrinters);
3915 TRACE("returning %d needed = %d\n", ret, needed);
3916 if(pcbNeeded) *pcbNeeded = needed;
3917 if(!ret)
3918 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3919 return ret;
3922 /*****************************************************************************
3923 * GetPrinterA [WINSPOOL.@]
3925 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3926 DWORD cbBuf, LPDWORD pcbNeeded)
3928 BOOL ret;
3929 LPBYTE buf = NULL;
3931 if (cbBuf)
3932 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3934 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3935 if (ret)
3936 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3937 HeapFree(GetProcessHeap(), 0, buf);
3939 return ret;
3942 /*****************************************************************************
3943 * WINSPOOL_EnumPrintersW
3945 * Implementation of EnumPrintersW
3947 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3948 DWORD dwLevel, LPBYTE lpbPrinters,
3949 DWORD cbBuf, LPDWORD lpdwNeeded,
3950 LPDWORD lpdwReturned)
3953 HKEY hkeyPrinters, hkeyPrinter;
3954 WCHAR PrinterName[255];
3955 DWORD needed = 0, number = 0;
3956 DWORD used, i, left;
3957 PBYTE pi, buf;
3959 if(lpbPrinters)
3960 memset(lpbPrinters, 0, cbBuf);
3961 if(lpdwReturned)
3962 *lpdwReturned = 0;
3963 if(lpdwNeeded)
3964 *lpdwNeeded = 0;
3966 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3967 if(dwType == PRINTER_ENUM_DEFAULT)
3968 return TRUE;
3970 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3971 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3972 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3973 if (!dwType) {
3974 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3975 return TRUE;
3980 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3981 FIXME("dwType = %08x\n", dwType);
3982 SetLastError(ERROR_INVALID_FLAGS);
3983 return FALSE;
3986 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3987 ERROR_SUCCESS) {
3988 ERR("Can't create Printers key\n");
3989 return FALSE;
3992 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3993 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3994 RegCloseKey(hkeyPrinters);
3995 ERR("Can't query Printers key\n");
3996 return FALSE;
3998 TRACE("Found %d printers\n", number);
4000 switch(dwLevel) {
4001 case 1:
4002 used = number * sizeof(PRINTER_INFO_1W);
4003 break;
4004 case 2:
4005 used = number * sizeof(PRINTER_INFO_2W);
4006 break;
4007 case 4:
4008 used = number * sizeof(PRINTER_INFO_4W);
4009 break;
4010 case 5:
4011 used = number * sizeof(PRINTER_INFO_5W);
4012 break;
4014 default:
4015 SetLastError(ERROR_INVALID_LEVEL);
4016 RegCloseKey(hkeyPrinters);
4017 return FALSE;
4019 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4021 for(i = 0; i < number; i++) {
4022 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4023 ERROR_SUCCESS) {
4024 ERR("Can't enum key number %d\n", i);
4025 RegCloseKey(hkeyPrinters);
4026 return FALSE;
4028 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4029 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4030 ERROR_SUCCESS) {
4031 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4032 RegCloseKey(hkeyPrinters);
4033 return FALSE;
4036 if(cbBuf > used) {
4037 buf = lpbPrinters + used;
4038 left = cbBuf - used;
4039 } else {
4040 buf = NULL;
4041 left = 0;
4044 switch(dwLevel) {
4045 case 1:
4046 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4047 left, &needed);
4048 used += needed;
4049 if(pi) pi += sizeof(PRINTER_INFO_1W);
4050 break;
4051 case 2:
4052 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4053 left, &needed);
4054 used += needed;
4055 if(pi) pi += sizeof(PRINTER_INFO_2W);
4056 break;
4057 case 4:
4058 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4059 left, &needed);
4060 used += needed;
4061 if(pi) pi += sizeof(PRINTER_INFO_4W);
4062 break;
4063 case 5:
4064 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4065 left, &needed);
4066 used += needed;
4067 if(pi) pi += sizeof(PRINTER_INFO_5W);
4068 break;
4069 default:
4070 ERR("Shouldn't be here!\n");
4071 RegCloseKey(hkeyPrinter);
4072 RegCloseKey(hkeyPrinters);
4073 return FALSE;
4075 RegCloseKey(hkeyPrinter);
4077 RegCloseKey(hkeyPrinters);
4079 if(lpdwNeeded)
4080 *lpdwNeeded = used;
4082 if(used > cbBuf) {
4083 if(lpbPrinters)
4084 memset(lpbPrinters, 0, cbBuf);
4085 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4086 return FALSE;
4088 if(lpdwReturned)
4089 *lpdwReturned = number;
4090 SetLastError(ERROR_SUCCESS);
4091 return TRUE;
4095 /******************************************************************
4096 * EnumPrintersW [WINSPOOL.@]
4098 * Enumerates the available printers, print servers and print
4099 * providers, depending on the specified flags, name and level.
4101 * RETURNS:
4103 * If level is set to 1:
4104 * Returns an array of PRINTER_INFO_1 data structures in the
4105 * lpbPrinters buffer.
4107 * If level is set to 2:
4108 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4109 * Returns an array of PRINTER_INFO_2 data structures in the
4110 * lpbPrinters buffer. Note that according to MSDN also an
4111 * OpenPrinter should be performed on every remote printer.
4113 * If level is set to 4 (officially WinNT only):
4114 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4115 * Fast: Only the registry is queried to retrieve printer names,
4116 * no connection to the driver is made.
4117 * Returns an array of PRINTER_INFO_4 data structures in the
4118 * lpbPrinters buffer.
4120 * If level is set to 5 (officially WinNT4/Win9x only):
4121 * Fast: Only the registry is queried to retrieve printer names,
4122 * no connection to the driver is made.
4123 * Returns an array of PRINTER_INFO_5 data structures in the
4124 * lpbPrinters buffer.
4126 * If level set to 3 or 6+:
4127 * returns zero (failure!)
4129 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4130 * for information.
4132 * BUGS:
4133 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4134 * - Only levels 2, 4 and 5 are implemented at the moment.
4135 * - 16-bit printer drivers are not enumerated.
4136 * - Returned amount of bytes used/needed does not match the real Windoze
4137 * implementation (as in this implementation, all strings are part
4138 * of the buffer, whereas Win32 keeps them somewhere else)
4139 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4141 * NOTE:
4142 * - In a regular Wine installation, no registry settings for printers
4143 * exist, which makes this function return an empty list.
4145 BOOL WINAPI EnumPrintersW(
4146 DWORD dwType, /* [in] Types of print objects to enumerate */
4147 LPWSTR lpszName, /* [in] name of objects to enumerate */
4148 DWORD dwLevel, /* [in] type of printer info structure */
4149 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4150 DWORD cbBuf, /* [in] max size of buffer in bytes */
4151 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4152 LPDWORD lpdwReturned /* [out] number of entries returned */
4155 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4156 lpdwNeeded, lpdwReturned);
4159 /******************************************************************
4160 * EnumPrintersA [WINSPOOL.@]
4162 * See EnumPrintersW
4165 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4166 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4168 BOOL ret;
4169 UNICODE_STRING pNameU;
4170 LPWSTR pNameW;
4171 LPBYTE pPrintersW;
4173 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4174 pPrinters, cbBuf, pcbNeeded, pcReturned);
4176 pNameW = asciitounicode(&pNameU, pName);
4178 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4179 MS Office need this */
4180 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4182 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4184 RtlFreeUnicodeString(&pNameU);
4185 if (ret) {
4186 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4188 HeapFree(GetProcessHeap(), 0, pPrintersW);
4189 return ret;
4192 /*****************************************************************************
4193 * WINSPOOL_GetDriverInfoFromReg [internal]
4195 * Enters the information from the registry into the DRIVER_INFO struct
4197 * RETURNS
4198 * zero if the printer driver does not exist in the registry
4199 * (only if Level > 1) otherwise nonzero
4201 static BOOL WINSPOOL_GetDriverInfoFromReg(
4202 HKEY hkeyDrivers,
4203 LPWSTR DriverName,
4204 const printenv_t * env,
4205 DWORD Level,
4206 LPBYTE ptr, /* DRIVER_INFO */
4207 LPBYTE pDriverStrings, /* strings buffer */
4208 DWORD cbBuf, /* size of string buffer */
4209 LPDWORD pcbNeeded) /* space needed for str. */
4211 DWORD size, tmp;
4212 HKEY hkeyDriver;
4213 WCHAR driverdir[MAX_PATH];
4214 DWORD dirlen;
4215 LPBYTE strPtr = pDriverStrings;
4216 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4218 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4219 debugstr_w(DriverName), env,
4220 Level, di, pDriverStrings, cbBuf);
4222 if (di) ZeroMemory(di, di_sizeof[Level]);
4224 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4225 if (*pcbNeeded <= cbBuf)
4226 strcpyW((LPWSTR)strPtr, DriverName);
4228 /* pName for level 1 has a different offset! */
4229 if (Level == 1) {
4230 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4231 return TRUE;
4234 /* .cVersion and .pName for level > 1 */
4235 if (di) {
4236 di->cVersion = env->driverversion;
4237 di->pName = (LPWSTR) strPtr;
4238 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4241 /* Reserve Space for the largest subdir and a Backslash*/
4242 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4243 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4244 /* Should never Fail */
4245 return FALSE;
4247 lstrcatW(driverdir, env->versionsubdir);
4248 lstrcatW(driverdir, backslashW);
4250 /* dirlen must not include the terminating zero */
4251 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4253 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4254 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4255 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4256 return FALSE;
4259 /* pEnvironment */
4260 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4262 *pcbNeeded += size;
4263 if (*pcbNeeded <= cbBuf) {
4264 lstrcpyW((LPWSTR)strPtr, env->envname);
4265 if (di) di->pEnvironment = (LPWSTR)strPtr;
4266 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4269 /* .pDriverPath is the Graphics rendering engine.
4270 The full Path is required to avoid a crash in some apps */
4271 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4272 *pcbNeeded += size;
4273 if (*pcbNeeded <= cbBuf)
4274 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4276 if (di) di->pDriverPath = (LPWSTR)strPtr;
4277 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4280 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4281 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4282 *pcbNeeded += size;
4283 if (*pcbNeeded <= cbBuf)
4284 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4286 if (di) di->pDataFile = (LPWSTR)strPtr;
4287 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4290 /* .pConfigFile is the Driver user Interface */
4291 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4292 *pcbNeeded += size;
4293 if (*pcbNeeded <= cbBuf)
4294 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4296 if (di) di->pConfigFile = (LPWSTR)strPtr;
4297 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4300 if (Level == 2 ) {
4301 RegCloseKey(hkeyDriver);
4302 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4303 return TRUE;
4306 if (Level == 5 ) {
4307 RegCloseKey(hkeyDriver);
4308 FIXME("level 5: incomplete\n");
4309 return TRUE;
4312 /* .pHelpFile */
4313 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4314 *pcbNeeded += size;
4315 if (*pcbNeeded <= cbBuf)
4316 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4318 if (di) di->pHelpFile = (LPWSTR)strPtr;
4319 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4322 /* .pDependentFiles */
4323 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4324 *pcbNeeded += size;
4325 if (*pcbNeeded <= cbBuf)
4326 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4328 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4329 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4331 else if (GetVersion() & 0x80000000) {
4332 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4333 size = 2 * sizeof(WCHAR);
4334 *pcbNeeded += size;
4335 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4337 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4338 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4341 /* .pMonitorName is the optional Language Monitor */
4342 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4343 *pcbNeeded += size;
4344 if (*pcbNeeded <= cbBuf)
4345 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4347 if (di) di->pMonitorName = (LPWSTR)strPtr;
4348 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4351 /* .pDefaultDataType */
4352 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4353 *pcbNeeded += size;
4354 if(*pcbNeeded <= cbBuf)
4355 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4357 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4358 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4361 if (Level == 3 ) {
4362 RegCloseKey(hkeyDriver);
4363 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4364 return TRUE;
4367 /* .pszzPreviousNames */
4368 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4369 *pcbNeeded += size;
4370 if(*pcbNeeded <= cbBuf)
4371 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4373 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4374 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4377 if (Level == 4 ) {
4378 RegCloseKey(hkeyDriver);
4379 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4380 return TRUE;
4383 /* support is missing, but not important enough for a FIXME */
4384 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4386 /* .pszMfgName */
4387 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4388 *pcbNeeded += size;
4389 if(*pcbNeeded <= cbBuf)
4390 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4392 if (di) di->pszMfgName = (LPWSTR)strPtr;
4393 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4396 /* .pszOEMUrl */
4397 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4398 *pcbNeeded += size;
4399 if(*pcbNeeded <= cbBuf)
4400 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4402 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4403 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4406 /* .pszHardwareID */
4407 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4408 *pcbNeeded += size;
4409 if(*pcbNeeded <= cbBuf)
4410 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4412 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4413 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4416 /* .pszProvider */
4417 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4418 *pcbNeeded += size;
4419 if(*pcbNeeded <= cbBuf)
4420 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4422 if (di) di->pszProvider = (LPWSTR)strPtr;
4423 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4426 if (Level == 6 ) {
4427 RegCloseKey(hkeyDriver);
4428 return TRUE;
4431 /* support is missing, but not important enough for a FIXME */
4432 TRACE("level 8: incomplete\n");
4434 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4435 RegCloseKey(hkeyDriver);
4436 return TRUE;
4439 /*****************************************************************************
4440 * GetPrinterDriverW [WINSPOOL.@]
4442 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4443 DWORD Level, LPBYTE pDriverInfo,
4444 DWORD cbBuf, LPDWORD pcbNeeded)
4446 LPCWSTR name;
4447 WCHAR DriverName[100];
4448 DWORD ret, type, size, needed = 0;
4449 LPBYTE ptr = NULL;
4450 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4451 const printenv_t * env;
4453 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4454 Level,pDriverInfo,cbBuf, pcbNeeded);
4456 if (cbBuf > 0)
4457 ZeroMemory(pDriverInfo, cbBuf);
4459 if (!(name = get_opened_printer_name(hPrinter))) {
4460 SetLastError(ERROR_INVALID_HANDLE);
4461 return FALSE;
4464 if (Level < 1 || Level == 7 || Level > 8) {
4465 SetLastError(ERROR_INVALID_LEVEL);
4466 return FALSE;
4469 env = validate_envW(pEnvironment);
4470 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4472 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4473 ERROR_SUCCESS) {
4474 ERR("Can't create Printers key\n");
4475 return FALSE;
4477 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4478 != ERROR_SUCCESS) {
4479 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4480 RegCloseKey(hkeyPrinters);
4481 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4482 return FALSE;
4484 size = sizeof(DriverName);
4485 DriverName[0] = 0;
4486 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4487 (LPBYTE)DriverName, &size);
4488 RegCloseKey(hkeyPrinter);
4489 RegCloseKey(hkeyPrinters);
4490 if(ret != ERROR_SUCCESS) {
4491 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4492 return FALSE;
4495 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4496 if(!hkeyDrivers) {
4497 ERR("Can't create Drivers key\n");
4498 return FALSE;
4501 size = di_sizeof[Level];
4502 if ((size <= cbBuf) && pDriverInfo)
4503 ptr = pDriverInfo + size;
4505 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4506 env, Level, pDriverInfo, ptr,
4507 (cbBuf < size) ? 0 : cbBuf - size,
4508 &needed)) {
4509 RegCloseKey(hkeyDrivers);
4510 return FALSE;
4513 RegCloseKey(hkeyDrivers);
4515 if(pcbNeeded) *pcbNeeded = size + needed;
4516 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4517 if(cbBuf >= size + needed) return TRUE;
4518 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4519 return FALSE;
4522 /*****************************************************************************
4523 * GetPrinterDriverA [WINSPOOL.@]
4525 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4526 DWORD Level, LPBYTE pDriverInfo,
4527 DWORD cbBuf, LPDWORD pcbNeeded)
4529 BOOL ret;
4530 UNICODE_STRING pEnvW;
4531 PWSTR pwstrEnvW;
4532 LPBYTE buf = NULL;
4534 if (cbBuf)
4536 ZeroMemory(pDriverInfo, cbBuf);
4537 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4540 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4541 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4542 cbBuf, pcbNeeded);
4543 if (ret)
4544 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4546 HeapFree(GetProcessHeap(), 0, buf);
4548 RtlFreeUnicodeString(&pEnvW);
4549 return ret;
4552 /*****************************************************************************
4553 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4555 * Return the PATH for the Printer-Drivers (UNICODE)
4557 * PARAMS
4558 * pName [I] Servername (NT only) or NULL (local Computer)
4559 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4560 * Level [I] Structure-Level (must be 1)
4561 * pDriverDirectory [O] PTR to Buffer that receives the Result
4562 * cbBuf [I] Size of Buffer at pDriverDirectory
4563 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4564 * required for pDriverDirectory
4566 * RETURNS
4567 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4568 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4569 * if cbBuf is too small
4571 * Native Values returned in pDriverDirectory on Success:
4572 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4573 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4574 *| win9x(Windows 4.0): "%winsysdir%"
4576 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4578 * FIXME
4579 *- Only NULL or "" is supported for pName
4582 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4583 DWORD Level, LPBYTE pDriverDirectory,
4584 DWORD cbBuf, LPDWORD pcbNeeded)
4586 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4587 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4589 if ((backend == NULL) && !load_backend()) return FALSE;
4591 if (Level != 1) {
4592 /* (Level != 1) is ignored in win9x */
4593 SetLastError(ERROR_INVALID_LEVEL);
4594 return FALSE;
4596 if (pcbNeeded == NULL) {
4597 /* (pcbNeeded == NULL) is ignored in win9x */
4598 SetLastError(RPC_X_NULL_REF_POINTER);
4599 return FALSE;
4602 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4603 pDriverDirectory, cbBuf, pcbNeeded);
4608 /*****************************************************************************
4609 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4611 * Return the PATH for the Printer-Drivers (ANSI)
4613 * See GetPrinterDriverDirectoryW.
4615 * NOTES
4616 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4619 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4620 DWORD Level, LPBYTE pDriverDirectory,
4621 DWORD cbBuf, LPDWORD pcbNeeded)
4623 UNICODE_STRING nameW, environmentW;
4624 BOOL ret;
4625 DWORD pcbNeededW;
4626 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4627 WCHAR *driverDirectoryW = NULL;
4629 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4630 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4632 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4634 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4635 else nameW.Buffer = NULL;
4636 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4637 else environmentW.Buffer = NULL;
4639 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4640 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4641 if (ret) {
4642 DWORD needed;
4643 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4644 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4645 if(pcbNeeded)
4646 *pcbNeeded = needed;
4647 ret = (needed <= cbBuf) ? TRUE : FALSE;
4648 } else
4649 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4651 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4653 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4654 RtlFreeUnicodeString(&environmentW);
4655 RtlFreeUnicodeString(&nameW);
4657 return ret;
4660 /*****************************************************************************
4661 * AddPrinterDriverA [WINSPOOL.@]
4663 * See AddPrinterDriverW.
4666 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4668 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4669 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4672 /******************************************************************************
4673 * AddPrinterDriverW (WINSPOOL.@)
4675 * Install a Printer Driver
4677 * PARAMS
4678 * pName [I] Servername or NULL (local Computer)
4679 * level [I] Level for the supplied DRIVER_INFO_*W struct
4680 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4682 * RESULTS
4683 * Success: TRUE
4684 * Failure: FALSE
4687 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4689 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4690 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4693 /*****************************************************************************
4694 * AddPrintProcessorA [WINSPOOL.@]
4696 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4697 LPSTR pPrintProcessorName)
4699 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4700 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4701 return FALSE;
4704 /*****************************************************************************
4705 * AddPrintProcessorW [WINSPOOL.@]
4707 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4708 LPWSTR pPrintProcessorName)
4710 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4711 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4712 return TRUE;
4715 /*****************************************************************************
4716 * AddPrintProvidorA [WINSPOOL.@]
4718 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4720 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4721 return FALSE;
4724 /*****************************************************************************
4725 * AddPrintProvidorW [WINSPOOL.@]
4727 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4729 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4730 return FALSE;
4733 /*****************************************************************************
4734 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4736 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4737 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4739 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4740 pDevModeOutput, pDevModeInput);
4741 return 0;
4744 /*****************************************************************************
4745 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4747 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4748 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4750 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4751 pDevModeOutput, pDevModeInput);
4752 return 0;
4755 /*****************************************************************************
4756 * PrinterProperties [WINSPOOL.@]
4758 * Displays a dialog to set the properties of the printer.
4760 * RETURNS
4761 * nonzero on success or zero on failure
4763 * BUGS
4764 * implemented as stub only
4766 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4767 HANDLE hPrinter /* [in] handle to printer object */
4769 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4770 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4771 return FALSE;
4774 /*****************************************************************************
4775 * EnumJobsA [WINSPOOL.@]
4778 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4779 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4780 LPDWORD pcReturned)
4782 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4783 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4785 if(pcbNeeded) *pcbNeeded = 0;
4786 if(pcReturned) *pcReturned = 0;
4787 return FALSE;
4791 /*****************************************************************************
4792 * EnumJobsW [WINSPOOL.@]
4795 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4796 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4797 LPDWORD pcReturned)
4799 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4800 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4802 if(pcbNeeded) *pcbNeeded = 0;
4803 if(pcReturned) *pcReturned = 0;
4804 return FALSE;
4807 /*****************************************************************************
4808 * WINSPOOL_EnumPrinterDrivers [internal]
4810 * Delivers information about all printer drivers installed on the
4811 * localhost or a given server
4813 * RETURNS
4814 * nonzero on success or zero on failure. If the buffer for the returned
4815 * information is too small the function will return an error
4817 * BUGS
4818 * - only implemented for localhost, foreign hosts will return an error
4820 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4821 DWORD Level, LPBYTE pDriverInfo,
4822 DWORD driver_index,
4823 DWORD cbBuf, LPDWORD pcbNeeded,
4824 LPDWORD pcFound, DWORD data_offset)
4826 { HKEY hkeyDrivers;
4827 DWORD i, size = 0;
4828 const printenv_t * env;
4830 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4831 debugstr_w(pName), debugstr_w(pEnvironment),
4832 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4834 env = validate_envW(pEnvironment);
4835 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4837 *pcFound = 0;
4839 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4840 if(!hkeyDrivers) {
4841 ERR("Can't open Drivers key\n");
4842 return FALSE;
4845 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4846 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4847 RegCloseKey(hkeyDrivers);
4848 ERR("Can't query Drivers key\n");
4849 return FALSE;
4851 TRACE("Found %d Drivers\n", *pcFound);
4853 /* get size of single struct
4854 * unicode and ascii structure have the same size
4856 size = di_sizeof[Level];
4858 if (data_offset == 0)
4859 data_offset = size * (*pcFound);
4860 *pcbNeeded = data_offset;
4862 for( i = 0; i < *pcFound; i++) {
4863 WCHAR DriverNameW[255];
4864 PBYTE table_ptr = NULL;
4865 PBYTE data_ptr = NULL;
4866 DWORD needed = 0;
4868 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4869 != ERROR_SUCCESS) {
4870 ERR("Can't enum key number %d\n", i);
4871 RegCloseKey(hkeyDrivers);
4872 return FALSE;
4875 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4876 table_ptr = pDriverInfo + (driver_index + i) * size;
4877 if (pDriverInfo && *pcbNeeded <= cbBuf)
4878 data_ptr = pDriverInfo + *pcbNeeded;
4880 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4881 env, Level, table_ptr, data_ptr,
4882 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4883 &needed)) {
4884 RegCloseKey(hkeyDrivers);
4885 return FALSE;
4888 *pcbNeeded += needed;
4891 RegCloseKey(hkeyDrivers);
4893 if(cbBuf < *pcbNeeded){
4894 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4895 return FALSE;
4898 return TRUE;
4901 /*****************************************************************************
4902 * EnumPrinterDriversW [WINSPOOL.@]
4904 * see function EnumPrinterDrivers for RETURNS, BUGS
4906 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4907 LPBYTE pDriverInfo, DWORD cbBuf,
4908 LPDWORD pcbNeeded, LPDWORD pcReturned)
4910 static const WCHAR allW[] = {'a','l','l',0};
4911 BOOL ret;
4912 DWORD found;
4914 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4916 SetLastError(RPC_X_NULL_REF_POINTER);
4917 return FALSE;
4920 /* check for local drivers */
4921 if((pName) && (pName[0])) {
4922 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4923 SetLastError(ERROR_ACCESS_DENIED);
4924 return FALSE;
4927 /* check input parameter */
4928 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4929 SetLastError(ERROR_INVALID_LEVEL);
4930 return FALSE;
4933 if(pDriverInfo && cbBuf > 0)
4934 memset( pDriverInfo, 0, cbBuf);
4936 /* Exception: pull all printers */
4937 if (pEnvironment && !strcmpW(pEnvironment, allW))
4939 DWORD i, needed, bufsize = cbBuf;
4940 DWORD total_needed = 0;
4941 DWORD total_found = 0;
4942 DWORD data_offset;
4944 /* Precompute the overall total; we need this to know
4945 where pointers end and data begins (i.e. data_offset) */
4946 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4948 needed = found = 0;
4949 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4950 NULL, 0, 0, &needed, &found, 0);
4951 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4952 total_needed += needed;
4953 total_found += found;
4956 data_offset = di_sizeof[Level] * total_found;
4958 *pcReturned = 0;
4959 *pcbNeeded = 0;
4960 total_found = 0;
4961 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4963 needed = found = 0;
4964 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4965 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4966 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4967 else if (ret)
4968 *pcReturned += found;
4969 *pcbNeeded = needed;
4970 data_offset = needed;
4971 total_found += found;
4973 return ret;
4976 /* Normal behavior */
4977 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4978 0, cbBuf, pcbNeeded, &found, 0);
4979 if (ret)
4980 *pcReturned = found;
4982 return ret;
4985 /*****************************************************************************
4986 * EnumPrinterDriversA [WINSPOOL.@]
4988 * see function EnumPrinterDrivers for RETURNS, BUGS
4990 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4991 LPBYTE pDriverInfo, DWORD cbBuf,
4992 LPDWORD pcbNeeded, LPDWORD pcReturned)
4994 BOOL ret;
4995 UNICODE_STRING pNameW, pEnvironmentW;
4996 PWSTR pwstrNameW, pwstrEnvironmentW;
4997 LPBYTE buf = NULL;
4999 if (cbBuf)
5000 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5002 pwstrNameW = asciitounicode(&pNameW, pName);
5003 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5005 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5006 buf, cbBuf, pcbNeeded, pcReturned);
5007 if (ret)
5008 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5010 HeapFree(GetProcessHeap(), 0, buf);
5012 RtlFreeUnicodeString(&pNameW);
5013 RtlFreeUnicodeString(&pEnvironmentW);
5015 return ret;
5018 /******************************************************************************
5019 * EnumPortsA (WINSPOOL.@)
5021 * See EnumPortsW.
5024 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5025 LPDWORD pcbNeeded, LPDWORD pcReturned)
5027 BOOL res;
5028 LPBYTE bufferW = NULL;
5029 LPWSTR nameW = NULL;
5030 DWORD needed = 0;
5031 DWORD numentries = 0;
5032 INT len;
5034 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5035 cbBuf, pcbNeeded, pcReturned);
5037 /* convert servername to unicode */
5038 if (pName) {
5039 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5040 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5041 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5043 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5044 needed = cbBuf * sizeof(WCHAR);
5045 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5046 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5048 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5049 if (pcbNeeded) needed = *pcbNeeded;
5050 /* HeapReAlloc return NULL, when bufferW was NULL */
5051 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5052 HeapAlloc(GetProcessHeap(), 0, needed);
5054 /* Try again with the large Buffer */
5055 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5057 needed = pcbNeeded ? *pcbNeeded : 0;
5058 numentries = pcReturned ? *pcReturned : 0;
5061 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5062 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5064 if (res) {
5065 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5066 DWORD entrysize = 0;
5067 DWORD index;
5068 LPSTR ptr;
5069 LPPORT_INFO_2W pi2w;
5070 LPPORT_INFO_2A pi2a;
5072 needed = 0;
5073 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5075 /* First pass: calculate the size for all Entries */
5076 pi2w = (LPPORT_INFO_2W) bufferW;
5077 pi2a = (LPPORT_INFO_2A) pPorts;
5078 index = 0;
5079 while (index < numentries) {
5080 index++;
5081 needed += entrysize; /* PORT_INFO_?A */
5082 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5084 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5085 NULL, 0, NULL, NULL);
5086 if (Level > 1) {
5087 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5088 NULL, 0, NULL, NULL);
5089 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5090 NULL, 0, NULL, NULL);
5092 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5093 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5094 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5097 /* check for errors and quit on failure */
5098 if (cbBuf < needed) {
5099 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5100 res = FALSE;
5101 goto cleanup;
5103 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5104 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5105 cbBuf -= len ; /* free Bytes in the user-Buffer */
5106 pi2w = (LPPORT_INFO_2W) bufferW;
5107 pi2a = (LPPORT_INFO_2A) pPorts;
5108 index = 0;
5109 /* Second Pass: Fill the User Buffer (if we have one) */
5110 while ((index < numentries) && pPorts) {
5111 index++;
5112 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5113 pi2a->pPortName = ptr;
5114 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5115 ptr, cbBuf , NULL, NULL);
5116 ptr += len;
5117 cbBuf -= len;
5118 if (Level > 1) {
5119 pi2a->pMonitorName = ptr;
5120 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5121 ptr, cbBuf, NULL, NULL);
5122 ptr += len;
5123 cbBuf -= len;
5125 pi2a->pDescription = ptr;
5126 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5127 ptr, cbBuf, NULL, NULL);
5128 ptr += len;
5129 cbBuf -= len;
5131 pi2a->fPortType = pi2w->fPortType;
5132 pi2a->Reserved = 0; /* documented: "must be zero" */
5135 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5136 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5137 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5141 cleanup:
5142 if (pcbNeeded) *pcbNeeded = needed;
5143 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5145 HeapFree(GetProcessHeap(), 0, nameW);
5146 HeapFree(GetProcessHeap(), 0, bufferW);
5148 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5149 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5151 return (res);
5155 /******************************************************************************
5156 * EnumPortsW (WINSPOOL.@)
5158 * Enumerate available Ports
5160 * PARAMS
5161 * pName [I] Servername or NULL (local Computer)
5162 * Level [I] Structure-Level (1 or 2)
5163 * pPorts [O] PTR to Buffer that receives the Result
5164 * cbBuf [I] Size of Buffer at pPorts
5165 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5166 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5168 * RETURNS
5169 * Success: TRUE
5170 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5173 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5176 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5177 cbBuf, pcbNeeded, pcReturned);
5179 if ((backend == NULL) && !load_backend()) return FALSE;
5181 /* Level is not checked in win9x */
5182 if (!Level || (Level > 2)) {
5183 WARN("level (%d) is ignored in win9x\n", Level);
5184 SetLastError(ERROR_INVALID_LEVEL);
5185 return FALSE;
5187 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5188 SetLastError(RPC_X_NULL_REF_POINTER);
5189 return FALSE;
5192 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5195 /******************************************************************************
5196 * GetDefaultPrinterW (WINSPOOL.@)
5198 * FIXME
5199 * This function must read the value from data 'device' of key
5200 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5202 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5204 BOOL retval = TRUE;
5205 DWORD insize, len;
5206 WCHAR *buffer, *ptr;
5208 if (!namesize)
5210 SetLastError(ERROR_INVALID_PARAMETER);
5211 return FALSE;
5214 /* make the buffer big enough for the stuff from the profile/registry,
5215 * the content must fit into the local buffer to compute the correct
5216 * size even if the extern buffer is too small or not given.
5217 * (20 for ,driver,port) */
5218 insize = *namesize;
5219 len = max(100, (insize + 20));
5220 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5222 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5224 SetLastError (ERROR_FILE_NOT_FOUND);
5225 retval = FALSE;
5226 goto end;
5228 TRACE("%s\n", debugstr_w(buffer));
5230 if ((ptr = strchrW(buffer, ',')) == NULL)
5232 SetLastError(ERROR_INVALID_NAME);
5233 retval = FALSE;
5234 goto end;
5237 *ptr = 0;
5238 *namesize = strlenW(buffer) + 1;
5239 if(!name || (*namesize > insize))
5241 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5242 retval = FALSE;
5243 goto end;
5245 strcpyW(name, buffer);
5247 end:
5248 HeapFree( GetProcessHeap(), 0, buffer);
5249 return retval;
5253 /******************************************************************************
5254 * GetDefaultPrinterA (WINSPOOL.@)
5256 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5258 BOOL retval = TRUE;
5259 DWORD insize = 0;
5260 WCHAR *bufferW = NULL;
5262 if (!namesize)
5264 SetLastError(ERROR_INVALID_PARAMETER);
5265 return FALSE;
5268 if(name && *namesize) {
5269 insize = *namesize;
5270 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5273 if(!GetDefaultPrinterW( bufferW, namesize)) {
5274 retval = FALSE;
5275 goto end;
5278 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5279 NULL, NULL);
5280 if (!*namesize)
5282 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5283 retval = FALSE;
5285 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5287 end:
5288 HeapFree( GetProcessHeap(), 0, bufferW);
5289 return retval;
5293 /******************************************************************************
5294 * SetDefaultPrinterW (WINSPOOL.204)
5296 * Set the Name of the Default Printer
5298 * PARAMS
5299 * pszPrinter [I] Name of the Printer or NULL
5301 * RETURNS
5302 * Success: True
5303 * Failure: FALSE
5305 * NOTES
5306 * When the Parameter is NULL or points to an Empty String and
5307 * a Default Printer was already present, then this Function changes nothing.
5308 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5309 * the First enumerated local Printer is used.
5312 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5314 WCHAR default_printer[MAX_PATH];
5315 LPWSTR buffer = NULL;
5316 HKEY hreg;
5317 DWORD size;
5318 DWORD namelen;
5319 LONG lres;
5321 TRACE("(%s)\n", debugstr_w(pszPrinter));
5322 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5324 default_printer[0] = '\0';
5325 size = sizeof(default_printer)/sizeof(WCHAR);
5327 /* if we have a default Printer, do nothing. */
5328 if (GetDefaultPrinterW(default_printer, &size))
5329 return TRUE;
5331 pszPrinter = NULL;
5332 /* we have no default Printer: search local Printers and use the first */
5333 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5335 default_printer[0] = '\0';
5336 size = sizeof(default_printer)/sizeof(WCHAR);
5337 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5339 pszPrinter = default_printer;
5340 TRACE("using %s\n", debugstr_w(pszPrinter));
5342 RegCloseKey(hreg);
5345 if (pszPrinter == NULL) {
5346 TRACE("no local printer found\n");
5347 SetLastError(ERROR_FILE_NOT_FOUND);
5348 return FALSE;
5352 /* "pszPrinter" is never empty or NULL here. */
5353 namelen = lstrlenW(pszPrinter);
5354 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5355 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5356 if (!buffer ||
5357 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5358 HeapFree(GetProcessHeap(), 0, buffer);
5359 SetLastError(ERROR_FILE_NOT_FOUND);
5360 return FALSE;
5363 /* read the devices entry for the printer (driver,port) to build the string for the
5364 default device entry (printer,driver,port) */
5365 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5366 buffer[namelen] = ',';
5367 namelen++; /* move index to the start of the driver */
5369 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5370 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5371 if (!lres) {
5372 TRACE("set device to %s\n", debugstr_w(buffer));
5374 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5375 TRACE("failed to set the device entry: %d\n", GetLastError());
5376 lres = ERROR_INVALID_PRINTER_NAME;
5379 /* remove the next section, when INIFileMapping is implemented */
5381 HKEY hdev;
5382 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5383 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5384 RegCloseKey(hdev);
5388 else
5390 if (lres != ERROR_FILE_NOT_FOUND)
5391 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5393 SetLastError(ERROR_INVALID_PRINTER_NAME);
5396 RegCloseKey(hreg);
5397 HeapFree(GetProcessHeap(), 0, buffer);
5398 return (lres == ERROR_SUCCESS);
5401 /******************************************************************************
5402 * SetDefaultPrinterA (WINSPOOL.202)
5404 * See SetDefaultPrinterW.
5407 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5409 LPWSTR bufferW = NULL;
5410 BOOL res;
5412 TRACE("(%s)\n", debugstr_a(pszPrinter));
5413 if(pszPrinter) {
5414 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5415 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5416 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5418 res = SetDefaultPrinterW(bufferW);
5419 HeapFree(GetProcessHeap(), 0, bufferW);
5420 return res;
5423 /******************************************************************************
5424 * SetPrinterDataExA (WINSPOOL.@)
5426 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5427 LPCSTR pValueName, DWORD Type,
5428 LPBYTE pData, DWORD cbData)
5430 HKEY hkeyPrinter, hkeySubkey;
5431 DWORD ret;
5433 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5434 debugstr_a(pValueName), Type, pData, cbData);
5436 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5437 != ERROR_SUCCESS)
5438 return ret;
5440 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5441 != ERROR_SUCCESS) {
5442 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5443 RegCloseKey(hkeyPrinter);
5444 return ret;
5446 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5447 RegCloseKey(hkeySubkey);
5448 RegCloseKey(hkeyPrinter);
5449 return ret;
5452 /******************************************************************************
5453 * SetPrinterDataExW (WINSPOOL.@)
5455 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5456 LPCWSTR pValueName, DWORD Type,
5457 LPBYTE pData, DWORD cbData)
5459 HKEY hkeyPrinter, hkeySubkey;
5460 DWORD ret;
5462 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5463 debugstr_w(pValueName), Type, pData, cbData);
5465 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5466 != ERROR_SUCCESS)
5467 return ret;
5469 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5470 != ERROR_SUCCESS) {
5471 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5472 RegCloseKey(hkeyPrinter);
5473 return ret;
5475 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5476 RegCloseKey(hkeySubkey);
5477 RegCloseKey(hkeyPrinter);
5478 return ret;
5481 /******************************************************************************
5482 * SetPrinterDataA (WINSPOOL.@)
5484 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5485 LPBYTE pData, DWORD cbData)
5487 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5488 pData, cbData);
5491 /******************************************************************************
5492 * SetPrinterDataW (WINSPOOL.@)
5494 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5495 LPBYTE pData, DWORD cbData)
5497 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5498 pData, cbData);
5501 /******************************************************************************
5502 * GetPrinterDataExA (WINSPOOL.@)
5504 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5505 LPCSTR pValueName, LPDWORD pType,
5506 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5508 opened_printer_t *printer;
5509 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5510 DWORD ret;
5512 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5513 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5515 printer = get_opened_printer(hPrinter);
5516 if(!printer) return ERROR_INVALID_HANDLE;
5518 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5519 if (ret) return ret;
5521 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5523 if (printer->name) {
5525 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5526 if (ret) {
5527 RegCloseKey(hkeyPrinters);
5528 return ret;
5530 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5531 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5532 RegCloseKey(hkeyPrinter);
5533 RegCloseKey(hkeyPrinters);
5534 return ret;
5537 *pcbNeeded = nSize;
5538 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5539 0, pType, pData, pcbNeeded);
5541 if (!ret && !pData) ret = ERROR_MORE_DATA;
5543 RegCloseKey(hkeySubkey);
5544 RegCloseKey(hkeyPrinter);
5545 RegCloseKey(hkeyPrinters);
5547 TRACE("--> %d\n", ret);
5548 return ret;
5551 /******************************************************************************
5552 * GetPrinterDataExW (WINSPOOL.@)
5554 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5555 LPCWSTR pValueName, LPDWORD pType,
5556 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5558 opened_printer_t *printer;
5559 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5560 DWORD ret;
5562 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5563 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5565 printer = get_opened_printer(hPrinter);
5566 if(!printer) return ERROR_INVALID_HANDLE;
5568 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5569 if (ret) return ret;
5571 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5573 if (printer->name) {
5575 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5576 if (ret) {
5577 RegCloseKey(hkeyPrinters);
5578 return ret;
5580 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5581 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5582 RegCloseKey(hkeyPrinter);
5583 RegCloseKey(hkeyPrinters);
5584 return ret;
5587 *pcbNeeded = nSize;
5588 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5589 0, pType, pData, pcbNeeded);
5591 if (!ret && !pData) ret = ERROR_MORE_DATA;
5593 RegCloseKey(hkeySubkey);
5594 RegCloseKey(hkeyPrinter);
5595 RegCloseKey(hkeyPrinters);
5597 TRACE("--> %d\n", ret);
5598 return ret;
5601 /******************************************************************************
5602 * GetPrinterDataA (WINSPOOL.@)
5604 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5605 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5607 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5608 pData, nSize, pcbNeeded);
5611 /******************************************************************************
5612 * GetPrinterDataW (WINSPOOL.@)
5614 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5615 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5617 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5618 pData, nSize, pcbNeeded);
5621 /*******************************************************************************
5622 * EnumPrinterDataExW [WINSPOOL.@]
5624 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5625 LPBYTE pEnumValues, DWORD cbEnumValues,
5626 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5628 HKEY hkPrinter, hkSubKey;
5629 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5630 cbValueNameLen, cbMaxValueLen, cbValueLen,
5631 cbBufSize, dwType;
5632 LPWSTR lpValueName;
5633 HANDLE hHeap;
5634 PBYTE lpValue;
5635 PPRINTER_ENUM_VALUESW ppev;
5637 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5639 if (pKeyName == NULL || *pKeyName == 0)
5640 return ERROR_INVALID_PARAMETER;
5642 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5643 if (ret != ERROR_SUCCESS)
5645 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5646 hPrinter, ret);
5647 return ret;
5650 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5651 if (ret != ERROR_SUCCESS)
5653 r = RegCloseKey (hkPrinter);
5654 if (r != ERROR_SUCCESS)
5655 WARN ("RegCloseKey returned %i\n", r);
5656 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5657 debugstr_w (pKeyName), ret);
5658 return ret;
5661 ret = RegCloseKey (hkPrinter);
5662 if (ret != ERROR_SUCCESS)
5664 ERR ("RegCloseKey returned %i\n", ret);
5665 r = RegCloseKey (hkSubKey);
5666 if (r != ERROR_SUCCESS)
5667 WARN ("RegCloseKey returned %i\n", r);
5668 return ret;
5671 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5672 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5673 if (ret != ERROR_SUCCESS)
5675 r = RegCloseKey (hkSubKey);
5676 if (r != ERROR_SUCCESS)
5677 WARN ("RegCloseKey returned %i\n", r);
5678 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5679 return ret;
5682 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5683 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5685 if (cValues == 0) /* empty key */
5687 r = RegCloseKey (hkSubKey);
5688 if (r != ERROR_SUCCESS)
5689 WARN ("RegCloseKey returned %i\n", r);
5690 *pcbEnumValues = *pnEnumValues = 0;
5691 return ERROR_SUCCESS;
5694 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5696 hHeap = GetProcessHeap ();
5697 if (hHeap == NULL)
5699 ERR ("GetProcessHeap failed\n");
5700 r = RegCloseKey (hkSubKey);
5701 if (r != ERROR_SUCCESS)
5702 WARN ("RegCloseKey returned %i\n", r);
5703 return ERROR_OUTOFMEMORY;
5706 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5707 if (lpValueName == NULL)
5709 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5710 r = RegCloseKey (hkSubKey);
5711 if (r != ERROR_SUCCESS)
5712 WARN ("RegCloseKey returned %i\n", r);
5713 return ERROR_OUTOFMEMORY;
5716 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5717 if (lpValue == NULL)
5719 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5720 if (HeapFree (hHeap, 0, lpValueName) == 0)
5721 WARN ("HeapFree failed with code %i\n", GetLastError ());
5722 r = RegCloseKey (hkSubKey);
5723 if (r != ERROR_SUCCESS)
5724 WARN ("RegCloseKey returned %i\n", r);
5725 return ERROR_OUTOFMEMORY;
5728 TRACE ("pass 1: calculating buffer required for all names and values\n");
5730 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5732 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5734 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5736 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5737 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5738 NULL, NULL, lpValue, &cbValueLen);
5739 if (ret != ERROR_SUCCESS)
5741 if (HeapFree (hHeap, 0, lpValue) == 0)
5742 WARN ("HeapFree failed with code %i\n", GetLastError ());
5743 if (HeapFree (hHeap, 0, lpValueName) == 0)
5744 WARN ("HeapFree failed with code %i\n", GetLastError ());
5745 r = RegCloseKey (hkSubKey);
5746 if (r != ERROR_SUCCESS)
5747 WARN ("RegCloseKey returned %i\n", r);
5748 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5749 return ret;
5752 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5753 debugstr_w (lpValueName), dwIndex,
5754 cbValueNameLen + 1, cbValueLen);
5756 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5757 cbBufSize += cbValueLen;
5760 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5762 *pcbEnumValues = cbBufSize;
5763 *pnEnumValues = cValues;
5765 if (cbEnumValues < cbBufSize) /* buffer too small */
5767 if (HeapFree (hHeap, 0, lpValue) == 0)
5768 WARN ("HeapFree failed with code %i\n", GetLastError ());
5769 if (HeapFree (hHeap, 0, lpValueName) == 0)
5770 WARN ("HeapFree failed with code %i\n", GetLastError ());
5771 r = RegCloseKey (hkSubKey);
5772 if (r != ERROR_SUCCESS)
5773 WARN ("RegCloseKey returned %i\n", r);
5774 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5775 return ERROR_MORE_DATA;
5778 TRACE ("pass 2: copying all names and values to buffer\n");
5780 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5781 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5783 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5785 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5786 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5787 NULL, &dwType, lpValue, &cbValueLen);
5788 if (ret != ERROR_SUCCESS)
5790 if (HeapFree (hHeap, 0, lpValue) == 0)
5791 WARN ("HeapFree failed with code %i\n", GetLastError ());
5792 if (HeapFree (hHeap, 0, lpValueName) == 0)
5793 WARN ("HeapFree failed with code %i\n", GetLastError ());
5794 r = RegCloseKey (hkSubKey);
5795 if (r != ERROR_SUCCESS)
5796 WARN ("RegCloseKey returned %i\n", r);
5797 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5798 return ret;
5801 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5802 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5803 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5804 pEnumValues += cbValueNameLen;
5806 /* return # of *bytes* (including trailing \0), not # of chars */
5807 ppev[dwIndex].cbValueName = cbValueNameLen;
5809 ppev[dwIndex].dwType = dwType;
5811 memcpy (pEnumValues, lpValue, cbValueLen);
5812 ppev[dwIndex].pData = pEnumValues;
5813 pEnumValues += cbValueLen;
5815 ppev[dwIndex].cbData = cbValueLen;
5817 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5818 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5821 if (HeapFree (hHeap, 0, lpValue) == 0)
5823 ret = GetLastError ();
5824 ERR ("HeapFree failed with code %i\n", ret);
5825 if (HeapFree (hHeap, 0, lpValueName) == 0)
5826 WARN ("HeapFree failed with code %i\n", GetLastError ());
5827 r = RegCloseKey (hkSubKey);
5828 if (r != ERROR_SUCCESS)
5829 WARN ("RegCloseKey returned %i\n", r);
5830 return ret;
5833 if (HeapFree (hHeap, 0, lpValueName) == 0)
5835 ret = GetLastError ();
5836 ERR ("HeapFree failed with code %i\n", ret);
5837 r = RegCloseKey (hkSubKey);
5838 if (r != ERROR_SUCCESS)
5839 WARN ("RegCloseKey returned %i\n", r);
5840 return ret;
5843 ret = RegCloseKey (hkSubKey);
5844 if (ret != ERROR_SUCCESS)
5846 ERR ("RegCloseKey returned %i\n", ret);
5847 return ret;
5850 return ERROR_SUCCESS;
5853 /*******************************************************************************
5854 * EnumPrinterDataExA [WINSPOOL.@]
5856 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5857 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5858 * what Windows 2000 SP1 does.
5861 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5862 LPBYTE pEnumValues, DWORD cbEnumValues,
5863 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5865 INT len;
5866 LPWSTR pKeyNameW;
5867 DWORD ret, dwIndex, dwBufSize;
5868 HANDLE hHeap;
5869 LPSTR pBuffer;
5871 TRACE ("%p %s\n", hPrinter, pKeyName);
5873 if (pKeyName == NULL || *pKeyName == 0)
5874 return ERROR_INVALID_PARAMETER;
5876 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5877 if (len == 0)
5879 ret = GetLastError ();
5880 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5881 return ret;
5884 hHeap = GetProcessHeap ();
5885 if (hHeap == NULL)
5887 ERR ("GetProcessHeap failed\n");
5888 return ERROR_OUTOFMEMORY;
5891 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5892 if (pKeyNameW == NULL)
5894 ERR ("Failed to allocate %i bytes from process heap\n",
5895 (LONG)(len * sizeof (WCHAR)));
5896 return ERROR_OUTOFMEMORY;
5899 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5901 ret = GetLastError ();
5902 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5903 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5904 WARN ("HeapFree failed with code %i\n", GetLastError ());
5905 return ret;
5908 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5909 pcbEnumValues, pnEnumValues);
5910 if (ret != ERROR_SUCCESS)
5912 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5913 WARN ("HeapFree failed with code %i\n", GetLastError ());
5914 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5915 return ret;
5918 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5920 ret = GetLastError ();
5921 ERR ("HeapFree failed with code %i\n", ret);
5922 return ret;
5925 if (*pnEnumValues == 0) /* empty key */
5926 return ERROR_SUCCESS;
5928 dwBufSize = 0;
5929 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5931 PPRINTER_ENUM_VALUESW ppev =
5932 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5934 if (dwBufSize < ppev->cbValueName)
5935 dwBufSize = ppev->cbValueName;
5937 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5938 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5939 dwBufSize = ppev->cbData;
5942 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5944 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5945 if (pBuffer == NULL)
5947 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5948 return ERROR_OUTOFMEMORY;
5951 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5953 PPRINTER_ENUM_VALUESW ppev =
5954 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5956 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5957 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5958 NULL);
5959 if (len == 0)
5961 ret = GetLastError ();
5962 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5963 if (HeapFree (hHeap, 0, pBuffer) == 0)
5964 WARN ("HeapFree failed with code %i\n", GetLastError ());
5965 return ret;
5968 memcpy (ppev->pValueName, pBuffer, len);
5970 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5972 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5973 ppev->dwType != REG_MULTI_SZ)
5974 continue;
5976 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5977 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5978 if (len == 0)
5980 ret = GetLastError ();
5981 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5982 if (HeapFree (hHeap, 0, pBuffer) == 0)
5983 WARN ("HeapFree failed with code %i\n", GetLastError ());
5984 return ret;
5987 memcpy (ppev->pData, pBuffer, len);
5989 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5990 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5993 if (HeapFree (hHeap, 0, pBuffer) == 0)
5995 ret = GetLastError ();
5996 ERR ("HeapFree failed with code %i\n", ret);
5997 return ret;
6000 return ERROR_SUCCESS;
6003 /******************************************************************************
6004 * AbortPrinter (WINSPOOL.@)
6006 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6008 FIXME("(%p), stub!\n", hPrinter);
6009 return TRUE;
6012 /******************************************************************************
6013 * AddPortA (WINSPOOL.@)
6015 * See AddPortW.
6018 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6020 LPWSTR nameW = NULL;
6021 LPWSTR monitorW = NULL;
6022 DWORD len;
6023 BOOL res;
6025 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6027 if (pName) {
6028 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6029 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6030 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6033 if (pMonitorName) {
6034 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6035 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6036 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6038 res = AddPortW(nameW, hWnd, monitorW);
6039 HeapFree(GetProcessHeap(), 0, nameW);
6040 HeapFree(GetProcessHeap(), 0, monitorW);
6041 return res;
6044 /******************************************************************************
6045 * AddPortW (WINSPOOL.@)
6047 * Add a Port for a specific Monitor
6049 * PARAMS
6050 * pName [I] Servername or NULL (local Computer)
6051 * hWnd [I] Handle to parent Window for the Dialog-Box
6052 * pMonitorName [I] Name of the Monitor that manage the Port
6054 * RETURNS
6055 * Success: TRUE
6056 * Failure: FALSE
6059 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6061 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6063 if ((backend == NULL) && !load_backend()) return FALSE;
6065 if (!pMonitorName) {
6066 SetLastError(RPC_X_NULL_REF_POINTER);
6067 return FALSE;
6070 return backend->fpAddPort(pName, hWnd, pMonitorName);
6073 /******************************************************************************
6074 * AddPortExA (WINSPOOL.@)
6076 * See AddPortExW.
6079 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6081 PORT_INFO_2W pi2W;
6082 PORT_INFO_2A * pi2A;
6083 LPWSTR nameW = NULL;
6084 LPWSTR monitorW = NULL;
6085 DWORD len;
6086 BOOL res;
6088 pi2A = (PORT_INFO_2A *) pBuffer;
6090 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6091 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6093 if ((level < 1) || (level > 2)) {
6094 SetLastError(ERROR_INVALID_LEVEL);
6095 return FALSE;
6098 if (!pi2A) {
6099 SetLastError(ERROR_INVALID_PARAMETER);
6100 return FALSE;
6103 if (pName) {
6104 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6105 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6106 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6109 if (pMonitorName) {
6110 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6111 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6112 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6115 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6117 if (pi2A->pPortName) {
6118 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6119 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6120 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6123 if (level > 1) {
6124 if (pi2A->pMonitorName) {
6125 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6126 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6127 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6130 if (pi2A->pDescription) {
6131 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6132 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6133 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6135 pi2W.fPortType = pi2A->fPortType;
6136 pi2W.Reserved = pi2A->Reserved;
6139 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6141 HeapFree(GetProcessHeap(), 0, nameW);
6142 HeapFree(GetProcessHeap(), 0, monitorW);
6143 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6144 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6145 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6146 return res;
6150 /******************************************************************************
6151 * AddPortExW (WINSPOOL.@)
6153 * Add a Port for a specific Monitor, without presenting a user interface
6155 * PARAMS
6156 * pName [I] Servername or NULL (local Computer)
6157 * level [I] Structure-Level (1 or 2) for pBuffer
6158 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6159 * pMonitorName [I] Name of the Monitor that manage the Port
6161 * RETURNS
6162 * Success: TRUE
6163 * Failure: FALSE
6166 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6168 PORT_INFO_2W * pi2;
6170 pi2 = (PORT_INFO_2W *) pBuffer;
6172 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6173 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6174 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6175 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6177 if ((backend == NULL) && !load_backend()) return FALSE;
6179 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6180 SetLastError(ERROR_INVALID_PARAMETER);
6181 return FALSE;
6184 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6187 /******************************************************************************
6188 * AddPrinterConnectionA (WINSPOOL.@)
6190 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6192 FIXME("%s\n", debugstr_a(pName));
6193 return FALSE;
6196 /******************************************************************************
6197 * AddPrinterConnectionW (WINSPOOL.@)
6199 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6201 FIXME("%s\n", debugstr_w(pName));
6202 return FALSE;
6205 /******************************************************************************
6206 * AddPrinterDriverExW (WINSPOOL.@)
6208 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6210 * PARAMS
6211 * pName [I] Servername or NULL (local Computer)
6212 * level [I] Level for the supplied DRIVER_INFO_*W struct
6213 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6214 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6216 * RESULTS
6217 * Success: TRUE
6218 * Failure: FALSE
6221 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6223 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6225 if ((backend == NULL) && !load_backend()) return FALSE;
6227 if (level < 2 || level == 5 || level == 7 || level > 8) {
6228 SetLastError(ERROR_INVALID_LEVEL);
6229 return FALSE;
6232 if (!pDriverInfo) {
6233 SetLastError(ERROR_INVALID_PARAMETER);
6234 return FALSE;
6237 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6240 /******************************************************************************
6241 * AddPrinterDriverExA (WINSPOOL.@)
6243 * See AddPrinterDriverExW.
6246 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6248 DRIVER_INFO_8A *diA;
6249 DRIVER_INFO_8W diW;
6250 LPWSTR nameW = NULL;
6251 DWORD lenA;
6252 DWORD len;
6253 DWORD res = FALSE;
6255 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6257 diA = (DRIVER_INFO_8A *) pDriverInfo;
6258 ZeroMemory(&diW, sizeof(diW));
6260 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6261 SetLastError(ERROR_INVALID_LEVEL);
6262 return FALSE;
6265 if (diA == NULL) {
6266 SetLastError(ERROR_INVALID_PARAMETER);
6267 return FALSE;
6270 /* convert servername to unicode */
6271 if (pName) {
6272 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6273 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6274 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6277 /* common fields */
6278 diW.cVersion = diA->cVersion;
6280 if (diA->pName) {
6281 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6282 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6283 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6286 if (diA->pEnvironment) {
6287 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6288 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6289 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6292 if (diA->pDriverPath) {
6293 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6294 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6295 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6298 if (diA->pDataFile) {
6299 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6300 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6301 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6304 if (diA->pConfigFile) {
6305 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6306 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6307 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6310 if ((Level > 2) && diA->pDependentFiles) {
6311 lenA = multi_sz_lenA(diA->pDependentFiles);
6312 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6313 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6314 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6317 if ((Level > 2) && diA->pMonitorName) {
6318 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6319 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6320 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6323 if ((Level > 3) && diA->pDefaultDataType) {
6324 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6325 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6326 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6329 if ((Level > 3) && diA->pszzPreviousNames) {
6330 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6331 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6332 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6333 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6336 if ((Level > 5) && diA->pszMfgName) {
6337 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6338 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6339 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6342 if ((Level > 5) && diA->pszOEMUrl) {
6343 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6344 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6345 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6348 if ((Level > 5) && diA->pszHardwareID) {
6349 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6350 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6351 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6354 if ((Level > 5) && diA->pszProvider) {
6355 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6356 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6357 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6360 if (Level > 7) {
6361 FIXME("level %u is incomplete\n", Level);
6364 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6365 TRACE("got %u with %u\n", res, GetLastError());
6366 HeapFree(GetProcessHeap(), 0, nameW);
6367 HeapFree(GetProcessHeap(), 0, diW.pName);
6368 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6369 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6370 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6371 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6372 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6373 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6374 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6375 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6376 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6377 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6378 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6379 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6381 TRACE("=> %u with %u\n", res, GetLastError());
6382 return res;
6385 /******************************************************************************
6386 * ConfigurePortA (WINSPOOL.@)
6388 * See ConfigurePortW.
6391 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6393 LPWSTR nameW = NULL;
6394 LPWSTR portW = NULL;
6395 INT len;
6396 DWORD res;
6398 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6400 /* convert servername to unicode */
6401 if (pName) {
6402 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6403 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6404 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6407 /* convert portname to unicode */
6408 if (pPortName) {
6409 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6410 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6411 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6414 res = ConfigurePortW(nameW, hWnd, portW);
6415 HeapFree(GetProcessHeap(), 0, nameW);
6416 HeapFree(GetProcessHeap(), 0, portW);
6417 return res;
6420 /******************************************************************************
6421 * ConfigurePortW (WINSPOOL.@)
6423 * Display the Configuration-Dialog for a specific Port
6425 * PARAMS
6426 * pName [I] Servername or NULL (local Computer)
6427 * hWnd [I] Handle to parent Window for the Dialog-Box
6428 * pPortName [I] Name of the Port, that should be configured
6430 * RETURNS
6431 * Success: TRUE
6432 * Failure: FALSE
6435 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6438 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6440 if ((backend == NULL) && !load_backend()) return FALSE;
6442 if (!pPortName) {
6443 SetLastError(RPC_X_NULL_REF_POINTER);
6444 return FALSE;
6447 return backend->fpConfigurePort(pName, hWnd, pPortName);
6450 /******************************************************************************
6451 * ConnectToPrinterDlg (WINSPOOL.@)
6453 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6455 FIXME("%p %x\n", hWnd, Flags);
6456 return NULL;
6459 /******************************************************************************
6460 * DeletePrinterConnectionA (WINSPOOL.@)
6462 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6464 FIXME("%s\n", debugstr_a(pName));
6465 return TRUE;
6468 /******************************************************************************
6469 * DeletePrinterConnectionW (WINSPOOL.@)
6471 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6473 FIXME("%s\n", debugstr_w(pName));
6474 return TRUE;
6477 /******************************************************************************
6478 * DeletePrinterDriverExW (WINSPOOL.@)
6480 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6481 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6483 HKEY hkey_drivers;
6484 BOOL ret = FALSE;
6486 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6487 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6489 if(pName && pName[0])
6491 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6492 SetLastError(ERROR_INVALID_PARAMETER);
6493 return FALSE;
6496 if(dwDeleteFlag)
6498 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6499 SetLastError(ERROR_INVALID_PARAMETER);
6500 return FALSE;
6503 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6505 if(!hkey_drivers)
6507 ERR("Can't open drivers key\n");
6508 return FALSE;
6511 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6512 ret = TRUE;
6514 RegCloseKey(hkey_drivers);
6516 return ret;
6519 /******************************************************************************
6520 * DeletePrinterDriverExA (WINSPOOL.@)
6522 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6523 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6525 UNICODE_STRING NameW, EnvW, DriverW;
6526 BOOL ret;
6528 asciitounicode(&NameW, pName);
6529 asciitounicode(&EnvW, pEnvironment);
6530 asciitounicode(&DriverW, pDriverName);
6532 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6534 RtlFreeUnicodeString(&DriverW);
6535 RtlFreeUnicodeString(&EnvW);
6536 RtlFreeUnicodeString(&NameW);
6538 return ret;
6541 /******************************************************************************
6542 * DeletePrinterDataExW (WINSPOOL.@)
6544 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6545 LPCWSTR pValueName)
6547 FIXME("%p %s %s\n", hPrinter,
6548 debugstr_w(pKeyName), debugstr_w(pValueName));
6549 return ERROR_INVALID_PARAMETER;
6552 /******************************************************************************
6553 * DeletePrinterDataExA (WINSPOOL.@)
6555 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6556 LPCSTR pValueName)
6558 FIXME("%p %s %s\n", hPrinter,
6559 debugstr_a(pKeyName), debugstr_a(pValueName));
6560 return ERROR_INVALID_PARAMETER;
6563 /******************************************************************************
6564 * DeletePrintProcessorA (WINSPOOL.@)
6566 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6568 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6569 debugstr_a(pPrintProcessorName));
6570 return TRUE;
6573 /******************************************************************************
6574 * DeletePrintProcessorW (WINSPOOL.@)
6576 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6578 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6579 debugstr_w(pPrintProcessorName));
6580 return TRUE;
6583 /******************************************************************************
6584 * DeletePrintProvidorA (WINSPOOL.@)
6586 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6588 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6589 debugstr_a(pPrintProviderName));
6590 return TRUE;
6593 /******************************************************************************
6594 * DeletePrintProvidorW (WINSPOOL.@)
6596 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6598 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6599 debugstr_w(pPrintProviderName));
6600 return TRUE;
6603 /******************************************************************************
6604 * EnumFormsA (WINSPOOL.@)
6606 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6607 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6609 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6610 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6611 return FALSE;
6614 /******************************************************************************
6615 * EnumFormsW (WINSPOOL.@)
6617 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6618 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6620 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6621 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6622 return FALSE;
6625 /*****************************************************************************
6626 * EnumMonitorsA [WINSPOOL.@]
6628 * See EnumMonitorsW.
6631 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6632 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6634 BOOL res;
6635 LPBYTE bufferW = NULL;
6636 LPWSTR nameW = NULL;
6637 DWORD needed = 0;
6638 DWORD numentries = 0;
6639 INT len;
6641 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6642 cbBuf, pcbNeeded, pcReturned);
6644 /* convert servername to unicode */
6645 if (pName) {
6646 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6647 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6648 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6650 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6651 needed = cbBuf * sizeof(WCHAR);
6652 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6653 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6655 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6656 if (pcbNeeded) needed = *pcbNeeded;
6657 /* HeapReAlloc return NULL, when bufferW was NULL */
6658 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6659 HeapAlloc(GetProcessHeap(), 0, needed);
6661 /* Try again with the large Buffer */
6662 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6664 numentries = pcReturned ? *pcReturned : 0;
6665 needed = 0;
6667 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6668 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6670 if (res) {
6671 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6672 DWORD entrysize = 0;
6673 DWORD index;
6674 LPSTR ptr;
6675 LPMONITOR_INFO_2W mi2w;
6676 LPMONITOR_INFO_2A mi2a;
6678 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6679 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6681 /* First pass: calculate the size for all Entries */
6682 mi2w = (LPMONITOR_INFO_2W) bufferW;
6683 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6684 index = 0;
6685 while (index < numentries) {
6686 index++;
6687 needed += entrysize; /* MONITOR_INFO_?A */
6688 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6690 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6691 NULL, 0, NULL, NULL);
6692 if (Level > 1) {
6693 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6694 NULL, 0, NULL, NULL);
6695 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6696 NULL, 0, NULL, NULL);
6698 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6699 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6700 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6703 /* check for errors and quit on failure */
6704 if (cbBuf < needed) {
6705 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6706 res = FALSE;
6707 goto emA_cleanup;
6709 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6710 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6711 cbBuf -= len ; /* free Bytes in the user-Buffer */
6712 mi2w = (LPMONITOR_INFO_2W) bufferW;
6713 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6714 index = 0;
6715 /* Second Pass: Fill the User Buffer (if we have one) */
6716 while ((index < numentries) && pMonitors) {
6717 index++;
6718 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6719 mi2a->pName = ptr;
6720 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6721 ptr, cbBuf , NULL, NULL);
6722 ptr += len;
6723 cbBuf -= len;
6724 if (Level > 1) {
6725 mi2a->pEnvironment = ptr;
6726 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6727 ptr, cbBuf, NULL, NULL);
6728 ptr += len;
6729 cbBuf -= len;
6731 mi2a->pDLLName = ptr;
6732 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6733 ptr, cbBuf, NULL, NULL);
6734 ptr += len;
6735 cbBuf -= len;
6737 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6738 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6739 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6742 emA_cleanup:
6743 if (pcbNeeded) *pcbNeeded = needed;
6744 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6746 HeapFree(GetProcessHeap(), 0, nameW);
6747 HeapFree(GetProcessHeap(), 0, bufferW);
6749 TRACE("returning %d with %d (%d byte for %d entries)\n",
6750 (res), GetLastError(), needed, numentries);
6752 return (res);
6756 /*****************************************************************************
6757 * EnumMonitorsW [WINSPOOL.@]
6759 * Enumerate available Port-Monitors
6761 * PARAMS
6762 * pName [I] Servername or NULL (local Computer)
6763 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6764 * pMonitors [O] PTR to Buffer that receives the Result
6765 * cbBuf [I] Size of Buffer at pMonitors
6766 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6767 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6769 * RETURNS
6770 * Success: TRUE
6771 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6774 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6775 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6778 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6779 cbBuf, pcbNeeded, pcReturned);
6781 if ((backend == NULL) && !load_backend()) return FALSE;
6783 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6784 SetLastError(RPC_X_NULL_REF_POINTER);
6785 return FALSE;
6788 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6791 /******************************************************************************
6792 * SpoolerInit (WINSPOOL.@)
6794 * Initialize the Spooler
6796 * RETURNS
6797 * Success: TRUE
6798 * Failure: FALSE
6800 * NOTES
6801 * The function fails on windows, when the spooler service is not running
6804 BOOL WINAPI SpoolerInit(void)
6807 if ((backend == NULL) && !load_backend()) return FALSE;
6808 return TRUE;
6811 /******************************************************************************
6812 * XcvDataW (WINSPOOL.@)
6814 * Execute commands in the Printmonitor DLL
6816 * PARAMS
6817 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6818 * pszDataName [i] Name of the command to execute
6819 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6820 * cbInputData [i] Size in Bytes of Buffer at pInputData
6821 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6822 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6823 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6824 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6826 * RETURNS
6827 * Success: TRUE
6828 * Failure: FALSE
6830 * NOTES
6831 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6832 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6834 * Minimal List of commands, that a Printmonitor DLL should support:
6836 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6837 *| "AddPort" : Add a Port
6838 *| "DeletePort": Delete a Port
6840 * Many Printmonitors support additional commands. Examples for localspl.dll:
6841 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6842 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6845 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6846 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6847 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6849 opened_printer_t *printer;
6851 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6852 pInputData, cbInputData, pOutputData,
6853 cbOutputData, pcbOutputNeeded, pdwStatus);
6855 if ((backend == NULL) && !load_backend()) return FALSE;
6857 printer = get_opened_printer(hXcv);
6858 if (!printer || (!printer->backend_printer)) {
6859 SetLastError(ERROR_INVALID_HANDLE);
6860 return FALSE;
6863 if (!pcbOutputNeeded) {
6864 SetLastError(ERROR_INVALID_PARAMETER);
6865 return FALSE;
6868 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6869 SetLastError(RPC_X_NULL_REF_POINTER);
6870 return FALSE;
6873 *pcbOutputNeeded = 0;
6875 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6876 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6880 /*****************************************************************************
6881 * EnumPrinterDataA [WINSPOOL.@]
6884 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6885 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6886 DWORD cbData, LPDWORD pcbData )
6888 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6889 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6890 return ERROR_NO_MORE_ITEMS;
6893 /*****************************************************************************
6894 * EnumPrinterDataW [WINSPOOL.@]
6897 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6898 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6899 DWORD cbData, LPDWORD pcbData )
6901 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6902 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6903 return ERROR_NO_MORE_ITEMS;
6906 /*****************************************************************************
6907 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6910 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6911 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6912 LPDWORD pcbNeeded, LPDWORD pcReturned)
6914 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6915 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6916 pcbNeeded, pcReturned);
6917 return FALSE;
6920 /*****************************************************************************
6921 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6924 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6925 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6926 LPDWORD pcbNeeded, LPDWORD pcReturned)
6928 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6929 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6930 pcbNeeded, pcReturned);
6931 return FALSE;
6934 /*****************************************************************************
6935 * EnumPrintProcessorsA [WINSPOOL.@]
6937 * See EnumPrintProcessorsW.
6940 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6941 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6943 BOOL res;
6944 LPBYTE bufferW = NULL;
6945 LPWSTR nameW = NULL;
6946 LPWSTR envW = NULL;
6947 DWORD needed = 0;
6948 DWORD numentries = 0;
6949 INT len;
6951 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6952 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6954 /* convert names to unicode */
6955 if (pName) {
6956 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6957 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6958 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6960 if (pEnvironment) {
6961 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6962 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6966 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6967 needed = cbBuf * sizeof(WCHAR);
6968 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6969 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6971 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6972 if (pcbNeeded) needed = *pcbNeeded;
6973 /* HeapReAlloc return NULL, when bufferW was NULL */
6974 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6975 HeapAlloc(GetProcessHeap(), 0, needed);
6977 /* Try again with the large Buffer */
6978 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6980 numentries = pcReturned ? *pcReturned : 0;
6981 needed = 0;
6983 if (res) {
6984 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6985 DWORD index;
6986 LPSTR ptr;
6987 PPRINTPROCESSOR_INFO_1W ppiw;
6988 PPRINTPROCESSOR_INFO_1A ppia;
6990 /* First pass: calculate the size for all Entries */
6991 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6992 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6993 index = 0;
6994 while (index < numentries) {
6995 index++;
6996 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6997 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6999 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7000 NULL, 0, NULL, NULL);
7002 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7003 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7006 /* check for errors and quit on failure */
7007 if (cbBuf < needed) {
7008 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7009 res = FALSE;
7010 goto epp_cleanup;
7013 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7014 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7015 cbBuf -= len ; /* free Bytes in the user-Buffer */
7016 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7017 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7018 index = 0;
7019 /* Second Pass: Fill the User Buffer (if we have one) */
7020 while ((index < numentries) && pPPInfo) {
7021 index++;
7022 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7023 ppia->pName = ptr;
7024 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7025 ptr, cbBuf , NULL, NULL);
7026 ptr += len;
7027 cbBuf -= len;
7029 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7030 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7034 epp_cleanup:
7035 if (pcbNeeded) *pcbNeeded = needed;
7036 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7038 HeapFree(GetProcessHeap(), 0, nameW);
7039 HeapFree(GetProcessHeap(), 0, envW);
7040 HeapFree(GetProcessHeap(), 0, bufferW);
7042 TRACE("returning %d with %d (%d byte for %d entries)\n",
7043 (res), GetLastError(), needed, numentries);
7045 return (res);
7048 /*****************************************************************************
7049 * EnumPrintProcessorsW [WINSPOOL.@]
7051 * Enumerate available Print Processors
7053 * PARAMS
7054 * pName [I] Servername or NULL (local Computer)
7055 * pEnvironment [I] Printing-Environment or NULL (Default)
7056 * Level [I] Structure-Level (Only 1 is allowed)
7057 * pPPInfo [O] PTR to Buffer that receives the Result
7058 * cbBuf [I] Size of Buffer at pPPInfo
7059 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7060 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7062 * RETURNS
7063 * Success: TRUE
7064 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7067 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7068 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7071 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7072 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7074 if ((backend == NULL) && !load_backend()) return FALSE;
7076 if (!pcbNeeded || !pcReturned) {
7077 SetLastError(RPC_X_NULL_REF_POINTER);
7078 return FALSE;
7081 if (!pPPInfo && (cbBuf > 0)) {
7082 SetLastError(ERROR_INVALID_USER_BUFFER);
7083 return FALSE;
7086 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7087 cbBuf, pcbNeeded, pcReturned);
7090 /*****************************************************************************
7091 * ExtDeviceMode [WINSPOOL.@]
7094 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7095 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7096 DWORD fMode)
7098 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7099 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7100 debugstr_a(pProfile), fMode);
7101 return -1;
7104 /*****************************************************************************
7105 * FindClosePrinterChangeNotification [WINSPOOL.@]
7108 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7110 FIXME("Stub: %p\n", hChange);
7111 return TRUE;
7114 /*****************************************************************************
7115 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7118 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7119 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7121 FIXME("Stub: %p %x %x %p\n",
7122 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7123 return INVALID_HANDLE_VALUE;
7126 /*****************************************************************************
7127 * FindNextPrinterChangeNotification [WINSPOOL.@]
7130 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7131 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7133 FIXME("Stub: %p %p %p %p\n",
7134 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7135 return FALSE;
7138 /*****************************************************************************
7139 * FreePrinterNotifyInfo [WINSPOOL.@]
7142 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7144 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7145 return TRUE;
7148 /*****************************************************************************
7149 * string_to_buf
7151 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7152 * ansi depending on the unicode parameter.
7154 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7156 if(!str)
7158 *size = 0;
7159 return TRUE;
7162 if(unicode)
7164 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7165 if(*size <= cb)
7167 memcpy(ptr, str, *size);
7168 return TRUE;
7170 return FALSE;
7172 else
7174 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7175 if(*size <= cb)
7177 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7178 return TRUE;
7180 return FALSE;
7184 /*****************************************************************************
7185 * get_job_info_1
7187 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7188 LPDWORD pcbNeeded, BOOL unicode)
7190 DWORD size, left = cbBuf;
7191 BOOL space = (cbBuf > 0);
7192 LPBYTE ptr = buf;
7194 *pcbNeeded = 0;
7196 if(space)
7198 ji1->JobId = job->job_id;
7201 string_to_buf(job->document_title, ptr, left, &size, unicode);
7202 if(space && size <= left)
7204 ji1->pDocument = (LPWSTR)ptr;
7205 ptr += size;
7206 left -= size;
7208 else
7209 space = FALSE;
7210 *pcbNeeded += size;
7212 if (job->printer_name)
7214 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7215 if(space && size <= left)
7217 ji1->pPrinterName = (LPWSTR)ptr;
7218 ptr += size;
7219 left -= size;
7221 else
7222 space = FALSE;
7223 *pcbNeeded += size;
7226 return space;
7229 /*****************************************************************************
7230 * get_job_info_2
7232 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7233 LPDWORD pcbNeeded, BOOL unicode)
7235 DWORD size, left = cbBuf;
7236 DWORD shift;
7237 BOOL space = (cbBuf > 0);
7238 LPBYTE ptr = buf;
7239 LPDEVMODEA dmA = NULL;
7240 LPDEVMODEW devmode;
7242 *pcbNeeded = 0;
7244 if(space)
7246 ji2->JobId = job->job_id;
7249 string_to_buf(job->document_title, ptr, left, &size, unicode);
7250 if(space && size <= left)
7252 ji2->pDocument = (LPWSTR)ptr;
7253 ptr += size;
7254 left -= size;
7256 else
7257 space = FALSE;
7258 *pcbNeeded += size;
7260 if (job->printer_name)
7262 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7263 if(space && size <= left)
7265 ji2->pPrinterName = (LPWSTR)ptr;
7266 ptr += size;
7267 left -= size;
7269 else
7270 space = FALSE;
7271 *pcbNeeded += size;
7274 if (job->devmode)
7276 if (!unicode)
7278 dmA = DEVMODEdupWtoA(job->devmode);
7279 devmode = (LPDEVMODEW) dmA;
7280 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7282 else
7284 devmode = job->devmode;
7285 size = devmode->dmSize + devmode->dmDriverExtra;
7288 if (!devmode)
7289 FIXME("Can't convert DEVMODE W to A\n");
7290 else
7292 /* align DEVMODE to a DWORD boundary */
7293 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7294 size += shift;
7296 if (size <= left)
7298 ptr += shift;
7299 memcpy(ptr, devmode, size-shift);
7300 ji2->pDevMode = (LPDEVMODEW)ptr;
7301 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7302 ptr += size;
7303 left -= size;
7305 else
7306 space = FALSE;
7307 *pcbNeeded +=size;
7311 return space;
7314 /*****************************************************************************
7315 * get_job_info
7317 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7318 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7320 BOOL ret = FALSE;
7321 DWORD needed = 0, size;
7322 job_t *job;
7323 LPBYTE ptr = pJob;
7325 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7327 EnterCriticalSection(&printer_handles_cs);
7328 job = get_job(hPrinter, JobId);
7329 if(!job)
7330 goto end;
7332 switch(Level)
7334 case 1:
7335 size = sizeof(JOB_INFO_1W);
7336 if(cbBuf >= size)
7338 cbBuf -= size;
7339 ptr += size;
7340 memset(pJob, 0, size);
7342 else
7343 cbBuf = 0;
7344 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7345 needed += size;
7346 break;
7348 case 2:
7349 size = sizeof(JOB_INFO_2W);
7350 if(cbBuf >= size)
7352 cbBuf -= size;
7353 ptr += size;
7354 memset(pJob, 0, size);
7356 else
7357 cbBuf = 0;
7358 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7359 needed += size;
7360 break;
7362 case 3:
7363 size = sizeof(JOB_INFO_3);
7364 if(cbBuf >= size)
7366 cbBuf -= size;
7367 memset(pJob, 0, size);
7368 ret = TRUE;
7370 else
7371 cbBuf = 0;
7372 needed = size;
7373 break;
7375 default:
7376 SetLastError(ERROR_INVALID_LEVEL);
7377 goto end;
7379 if(pcbNeeded)
7380 *pcbNeeded = needed;
7381 end:
7382 LeaveCriticalSection(&printer_handles_cs);
7383 return ret;
7386 /*****************************************************************************
7387 * GetJobA [WINSPOOL.@]
7390 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7391 DWORD cbBuf, LPDWORD pcbNeeded)
7393 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7396 /*****************************************************************************
7397 * GetJobW [WINSPOOL.@]
7400 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7401 DWORD cbBuf, LPDWORD pcbNeeded)
7403 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7406 /*****************************************************************************
7407 * schedule_pipe
7409 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7411 #ifdef HAVE_FORK
7412 char *unixname, *cmdA;
7413 DWORD len;
7414 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7415 BOOL ret = FALSE;
7416 char buf[1024];
7417 pid_t pid, wret;
7418 int status;
7420 if(!(unixname = wine_get_unix_file_name(filename)))
7421 return FALSE;
7423 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7424 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7425 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7427 TRACE("printing with: %s\n", cmdA);
7429 if((file_fd = open(unixname, O_RDONLY)) == -1)
7430 goto end;
7432 if (pipe(fds))
7434 ERR("pipe() failed!\n");
7435 goto end;
7438 if ((pid = fork()) == 0)
7440 close(0);
7441 dup2(fds[0], 0);
7442 close(fds[1]);
7444 /* reset signals that we previously set to SIG_IGN */
7445 signal(SIGPIPE, SIG_DFL);
7447 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7448 _exit(1);
7450 else if (pid == -1)
7452 ERR("fork() failed!\n");
7453 goto end;
7456 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7457 write(fds[1], buf, no_read);
7459 close(fds[1]);
7460 fds[1] = -1;
7462 /* reap child */
7463 do {
7464 wret = waitpid(pid, &status, 0);
7465 } while (wret < 0 && errno == EINTR);
7466 if (wret < 0)
7468 ERR("waitpid() failed!\n");
7469 goto end;
7471 if (!WIFEXITED(status) || WEXITSTATUS(status))
7473 ERR("child process failed! %d\n", status);
7474 goto end;
7477 ret = TRUE;
7479 end:
7480 if(file_fd != -1) close(file_fd);
7481 if(fds[0] != -1) close(fds[0]);
7482 if(fds[1] != -1) close(fds[1]);
7484 HeapFree(GetProcessHeap(), 0, cmdA);
7485 HeapFree(GetProcessHeap(), 0, unixname);
7486 return ret;
7487 #else
7488 return FALSE;
7489 #endif
7492 /*****************************************************************************
7493 * schedule_lpr
7495 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7497 WCHAR *cmd;
7498 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7499 BOOL r;
7501 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7502 sprintfW(cmd, fmtW, printer_name);
7504 r = schedule_pipe(cmd, filename);
7506 HeapFree(GetProcessHeap(), 0, cmd);
7507 return r;
7510 /*****************************************************************************
7511 * schedule_cups
7513 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7515 #ifdef SONAME_LIBCUPS
7516 if(pcupsPrintFile)
7518 char *unixname, *queue, *unix_doc_title;
7519 DWORD len;
7520 BOOL ret;
7522 if(!(unixname = wine_get_unix_file_name(filename)))
7523 return FALSE;
7525 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7526 queue = HeapAlloc(GetProcessHeap(), 0, len);
7527 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7529 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7530 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7531 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7533 TRACE("printing via cups\n");
7534 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7535 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7536 HeapFree(GetProcessHeap(), 0, queue);
7537 HeapFree(GetProcessHeap(), 0, unixname);
7538 return ret;
7540 else
7541 #endif
7543 return schedule_lpr(printer_name, filename);
7547 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7549 LPWSTR filename;
7551 switch(msg)
7553 case WM_INITDIALOG:
7554 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7555 return TRUE;
7557 case WM_COMMAND:
7558 if(HIWORD(wparam) == BN_CLICKED)
7560 if(LOWORD(wparam) == IDOK)
7562 HANDLE hf;
7563 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7564 LPWSTR *output;
7566 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7567 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7569 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7571 WCHAR caption[200], message[200];
7572 int mb_ret;
7574 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7575 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7576 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7577 if(mb_ret == IDCANCEL)
7579 HeapFree(GetProcessHeap(), 0, filename);
7580 return TRUE;
7583 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7584 if(hf == INVALID_HANDLE_VALUE)
7586 WCHAR caption[200], message[200];
7588 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7589 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7590 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7591 HeapFree(GetProcessHeap(), 0, filename);
7592 return TRUE;
7594 CloseHandle(hf);
7595 DeleteFileW(filename);
7596 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7597 *output = filename;
7598 EndDialog(hwnd, IDOK);
7599 return TRUE;
7601 if(LOWORD(wparam) == IDCANCEL)
7603 EndDialog(hwnd, IDCANCEL);
7604 return TRUE;
7607 return FALSE;
7609 return FALSE;
7612 /*****************************************************************************
7613 * get_filename
7615 static BOOL get_filename(LPWSTR *filename)
7617 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7618 file_dlg_proc, (LPARAM)filename) == IDOK;
7621 /*****************************************************************************
7622 * schedule_file
7624 static BOOL schedule_file(LPCWSTR filename)
7626 LPWSTR output = NULL;
7628 if(get_filename(&output))
7630 BOOL r;
7631 TRACE("copy to %s\n", debugstr_w(output));
7632 r = CopyFileW(filename, output, FALSE);
7633 HeapFree(GetProcessHeap(), 0, output);
7634 return r;
7636 return FALSE;
7639 /*****************************************************************************
7640 * schedule_unixfile
7642 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7644 int in_fd, out_fd, no_read;
7645 char buf[1024];
7646 BOOL ret = FALSE;
7647 char *unixname, *outputA;
7648 DWORD len;
7650 if(!(unixname = wine_get_unix_file_name(filename)))
7651 return FALSE;
7653 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7654 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7655 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7657 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7658 in_fd = open(unixname, O_RDONLY);
7659 if(out_fd == -1 || in_fd == -1)
7660 goto end;
7662 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7663 write(out_fd, buf, no_read);
7665 ret = TRUE;
7666 end:
7667 if(in_fd != -1) close(in_fd);
7668 if(out_fd != -1) close(out_fd);
7669 HeapFree(GetProcessHeap(), 0, outputA);
7670 HeapFree(GetProcessHeap(), 0, unixname);
7671 return ret;
7674 /*****************************************************************************
7675 * ScheduleJob [WINSPOOL.@]
7678 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7680 opened_printer_t *printer;
7681 BOOL ret = FALSE;
7682 struct list *cursor, *cursor2;
7684 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7685 EnterCriticalSection(&printer_handles_cs);
7686 printer = get_opened_printer(hPrinter);
7687 if(!printer)
7688 goto end;
7690 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7692 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7693 HANDLE hf;
7695 if(job->job_id != dwJobID) continue;
7697 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7698 if(hf != INVALID_HANDLE_VALUE)
7700 PRINTER_INFO_5W *pi5 = NULL;
7701 LPWSTR portname = job->portname;
7702 DWORD needed;
7703 HKEY hkey;
7704 WCHAR output[1024];
7705 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7706 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7708 if (!portname)
7710 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7711 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7712 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7713 portname = pi5->pPortName;
7715 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7716 debugstr_w(portname));
7718 output[0] = 0;
7720 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7721 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7723 DWORD type, count = sizeof(output);
7724 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7725 RegCloseKey(hkey);
7727 if(output[0] == '|')
7729 ret = schedule_pipe(output + 1, job->filename);
7731 else if(output[0])
7733 ret = schedule_unixfile(output, job->filename);
7735 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7737 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7739 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7741 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7743 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7745 ret = schedule_file(job->filename);
7747 else
7749 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7751 HeapFree(GetProcessHeap(), 0, pi5);
7752 CloseHandle(hf);
7753 DeleteFileW(job->filename);
7755 list_remove(cursor);
7756 HeapFree(GetProcessHeap(), 0, job->document_title);
7757 HeapFree(GetProcessHeap(), 0, job->printer_name);
7758 HeapFree(GetProcessHeap(), 0, job->portname);
7759 HeapFree(GetProcessHeap(), 0, job->filename);
7760 HeapFree(GetProcessHeap(), 0, job->devmode);
7761 HeapFree(GetProcessHeap(), 0, job);
7762 break;
7764 end:
7765 LeaveCriticalSection(&printer_handles_cs);
7766 return ret;
7769 /*****************************************************************************
7770 * StartDocDlgA [WINSPOOL.@]
7772 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7774 UNICODE_STRING usBuffer;
7775 DOCINFOW docW;
7776 LPWSTR retW;
7777 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7778 LPSTR ret = NULL;
7780 docW.cbSize = sizeof(docW);
7781 if (doc->lpszDocName)
7783 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7784 if (!(docW.lpszDocName = docnameW)) return NULL;
7786 if (doc->lpszOutput)
7788 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7789 if (!(docW.lpszOutput = outputW)) return NULL;
7791 if (doc->lpszDatatype)
7793 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7794 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7796 docW.fwType = doc->fwType;
7798 retW = StartDocDlgW(hPrinter, &docW);
7800 if(retW)
7802 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7803 ret = HeapAlloc(GetProcessHeap(), 0, len);
7804 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7805 HeapFree(GetProcessHeap(), 0, retW);
7808 HeapFree(GetProcessHeap(), 0, datatypeW);
7809 HeapFree(GetProcessHeap(), 0, outputW);
7810 HeapFree(GetProcessHeap(), 0, docnameW);
7812 return ret;
7815 /*****************************************************************************
7816 * StartDocDlgW [WINSPOOL.@]
7818 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7819 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7820 * port is "FILE:". Also returns the full path if passed a relative path.
7822 * The caller should free the returned string from the process heap.
7824 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7826 LPWSTR ret = NULL;
7827 DWORD len, attr;
7829 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7831 PRINTER_INFO_5W *pi5;
7832 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7833 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7834 return NULL;
7835 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7836 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7837 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7839 HeapFree(GetProcessHeap(), 0, pi5);
7840 return NULL;
7842 HeapFree(GetProcessHeap(), 0, pi5);
7845 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7847 LPWSTR name;
7849 if (get_filename(&name))
7851 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7853 HeapFree(GetProcessHeap(), 0, name);
7854 return NULL;
7856 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7857 GetFullPathNameW(name, len, ret, NULL);
7858 HeapFree(GetProcessHeap(), 0, name);
7860 return ret;
7863 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7864 return NULL;
7866 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7867 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7869 attr = GetFileAttributesW(ret);
7870 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7872 HeapFree(GetProcessHeap(), 0, ret);
7873 ret = NULL;
7875 return ret;