winspool: Keep track of any supplied devmode.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blobd832b4b711dd19dd893106d9820db16208ed4552
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 DEVMODEW *devmode;
100 } opened_printer_t;
102 typedef struct {
103 struct list entry;
104 DWORD job_id;
105 WCHAR *filename;
106 WCHAR *portname;
107 WCHAR *document_title;
108 WCHAR *printer_name;
109 LPDEVMODEW devmode;
110 } job_t;
113 typedef struct {
114 LPCWSTR envname;
115 LPCWSTR subdir;
116 DWORD driverversion;
117 LPCWSTR versionregpath;
118 LPCWSTR versionsubdir;
119 } printenv_t;
121 /* ############################### */
123 static opened_printer_t **printer_handles;
124 static UINT nb_printer_handles;
125 static LONG next_job_id = 1;
127 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
128 WORD fwCapability, LPSTR lpszOutput,
129 LPDEVMODEA lpdm );
130 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
131 LPSTR lpszDevice, LPSTR lpszPort,
132 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
133 DWORD fwMode );
135 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
186 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
187 static const WCHAR backslashW[] = {'\\',0};
188 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
189 'i','o','n',' ','F','i','l','e',0};
190 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
191 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
192 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
193 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
194 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
195 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
196 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
197 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
198 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
199 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
200 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
201 static const WCHAR NameW[] = {'N','a','m','e',0};
202 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
203 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
204 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
205 static const WCHAR PortW[] = {'P','o','r','t',0};
206 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
207 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
208 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
209 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
210 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
211 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
212 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
213 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
214 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
215 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
216 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
217 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
218 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
219 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
220 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
221 static WCHAR rawW[] = {'R','A','W',0};
222 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
223 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
224 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
225 static const WCHAR commaW[] = {',',0};
226 static WCHAR emptyStringW[] = {0};
228 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
230 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
231 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
232 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
234 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
235 'D','o','c','u','m','e','n','t',0};
237 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
238 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
239 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
240 0, sizeof(DRIVER_INFO_8W)};
243 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
244 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
245 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
246 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
247 sizeof(PRINTER_INFO_9W)};
249 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
250 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
251 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
253 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
255 /******************************************************************
256 * validate the user-supplied printing-environment [internal]
258 * PARAMS
259 * env [I] PTR to Environment-String or NULL
261 * RETURNS
262 * Failure: NULL
263 * Success: PTR to printenv_t
265 * NOTES
266 * An empty string is handled the same way as NULL.
267 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
271 static const printenv_t * validate_envW(LPCWSTR env)
273 const printenv_t *result = NULL;
274 unsigned int i;
276 TRACE("testing %s\n", debugstr_w(env));
277 if (env && env[0])
279 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
281 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
283 result = all_printenv[i];
284 break;
288 if (result == NULL) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env));
290 SetLastError(ERROR_INVALID_ENVIRONMENT);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
294 else
296 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
298 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
300 return result;
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
309 if ( (src) )
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
312 return usBufferPtr->Buffer;
314 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
315 return NULL;
318 static LPWSTR strdupW(LPCWSTR p)
320 LPWSTR ret;
321 DWORD len;
323 if(!p) return NULL;
324 len = (strlenW(p) + 1) * sizeof(WCHAR);
325 ret = HeapAlloc(GetProcessHeap(), 0, len);
326 memcpy(ret, p, len);
327 return ret;
330 static LPSTR strdupWtoA( LPCWSTR str )
332 LPSTR ret;
333 INT len;
335 if (!str) return NULL;
336 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
337 ret = HeapAlloc( GetProcessHeap(), 0, len );
338 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
339 return ret;
342 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
344 DEVMODEW *ret;
346 if (!dm) return NULL;
347 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
348 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
349 return ret;
352 /******************************************************************
353 * verify, that the filename is a local file
356 static inline BOOL is_local_file(LPWSTR name)
358 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
361 /* ################################ */
363 static int multi_sz_lenA(const char *str)
365 const char *ptr = str;
366 if(!str) return 0;
369 ptr += lstrlenA(ptr) + 1;
370 } while(*ptr);
372 return ptr - str + 1;
375 static void
376 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
377 char qbuf[200];
379 /* If forcing, or no profile string entry for device yet, set the entry
381 * The always change entry if not WINEPS yet is discussable.
383 if (force ||
384 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
385 !strcmp(qbuf,"*") ||
386 !strstr(qbuf,"WINEPS.DRV")
388 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
389 HKEY hkey;
391 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
392 WriteProfileStringA("windows","device",buf);
393 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
394 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
395 RegCloseKey(hkey);
397 HeapFree(GetProcessHeap(),0,buf);
401 static BOOL add_printer_driver(WCHAR *name)
403 DRIVER_INFO_3W di3;
405 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
406 di3.cVersion = 3;
407 di3.pName = name;
408 di3.pEnvironment = envname_x86W;
409 di3.pDriverPath = driver_nt;
410 di3.pDataFile = generic_ppdW;
411 di3.pConfigFile = driver_nt;
412 di3.pDefaultDataType = rawW;
414 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
415 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
417 di3.cVersion = 0;
418 di3.pEnvironment = envname_win40W;
419 di3.pDriverPath = driver_9x;
420 di3.pConfigFile = driver_9x;
421 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
422 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
424 return TRUE;
427 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
428 return FALSE;
431 #ifdef SONAME_LIBCUPS
432 static typeof(cupsFreeDests) *pcupsFreeDests;
433 static typeof(cupsGetDests) *pcupsGetDests;
434 static typeof(cupsGetPPD) *pcupsGetPPD;
435 static typeof(cupsPrintFile) *pcupsPrintFile;
436 static void *cupshandle;
438 static BOOL CUPS_LoadPrinters(void)
440 int i, nrofdests;
441 BOOL hadprinter = FALSE, haddefault = FALSE;
442 cups_dest_t *dests;
443 PRINTER_INFO_2W pi2;
444 WCHAR *port;
445 HKEY hkeyPrinter, hkeyPrinters;
446 char loaderror[256];
447 WCHAR nameW[MAX_PATH];
449 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
450 if (!cupshandle) {
451 TRACE("%s\n", loaderror);
452 return FALSE;
454 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
456 #define DYNCUPS(x) \
457 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
458 if (!p##x) return FALSE;
460 DYNCUPS(cupsFreeDests);
461 DYNCUPS(cupsGetPPD);
462 DYNCUPS(cupsGetDests);
463 DYNCUPS(cupsPrintFile);
464 #undef DYNCUPS
466 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
467 ERROR_SUCCESS) {
468 ERR("Can't create Printers key\n");
469 return FALSE;
472 nrofdests = pcupsGetDests(&dests);
473 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
474 for (i=0;i<nrofdests;i++) {
475 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
477 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
478 lstrcpyW(port, CUPS_Port);
479 lstrcatW(port, nameW);
481 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
482 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
483 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
484 and continue */
485 TRACE("Printer already exists\n");
486 /* overwrite old LPR:* port */
487 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
488 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
489 RegCloseKey(hkeyPrinter);
490 } else {
491 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
492 ' ','u','s','i','n','g',' ','C','U','P','S',0};
494 add_printer_driver(nameW);
496 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
497 pi2.pPrinterName = nameW;
498 pi2.pDatatype = rawW;
499 pi2.pPrintProcessor = WinPrintW;
500 pi2.pDriverName = nameW;
501 pi2.pComment = comment_cups;
502 pi2.pLocation = emptyStringW;
503 pi2.pPortName = port;
504 pi2.pParameters = emptyStringW;
505 pi2.pShareName = emptyStringW;
506 pi2.pSepFile = emptyStringW;
508 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
509 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
510 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
513 HeapFree(GetProcessHeap(),0,port);
515 hadprinter = TRUE;
516 if (dests[i].is_default) {
517 SetDefaultPrinterW(nameW);
518 haddefault = TRUE;
521 if (hadprinter && !haddefault) {
522 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
523 SetDefaultPrinterW(nameW);
525 pcupsFreeDests(nrofdests, dests);
526 RegCloseKey(hkeyPrinters);
527 return hadprinter;
529 #endif
531 static BOOL
532 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
533 PRINTER_INFO_2A pinfo2a;
534 const char *r;
535 size_t name_len;
536 char *e,*s,*name,*prettyname,*devname;
537 BOOL ret = FALSE, set_default = FALSE;
538 char *port = NULL, *env_default;
539 HKEY hkeyPrinter, hkeyPrinters;
540 WCHAR devnameW[MAX_PATH];
542 while (isspace(*pent)) pent++;
543 r = strchr(pent,':');
544 if (r)
545 name_len = r - pent;
546 else
547 name_len = strlen(pent);
548 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
549 memcpy(name, pent, name_len);
550 name[name_len] = '\0';
551 if (r)
552 pent = r;
553 else
554 pent = "";
556 TRACE("name=%s entry=%s\n",name, pent);
558 if(ispunct(*name)) { /* a tc entry, not a real printer */
559 TRACE("skipping tc entry\n");
560 goto end;
563 if(strstr(pent,":server")) { /* server only version so skip */
564 TRACE("skipping server entry\n");
565 goto end;
568 /* Determine whether this is a postscript printer. */
570 ret = TRUE;
571 env_default = getenv("PRINTER");
572 prettyname = name;
573 /* Get longest name, usually the one at the right for later display. */
574 while((s=strchr(prettyname,'|'))) {
575 *s = '\0';
576 e = s;
577 while(isspace(*--e)) *e = '\0';
578 TRACE("\t%s\n", debugstr_a(prettyname));
579 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
580 for(prettyname = s+1; isspace(*prettyname); prettyname++)
583 e = prettyname + strlen(prettyname);
584 while(isspace(*--e)) *e = '\0';
585 TRACE("\t%s\n", debugstr_a(prettyname));
586 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
588 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
589 * if it is too long, we use it as comment below. */
590 devname = prettyname;
591 if (strlen(devname)>=CCHDEVICENAME-1)
592 devname = name;
593 if (strlen(devname)>=CCHDEVICENAME-1) {
594 ret = FALSE;
595 goto end;
598 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
599 sprintf(port,"LPR:%s",name);
601 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
602 ERROR_SUCCESS) {
603 ERR("Can't create Printers key\n");
604 ret = FALSE;
605 goto end;
608 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
610 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
611 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
612 and continue */
613 TRACE("Printer already exists\n");
614 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
615 RegCloseKey(hkeyPrinter);
616 } else {
617 static CHAR data_type[] = "RAW",
618 print_proc[] = "WinPrint",
619 comment[] = "WINEPS Printer using LPR",
620 params[] = "<parameters?>",
621 share_name[] = "<share name?>",
622 sep_file[] = "<sep file?>";
624 add_printer_driver(devnameW);
626 memset(&pinfo2a,0,sizeof(pinfo2a));
627 pinfo2a.pPrinterName = devname;
628 pinfo2a.pDatatype = data_type;
629 pinfo2a.pPrintProcessor = print_proc;
630 pinfo2a.pDriverName = devname;
631 pinfo2a.pComment = comment;
632 pinfo2a.pLocation = prettyname;
633 pinfo2a.pPortName = port;
634 pinfo2a.pParameters = params;
635 pinfo2a.pShareName = share_name;
636 pinfo2a.pSepFile = sep_file;
638 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
639 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
640 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
643 RegCloseKey(hkeyPrinters);
645 if (isfirst || set_default)
646 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
648 end:
649 HeapFree(GetProcessHeap(), 0, port);
650 HeapFree(GetProcessHeap(), 0, name);
651 return ret;
654 static BOOL
655 PRINTCAP_LoadPrinters(void) {
656 BOOL hadprinter = FALSE;
657 char buf[200];
658 FILE *f;
659 char *pent = NULL;
660 BOOL had_bash = FALSE;
662 f = fopen("/etc/printcap","r");
663 if (!f)
664 return FALSE;
666 while(fgets(buf,sizeof(buf),f)) {
667 char *start, *end;
669 end=strchr(buf,'\n');
670 if (end) *end='\0';
672 start = buf;
673 while(isspace(*start)) start++;
674 if(*start == '#' || *start == '\0')
675 continue;
677 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
678 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
679 HeapFree(GetProcessHeap(),0,pent);
680 pent = NULL;
683 if (end && *--end == '\\') {
684 *end = '\0';
685 had_bash = TRUE;
686 } else
687 had_bash = FALSE;
689 if (pent) {
690 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
691 strcat(pent,start);
692 } else {
693 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
694 strcpy(pent,start);
698 if(pent) {
699 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
700 HeapFree(GetProcessHeap(),0,pent);
702 fclose(f);
703 return hadprinter;
706 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
708 if (value)
709 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
710 (lstrlenW(value) + 1) * sizeof(WCHAR));
711 else
712 return ERROR_FILE_NOT_FOUND;
715 /******************************************************************
716 * get_servername_from_name (internal)
718 * for an external server, a copy of the serverpart from the full name is returned
721 static LPWSTR get_servername_from_name(LPCWSTR name)
723 LPWSTR server;
724 LPWSTR ptr;
725 WCHAR buffer[MAX_PATH];
726 DWORD len;
728 if (name == NULL) return NULL;
729 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
731 server = strdupW(&name[2]); /* skip over both backslash */
732 if (server == NULL) return NULL;
734 /* strip '\' and the printername */
735 ptr = strchrW(server, '\\');
736 if (ptr) ptr[0] = '\0';
738 TRACE("found %s\n", debugstr_w(server));
740 len = sizeof(buffer)/sizeof(buffer[0]);
741 if (GetComputerNameW(buffer, &len)) {
742 if (lstrcmpW(buffer, server) == 0) {
743 /* The requested Servername is our computername */
744 HeapFree(GetProcessHeap(), 0, server);
745 return NULL;
748 return server;
751 /******************************************************************
752 * get_basename_from_name (internal)
754 * skip over the serverpart from the full name
757 static LPCWSTR get_basename_from_name(LPCWSTR name)
759 if (name == NULL) return NULL;
760 if ((name[0] == '\\') && (name[1] == '\\')) {
761 /* skip over the servername and search for the following '\' */
762 name = strchrW(&name[2], '\\');
763 if ((name) && (name[1])) {
764 /* found a separator ('\') followed by a name:
765 skip over the separator and return the rest */
766 name++;
768 else
770 /* no basename present (we found only a servername) */
771 return NULL;
774 return name;
777 static void free_printer_entry( opened_printer_t *printer )
779 /* the queue is shared, so don't free that here */
780 HeapFree( GetProcessHeap(), 0, printer->printername );
781 HeapFree( GetProcessHeap(), 0, printer->name );
782 HeapFree( GetProcessHeap(), 0, printer->devmode );
783 HeapFree( GetProcessHeap(), 0, printer );
786 /******************************************************************
787 * get_opened_printer_entry
788 * Get the first place empty in the opened printer table
790 * ToDo:
791 * - pDefault is ignored
793 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
795 UINT_PTR handle = nb_printer_handles, i;
796 jobqueue_t *queue = NULL;
797 opened_printer_t *printer = NULL;
798 LPWSTR servername;
799 LPCWSTR printername;
801 if ((backend == NULL) && !load_backend()) return NULL;
803 servername = get_servername_from_name(name);
804 if (servername) {
805 FIXME("server %s not supported\n", debugstr_w(servername));
806 HeapFree(GetProcessHeap(), 0, servername);
807 SetLastError(ERROR_INVALID_PRINTER_NAME);
808 return NULL;
811 printername = get_basename_from_name(name);
812 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
814 /* an empty printername is invalid */
815 if (printername && (!printername[0])) {
816 SetLastError(ERROR_INVALID_PARAMETER);
817 return NULL;
820 EnterCriticalSection(&printer_handles_cs);
822 for (i = 0; i < nb_printer_handles; i++)
824 if (!printer_handles[i])
826 if(handle == nb_printer_handles)
827 handle = i;
829 else
831 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
832 queue = printer_handles[i]->queue;
836 if (handle >= nb_printer_handles)
838 opened_printer_t **new_array;
839 if (printer_handles)
840 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
841 (nb_printer_handles + 16) * sizeof(*new_array) );
842 else
843 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
844 (nb_printer_handles + 16) * sizeof(*new_array) );
846 if (!new_array)
848 handle = 0;
849 goto end;
851 printer_handles = new_array;
852 nb_printer_handles += 16;
855 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
857 handle = 0;
858 goto end;
861 /* get a printer handle from the backend */
862 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
863 handle = 0;
864 goto end;
867 /* clone the base name. This is NULL for the printserver */
868 printer->printername = strdupW(printername);
870 /* clone the full name */
871 printer->name = strdupW(name);
872 if (name && (!printer->name)) {
873 handle = 0;
874 goto end;
877 if (pDefault && pDefault->pDevMode)
878 printer->devmode = dup_devmode( pDefault->pDevMode );
880 if(queue)
881 printer->queue = queue;
882 else
884 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
885 if (!printer->queue) {
886 handle = 0;
887 goto end;
889 list_init(&printer->queue->jobs);
890 printer->queue->ref = 0;
892 InterlockedIncrement(&printer->queue->ref);
894 printer_handles[handle] = printer;
895 handle++;
896 end:
897 LeaveCriticalSection(&printer_handles_cs);
898 if (!handle && printer) {
899 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
900 free_printer_entry( printer );
903 return (HANDLE)handle;
906 /******************************************************************
907 * get_opened_printer
908 * Get the pointer to the opened printer referred by the handle
910 static opened_printer_t *get_opened_printer(HANDLE hprn)
912 UINT_PTR idx = (UINT_PTR)hprn;
913 opened_printer_t *ret = NULL;
915 EnterCriticalSection(&printer_handles_cs);
917 if ((idx > 0) && (idx <= nb_printer_handles)) {
918 ret = printer_handles[idx - 1];
920 LeaveCriticalSection(&printer_handles_cs);
921 return ret;
924 /******************************************************************
925 * get_opened_printer_name
926 * Get the pointer to the opened printer name referred by the handle
928 static LPCWSTR get_opened_printer_name(HANDLE hprn)
930 opened_printer_t *printer = get_opened_printer(hprn);
931 if(!printer) return NULL;
932 return printer->name;
935 /******************************************************************
936 * WINSPOOL_GetOpenedPrinterRegKey
939 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
941 LPCWSTR name = get_opened_printer_name(hPrinter);
942 DWORD ret;
943 HKEY hkeyPrinters;
945 if(!name) return ERROR_INVALID_HANDLE;
947 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
948 ERROR_SUCCESS)
949 return ret;
951 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
953 ERR("Can't find opened printer %s in registry\n",
954 debugstr_w(name));
955 RegCloseKey(hkeyPrinters);
956 return ERROR_INVALID_PRINTER_NAME; /* ? */
958 RegCloseKey(hkeyPrinters);
959 return ERROR_SUCCESS;
962 void WINSPOOL_LoadSystemPrinters(void)
964 HKEY hkey, hkeyPrinters;
965 HANDLE hprn;
966 DWORD needed, num, i;
967 WCHAR PrinterName[256];
968 BOOL done = FALSE;
970 /* This ensures that all printer entries have a valid Name value. If causes
971 problems later if they don't. If one is found to be missed we create one
972 and set it equal to the name of the key */
973 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
974 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
975 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
976 for(i = 0; i < num; i++) {
977 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
978 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
979 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
980 set_reg_szW(hkey, NameW, PrinterName);
982 RegCloseKey(hkey);
987 RegCloseKey(hkeyPrinters);
990 /* We want to avoid calling AddPrinter on printers as much as
991 possible, because on cups printers this will (eventually) lead
992 to a call to cupsGetPPD which takes forever, even with non-cups
993 printers AddPrinter takes a while. So we'll tag all printers that
994 were automatically added last time around, if they still exist
995 we'll leave them be otherwise we'll delete them. */
996 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
997 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
998 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
999 for(i = 0; i < num; i++) {
1000 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1001 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1002 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1003 DWORD dw = 1;
1004 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1005 RegCloseKey(hkey);
1007 ClosePrinter(hprn);
1012 HeapFree(GetProcessHeap(), 0, pi);
1016 #ifdef SONAME_LIBCUPS
1017 done = CUPS_LoadPrinters();
1018 #endif
1020 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1021 PRINTCAP_LoadPrinters();
1023 /* Now enumerate the list again and delete any printers that are still tagged */
1024 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1025 if(needed) {
1026 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1027 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1028 for(i = 0; i < num; i++) {
1029 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1030 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1031 BOOL delete_driver = FALSE;
1032 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1033 DWORD dw, type, size = sizeof(dw);
1034 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1035 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1036 DeletePrinter(hprn);
1037 delete_driver = TRUE;
1039 RegCloseKey(hkey);
1041 ClosePrinter(hprn);
1042 if(delete_driver)
1043 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1048 HeapFree(GetProcessHeap(), 0, pi);
1051 return;
1055 /******************************************************************
1056 * get_job
1058 * Get the pointer to the specified job.
1059 * Should hold the printer_handles_cs before calling.
1061 static job_t *get_job(HANDLE hprn, DWORD JobId)
1063 opened_printer_t *printer = get_opened_printer(hprn);
1064 job_t *job;
1066 if(!printer) return NULL;
1067 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1069 if(job->job_id == JobId)
1070 return job;
1072 return NULL;
1075 /***********************************************************
1076 * DEVMODEcpyAtoW
1078 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1080 BOOL Formname;
1081 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1082 DWORD size;
1084 Formname = (dmA->dmSize > off_formname);
1085 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1086 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1087 dmW->dmDeviceName, CCHDEVICENAME);
1088 if(!Formname) {
1089 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1090 dmA->dmSize - CCHDEVICENAME);
1091 } else {
1092 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1093 off_formname - CCHDEVICENAME);
1094 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1095 dmW->dmFormName, CCHFORMNAME);
1096 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1097 (off_formname + CCHFORMNAME));
1099 dmW->dmSize = size;
1100 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1101 dmA->dmDriverExtra);
1102 return dmW;
1105 /***********************************************************
1106 * DEVMODEdupWtoA
1107 * Creates an ansi copy of supplied devmode
1109 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1111 LPDEVMODEA dmA;
1112 DWORD size;
1114 if (!dmW) return NULL;
1115 size = dmW->dmSize - CCHDEVICENAME -
1116 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1118 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1119 if (!dmA) return NULL;
1121 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1122 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1124 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1125 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1126 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1128 else
1130 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1131 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1132 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1133 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1135 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1138 dmA->dmSize = size;
1139 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1140 return dmA;
1143 /******************************************************************
1144 * convert_printerinfo_W_to_A [internal]
1147 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1148 DWORD level, DWORD outlen, DWORD numentries)
1150 DWORD id = 0;
1151 LPSTR ptr;
1152 INT len;
1154 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1156 len = pi_sizeof[level] * numentries;
1157 ptr = (LPSTR) out + len;
1158 outlen -= len;
1160 /* copy the numbers of all PRINTER_INFO_* first */
1161 memcpy(out, pPrintersW, len);
1163 while (id < numentries) {
1164 switch (level) {
1165 case 1:
1167 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1168 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1170 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1171 if (piW->pDescription) {
1172 piA->pDescription = ptr;
1173 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1174 ptr, outlen, NULL, NULL);
1175 ptr += len;
1176 outlen -= len;
1178 if (piW->pName) {
1179 piA->pName = ptr;
1180 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1181 ptr, outlen, NULL, NULL);
1182 ptr += len;
1183 outlen -= len;
1185 if (piW->pComment) {
1186 piA->pComment = ptr;
1187 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1188 ptr, outlen, NULL, NULL);
1189 ptr += len;
1190 outlen -= len;
1192 break;
1195 case 2:
1197 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1198 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1199 LPDEVMODEA dmA;
1201 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1202 if (piW->pServerName) {
1203 piA->pServerName = ptr;
1204 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1205 ptr, outlen, NULL, NULL);
1206 ptr += len;
1207 outlen -= len;
1209 if (piW->pPrinterName) {
1210 piA->pPrinterName = ptr;
1211 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1212 ptr, outlen, NULL, NULL);
1213 ptr += len;
1214 outlen -= len;
1216 if (piW->pShareName) {
1217 piA->pShareName = ptr;
1218 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1219 ptr, outlen, NULL, NULL);
1220 ptr += len;
1221 outlen -= len;
1223 if (piW->pPortName) {
1224 piA->pPortName = ptr;
1225 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1226 ptr, outlen, NULL, NULL);
1227 ptr += len;
1228 outlen -= len;
1230 if (piW->pDriverName) {
1231 piA->pDriverName = ptr;
1232 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1233 ptr, outlen, NULL, NULL);
1234 ptr += len;
1235 outlen -= len;
1237 if (piW->pComment) {
1238 piA->pComment = ptr;
1239 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1240 ptr, outlen, NULL, NULL);
1241 ptr += len;
1242 outlen -= len;
1244 if (piW->pLocation) {
1245 piA->pLocation = ptr;
1246 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1247 ptr, outlen, NULL, NULL);
1248 ptr += len;
1249 outlen -= len;
1252 dmA = DEVMODEdupWtoA(piW->pDevMode);
1253 if (dmA) {
1254 /* align DEVMODEA to a DWORD boundary */
1255 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1256 ptr += len;
1257 outlen -= len;
1259 piA->pDevMode = (LPDEVMODEA) ptr;
1260 len = dmA->dmSize + dmA->dmDriverExtra;
1261 memcpy(ptr, dmA, len);
1262 HeapFree(GetProcessHeap(), 0, dmA);
1264 ptr += len;
1265 outlen -= len;
1268 if (piW->pSepFile) {
1269 piA->pSepFile = ptr;
1270 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1271 ptr, outlen, NULL, NULL);
1272 ptr += len;
1273 outlen -= len;
1275 if (piW->pPrintProcessor) {
1276 piA->pPrintProcessor = ptr;
1277 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1278 ptr, outlen, NULL, NULL);
1279 ptr += len;
1280 outlen -= len;
1282 if (piW->pDatatype) {
1283 piA->pDatatype = ptr;
1284 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1285 ptr, outlen, NULL, NULL);
1286 ptr += len;
1287 outlen -= len;
1289 if (piW->pParameters) {
1290 piA->pParameters = ptr;
1291 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1292 ptr, outlen, NULL, NULL);
1293 ptr += len;
1294 outlen -= len;
1296 if (piW->pSecurityDescriptor) {
1297 piA->pSecurityDescriptor = NULL;
1298 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1300 break;
1303 case 4:
1305 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1306 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1308 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1310 if (piW->pPrinterName) {
1311 piA->pPrinterName = ptr;
1312 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1313 ptr, outlen, NULL, NULL);
1314 ptr += len;
1315 outlen -= len;
1317 if (piW->pServerName) {
1318 piA->pServerName = ptr;
1319 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1320 ptr, outlen, NULL, NULL);
1321 ptr += len;
1322 outlen -= len;
1324 break;
1327 case 5:
1329 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1330 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1332 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1334 if (piW->pPrinterName) {
1335 piA->pPrinterName = ptr;
1336 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1337 ptr, outlen, NULL, NULL);
1338 ptr += len;
1339 outlen -= len;
1341 if (piW->pPortName) {
1342 piA->pPortName = ptr;
1343 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1344 ptr, outlen, NULL, NULL);
1345 ptr += len;
1346 outlen -= len;
1348 break;
1351 case 6: /* 6A and 6W are the same structure */
1352 break;
1354 case 7:
1356 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1357 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1359 TRACE("(%u) #%u\n", level, id);
1360 if (piW->pszObjectGUID) {
1361 piA->pszObjectGUID = ptr;
1362 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1363 ptr, outlen, NULL, NULL);
1364 ptr += len;
1365 outlen -= len;
1367 break;
1370 case 9:
1372 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1373 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1374 LPDEVMODEA dmA;
1376 TRACE("(%u) #%u\n", level, id);
1377 dmA = DEVMODEdupWtoA(piW->pDevMode);
1378 if (dmA) {
1379 /* align DEVMODEA to a DWORD boundary */
1380 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1381 ptr += len;
1382 outlen -= len;
1384 piA->pDevMode = (LPDEVMODEA) ptr;
1385 len = dmA->dmSize + dmA->dmDriverExtra;
1386 memcpy(ptr, dmA, len);
1387 HeapFree(GetProcessHeap(), 0, dmA);
1389 ptr += len;
1390 outlen -= len;
1393 break;
1396 default:
1397 FIXME("for level %u\n", level);
1399 pPrintersW += pi_sizeof[level];
1400 out += pi_sizeof[level];
1401 id++;
1405 /******************************************************************
1406 * convert_driverinfo_W_to_A [internal]
1409 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1410 DWORD level, DWORD outlen, DWORD numentries)
1412 DWORD id = 0;
1413 LPSTR ptr;
1414 INT len;
1416 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1418 len = di_sizeof[level] * numentries;
1419 ptr = (LPSTR) out + len;
1420 outlen -= len;
1422 /* copy the numbers of all PRINTER_INFO_* first */
1423 memcpy(out, pDriversW, len);
1425 #define COPY_STRING(fld) \
1426 { if (diW->fld){ \
1427 diA->fld = ptr; \
1428 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1429 ptr += len; outlen -= len;\
1431 #define COPY_MULTIZ_STRING(fld) \
1432 { LPWSTR p = diW->fld; if (p){ \
1433 diA->fld = ptr; \
1434 do {\
1435 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1436 ptr += len; outlen -= len; p += len;\
1438 while(len > 1 && outlen > 0); \
1441 while (id < numentries)
1443 switch (level)
1445 case 1:
1447 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1448 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1450 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1452 COPY_STRING(pName);
1453 break;
1455 case 2:
1457 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1458 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1460 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1462 COPY_STRING(pName);
1463 COPY_STRING(pEnvironment);
1464 COPY_STRING(pDriverPath);
1465 COPY_STRING(pDataFile);
1466 COPY_STRING(pConfigFile);
1467 break;
1469 case 3:
1471 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1472 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1474 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1476 COPY_STRING(pName);
1477 COPY_STRING(pEnvironment);
1478 COPY_STRING(pDriverPath);
1479 COPY_STRING(pDataFile);
1480 COPY_STRING(pConfigFile);
1481 COPY_STRING(pHelpFile);
1482 COPY_MULTIZ_STRING(pDependentFiles);
1483 COPY_STRING(pMonitorName);
1484 COPY_STRING(pDefaultDataType);
1485 break;
1487 case 4:
1489 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1490 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1492 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1494 COPY_STRING(pName);
1495 COPY_STRING(pEnvironment);
1496 COPY_STRING(pDriverPath);
1497 COPY_STRING(pDataFile);
1498 COPY_STRING(pConfigFile);
1499 COPY_STRING(pHelpFile);
1500 COPY_MULTIZ_STRING(pDependentFiles);
1501 COPY_STRING(pMonitorName);
1502 COPY_STRING(pDefaultDataType);
1503 COPY_MULTIZ_STRING(pszzPreviousNames);
1504 break;
1506 case 5:
1508 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1509 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1511 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1513 COPY_STRING(pName);
1514 COPY_STRING(pEnvironment);
1515 COPY_STRING(pDriverPath);
1516 COPY_STRING(pDataFile);
1517 COPY_STRING(pConfigFile);
1518 break;
1520 case 6:
1522 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1523 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1525 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1527 COPY_STRING(pName);
1528 COPY_STRING(pEnvironment);
1529 COPY_STRING(pDriverPath);
1530 COPY_STRING(pDataFile);
1531 COPY_STRING(pConfigFile);
1532 COPY_STRING(pHelpFile);
1533 COPY_MULTIZ_STRING(pDependentFiles);
1534 COPY_STRING(pMonitorName);
1535 COPY_STRING(pDefaultDataType);
1536 COPY_MULTIZ_STRING(pszzPreviousNames);
1537 COPY_STRING(pszMfgName);
1538 COPY_STRING(pszOEMUrl);
1539 COPY_STRING(pszHardwareID);
1540 COPY_STRING(pszProvider);
1541 break;
1543 case 8:
1545 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1546 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1548 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1550 COPY_STRING(pName);
1551 COPY_STRING(pEnvironment);
1552 COPY_STRING(pDriverPath);
1553 COPY_STRING(pDataFile);
1554 COPY_STRING(pConfigFile);
1555 COPY_STRING(pHelpFile);
1556 COPY_MULTIZ_STRING(pDependentFiles);
1557 COPY_STRING(pMonitorName);
1558 COPY_STRING(pDefaultDataType);
1559 COPY_MULTIZ_STRING(pszzPreviousNames);
1560 COPY_STRING(pszMfgName);
1561 COPY_STRING(pszOEMUrl);
1562 COPY_STRING(pszHardwareID);
1563 COPY_STRING(pszProvider);
1564 COPY_STRING(pszPrintProcessor);
1565 COPY_STRING(pszVendorSetup);
1566 COPY_MULTIZ_STRING(pszzColorProfiles);
1567 COPY_STRING(pszInfPath);
1568 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1569 break;
1573 default:
1574 FIXME("for level %u\n", level);
1577 pDriversW += di_sizeof[level];
1578 out += di_sizeof[level];
1579 id++;
1582 #undef COPY_STRING
1583 #undef COPY_MULTIZ_STRING
1587 /***********************************************************
1588 * PRINTER_INFO_2AtoW
1589 * Creates a unicode copy of PRINTER_INFO_2A on heap
1591 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1593 LPPRINTER_INFO_2W piW;
1594 UNICODE_STRING usBuffer;
1596 if(!piA) return NULL;
1597 piW = HeapAlloc(heap, 0, sizeof(*piW));
1598 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1600 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1601 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1602 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1603 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1604 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1605 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1606 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1607 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1608 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1609 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1610 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1611 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1612 return piW;
1615 /***********************************************************
1616 * FREE_PRINTER_INFO_2W
1617 * Free PRINTER_INFO_2W and all strings
1619 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1621 if(!piW) return;
1623 HeapFree(heap,0,piW->pServerName);
1624 HeapFree(heap,0,piW->pPrinterName);
1625 HeapFree(heap,0,piW->pShareName);
1626 HeapFree(heap,0,piW->pPortName);
1627 HeapFree(heap,0,piW->pDriverName);
1628 HeapFree(heap,0,piW->pComment);
1629 HeapFree(heap,0,piW->pLocation);
1630 HeapFree(heap,0,piW->pDevMode);
1631 HeapFree(heap,0,piW->pSepFile);
1632 HeapFree(heap,0,piW->pPrintProcessor);
1633 HeapFree(heap,0,piW->pDatatype);
1634 HeapFree(heap,0,piW->pParameters);
1635 HeapFree(heap,0,piW);
1636 return;
1639 /******************************************************************
1640 * DeviceCapabilities [WINSPOOL.@]
1641 * DeviceCapabilitiesA [WINSPOOL.@]
1644 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1645 LPSTR pOutput, LPDEVMODEA lpdm)
1647 INT ret;
1649 if (!GDI_CallDeviceCapabilities16)
1651 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1652 (LPCSTR)104 );
1653 if (!GDI_CallDeviceCapabilities16) return -1;
1655 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1657 /* If DC_PAPERSIZE map POINT16s to POINTs */
1658 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1659 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1660 POINT *pt = (POINT *)pOutput;
1661 INT i;
1662 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1663 for(i = 0; i < ret; i++, pt++)
1665 pt->x = tmp[i].x;
1666 pt->y = tmp[i].y;
1668 HeapFree( GetProcessHeap(), 0, tmp );
1670 return ret;
1674 /*****************************************************************************
1675 * DeviceCapabilitiesW [WINSPOOL.@]
1677 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1680 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1681 WORD fwCapability, LPWSTR pOutput,
1682 const DEVMODEW *pDevMode)
1684 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1685 LPSTR pDeviceA = strdupWtoA(pDevice);
1686 LPSTR pPortA = strdupWtoA(pPort);
1687 INT ret;
1689 if(pOutput && (fwCapability == DC_BINNAMES ||
1690 fwCapability == DC_FILEDEPENDENCIES ||
1691 fwCapability == DC_PAPERNAMES)) {
1692 /* These need A -> W translation */
1693 INT size = 0, i;
1694 LPSTR pOutputA;
1695 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1696 dmA);
1697 if(ret == -1)
1698 return ret;
1699 switch(fwCapability) {
1700 case DC_BINNAMES:
1701 size = 24;
1702 break;
1703 case DC_PAPERNAMES:
1704 case DC_FILEDEPENDENCIES:
1705 size = 64;
1706 break;
1708 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1709 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1710 dmA);
1711 for(i = 0; i < ret; i++)
1712 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1713 pOutput + (i * size), size);
1714 HeapFree(GetProcessHeap(), 0, pOutputA);
1715 } else {
1716 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1717 (LPSTR)pOutput, dmA);
1719 HeapFree(GetProcessHeap(),0,pPortA);
1720 HeapFree(GetProcessHeap(),0,pDeviceA);
1721 HeapFree(GetProcessHeap(),0,dmA);
1722 return ret;
1725 /******************************************************************
1726 * DocumentPropertiesA [WINSPOOL.@]
1728 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1730 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1731 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1732 LPDEVMODEA pDevModeInput,DWORD fMode )
1734 LPSTR lpName = pDeviceName;
1735 static CHAR port[] = "LPT1:";
1736 LONG ret;
1738 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1739 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1742 if(!pDeviceName) {
1743 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1744 if(!lpNameW) {
1745 ERR("no name from hPrinter?\n");
1746 SetLastError(ERROR_INVALID_HANDLE);
1747 return -1;
1749 lpName = strdupWtoA(lpNameW);
1752 if (!GDI_CallExtDeviceMode16)
1754 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1755 (LPCSTR)102 );
1756 if (!GDI_CallExtDeviceMode16) {
1757 ERR("No CallExtDeviceMode16?\n");
1758 return -1;
1761 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1762 pDevModeInput, NULL, fMode);
1764 if(!pDeviceName)
1765 HeapFree(GetProcessHeap(),0,lpName);
1766 return ret;
1770 /*****************************************************************************
1771 * DocumentPropertiesW (WINSPOOL.@)
1773 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1775 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1776 LPWSTR pDeviceName,
1777 LPDEVMODEW pDevModeOutput,
1778 LPDEVMODEW pDevModeInput, DWORD fMode)
1781 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1782 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1783 LPDEVMODEA pDevModeOutputA = NULL;
1784 LONG ret;
1786 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1787 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1788 fMode);
1789 if(pDevModeOutput) {
1790 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1791 if(ret < 0) return ret;
1792 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1794 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1795 pDevModeInputA, fMode);
1796 if(pDevModeOutput) {
1797 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1798 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1800 if(fMode == 0 && ret > 0)
1801 ret += (CCHDEVICENAME + CCHFORMNAME);
1802 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1803 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1804 return ret;
1807 /*****************************************************************************
1808 * IsValidDevmodeA [WINSPOOL.@]
1810 * Validate a DEVMODE structure and fix errors if possible.
1813 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1815 FIXME("(%p,%ld): stub\n", pDevMode, size);
1817 if(!pDevMode)
1818 return FALSE;
1820 return TRUE;
1823 /*****************************************************************************
1824 * IsValidDevmodeW [WINSPOOL.@]
1826 * Validate a DEVMODE structure and fix errors if possible.
1829 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1831 FIXME("(%p,%ld): stub\n", pDevMode, size);
1833 if(!pDevMode)
1834 return FALSE;
1836 return TRUE;
1839 /******************************************************************
1840 * OpenPrinterA [WINSPOOL.@]
1842 * See OpenPrinterW.
1845 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1846 LPPRINTER_DEFAULTSA pDefault)
1848 UNICODE_STRING lpPrinterNameW;
1849 UNICODE_STRING usBuffer;
1850 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1851 PWSTR pwstrPrinterNameW;
1852 BOOL ret;
1854 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1856 if(pDefault) {
1857 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1858 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1859 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1860 pDefaultW = &DefaultW;
1862 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1863 if(pDefault) {
1864 RtlFreeUnicodeString(&usBuffer);
1865 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1867 RtlFreeUnicodeString(&lpPrinterNameW);
1868 return ret;
1871 /******************************************************************
1872 * OpenPrinterW [WINSPOOL.@]
1874 * Open a Printer / Printserver or a Printer-Object
1876 * PARAMS
1877 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1878 * phPrinter [O] The resulting Handle is stored here
1879 * pDefault [I] PTR to Default Printer Settings or NULL
1881 * RETURNS
1882 * Success: TRUE
1883 * Failure: FALSE
1885 * NOTES
1886 * lpPrinterName is one of:
1887 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1888 *| Printer: "PrinterName"
1889 *| Printer-Object: "PrinterName,Job xxx"
1890 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1891 *| XcvPort: "Servername,XcvPort PortName"
1893 * BUGS
1894 *| Printer-Object not supported
1895 *| pDefaults is ignored
1898 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1901 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1902 if (pDefault) {
1903 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1904 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1907 if(!phPrinter) {
1908 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1909 SetLastError(ERROR_INVALID_PARAMETER);
1910 return FALSE;
1913 /* Get the unique handle of the printer or Printserver */
1914 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1915 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1916 return (*phPrinter != 0);
1919 /******************************************************************
1920 * AddMonitorA [WINSPOOL.@]
1922 * See AddMonitorW.
1925 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1927 LPWSTR nameW = NULL;
1928 INT len;
1929 BOOL res;
1930 LPMONITOR_INFO_2A mi2a;
1931 MONITOR_INFO_2W mi2w;
1933 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1934 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1935 debugstr_a(mi2a ? mi2a->pName : NULL),
1936 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1937 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1939 if (Level != 2) {
1940 SetLastError(ERROR_INVALID_LEVEL);
1941 return FALSE;
1944 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1945 if (mi2a == NULL) {
1946 return FALSE;
1949 if (pName) {
1950 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1951 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1952 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1955 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1956 if (mi2a->pName) {
1957 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1958 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1959 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1961 if (mi2a->pEnvironment) {
1962 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1963 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1964 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1966 if (mi2a->pDLLName) {
1967 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1968 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1969 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1972 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1974 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1975 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1976 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1978 HeapFree(GetProcessHeap(), 0, nameW);
1979 return (res);
1982 /******************************************************************************
1983 * AddMonitorW [WINSPOOL.@]
1985 * Install a Printmonitor
1987 * PARAMS
1988 * pName [I] Servername or NULL (local Computer)
1989 * Level [I] Structure-Level (Must be 2)
1990 * pMonitors [I] PTR to MONITOR_INFO_2
1992 * RETURNS
1993 * Success: TRUE
1994 * Failure: FALSE
1996 * NOTES
1997 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2000 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2002 LPMONITOR_INFO_2W mi2w;
2004 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2005 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2006 debugstr_w(mi2w ? mi2w->pName : NULL),
2007 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2008 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2010 if ((backend == NULL) && !load_backend()) return FALSE;
2012 if (Level != 2) {
2013 SetLastError(ERROR_INVALID_LEVEL);
2014 return FALSE;
2017 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2018 if (mi2w == NULL) {
2019 return FALSE;
2022 return backend->fpAddMonitor(pName, Level, pMonitors);
2025 /******************************************************************
2026 * DeletePrinterDriverA [WINSPOOL.@]
2029 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2031 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2034 /******************************************************************
2035 * DeletePrinterDriverW [WINSPOOL.@]
2038 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2040 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2043 /******************************************************************
2044 * DeleteMonitorA [WINSPOOL.@]
2046 * See DeleteMonitorW.
2049 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2051 LPWSTR nameW = NULL;
2052 LPWSTR EnvironmentW = NULL;
2053 LPWSTR MonitorNameW = NULL;
2054 BOOL res;
2055 INT len;
2057 if (pName) {
2058 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2059 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2060 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2063 if (pEnvironment) {
2064 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2065 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2066 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2068 if (pMonitorName) {
2069 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2070 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2071 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2074 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2076 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2077 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2078 HeapFree(GetProcessHeap(), 0, nameW);
2079 return (res);
2082 /******************************************************************
2083 * DeleteMonitorW [WINSPOOL.@]
2085 * Delete a specific Printmonitor from a Printing-Environment
2087 * PARAMS
2088 * pName [I] Servername or NULL (local Computer)
2089 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2090 * pMonitorName [I] Name of the Monitor, that should be deleted
2092 * RETURNS
2093 * Success: TRUE
2094 * Failure: FALSE
2096 * NOTES
2097 * pEnvironment is ignored in Windows for the local Computer.
2100 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2103 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2104 debugstr_w(pMonitorName));
2106 if ((backend == NULL) && !load_backend()) return FALSE;
2108 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2112 /******************************************************************
2113 * DeletePortA [WINSPOOL.@]
2115 * See DeletePortW.
2118 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2120 LPWSTR nameW = NULL;
2121 LPWSTR portW = NULL;
2122 INT len;
2123 DWORD res;
2125 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2127 /* convert servername to unicode */
2128 if (pName) {
2129 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2130 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2131 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2134 /* convert portname to unicode */
2135 if (pPortName) {
2136 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2137 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2138 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2141 res = DeletePortW(nameW, hWnd, portW);
2142 HeapFree(GetProcessHeap(), 0, nameW);
2143 HeapFree(GetProcessHeap(), 0, portW);
2144 return res;
2147 /******************************************************************
2148 * DeletePortW [WINSPOOL.@]
2150 * Delete a specific Port
2152 * PARAMS
2153 * pName [I] Servername or NULL (local Computer)
2154 * hWnd [I] Handle to parent Window for the Dialog-Box
2155 * pPortName [I] Name of the Port, that should be deleted
2157 * RETURNS
2158 * Success: TRUE
2159 * Failure: FALSE
2162 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2164 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2166 if ((backend == NULL) && !load_backend()) return FALSE;
2168 if (!pPortName) {
2169 SetLastError(RPC_X_NULL_REF_POINTER);
2170 return FALSE;
2173 return backend->fpDeletePort(pName, hWnd, pPortName);
2176 /******************************************************************************
2177 * SetPrinterW [WINSPOOL.@]
2179 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2181 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2183 return FALSE;
2186 /******************************************************************************
2187 * WritePrinter [WINSPOOL.@]
2189 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2191 opened_printer_t *printer;
2192 BOOL ret = FALSE;
2194 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2196 EnterCriticalSection(&printer_handles_cs);
2197 printer = get_opened_printer(hPrinter);
2198 if(!printer)
2200 SetLastError(ERROR_INVALID_HANDLE);
2201 goto end;
2204 if(!printer->doc)
2206 SetLastError(ERROR_SPL_NO_STARTDOC);
2207 goto end;
2210 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2211 end:
2212 LeaveCriticalSection(&printer_handles_cs);
2213 return ret;
2216 /*****************************************************************************
2217 * AddFormA [WINSPOOL.@]
2219 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2221 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2222 return 1;
2225 /*****************************************************************************
2226 * AddFormW [WINSPOOL.@]
2228 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2230 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2231 return 1;
2234 /*****************************************************************************
2235 * AddJobA [WINSPOOL.@]
2237 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2239 BOOL ret;
2240 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2241 DWORD needed;
2243 if(Level != 1) {
2244 SetLastError(ERROR_INVALID_LEVEL);
2245 return FALSE;
2248 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2250 if(ret) {
2251 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2252 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2253 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2254 if(*pcbNeeded > cbBuf) {
2255 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2256 ret = FALSE;
2257 } else {
2258 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2259 addjobA->JobId = addjobW->JobId;
2260 addjobA->Path = (char *)(addjobA + 1);
2261 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2264 return ret;
2267 /*****************************************************************************
2268 * AddJobW [WINSPOOL.@]
2270 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2272 opened_printer_t *printer;
2273 job_t *job;
2274 BOOL ret = FALSE;
2275 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2276 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2277 WCHAR path[MAX_PATH], filename[MAX_PATH];
2278 DWORD len;
2279 ADDJOB_INFO_1W *addjob;
2281 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2283 EnterCriticalSection(&printer_handles_cs);
2285 printer = get_opened_printer(hPrinter);
2287 if(!printer) {
2288 SetLastError(ERROR_INVALID_HANDLE);
2289 goto end;
2292 if(Level != 1) {
2293 SetLastError(ERROR_INVALID_LEVEL);
2294 goto end;
2297 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2298 if(!job)
2299 goto end;
2301 job->job_id = InterlockedIncrement(&next_job_id);
2303 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2304 if(path[len - 1] != '\\')
2305 path[len++] = '\\';
2306 memcpy(path + len, spool_path, sizeof(spool_path));
2307 sprintfW(filename, fmtW, path, job->job_id);
2309 len = strlenW(filename);
2310 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2311 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2312 job->document_title = strdupW(default_doc_title);
2313 job->printer_name = strdupW(printer->name);
2314 job->devmode = NULL;
2315 list_add_tail(&printer->queue->jobs, &job->entry);
2317 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2318 if(*pcbNeeded <= cbBuf) {
2319 addjob = (ADDJOB_INFO_1W*)pData;
2320 addjob->JobId = job->job_id;
2321 addjob->Path = (WCHAR *)(addjob + 1);
2322 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2323 ret = TRUE;
2324 } else
2325 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2327 end:
2328 LeaveCriticalSection(&printer_handles_cs);
2329 return ret;
2332 /*****************************************************************************
2333 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2335 * Return the PATH for the Print-Processors
2337 * See GetPrintProcessorDirectoryW.
2341 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2342 DWORD level, LPBYTE Info,
2343 DWORD cbBuf, LPDWORD pcbNeeded)
2345 LPWSTR serverW = NULL;
2346 LPWSTR envW = NULL;
2347 BOOL ret;
2348 INT len;
2350 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2351 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2354 if (server) {
2355 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2356 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2357 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2360 if (env) {
2361 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2362 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2363 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2366 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2367 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2369 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2370 cbBuf, pcbNeeded);
2372 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2373 cbBuf, NULL, NULL) > 0;
2376 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2377 HeapFree(GetProcessHeap(), 0, envW);
2378 HeapFree(GetProcessHeap(), 0, serverW);
2379 return ret;
2382 /*****************************************************************************
2383 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2385 * Return the PATH for the Print-Processors
2387 * PARAMS
2388 * server [I] Servername (NT only) or NULL (local Computer)
2389 * env [I] Printing-Environment (see below) or NULL (Default)
2390 * level [I] Structure-Level (must be 1)
2391 * Info [O] PTR to Buffer that receives the Result
2392 * cbBuf [I] Size of Buffer at "Info"
2393 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2394 * required for the Buffer at "Info"
2396 * RETURNS
2397 * Success: TRUE and in pcbNeeded the Bytes used in Info
2398 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2399 * if cbBuf is too small
2401 * Native Values returned in Info on Success:
2402 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2403 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2404 *| win9x(Windows 4.0): "%winsysdir%"
2406 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2408 * BUGS
2409 * Only NULL or "" is supported for server
2412 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2413 DWORD level, LPBYTE Info,
2414 DWORD cbBuf, LPDWORD pcbNeeded)
2417 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2418 Info, cbBuf, pcbNeeded);
2420 if ((backend == NULL) && !load_backend()) return FALSE;
2422 if (level != 1) {
2423 /* (Level != 1) is ignored in win9x */
2424 SetLastError(ERROR_INVALID_LEVEL);
2425 return FALSE;
2428 if (pcbNeeded == NULL) {
2429 /* (pcbNeeded == NULL) is ignored in win9x */
2430 SetLastError(RPC_X_NULL_REF_POINTER);
2431 return FALSE;
2434 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2437 /*****************************************************************************
2438 * WINSPOOL_OpenDriverReg [internal]
2440 * opens the registry for the printer drivers depending on the given input
2441 * variable pEnvironment
2443 * RETURNS:
2444 * the opened hkey on success
2445 * NULL on error
2447 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2449 HKEY retval = NULL;
2450 LPWSTR buffer;
2451 const printenv_t * env;
2453 TRACE("(%s)\n", debugstr_w(pEnvironment));
2455 env = validate_envW(pEnvironment);
2456 if (!env) return NULL;
2458 buffer = HeapAlloc( GetProcessHeap(), 0,
2459 (strlenW(DriversW) + strlenW(env->envname) +
2460 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2461 if(buffer) {
2462 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2463 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2464 HeapFree(GetProcessHeap(), 0, buffer);
2466 return retval;
2469 /*****************************************************************************
2470 * set_devices_and_printerports [internal]
2472 * set the [Devices] and [PrinterPorts] entries for a printer.
2475 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2477 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2478 WCHAR *devline;
2479 HKEY hkey;
2481 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2483 /* FIXME: the driver must change to "winspool" */
2484 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2485 if (devline) {
2486 lstrcpyW(devline, driver_nt);
2487 lstrcatW(devline, commaW);
2488 lstrcatW(devline, pi->pPortName);
2490 TRACE("using %s\n", debugstr_w(devline));
2491 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2492 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2493 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2494 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2495 RegCloseKey(hkey);
2498 lstrcatW(devline, timeout_15_45);
2499 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2500 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2501 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2502 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2503 RegCloseKey(hkey);
2505 HeapFree(GetProcessHeap(), 0, devline);
2509 /*****************************************************************************
2510 * AddPrinterW [WINSPOOL.@]
2512 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2514 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2515 LPDEVMODEA dmA;
2516 LPDEVMODEW dmW;
2517 HANDLE retval;
2518 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2519 LONG size;
2520 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2521 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2522 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2523 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2524 statusW[] = {'S','t','a','t','u','s',0},
2525 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2527 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2529 if(pName != NULL) {
2530 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2531 SetLastError(ERROR_INVALID_PARAMETER);
2532 return 0;
2534 if(Level != 2) {
2535 ERR("Level = %d, unsupported!\n", Level);
2536 SetLastError(ERROR_INVALID_LEVEL);
2537 return 0;
2539 if(!pPrinter) {
2540 SetLastError(ERROR_INVALID_PARAMETER);
2541 return 0;
2543 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2544 ERROR_SUCCESS) {
2545 ERR("Can't create Printers key\n");
2546 return 0;
2548 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2549 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2550 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2551 RegCloseKey(hkeyPrinter);
2552 RegCloseKey(hkeyPrinters);
2553 return 0;
2555 RegCloseKey(hkeyPrinter);
2557 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2558 if(!hkeyDrivers) {
2559 ERR("Can't create Drivers key\n");
2560 RegCloseKey(hkeyPrinters);
2561 return 0;
2563 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2564 ERROR_SUCCESS) {
2565 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2566 RegCloseKey(hkeyPrinters);
2567 RegCloseKey(hkeyDrivers);
2568 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2569 return 0;
2571 RegCloseKey(hkeyDriver);
2572 RegCloseKey(hkeyDrivers);
2574 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2575 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2576 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2577 RegCloseKey(hkeyPrinters);
2578 return 0;
2581 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2582 ERROR_SUCCESS) {
2583 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2584 SetLastError(ERROR_INVALID_PRINTER_NAME);
2585 RegCloseKey(hkeyPrinters);
2586 return 0;
2589 set_devices_and_printerports(pi);
2590 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2591 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2592 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2594 /* See if we can load the driver. We may need the devmode structure anyway
2596 * FIXME:
2597 * Note that DocumentPropertiesW will briefly try to open the printer we
2598 * just create to find a DEVMODEA struct (it will use the WINEPS default
2599 * one in case it is not there, so we are ok).
2601 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2603 if(size < 0) {
2604 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2605 size = sizeof(DEVMODEW);
2607 if(pi->pDevMode)
2608 dmW = pi->pDevMode;
2609 else
2611 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2612 dmW->dmSize = size;
2613 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2615 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2616 HeapFree(GetProcessHeap(),0,dmW);
2617 dmW=NULL;
2619 else
2621 /* set devmode to printer name */
2622 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2626 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2627 and we support these drivers. NT writes DEVMODEW so somehow
2628 we'll need to distinguish between these when we support NT
2629 drivers */
2630 if (dmW)
2632 dmA = DEVMODEdupWtoA(dmW);
2633 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2634 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2635 HeapFree(GetProcessHeap(), 0, dmA);
2636 if(!pi->pDevMode)
2637 HeapFree(GetProcessHeap(), 0, dmW);
2639 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2640 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2641 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2642 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2644 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2645 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2646 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2647 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2648 (LPBYTE)&pi->Priority, sizeof(DWORD));
2649 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2650 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2651 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2652 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2653 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2654 (LPBYTE)&pi->Status, sizeof(DWORD));
2655 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2656 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2658 RegCloseKey(hkeyPrinter);
2659 RegCloseKey(hkeyPrinters);
2660 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2661 ERR("OpenPrinter failing\n");
2662 return 0;
2664 return retval;
2667 /*****************************************************************************
2668 * AddPrinterA [WINSPOOL.@]
2670 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2672 UNICODE_STRING pNameW;
2673 PWSTR pwstrNameW;
2674 PRINTER_INFO_2W *piW;
2675 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2676 HANDLE ret;
2678 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2679 if(Level != 2) {
2680 ERR("Level = %d, unsupported!\n", Level);
2681 SetLastError(ERROR_INVALID_LEVEL);
2682 return 0;
2684 pwstrNameW = asciitounicode(&pNameW,pName);
2685 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2687 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2689 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2690 RtlFreeUnicodeString(&pNameW);
2691 return ret;
2695 /*****************************************************************************
2696 * ClosePrinter [WINSPOOL.@]
2698 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2700 UINT_PTR i = (UINT_PTR)hPrinter;
2701 opened_printer_t *printer = NULL;
2702 BOOL ret = FALSE;
2704 TRACE("(%p)\n", hPrinter);
2706 EnterCriticalSection(&printer_handles_cs);
2708 if ((i > 0) && (i <= nb_printer_handles))
2709 printer = printer_handles[i - 1];
2712 if(printer)
2714 struct list *cursor, *cursor2;
2716 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2718 if (printer->backend_printer) {
2719 backend->fpClosePrinter(printer->backend_printer);
2722 if(printer->doc)
2723 EndDocPrinter(hPrinter);
2725 if(InterlockedDecrement(&printer->queue->ref) == 0)
2727 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2729 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2730 ScheduleJob(hPrinter, job->job_id);
2732 HeapFree(GetProcessHeap(), 0, printer->queue);
2735 free_printer_entry( printer );
2736 printer_handles[i - 1] = NULL;
2737 ret = TRUE;
2739 LeaveCriticalSection(&printer_handles_cs);
2740 return ret;
2743 /*****************************************************************************
2744 * DeleteFormA [WINSPOOL.@]
2746 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2748 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2749 return 1;
2752 /*****************************************************************************
2753 * DeleteFormW [WINSPOOL.@]
2755 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2757 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2758 return 1;
2761 /*****************************************************************************
2762 * DeletePrinter [WINSPOOL.@]
2764 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2766 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2767 HKEY hkeyPrinters, hkey;
2769 if(!lpNameW) {
2770 SetLastError(ERROR_INVALID_HANDLE);
2771 return FALSE;
2773 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2774 RegDeleteTreeW(hkeyPrinters, lpNameW);
2775 RegCloseKey(hkeyPrinters);
2777 WriteProfileStringW(devicesW, lpNameW, NULL);
2778 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2780 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2781 RegDeleteValueW(hkey, lpNameW);
2782 RegCloseKey(hkey);
2785 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2786 RegDeleteValueW(hkey, lpNameW);
2787 RegCloseKey(hkey);
2789 return TRUE;
2792 /*****************************************************************************
2793 * SetPrinterA [WINSPOOL.@]
2795 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2796 DWORD Command)
2798 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2799 return FALSE;
2802 /*****************************************************************************
2803 * SetJobA [WINSPOOL.@]
2805 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2806 LPBYTE pJob, DWORD Command)
2808 BOOL ret;
2809 LPBYTE JobW;
2810 UNICODE_STRING usBuffer;
2812 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2814 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2815 are all ignored by SetJob, so we don't bother copying them */
2816 switch(Level)
2818 case 0:
2819 JobW = NULL;
2820 break;
2821 case 1:
2823 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2824 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2826 JobW = (LPBYTE)info1W;
2827 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2828 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2829 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2830 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2831 info1W->Status = info1A->Status;
2832 info1W->Priority = info1A->Priority;
2833 info1W->Position = info1A->Position;
2834 info1W->PagesPrinted = info1A->PagesPrinted;
2835 break;
2837 case 2:
2839 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2840 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2842 JobW = (LPBYTE)info2W;
2843 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2844 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2845 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2846 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2847 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2848 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2849 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2850 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2851 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2852 info2W->Status = info2A->Status;
2853 info2W->Priority = info2A->Priority;
2854 info2W->Position = info2A->Position;
2855 info2W->StartTime = info2A->StartTime;
2856 info2W->UntilTime = info2A->UntilTime;
2857 info2W->PagesPrinted = info2A->PagesPrinted;
2858 break;
2860 case 3:
2861 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2862 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2863 break;
2864 default:
2865 SetLastError(ERROR_INVALID_LEVEL);
2866 return FALSE;
2869 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2871 switch(Level)
2873 case 1:
2875 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2876 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2877 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2878 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2879 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2880 break;
2882 case 2:
2884 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2885 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2886 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2887 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2888 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2889 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2890 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2891 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2892 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2893 break;
2896 HeapFree(GetProcessHeap(), 0, JobW);
2898 return ret;
2901 /*****************************************************************************
2902 * SetJobW [WINSPOOL.@]
2904 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2905 LPBYTE pJob, DWORD Command)
2907 BOOL ret = FALSE;
2908 job_t *job;
2910 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2911 FIXME("Ignoring everything other than document title\n");
2913 EnterCriticalSection(&printer_handles_cs);
2914 job = get_job(hPrinter, JobId);
2915 if(!job)
2916 goto end;
2918 switch(Level)
2920 case 0:
2921 break;
2922 case 1:
2924 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2925 HeapFree(GetProcessHeap(), 0, job->document_title);
2926 job->document_title = strdupW(info1->pDocument);
2927 break;
2929 case 2:
2931 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2932 HeapFree(GetProcessHeap(), 0, job->document_title);
2933 job->document_title = strdupW(info2->pDocument);
2934 HeapFree(GetProcessHeap(), 0, job->devmode);
2935 job->devmode = dup_devmode( info2->pDevMode );
2936 break;
2938 case 3:
2939 break;
2940 default:
2941 SetLastError(ERROR_INVALID_LEVEL);
2942 goto end;
2944 ret = TRUE;
2945 end:
2946 LeaveCriticalSection(&printer_handles_cs);
2947 return ret;
2950 /*****************************************************************************
2951 * EndDocPrinter [WINSPOOL.@]
2953 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2955 opened_printer_t *printer;
2956 BOOL ret = FALSE;
2957 TRACE("(%p)\n", hPrinter);
2959 EnterCriticalSection(&printer_handles_cs);
2961 printer = get_opened_printer(hPrinter);
2962 if(!printer)
2964 SetLastError(ERROR_INVALID_HANDLE);
2965 goto end;
2968 if(!printer->doc)
2970 SetLastError(ERROR_SPL_NO_STARTDOC);
2971 goto end;
2974 CloseHandle(printer->doc->hf);
2975 ScheduleJob(hPrinter, printer->doc->job_id);
2976 HeapFree(GetProcessHeap(), 0, printer->doc);
2977 printer->doc = NULL;
2978 ret = TRUE;
2979 end:
2980 LeaveCriticalSection(&printer_handles_cs);
2981 return ret;
2984 /*****************************************************************************
2985 * EndPagePrinter [WINSPOOL.@]
2987 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2989 FIXME("(%p): stub\n", hPrinter);
2990 return TRUE;
2993 /*****************************************************************************
2994 * StartDocPrinterA [WINSPOOL.@]
2996 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2998 UNICODE_STRING usBuffer;
2999 DOC_INFO_2W doc2W;
3000 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3001 DWORD ret;
3003 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3004 or one (DOC_INFO_3) extra DWORDs */
3006 switch(Level) {
3007 case 2:
3008 doc2W.JobId = doc2->JobId;
3009 /* fall through */
3010 case 3:
3011 doc2W.dwMode = doc2->dwMode;
3012 /* fall through */
3013 case 1:
3014 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3015 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3016 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3017 break;
3019 default:
3020 SetLastError(ERROR_INVALID_LEVEL);
3021 return FALSE;
3024 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3026 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3027 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3028 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3030 return ret;
3033 /*****************************************************************************
3034 * StartDocPrinterW [WINSPOOL.@]
3036 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3038 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3039 opened_printer_t *printer;
3040 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3041 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3042 JOB_INFO_1W job_info;
3043 DWORD needed, ret = 0;
3044 HANDLE hf;
3045 WCHAR *filename;
3046 job_t *job;
3048 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3049 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3050 debugstr_w(doc->pDatatype));
3052 if(Level < 1 || Level > 3)
3054 SetLastError(ERROR_INVALID_LEVEL);
3055 return 0;
3058 EnterCriticalSection(&printer_handles_cs);
3059 printer = get_opened_printer(hPrinter);
3060 if(!printer)
3062 SetLastError(ERROR_INVALID_HANDLE);
3063 goto end;
3066 if(printer->doc)
3068 SetLastError(ERROR_INVALID_PRINTER_STATE);
3069 goto end;
3072 /* Even if we're printing to a file we still add a print job, we'll
3073 just ignore the spool file name */
3075 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3077 ERR("AddJob failed gle %u\n", GetLastError());
3078 goto end;
3081 /* use pOutputFile only, when it is a real filename */
3082 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3083 filename = doc->pOutputFile;
3084 else
3085 filename = addjob->Path;
3087 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3088 if(hf == INVALID_HANDLE_VALUE)
3089 goto end;
3091 memset(&job_info, 0, sizeof(job_info));
3092 job_info.pDocument = doc->pDocName;
3093 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3095 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3096 printer->doc->hf = hf;
3097 ret = printer->doc->job_id = addjob->JobId;
3098 job = get_job(hPrinter, ret);
3099 job->portname = strdupW(doc->pOutputFile);
3101 end:
3102 LeaveCriticalSection(&printer_handles_cs);
3104 return ret;
3107 /*****************************************************************************
3108 * StartPagePrinter [WINSPOOL.@]
3110 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3112 FIXME("(%p): stub\n", hPrinter);
3113 return TRUE;
3116 /*****************************************************************************
3117 * GetFormA [WINSPOOL.@]
3119 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3120 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3122 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3123 Level,pForm,cbBuf,pcbNeeded);
3124 return FALSE;
3127 /*****************************************************************************
3128 * GetFormW [WINSPOOL.@]
3130 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3131 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3133 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3134 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3135 return FALSE;
3138 /*****************************************************************************
3139 * SetFormA [WINSPOOL.@]
3141 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3142 LPBYTE pForm)
3144 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3145 return FALSE;
3148 /*****************************************************************************
3149 * SetFormW [WINSPOOL.@]
3151 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3152 LPBYTE pForm)
3154 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3155 return FALSE;
3158 /*****************************************************************************
3159 * ReadPrinter [WINSPOOL.@]
3161 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3162 LPDWORD pNoBytesRead)
3164 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3165 return FALSE;
3168 /*****************************************************************************
3169 * ResetPrinterA [WINSPOOL.@]
3171 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3173 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3174 return FALSE;
3177 /*****************************************************************************
3178 * ResetPrinterW [WINSPOOL.@]
3180 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3182 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3183 return FALSE;
3186 /*****************************************************************************
3187 * WINSPOOL_GetDWORDFromReg
3189 * Return DWORD associated with ValueName from hkey.
3191 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3193 DWORD sz = sizeof(DWORD), type, value = 0;
3194 LONG ret;
3196 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3198 if(ret != ERROR_SUCCESS) {
3199 WARN("Got ret = %d on name %s\n", ret, ValueName);
3200 return 0;
3202 if(type != REG_DWORD) {
3203 ERR("Got type %d\n", type);
3204 return 0;
3206 return value;
3210 /*****************************************************************************
3211 * get_filename_from_reg [internal]
3213 * Get ValueName from hkey storing result in out
3214 * when the Value in the registry has only a filename, use driverdir as prefix
3215 * outlen is space left in out
3216 * String is stored either as unicode or ascii
3220 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3221 LPBYTE out, DWORD outlen, LPDWORD needed)
3223 WCHAR filename[MAX_PATH];
3224 DWORD size;
3225 DWORD type;
3226 LONG ret;
3227 LPWSTR buffer = filename;
3228 LPWSTR ptr;
3230 *needed = 0;
3231 size = sizeof(filename);
3232 buffer[0] = '\0';
3233 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3234 if (ret == ERROR_MORE_DATA) {
3235 TRACE("need dynamic buffer: %u\n", size);
3236 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3237 if (!buffer) {
3238 /* No Memory is bad */
3239 return FALSE;
3241 buffer[0] = '\0';
3242 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3245 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3246 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3247 return FALSE;
3250 ptr = buffer;
3251 while (ptr) {
3252 /* do we have a full path ? */
3253 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3254 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3256 if (!ret) {
3257 /* we must build the full Path */
3258 *needed += dirlen;
3259 if ((out) && (outlen > dirlen)) {
3260 lstrcpyW((LPWSTR)out, driverdir);
3261 out += dirlen;
3262 outlen -= dirlen;
3264 else
3265 out = NULL;
3268 /* write the filename */
3269 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3270 if ((out) && (outlen >= size)) {
3271 lstrcpyW((LPWSTR)out, ptr);
3272 out += size;
3273 outlen -= size;
3275 else
3276 out = NULL;
3277 *needed += size;
3278 ptr += lstrlenW(ptr)+1;
3279 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3282 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3284 /* write the multisz-termination */
3285 if (type == REG_MULTI_SZ) {
3286 size = sizeof(WCHAR);
3288 *needed += size;
3289 if (out && (outlen >= size)) {
3290 memset (out, 0, size);
3293 return TRUE;
3296 /*****************************************************************************
3297 * WINSPOOL_GetStringFromReg
3299 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3300 * String is stored as unicode.
3302 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3303 DWORD buflen, DWORD *needed)
3305 DWORD sz = buflen, type;
3306 LONG ret;
3308 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3309 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3310 WARN("Got ret = %d\n", ret);
3311 *needed = 0;
3312 return FALSE;
3314 /* add space for terminating '\0' */
3315 sz += sizeof(WCHAR);
3316 *needed = sz;
3318 if (ptr)
3319 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3321 return TRUE;
3324 /*****************************************************************************
3325 * WINSPOOL_GetDefaultDevMode
3327 * Get a default DevMode values for wineps.
3328 * FIXME - use ppd.
3331 static void WINSPOOL_GetDefaultDevMode(
3332 LPBYTE ptr,
3333 DWORD buflen, DWORD *needed)
3335 DEVMODEW dm;
3336 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3338 /* fill default DEVMODE - should be read from ppd... */
3339 ZeroMemory( &dm, sizeof(dm) );
3340 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3341 dm.dmSpecVersion = DM_SPECVERSION;
3342 dm.dmDriverVersion = 1;
3343 dm.dmSize = sizeof(DEVMODEW);
3344 dm.dmDriverExtra = 0;
3345 dm.dmFields =
3346 DM_ORIENTATION | DM_PAPERSIZE |
3347 DM_PAPERLENGTH | DM_PAPERWIDTH |
3348 DM_SCALE |
3349 DM_COPIES |
3350 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3351 DM_YRESOLUTION | DM_TTOPTION;
3353 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3354 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3355 dm.u1.s1.dmPaperLength = 2970;
3356 dm.u1.s1.dmPaperWidth = 2100;
3358 dm.u1.s1.dmScale = 100;
3359 dm.u1.s1.dmCopies = 1;
3360 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3361 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3362 /* dm.dmColor */
3363 /* dm.dmDuplex */
3364 dm.dmYResolution = 300; /* 300dpi */
3365 dm.dmTTOption = DMTT_BITMAP;
3366 /* dm.dmCollate */
3367 /* dm.dmFormName */
3368 /* dm.dmLogPixels */
3369 /* dm.dmBitsPerPel */
3370 /* dm.dmPelsWidth */
3371 /* dm.dmPelsHeight */
3372 /* dm.u2.dmDisplayFlags */
3373 /* dm.dmDisplayFrequency */
3374 /* dm.dmICMMethod */
3375 /* dm.dmICMIntent */
3376 /* dm.dmMediaType */
3377 /* dm.dmDitherType */
3378 /* dm.dmReserved1 */
3379 /* dm.dmReserved2 */
3380 /* dm.dmPanningWidth */
3381 /* dm.dmPanningHeight */
3383 if(buflen >= sizeof(DEVMODEW))
3384 memcpy(ptr, &dm, sizeof(DEVMODEW));
3385 *needed = sizeof(DEVMODEW);
3388 /*****************************************************************************
3389 * WINSPOOL_GetDevModeFromReg
3391 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3392 * DevMode is stored either as unicode or ascii.
3394 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3395 LPBYTE ptr,
3396 DWORD buflen, DWORD *needed)
3398 DWORD sz = buflen, type;
3399 LONG ret;
3401 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3402 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3403 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3404 if (sz < sizeof(DEVMODEA))
3406 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3407 return FALSE;
3409 /* ensures that dmSize is not erratically bogus if registry is invalid */
3410 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3411 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3412 sz += (CCHDEVICENAME + CCHFORMNAME);
3413 if (ptr && (buflen >= sz)) {
3414 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3415 memcpy(ptr, dmW, sz);
3416 HeapFree(GetProcessHeap(),0,dmW);
3418 *needed = sz;
3419 return TRUE;
3422 /*********************************************************************
3423 * WINSPOOL_GetPrinter_1
3425 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3427 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3428 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3430 DWORD size, left = cbBuf;
3431 BOOL space = (cbBuf > 0);
3432 LPBYTE ptr = buf;
3434 *pcbNeeded = 0;
3436 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3437 if(space && size <= left) {
3438 pi1->pName = (LPWSTR)ptr;
3439 ptr += size;
3440 left -= size;
3441 } else
3442 space = FALSE;
3443 *pcbNeeded += size;
3446 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3447 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3448 if(space && size <= left) {
3449 pi1->pDescription = (LPWSTR)ptr;
3450 ptr += size;
3451 left -= size;
3452 } else
3453 space = FALSE;
3454 *pcbNeeded += size;
3457 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3458 if(space && size <= left) {
3459 pi1->pComment = (LPWSTR)ptr;
3460 ptr += size;
3461 left -= size;
3462 } else
3463 space = FALSE;
3464 *pcbNeeded += size;
3467 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3469 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3470 memset(pi1, 0, sizeof(*pi1));
3472 return space;
3474 /*********************************************************************
3475 * WINSPOOL_GetPrinter_2
3477 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3479 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3480 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3482 DWORD size, left = cbBuf;
3483 BOOL space = (cbBuf > 0);
3484 LPBYTE ptr = buf;
3486 *pcbNeeded = 0;
3488 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3489 if(space && size <= left) {
3490 pi2->pPrinterName = (LPWSTR)ptr;
3491 ptr += size;
3492 left -= size;
3493 } else
3494 space = FALSE;
3495 *pcbNeeded += size;
3497 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3498 if(space && size <= left) {
3499 pi2->pShareName = (LPWSTR)ptr;
3500 ptr += size;
3501 left -= size;
3502 } else
3503 space = FALSE;
3504 *pcbNeeded += size;
3506 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3507 if(space && size <= left) {
3508 pi2->pPortName = (LPWSTR)ptr;
3509 ptr += size;
3510 left -= size;
3511 } else
3512 space = FALSE;
3513 *pcbNeeded += size;
3515 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3516 if(space && size <= left) {
3517 pi2->pDriverName = (LPWSTR)ptr;
3518 ptr += size;
3519 left -= size;
3520 } else
3521 space = FALSE;
3522 *pcbNeeded += size;
3524 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3525 if(space && size <= left) {
3526 pi2->pComment = (LPWSTR)ptr;
3527 ptr += size;
3528 left -= size;
3529 } else
3530 space = FALSE;
3531 *pcbNeeded += size;
3533 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3534 if(space && size <= left) {
3535 pi2->pLocation = (LPWSTR)ptr;
3536 ptr += size;
3537 left -= size;
3538 } else
3539 space = FALSE;
3540 *pcbNeeded += size;
3542 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3543 if(space && size <= left) {
3544 pi2->pDevMode = (LPDEVMODEW)ptr;
3545 ptr += size;
3546 left -= size;
3547 } else
3548 space = FALSE;
3549 *pcbNeeded += size;
3551 else
3553 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3554 if(space && size <= left) {
3555 pi2->pDevMode = (LPDEVMODEW)ptr;
3556 ptr += size;
3557 left -= size;
3558 } else
3559 space = FALSE;
3560 *pcbNeeded += size;
3562 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3563 if(space && size <= left) {
3564 pi2->pSepFile = (LPWSTR)ptr;
3565 ptr += size;
3566 left -= size;
3567 } else
3568 space = FALSE;
3569 *pcbNeeded += size;
3571 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3572 if(space && size <= left) {
3573 pi2->pPrintProcessor = (LPWSTR)ptr;
3574 ptr += size;
3575 left -= size;
3576 } else
3577 space = FALSE;
3578 *pcbNeeded += size;
3580 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3581 if(space && size <= left) {
3582 pi2->pDatatype = (LPWSTR)ptr;
3583 ptr += size;
3584 left -= size;
3585 } else
3586 space = FALSE;
3587 *pcbNeeded += size;
3589 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3590 if(space && size <= left) {
3591 pi2->pParameters = (LPWSTR)ptr;
3592 ptr += size;
3593 left -= size;
3594 } else
3595 space = FALSE;
3596 *pcbNeeded += size;
3598 if(pi2) {
3599 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3600 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3601 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3602 "Default Priority");
3603 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3604 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3607 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3608 memset(pi2, 0, sizeof(*pi2));
3610 return space;
3613 /*********************************************************************
3614 * WINSPOOL_GetPrinter_4
3616 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3618 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3619 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3621 DWORD size, left = cbBuf;
3622 BOOL space = (cbBuf > 0);
3623 LPBYTE ptr = buf;
3625 *pcbNeeded = 0;
3627 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3628 if(space && size <= left) {
3629 pi4->pPrinterName = (LPWSTR)ptr;
3630 ptr += size;
3631 left -= size;
3632 } else
3633 space = FALSE;
3634 *pcbNeeded += size;
3636 if(pi4) {
3637 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3640 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3641 memset(pi4, 0, sizeof(*pi4));
3643 return space;
3646 /*********************************************************************
3647 * WINSPOOL_GetPrinter_5
3649 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3651 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3652 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3654 DWORD size, left = cbBuf;
3655 BOOL space = (cbBuf > 0);
3656 LPBYTE ptr = buf;
3658 *pcbNeeded = 0;
3660 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3661 if(space && size <= left) {
3662 pi5->pPrinterName = (LPWSTR)ptr;
3663 ptr += size;
3664 left -= size;
3665 } else
3666 space = FALSE;
3667 *pcbNeeded += size;
3669 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3670 if(space && size <= left) {
3671 pi5->pPortName = (LPWSTR)ptr;
3672 ptr += size;
3673 left -= size;
3674 } else
3675 space = FALSE;
3676 *pcbNeeded += size;
3678 if(pi5) {
3679 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3680 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3681 "dnsTimeout");
3682 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3683 "txTimeout");
3686 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3687 memset(pi5, 0, sizeof(*pi5));
3689 return space;
3692 /*********************************************************************
3693 * WINSPOOL_GetPrinter_7
3695 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3697 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3698 DWORD cbBuf, LPDWORD pcbNeeded)
3700 DWORD size, left = cbBuf;
3701 BOOL space = (cbBuf > 0);
3702 LPBYTE ptr = buf;
3704 *pcbNeeded = 0;
3706 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3708 ptr = NULL;
3709 size = sizeof(pi7->pszObjectGUID);
3711 if (space && size <= left) {
3712 pi7->pszObjectGUID = (LPWSTR)ptr;
3713 ptr += size;
3714 left -= size;
3715 } else
3716 space = FALSE;
3717 *pcbNeeded += size;
3718 if (pi7) {
3719 /* We do not have a Directory Service */
3720 pi7->dwAction = DSPRINT_UNPUBLISH;
3723 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3724 memset(pi7, 0, sizeof(*pi7));
3726 return space;
3729 /*********************************************************************
3730 * WINSPOOL_GetPrinter_9
3732 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3734 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3735 DWORD cbBuf, LPDWORD pcbNeeded)
3737 DWORD size;
3738 BOOL space = (cbBuf > 0);
3740 *pcbNeeded = 0;
3742 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3743 if(space && size <= cbBuf) {
3744 pi9->pDevMode = (LPDEVMODEW)buf;
3745 } else
3746 space = FALSE;
3747 *pcbNeeded += size;
3749 else
3751 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3752 if(space && size <= cbBuf) {
3753 pi9->pDevMode = (LPDEVMODEW)buf;
3754 } else
3755 space = FALSE;
3756 *pcbNeeded += size;
3759 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3760 memset(pi9, 0, sizeof(*pi9));
3762 return space;
3765 /*****************************************************************************
3766 * GetPrinterW [WINSPOOL.@]
3768 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3769 DWORD cbBuf, LPDWORD pcbNeeded)
3771 LPCWSTR name;
3772 DWORD size, needed = 0;
3773 LPBYTE ptr = NULL;
3774 HKEY hkeyPrinter, hkeyPrinters;
3775 BOOL ret;
3777 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3779 if (!(name = get_opened_printer_name(hPrinter))) {
3780 SetLastError(ERROR_INVALID_HANDLE);
3781 return FALSE;
3784 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3785 ERROR_SUCCESS) {
3786 ERR("Can't create Printers key\n");
3787 return FALSE;
3789 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3791 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3792 RegCloseKey(hkeyPrinters);
3793 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3794 return FALSE;
3797 switch(Level) {
3798 case 2:
3800 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3802 size = sizeof(PRINTER_INFO_2W);
3803 if(size <= cbBuf) {
3804 ptr = pPrinter + size;
3805 cbBuf -= size;
3806 memset(pPrinter, 0, size);
3807 } else {
3808 pi2 = NULL;
3809 cbBuf = 0;
3811 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3812 needed += size;
3813 break;
3816 case 4:
3818 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3820 size = sizeof(PRINTER_INFO_4W);
3821 if(size <= cbBuf) {
3822 ptr = pPrinter + size;
3823 cbBuf -= size;
3824 memset(pPrinter, 0, size);
3825 } else {
3826 pi4 = NULL;
3827 cbBuf = 0;
3829 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3830 needed += size;
3831 break;
3835 case 5:
3837 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3839 size = sizeof(PRINTER_INFO_5W);
3840 if(size <= cbBuf) {
3841 ptr = pPrinter + size;
3842 cbBuf -= size;
3843 memset(pPrinter, 0, size);
3844 } else {
3845 pi5 = NULL;
3846 cbBuf = 0;
3849 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3850 needed += size;
3851 break;
3855 case 6:
3857 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3859 size = sizeof(PRINTER_INFO_6);
3860 if (size <= cbBuf) {
3861 /* FIXME: We do not update the status yet */
3862 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3863 ret = TRUE;
3864 } else {
3865 ret = FALSE;
3868 needed += size;
3869 break;
3872 case 7:
3874 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3876 size = sizeof(PRINTER_INFO_7W);
3877 if (size <= cbBuf) {
3878 ptr = pPrinter + size;
3879 cbBuf -= size;
3880 memset(pPrinter, 0, size);
3881 } else {
3882 pi7 = NULL;
3883 cbBuf = 0;
3886 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3887 needed += size;
3888 break;
3892 case 9:
3894 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3896 size = sizeof(PRINTER_INFO_9W);
3897 if(size <= cbBuf) {
3898 ptr = pPrinter + size;
3899 cbBuf -= size;
3900 memset(pPrinter, 0, size);
3901 } else {
3902 pi9 = NULL;
3903 cbBuf = 0;
3906 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3907 needed += size;
3908 break;
3912 default:
3913 FIXME("Unimplemented level %d\n", Level);
3914 SetLastError(ERROR_INVALID_LEVEL);
3915 RegCloseKey(hkeyPrinters);
3916 RegCloseKey(hkeyPrinter);
3917 return FALSE;
3920 RegCloseKey(hkeyPrinter);
3921 RegCloseKey(hkeyPrinters);
3923 TRACE("returning %d needed = %d\n", ret, needed);
3924 if(pcbNeeded) *pcbNeeded = needed;
3925 if(!ret)
3926 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3927 return ret;
3930 /*****************************************************************************
3931 * GetPrinterA [WINSPOOL.@]
3933 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3934 DWORD cbBuf, LPDWORD pcbNeeded)
3936 BOOL ret;
3937 LPBYTE buf = NULL;
3939 if (cbBuf)
3940 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3942 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3943 if (ret)
3944 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3945 HeapFree(GetProcessHeap(), 0, buf);
3947 return ret;
3950 /*****************************************************************************
3951 * WINSPOOL_EnumPrintersW
3953 * Implementation of EnumPrintersW
3955 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3956 DWORD dwLevel, LPBYTE lpbPrinters,
3957 DWORD cbBuf, LPDWORD lpdwNeeded,
3958 LPDWORD lpdwReturned)
3961 HKEY hkeyPrinters, hkeyPrinter;
3962 WCHAR PrinterName[255];
3963 DWORD needed = 0, number = 0;
3964 DWORD used, i, left;
3965 PBYTE pi, buf;
3967 if(lpbPrinters)
3968 memset(lpbPrinters, 0, cbBuf);
3969 if(lpdwReturned)
3970 *lpdwReturned = 0;
3971 if(lpdwNeeded)
3972 *lpdwNeeded = 0;
3974 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3975 if(dwType == PRINTER_ENUM_DEFAULT)
3976 return TRUE;
3978 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3979 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3980 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3981 if (!dwType) {
3982 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3983 return TRUE;
3988 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3989 FIXME("dwType = %08x\n", dwType);
3990 SetLastError(ERROR_INVALID_FLAGS);
3991 return FALSE;
3994 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3995 ERROR_SUCCESS) {
3996 ERR("Can't create Printers key\n");
3997 return FALSE;
4000 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4001 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4002 RegCloseKey(hkeyPrinters);
4003 ERR("Can't query Printers key\n");
4004 return FALSE;
4006 TRACE("Found %d printers\n", number);
4008 switch(dwLevel) {
4009 case 1:
4010 used = number * sizeof(PRINTER_INFO_1W);
4011 break;
4012 case 2:
4013 used = number * sizeof(PRINTER_INFO_2W);
4014 break;
4015 case 4:
4016 used = number * sizeof(PRINTER_INFO_4W);
4017 break;
4018 case 5:
4019 used = number * sizeof(PRINTER_INFO_5W);
4020 break;
4022 default:
4023 SetLastError(ERROR_INVALID_LEVEL);
4024 RegCloseKey(hkeyPrinters);
4025 return FALSE;
4027 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4029 for(i = 0; i < number; i++) {
4030 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4031 ERROR_SUCCESS) {
4032 ERR("Can't enum key number %d\n", i);
4033 RegCloseKey(hkeyPrinters);
4034 return FALSE;
4036 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4037 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4038 ERROR_SUCCESS) {
4039 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4040 RegCloseKey(hkeyPrinters);
4041 return FALSE;
4044 if(cbBuf > used) {
4045 buf = lpbPrinters + used;
4046 left = cbBuf - used;
4047 } else {
4048 buf = NULL;
4049 left = 0;
4052 switch(dwLevel) {
4053 case 1:
4054 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4055 left, &needed);
4056 used += needed;
4057 if(pi) pi += sizeof(PRINTER_INFO_1W);
4058 break;
4059 case 2:
4060 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4061 left, &needed);
4062 used += needed;
4063 if(pi) pi += sizeof(PRINTER_INFO_2W);
4064 break;
4065 case 4:
4066 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4067 left, &needed);
4068 used += needed;
4069 if(pi) pi += sizeof(PRINTER_INFO_4W);
4070 break;
4071 case 5:
4072 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4073 left, &needed);
4074 used += needed;
4075 if(pi) pi += sizeof(PRINTER_INFO_5W);
4076 break;
4077 default:
4078 ERR("Shouldn't be here!\n");
4079 RegCloseKey(hkeyPrinter);
4080 RegCloseKey(hkeyPrinters);
4081 return FALSE;
4083 RegCloseKey(hkeyPrinter);
4085 RegCloseKey(hkeyPrinters);
4087 if(lpdwNeeded)
4088 *lpdwNeeded = used;
4090 if(used > cbBuf) {
4091 if(lpbPrinters)
4092 memset(lpbPrinters, 0, cbBuf);
4093 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4094 return FALSE;
4096 if(lpdwReturned)
4097 *lpdwReturned = number;
4098 SetLastError(ERROR_SUCCESS);
4099 return TRUE;
4103 /******************************************************************
4104 * EnumPrintersW [WINSPOOL.@]
4106 * Enumerates the available printers, print servers and print
4107 * providers, depending on the specified flags, name and level.
4109 * RETURNS:
4111 * If level is set to 1:
4112 * Returns an array of PRINTER_INFO_1 data structures in the
4113 * lpbPrinters buffer.
4115 * If level is set to 2:
4116 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4117 * Returns an array of PRINTER_INFO_2 data structures in the
4118 * lpbPrinters buffer. Note that according to MSDN also an
4119 * OpenPrinter should be performed on every remote printer.
4121 * If level is set to 4 (officially WinNT only):
4122 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4123 * Fast: Only the registry is queried to retrieve printer names,
4124 * no connection to the driver is made.
4125 * Returns an array of PRINTER_INFO_4 data structures in the
4126 * lpbPrinters buffer.
4128 * If level is set to 5 (officially WinNT4/Win9x only):
4129 * Fast: Only the registry is queried to retrieve printer names,
4130 * no connection to the driver is made.
4131 * Returns an array of PRINTER_INFO_5 data structures in the
4132 * lpbPrinters buffer.
4134 * If level set to 3 or 6+:
4135 * returns zero (failure!)
4137 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4138 * for information.
4140 * BUGS:
4141 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4142 * - Only levels 2, 4 and 5 are implemented at the moment.
4143 * - 16-bit printer drivers are not enumerated.
4144 * - Returned amount of bytes used/needed does not match the real Windoze
4145 * implementation (as in this implementation, all strings are part
4146 * of the buffer, whereas Win32 keeps them somewhere else)
4147 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4149 * NOTE:
4150 * - In a regular Wine installation, no registry settings for printers
4151 * exist, which makes this function return an empty list.
4153 BOOL WINAPI EnumPrintersW(
4154 DWORD dwType, /* [in] Types of print objects to enumerate */
4155 LPWSTR lpszName, /* [in] name of objects to enumerate */
4156 DWORD dwLevel, /* [in] type of printer info structure */
4157 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4158 DWORD cbBuf, /* [in] max size of buffer in bytes */
4159 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4160 LPDWORD lpdwReturned /* [out] number of entries returned */
4163 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4164 lpdwNeeded, lpdwReturned);
4167 /******************************************************************
4168 * EnumPrintersA [WINSPOOL.@]
4170 * See EnumPrintersW
4173 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4174 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4176 BOOL ret;
4177 UNICODE_STRING pNameU;
4178 LPWSTR pNameW;
4179 LPBYTE pPrintersW;
4181 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4182 pPrinters, cbBuf, pcbNeeded, pcReturned);
4184 pNameW = asciitounicode(&pNameU, pName);
4186 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4187 MS Office need this */
4188 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4190 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4192 RtlFreeUnicodeString(&pNameU);
4193 if (ret) {
4194 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4196 HeapFree(GetProcessHeap(), 0, pPrintersW);
4197 return ret;
4200 /*****************************************************************************
4201 * WINSPOOL_GetDriverInfoFromReg [internal]
4203 * Enters the information from the registry into the DRIVER_INFO struct
4205 * RETURNS
4206 * zero if the printer driver does not exist in the registry
4207 * (only if Level > 1) otherwise nonzero
4209 static BOOL WINSPOOL_GetDriverInfoFromReg(
4210 HKEY hkeyDrivers,
4211 LPWSTR DriverName,
4212 const printenv_t * env,
4213 DWORD Level,
4214 LPBYTE ptr, /* DRIVER_INFO */
4215 LPBYTE pDriverStrings, /* strings buffer */
4216 DWORD cbBuf, /* size of string buffer */
4217 LPDWORD pcbNeeded) /* space needed for str. */
4219 DWORD size, tmp;
4220 HKEY hkeyDriver;
4221 WCHAR driverdir[MAX_PATH];
4222 DWORD dirlen;
4223 LPBYTE strPtr = pDriverStrings;
4224 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4226 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4227 debugstr_w(DriverName), env,
4228 Level, di, pDriverStrings, cbBuf);
4230 if (di) ZeroMemory(di, di_sizeof[Level]);
4232 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4233 if (*pcbNeeded <= cbBuf)
4234 strcpyW((LPWSTR)strPtr, DriverName);
4236 /* pName for level 1 has a different offset! */
4237 if (Level == 1) {
4238 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4239 return TRUE;
4242 /* .cVersion and .pName for level > 1 */
4243 if (di) {
4244 di->cVersion = env->driverversion;
4245 di->pName = (LPWSTR) strPtr;
4246 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4249 /* Reserve Space for the largest subdir and a Backslash*/
4250 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4251 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4252 /* Should never Fail */
4253 return FALSE;
4255 lstrcatW(driverdir, env->versionsubdir);
4256 lstrcatW(driverdir, backslashW);
4258 /* dirlen must not include the terminating zero */
4259 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4261 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4262 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4263 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4264 return FALSE;
4267 /* pEnvironment */
4268 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4270 *pcbNeeded += size;
4271 if (*pcbNeeded <= cbBuf) {
4272 lstrcpyW((LPWSTR)strPtr, env->envname);
4273 if (di) di->pEnvironment = (LPWSTR)strPtr;
4274 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4277 /* .pDriverPath is the Graphics rendering engine.
4278 The full Path is required to avoid a crash in some apps */
4279 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4280 *pcbNeeded += size;
4281 if (*pcbNeeded <= cbBuf)
4282 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4284 if (di) di->pDriverPath = (LPWSTR)strPtr;
4285 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4288 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4289 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4290 *pcbNeeded += size;
4291 if (*pcbNeeded <= cbBuf)
4292 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4294 if (di) di->pDataFile = (LPWSTR)strPtr;
4295 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4298 /* .pConfigFile is the Driver user Interface */
4299 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4300 *pcbNeeded += size;
4301 if (*pcbNeeded <= cbBuf)
4302 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4304 if (di) di->pConfigFile = (LPWSTR)strPtr;
4305 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4308 if (Level == 2 ) {
4309 RegCloseKey(hkeyDriver);
4310 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4311 return TRUE;
4314 if (Level == 5 ) {
4315 RegCloseKey(hkeyDriver);
4316 FIXME("level 5: incomplete\n");
4317 return TRUE;
4320 /* .pHelpFile */
4321 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4322 *pcbNeeded += size;
4323 if (*pcbNeeded <= cbBuf)
4324 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4326 if (di) di->pHelpFile = (LPWSTR)strPtr;
4327 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4330 /* .pDependentFiles */
4331 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4332 *pcbNeeded += size;
4333 if (*pcbNeeded <= cbBuf)
4334 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4336 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4337 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4339 else if (GetVersion() & 0x80000000) {
4340 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4341 size = 2 * sizeof(WCHAR);
4342 *pcbNeeded += size;
4343 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4345 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4346 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4349 /* .pMonitorName is the optional Language Monitor */
4350 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4351 *pcbNeeded += size;
4352 if (*pcbNeeded <= cbBuf)
4353 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4355 if (di) di->pMonitorName = (LPWSTR)strPtr;
4356 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4359 /* .pDefaultDataType */
4360 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4361 *pcbNeeded += size;
4362 if(*pcbNeeded <= cbBuf)
4363 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4365 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4366 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4369 if (Level == 3 ) {
4370 RegCloseKey(hkeyDriver);
4371 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4372 return TRUE;
4375 /* .pszzPreviousNames */
4376 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4377 *pcbNeeded += size;
4378 if(*pcbNeeded <= cbBuf)
4379 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4381 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4382 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4385 if (Level == 4 ) {
4386 RegCloseKey(hkeyDriver);
4387 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4388 return TRUE;
4391 /* support is missing, but not important enough for a FIXME */
4392 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4394 /* .pszMfgName */
4395 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4396 *pcbNeeded += size;
4397 if(*pcbNeeded <= cbBuf)
4398 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4400 if (di) di->pszMfgName = (LPWSTR)strPtr;
4401 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4404 /* .pszOEMUrl */
4405 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4406 *pcbNeeded += size;
4407 if(*pcbNeeded <= cbBuf)
4408 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4410 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4411 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4414 /* .pszHardwareID */
4415 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4416 *pcbNeeded += size;
4417 if(*pcbNeeded <= cbBuf)
4418 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4420 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4421 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4424 /* .pszProvider */
4425 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4426 *pcbNeeded += size;
4427 if(*pcbNeeded <= cbBuf)
4428 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4430 if (di) di->pszProvider = (LPWSTR)strPtr;
4431 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4434 if (Level == 6 ) {
4435 RegCloseKey(hkeyDriver);
4436 return TRUE;
4439 /* support is missing, but not important enough for a FIXME */
4440 TRACE("level 8: incomplete\n");
4442 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4443 RegCloseKey(hkeyDriver);
4444 return TRUE;
4447 /*****************************************************************************
4448 * GetPrinterDriverW [WINSPOOL.@]
4450 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4451 DWORD Level, LPBYTE pDriverInfo,
4452 DWORD cbBuf, LPDWORD pcbNeeded)
4454 LPCWSTR name;
4455 WCHAR DriverName[100];
4456 DWORD ret, type, size, needed = 0;
4457 LPBYTE ptr = NULL;
4458 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4459 const printenv_t * env;
4461 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4462 Level,pDriverInfo,cbBuf, pcbNeeded);
4464 if (cbBuf > 0)
4465 ZeroMemory(pDriverInfo, cbBuf);
4467 if (!(name = get_opened_printer_name(hPrinter))) {
4468 SetLastError(ERROR_INVALID_HANDLE);
4469 return FALSE;
4472 if (Level < 1 || Level == 7 || Level > 8) {
4473 SetLastError(ERROR_INVALID_LEVEL);
4474 return FALSE;
4477 env = validate_envW(pEnvironment);
4478 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4480 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4481 ERROR_SUCCESS) {
4482 ERR("Can't create Printers key\n");
4483 return FALSE;
4485 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4486 != ERROR_SUCCESS) {
4487 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4488 RegCloseKey(hkeyPrinters);
4489 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4490 return FALSE;
4492 size = sizeof(DriverName);
4493 DriverName[0] = 0;
4494 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4495 (LPBYTE)DriverName, &size);
4496 RegCloseKey(hkeyPrinter);
4497 RegCloseKey(hkeyPrinters);
4498 if(ret != ERROR_SUCCESS) {
4499 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4500 return FALSE;
4503 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4504 if(!hkeyDrivers) {
4505 ERR("Can't create Drivers key\n");
4506 return FALSE;
4509 size = di_sizeof[Level];
4510 if ((size <= cbBuf) && pDriverInfo)
4511 ptr = pDriverInfo + size;
4513 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4514 env, Level, pDriverInfo, ptr,
4515 (cbBuf < size) ? 0 : cbBuf - size,
4516 &needed)) {
4517 RegCloseKey(hkeyDrivers);
4518 return FALSE;
4521 RegCloseKey(hkeyDrivers);
4523 if(pcbNeeded) *pcbNeeded = size + needed;
4524 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4525 if(cbBuf >= size + needed) return TRUE;
4526 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4527 return FALSE;
4530 /*****************************************************************************
4531 * GetPrinterDriverA [WINSPOOL.@]
4533 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4534 DWORD Level, LPBYTE pDriverInfo,
4535 DWORD cbBuf, LPDWORD pcbNeeded)
4537 BOOL ret;
4538 UNICODE_STRING pEnvW;
4539 PWSTR pwstrEnvW;
4540 LPBYTE buf = NULL;
4542 if (cbBuf)
4544 ZeroMemory(pDriverInfo, cbBuf);
4545 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4548 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4549 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4550 cbBuf, pcbNeeded);
4551 if (ret)
4552 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4554 HeapFree(GetProcessHeap(), 0, buf);
4556 RtlFreeUnicodeString(&pEnvW);
4557 return ret;
4560 /*****************************************************************************
4561 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4563 * Return the PATH for the Printer-Drivers (UNICODE)
4565 * PARAMS
4566 * pName [I] Servername (NT only) or NULL (local Computer)
4567 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4568 * Level [I] Structure-Level (must be 1)
4569 * pDriverDirectory [O] PTR to Buffer that receives the Result
4570 * cbBuf [I] Size of Buffer at pDriverDirectory
4571 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4572 * required for pDriverDirectory
4574 * RETURNS
4575 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4576 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4577 * if cbBuf is too small
4579 * Native Values returned in pDriverDirectory on Success:
4580 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4581 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4582 *| win9x(Windows 4.0): "%winsysdir%"
4584 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4586 * FIXME
4587 *- Only NULL or "" is supported for pName
4590 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4591 DWORD Level, LPBYTE pDriverDirectory,
4592 DWORD cbBuf, LPDWORD pcbNeeded)
4594 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4595 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4597 if ((backend == NULL) && !load_backend()) return FALSE;
4599 if (Level != 1) {
4600 /* (Level != 1) is ignored in win9x */
4601 SetLastError(ERROR_INVALID_LEVEL);
4602 return FALSE;
4604 if (pcbNeeded == NULL) {
4605 /* (pcbNeeded == NULL) is ignored in win9x */
4606 SetLastError(RPC_X_NULL_REF_POINTER);
4607 return FALSE;
4610 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4611 pDriverDirectory, cbBuf, pcbNeeded);
4616 /*****************************************************************************
4617 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4619 * Return the PATH for the Printer-Drivers (ANSI)
4621 * See GetPrinterDriverDirectoryW.
4623 * NOTES
4624 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4627 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4628 DWORD Level, LPBYTE pDriverDirectory,
4629 DWORD cbBuf, LPDWORD pcbNeeded)
4631 UNICODE_STRING nameW, environmentW;
4632 BOOL ret;
4633 DWORD pcbNeededW;
4634 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4635 WCHAR *driverDirectoryW = NULL;
4637 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4638 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4640 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4642 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4643 else nameW.Buffer = NULL;
4644 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4645 else environmentW.Buffer = NULL;
4647 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4648 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4649 if (ret) {
4650 DWORD needed;
4651 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4652 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4653 if(pcbNeeded)
4654 *pcbNeeded = needed;
4655 ret = (needed <= cbBuf) ? TRUE : FALSE;
4656 } else
4657 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4659 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4661 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4662 RtlFreeUnicodeString(&environmentW);
4663 RtlFreeUnicodeString(&nameW);
4665 return ret;
4668 /*****************************************************************************
4669 * AddPrinterDriverA [WINSPOOL.@]
4671 * See AddPrinterDriverW.
4674 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4676 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4677 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4680 /******************************************************************************
4681 * AddPrinterDriverW (WINSPOOL.@)
4683 * Install a Printer Driver
4685 * PARAMS
4686 * pName [I] Servername or NULL (local Computer)
4687 * level [I] Level for the supplied DRIVER_INFO_*W struct
4688 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4690 * RESULTS
4691 * Success: TRUE
4692 * Failure: FALSE
4695 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4697 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4698 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4701 /*****************************************************************************
4702 * AddPrintProcessorA [WINSPOOL.@]
4704 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4705 LPSTR pPrintProcessorName)
4707 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4708 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4709 return FALSE;
4712 /*****************************************************************************
4713 * AddPrintProcessorW [WINSPOOL.@]
4715 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4716 LPWSTR pPrintProcessorName)
4718 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4719 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4720 return TRUE;
4723 /*****************************************************************************
4724 * AddPrintProvidorA [WINSPOOL.@]
4726 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4728 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4729 return FALSE;
4732 /*****************************************************************************
4733 * AddPrintProvidorW [WINSPOOL.@]
4735 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4737 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4738 return FALSE;
4741 /*****************************************************************************
4742 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4744 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4745 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4747 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4748 pDevModeOutput, pDevModeInput);
4749 return 0;
4752 /*****************************************************************************
4753 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4755 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4756 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4758 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4759 pDevModeOutput, pDevModeInput);
4760 return 0;
4763 /*****************************************************************************
4764 * PrinterProperties [WINSPOOL.@]
4766 * Displays a dialog to set the properties of the printer.
4768 * RETURNS
4769 * nonzero on success or zero on failure
4771 * BUGS
4772 * implemented as stub only
4774 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4775 HANDLE hPrinter /* [in] handle to printer object */
4777 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4778 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4779 return FALSE;
4782 /*****************************************************************************
4783 * EnumJobsA [WINSPOOL.@]
4786 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4787 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4788 LPDWORD pcReturned)
4790 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4791 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4793 if(pcbNeeded) *pcbNeeded = 0;
4794 if(pcReturned) *pcReturned = 0;
4795 return FALSE;
4799 /*****************************************************************************
4800 * EnumJobsW [WINSPOOL.@]
4803 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4804 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4805 LPDWORD pcReturned)
4807 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4808 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4810 if(pcbNeeded) *pcbNeeded = 0;
4811 if(pcReturned) *pcReturned = 0;
4812 return FALSE;
4815 /*****************************************************************************
4816 * WINSPOOL_EnumPrinterDrivers [internal]
4818 * Delivers information about all printer drivers installed on the
4819 * localhost or a given server
4821 * RETURNS
4822 * nonzero on success or zero on failure. If the buffer for the returned
4823 * information is too small the function will return an error
4825 * BUGS
4826 * - only implemented for localhost, foreign hosts will return an error
4828 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4829 DWORD Level, LPBYTE pDriverInfo,
4830 DWORD driver_index,
4831 DWORD cbBuf, LPDWORD pcbNeeded,
4832 LPDWORD pcFound, DWORD data_offset)
4834 { HKEY hkeyDrivers;
4835 DWORD i, size = 0;
4836 const printenv_t * env;
4838 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4839 debugstr_w(pName), debugstr_w(pEnvironment),
4840 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4842 env = validate_envW(pEnvironment);
4843 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4845 *pcFound = 0;
4847 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4848 if(!hkeyDrivers) {
4849 ERR("Can't open Drivers key\n");
4850 return FALSE;
4853 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4854 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4855 RegCloseKey(hkeyDrivers);
4856 ERR("Can't query Drivers key\n");
4857 return FALSE;
4859 TRACE("Found %d Drivers\n", *pcFound);
4861 /* get size of single struct
4862 * unicode and ascii structure have the same size
4864 size = di_sizeof[Level];
4866 if (data_offset == 0)
4867 data_offset = size * (*pcFound);
4868 *pcbNeeded = data_offset;
4870 for( i = 0; i < *pcFound; i++) {
4871 WCHAR DriverNameW[255];
4872 PBYTE table_ptr = NULL;
4873 PBYTE data_ptr = NULL;
4874 DWORD needed = 0;
4876 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4877 != ERROR_SUCCESS) {
4878 ERR("Can't enum key number %d\n", i);
4879 RegCloseKey(hkeyDrivers);
4880 return FALSE;
4883 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4884 table_ptr = pDriverInfo + (driver_index + i) * size;
4885 if (pDriverInfo && *pcbNeeded <= cbBuf)
4886 data_ptr = pDriverInfo + *pcbNeeded;
4888 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4889 env, Level, table_ptr, data_ptr,
4890 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4891 &needed)) {
4892 RegCloseKey(hkeyDrivers);
4893 return FALSE;
4896 *pcbNeeded += needed;
4899 RegCloseKey(hkeyDrivers);
4901 if(cbBuf < *pcbNeeded){
4902 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4903 return FALSE;
4906 return TRUE;
4909 /*****************************************************************************
4910 * EnumPrinterDriversW [WINSPOOL.@]
4912 * see function EnumPrinterDrivers for RETURNS, BUGS
4914 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4915 LPBYTE pDriverInfo, DWORD cbBuf,
4916 LPDWORD pcbNeeded, LPDWORD pcReturned)
4918 static const WCHAR allW[] = {'a','l','l',0};
4919 BOOL ret;
4920 DWORD found;
4922 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4924 SetLastError(RPC_X_NULL_REF_POINTER);
4925 return FALSE;
4928 /* check for local drivers */
4929 if((pName) && (pName[0])) {
4930 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4931 SetLastError(ERROR_ACCESS_DENIED);
4932 return FALSE;
4935 /* check input parameter */
4936 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4937 SetLastError(ERROR_INVALID_LEVEL);
4938 return FALSE;
4941 if(pDriverInfo && cbBuf > 0)
4942 memset( pDriverInfo, 0, cbBuf);
4944 /* Exception: pull all printers */
4945 if (pEnvironment && !strcmpW(pEnvironment, allW))
4947 DWORD i, needed, bufsize = cbBuf;
4948 DWORD total_needed = 0;
4949 DWORD total_found = 0;
4950 DWORD data_offset;
4952 /* Precompute the overall total; we need this to know
4953 where pointers end and data begins (i.e. data_offset) */
4954 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4956 needed = found = 0;
4957 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4958 NULL, 0, 0, &needed, &found, 0);
4959 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4960 total_needed += needed;
4961 total_found += found;
4964 data_offset = di_sizeof[Level] * total_found;
4966 *pcReturned = 0;
4967 *pcbNeeded = 0;
4968 total_found = 0;
4969 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4971 needed = found = 0;
4972 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4973 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4974 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4975 else if (ret)
4976 *pcReturned += found;
4977 *pcbNeeded = needed;
4978 data_offset = needed;
4979 total_found += found;
4981 return ret;
4984 /* Normal behavior */
4985 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4986 0, cbBuf, pcbNeeded, &found, 0);
4987 if (ret)
4988 *pcReturned = found;
4990 return ret;
4993 /*****************************************************************************
4994 * EnumPrinterDriversA [WINSPOOL.@]
4996 * see function EnumPrinterDrivers for RETURNS, BUGS
4998 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4999 LPBYTE pDriverInfo, DWORD cbBuf,
5000 LPDWORD pcbNeeded, LPDWORD pcReturned)
5002 BOOL ret;
5003 UNICODE_STRING pNameW, pEnvironmentW;
5004 PWSTR pwstrNameW, pwstrEnvironmentW;
5005 LPBYTE buf = NULL;
5007 if (cbBuf)
5008 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5010 pwstrNameW = asciitounicode(&pNameW, pName);
5011 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5013 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5014 buf, cbBuf, pcbNeeded, pcReturned);
5015 if (ret)
5016 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5018 HeapFree(GetProcessHeap(), 0, buf);
5020 RtlFreeUnicodeString(&pNameW);
5021 RtlFreeUnicodeString(&pEnvironmentW);
5023 return ret;
5026 /******************************************************************************
5027 * EnumPortsA (WINSPOOL.@)
5029 * See EnumPortsW.
5032 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5033 LPDWORD pcbNeeded, LPDWORD pcReturned)
5035 BOOL res;
5036 LPBYTE bufferW = NULL;
5037 LPWSTR nameW = NULL;
5038 DWORD needed = 0;
5039 DWORD numentries = 0;
5040 INT len;
5042 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5043 cbBuf, pcbNeeded, pcReturned);
5045 /* convert servername to unicode */
5046 if (pName) {
5047 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5048 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5049 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5051 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5052 needed = cbBuf * sizeof(WCHAR);
5053 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5054 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5056 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5057 if (pcbNeeded) needed = *pcbNeeded;
5058 /* HeapReAlloc return NULL, when bufferW was NULL */
5059 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5060 HeapAlloc(GetProcessHeap(), 0, needed);
5062 /* Try again with the large Buffer */
5063 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5065 needed = pcbNeeded ? *pcbNeeded : 0;
5066 numentries = pcReturned ? *pcReturned : 0;
5069 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5070 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5072 if (res) {
5073 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5074 DWORD entrysize = 0;
5075 DWORD index;
5076 LPSTR ptr;
5077 LPPORT_INFO_2W pi2w;
5078 LPPORT_INFO_2A pi2a;
5080 needed = 0;
5081 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5083 /* First pass: calculate the size for all Entries */
5084 pi2w = (LPPORT_INFO_2W) bufferW;
5085 pi2a = (LPPORT_INFO_2A) pPorts;
5086 index = 0;
5087 while (index < numentries) {
5088 index++;
5089 needed += entrysize; /* PORT_INFO_?A */
5090 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5092 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5093 NULL, 0, NULL, NULL);
5094 if (Level > 1) {
5095 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5096 NULL, 0, NULL, NULL);
5097 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5098 NULL, 0, NULL, NULL);
5100 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5101 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5102 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5105 /* check for errors and quit on failure */
5106 if (cbBuf < needed) {
5107 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5108 res = FALSE;
5109 goto cleanup;
5111 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5112 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5113 cbBuf -= len ; /* free Bytes in the user-Buffer */
5114 pi2w = (LPPORT_INFO_2W) bufferW;
5115 pi2a = (LPPORT_INFO_2A) pPorts;
5116 index = 0;
5117 /* Second Pass: Fill the User Buffer (if we have one) */
5118 while ((index < numentries) && pPorts) {
5119 index++;
5120 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5121 pi2a->pPortName = ptr;
5122 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5123 ptr, cbBuf , NULL, NULL);
5124 ptr += len;
5125 cbBuf -= len;
5126 if (Level > 1) {
5127 pi2a->pMonitorName = ptr;
5128 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5129 ptr, cbBuf, NULL, NULL);
5130 ptr += len;
5131 cbBuf -= len;
5133 pi2a->pDescription = ptr;
5134 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5135 ptr, cbBuf, NULL, NULL);
5136 ptr += len;
5137 cbBuf -= len;
5139 pi2a->fPortType = pi2w->fPortType;
5140 pi2a->Reserved = 0; /* documented: "must be zero" */
5143 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5144 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5145 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5149 cleanup:
5150 if (pcbNeeded) *pcbNeeded = needed;
5151 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5153 HeapFree(GetProcessHeap(), 0, nameW);
5154 HeapFree(GetProcessHeap(), 0, bufferW);
5156 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5157 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5159 return (res);
5163 /******************************************************************************
5164 * EnumPortsW (WINSPOOL.@)
5166 * Enumerate available Ports
5168 * PARAMS
5169 * pName [I] Servername or NULL (local Computer)
5170 * Level [I] Structure-Level (1 or 2)
5171 * pPorts [O] PTR to Buffer that receives the Result
5172 * cbBuf [I] Size of Buffer at pPorts
5173 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5174 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5176 * RETURNS
5177 * Success: TRUE
5178 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5181 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5184 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5185 cbBuf, pcbNeeded, pcReturned);
5187 if ((backend == NULL) && !load_backend()) return FALSE;
5189 /* Level is not checked in win9x */
5190 if (!Level || (Level > 2)) {
5191 WARN("level (%d) is ignored in win9x\n", Level);
5192 SetLastError(ERROR_INVALID_LEVEL);
5193 return FALSE;
5195 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5196 SetLastError(RPC_X_NULL_REF_POINTER);
5197 return FALSE;
5200 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5203 /******************************************************************************
5204 * GetDefaultPrinterW (WINSPOOL.@)
5206 * FIXME
5207 * This function must read the value from data 'device' of key
5208 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5210 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5212 BOOL retval = TRUE;
5213 DWORD insize, len;
5214 WCHAR *buffer, *ptr;
5216 if (!namesize)
5218 SetLastError(ERROR_INVALID_PARAMETER);
5219 return FALSE;
5222 /* make the buffer big enough for the stuff from the profile/registry,
5223 * the content must fit into the local buffer to compute the correct
5224 * size even if the extern buffer is too small or not given.
5225 * (20 for ,driver,port) */
5226 insize = *namesize;
5227 len = max(100, (insize + 20));
5228 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5230 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5232 SetLastError (ERROR_FILE_NOT_FOUND);
5233 retval = FALSE;
5234 goto end;
5236 TRACE("%s\n", debugstr_w(buffer));
5238 if ((ptr = strchrW(buffer, ',')) == NULL)
5240 SetLastError(ERROR_INVALID_NAME);
5241 retval = FALSE;
5242 goto end;
5245 *ptr = 0;
5246 *namesize = strlenW(buffer) + 1;
5247 if(!name || (*namesize > insize))
5249 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5250 retval = FALSE;
5251 goto end;
5253 strcpyW(name, buffer);
5255 end:
5256 HeapFree( GetProcessHeap(), 0, buffer);
5257 return retval;
5261 /******************************************************************************
5262 * GetDefaultPrinterA (WINSPOOL.@)
5264 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5266 BOOL retval = TRUE;
5267 DWORD insize = 0;
5268 WCHAR *bufferW = NULL;
5270 if (!namesize)
5272 SetLastError(ERROR_INVALID_PARAMETER);
5273 return FALSE;
5276 if(name && *namesize) {
5277 insize = *namesize;
5278 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5281 if(!GetDefaultPrinterW( bufferW, namesize)) {
5282 retval = FALSE;
5283 goto end;
5286 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5287 NULL, NULL);
5288 if (!*namesize)
5290 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5291 retval = FALSE;
5293 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5295 end:
5296 HeapFree( GetProcessHeap(), 0, bufferW);
5297 return retval;
5301 /******************************************************************************
5302 * SetDefaultPrinterW (WINSPOOL.204)
5304 * Set the Name of the Default Printer
5306 * PARAMS
5307 * pszPrinter [I] Name of the Printer or NULL
5309 * RETURNS
5310 * Success: True
5311 * Failure: FALSE
5313 * NOTES
5314 * When the Parameter is NULL or points to an Empty String and
5315 * a Default Printer was already present, then this Function changes nothing.
5316 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5317 * the First enumerated local Printer is used.
5320 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5322 WCHAR default_printer[MAX_PATH];
5323 LPWSTR buffer = NULL;
5324 HKEY hreg;
5325 DWORD size;
5326 DWORD namelen;
5327 LONG lres;
5329 TRACE("(%s)\n", debugstr_w(pszPrinter));
5330 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5332 default_printer[0] = '\0';
5333 size = sizeof(default_printer)/sizeof(WCHAR);
5335 /* if we have a default Printer, do nothing. */
5336 if (GetDefaultPrinterW(default_printer, &size))
5337 return TRUE;
5339 pszPrinter = NULL;
5340 /* we have no default Printer: search local Printers and use the first */
5341 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5343 default_printer[0] = '\0';
5344 size = sizeof(default_printer)/sizeof(WCHAR);
5345 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5347 pszPrinter = default_printer;
5348 TRACE("using %s\n", debugstr_w(pszPrinter));
5350 RegCloseKey(hreg);
5353 if (pszPrinter == NULL) {
5354 TRACE("no local printer found\n");
5355 SetLastError(ERROR_FILE_NOT_FOUND);
5356 return FALSE;
5360 /* "pszPrinter" is never empty or NULL here. */
5361 namelen = lstrlenW(pszPrinter);
5362 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5363 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5364 if (!buffer ||
5365 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5366 HeapFree(GetProcessHeap(), 0, buffer);
5367 SetLastError(ERROR_FILE_NOT_FOUND);
5368 return FALSE;
5371 /* read the devices entry for the printer (driver,port) to build the string for the
5372 default device entry (printer,driver,port) */
5373 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5374 buffer[namelen] = ',';
5375 namelen++; /* move index to the start of the driver */
5377 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5378 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5379 if (!lres) {
5380 TRACE("set device to %s\n", debugstr_w(buffer));
5382 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5383 TRACE("failed to set the device entry: %d\n", GetLastError());
5384 lres = ERROR_INVALID_PRINTER_NAME;
5387 /* remove the next section, when INIFileMapping is implemented */
5389 HKEY hdev;
5390 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5391 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5392 RegCloseKey(hdev);
5396 else
5398 if (lres != ERROR_FILE_NOT_FOUND)
5399 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5401 SetLastError(ERROR_INVALID_PRINTER_NAME);
5404 RegCloseKey(hreg);
5405 HeapFree(GetProcessHeap(), 0, buffer);
5406 return (lres == ERROR_SUCCESS);
5409 /******************************************************************************
5410 * SetDefaultPrinterA (WINSPOOL.202)
5412 * See SetDefaultPrinterW.
5415 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5417 LPWSTR bufferW = NULL;
5418 BOOL res;
5420 TRACE("(%s)\n", debugstr_a(pszPrinter));
5421 if(pszPrinter) {
5422 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5423 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5424 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5426 res = SetDefaultPrinterW(bufferW);
5427 HeapFree(GetProcessHeap(), 0, bufferW);
5428 return res;
5431 /******************************************************************************
5432 * SetPrinterDataExA (WINSPOOL.@)
5434 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5435 LPCSTR pValueName, DWORD Type,
5436 LPBYTE pData, DWORD cbData)
5438 HKEY hkeyPrinter, hkeySubkey;
5439 DWORD ret;
5441 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5442 debugstr_a(pValueName), Type, pData, cbData);
5444 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5445 != ERROR_SUCCESS)
5446 return ret;
5448 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5449 != ERROR_SUCCESS) {
5450 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5451 RegCloseKey(hkeyPrinter);
5452 return ret;
5454 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5455 RegCloseKey(hkeySubkey);
5456 RegCloseKey(hkeyPrinter);
5457 return ret;
5460 /******************************************************************************
5461 * SetPrinterDataExW (WINSPOOL.@)
5463 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5464 LPCWSTR pValueName, DWORD Type,
5465 LPBYTE pData, DWORD cbData)
5467 HKEY hkeyPrinter, hkeySubkey;
5468 DWORD ret;
5470 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5471 debugstr_w(pValueName), Type, pData, cbData);
5473 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5474 != ERROR_SUCCESS)
5475 return ret;
5477 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5478 != ERROR_SUCCESS) {
5479 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5480 RegCloseKey(hkeyPrinter);
5481 return ret;
5483 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5484 RegCloseKey(hkeySubkey);
5485 RegCloseKey(hkeyPrinter);
5486 return ret;
5489 /******************************************************************************
5490 * SetPrinterDataA (WINSPOOL.@)
5492 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5493 LPBYTE pData, DWORD cbData)
5495 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5496 pData, cbData);
5499 /******************************************************************************
5500 * SetPrinterDataW (WINSPOOL.@)
5502 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5503 LPBYTE pData, DWORD cbData)
5505 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5506 pData, cbData);
5509 /******************************************************************************
5510 * GetPrinterDataExA (WINSPOOL.@)
5512 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5513 LPCSTR pValueName, LPDWORD pType,
5514 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5516 opened_printer_t *printer;
5517 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5518 DWORD ret;
5520 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5521 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5523 printer = get_opened_printer(hPrinter);
5524 if(!printer) return ERROR_INVALID_HANDLE;
5526 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5527 if (ret) return ret;
5529 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5531 if (printer->name) {
5533 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5534 if (ret) {
5535 RegCloseKey(hkeyPrinters);
5536 return ret;
5538 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5539 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5540 RegCloseKey(hkeyPrinter);
5541 RegCloseKey(hkeyPrinters);
5542 return ret;
5545 *pcbNeeded = nSize;
5546 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5547 0, pType, pData, pcbNeeded);
5549 if (!ret && !pData) ret = ERROR_MORE_DATA;
5551 RegCloseKey(hkeySubkey);
5552 RegCloseKey(hkeyPrinter);
5553 RegCloseKey(hkeyPrinters);
5555 TRACE("--> %d\n", ret);
5556 return ret;
5559 /******************************************************************************
5560 * GetPrinterDataExW (WINSPOOL.@)
5562 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5563 LPCWSTR pValueName, LPDWORD pType,
5564 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5566 opened_printer_t *printer;
5567 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5568 DWORD ret;
5570 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5571 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5573 printer = get_opened_printer(hPrinter);
5574 if(!printer) return ERROR_INVALID_HANDLE;
5576 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5577 if (ret) return ret;
5579 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5581 if (printer->name) {
5583 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5584 if (ret) {
5585 RegCloseKey(hkeyPrinters);
5586 return ret;
5588 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5589 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5590 RegCloseKey(hkeyPrinter);
5591 RegCloseKey(hkeyPrinters);
5592 return ret;
5595 *pcbNeeded = nSize;
5596 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5597 0, pType, pData, pcbNeeded);
5599 if (!ret && !pData) ret = ERROR_MORE_DATA;
5601 RegCloseKey(hkeySubkey);
5602 RegCloseKey(hkeyPrinter);
5603 RegCloseKey(hkeyPrinters);
5605 TRACE("--> %d\n", ret);
5606 return ret;
5609 /******************************************************************************
5610 * GetPrinterDataA (WINSPOOL.@)
5612 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5613 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5615 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5616 pData, nSize, pcbNeeded);
5619 /******************************************************************************
5620 * GetPrinterDataW (WINSPOOL.@)
5622 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5623 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5625 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5626 pData, nSize, pcbNeeded);
5629 /*******************************************************************************
5630 * EnumPrinterDataExW [WINSPOOL.@]
5632 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5633 LPBYTE pEnumValues, DWORD cbEnumValues,
5634 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5636 HKEY hkPrinter, hkSubKey;
5637 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5638 cbValueNameLen, cbMaxValueLen, cbValueLen,
5639 cbBufSize, dwType;
5640 LPWSTR lpValueName;
5641 HANDLE hHeap;
5642 PBYTE lpValue;
5643 PPRINTER_ENUM_VALUESW ppev;
5645 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5647 if (pKeyName == NULL || *pKeyName == 0)
5648 return ERROR_INVALID_PARAMETER;
5650 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5651 if (ret != ERROR_SUCCESS)
5653 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5654 hPrinter, ret);
5655 return ret;
5658 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5659 if (ret != ERROR_SUCCESS)
5661 r = RegCloseKey (hkPrinter);
5662 if (r != ERROR_SUCCESS)
5663 WARN ("RegCloseKey returned %i\n", r);
5664 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5665 debugstr_w (pKeyName), ret);
5666 return ret;
5669 ret = RegCloseKey (hkPrinter);
5670 if (ret != ERROR_SUCCESS)
5672 ERR ("RegCloseKey returned %i\n", ret);
5673 r = RegCloseKey (hkSubKey);
5674 if (r != ERROR_SUCCESS)
5675 WARN ("RegCloseKey returned %i\n", r);
5676 return ret;
5679 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5680 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5681 if (ret != ERROR_SUCCESS)
5683 r = RegCloseKey (hkSubKey);
5684 if (r != ERROR_SUCCESS)
5685 WARN ("RegCloseKey returned %i\n", r);
5686 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5687 return ret;
5690 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5691 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5693 if (cValues == 0) /* empty key */
5695 r = RegCloseKey (hkSubKey);
5696 if (r != ERROR_SUCCESS)
5697 WARN ("RegCloseKey returned %i\n", r);
5698 *pcbEnumValues = *pnEnumValues = 0;
5699 return ERROR_SUCCESS;
5702 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5704 hHeap = GetProcessHeap ();
5705 if (hHeap == NULL)
5707 ERR ("GetProcessHeap failed\n");
5708 r = RegCloseKey (hkSubKey);
5709 if (r != ERROR_SUCCESS)
5710 WARN ("RegCloseKey returned %i\n", r);
5711 return ERROR_OUTOFMEMORY;
5714 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5715 if (lpValueName == NULL)
5717 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5718 r = RegCloseKey (hkSubKey);
5719 if (r != ERROR_SUCCESS)
5720 WARN ("RegCloseKey returned %i\n", r);
5721 return ERROR_OUTOFMEMORY;
5724 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5725 if (lpValue == NULL)
5727 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5728 if (HeapFree (hHeap, 0, lpValueName) == 0)
5729 WARN ("HeapFree failed with code %i\n", GetLastError ());
5730 r = RegCloseKey (hkSubKey);
5731 if (r != ERROR_SUCCESS)
5732 WARN ("RegCloseKey returned %i\n", r);
5733 return ERROR_OUTOFMEMORY;
5736 TRACE ("pass 1: calculating buffer required for all names and values\n");
5738 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5740 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5742 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5744 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5745 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5746 NULL, NULL, lpValue, &cbValueLen);
5747 if (ret != ERROR_SUCCESS)
5749 if (HeapFree (hHeap, 0, lpValue) == 0)
5750 WARN ("HeapFree failed with code %i\n", GetLastError ());
5751 if (HeapFree (hHeap, 0, lpValueName) == 0)
5752 WARN ("HeapFree failed with code %i\n", GetLastError ());
5753 r = RegCloseKey (hkSubKey);
5754 if (r != ERROR_SUCCESS)
5755 WARN ("RegCloseKey returned %i\n", r);
5756 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5757 return ret;
5760 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5761 debugstr_w (lpValueName), dwIndex,
5762 cbValueNameLen + 1, cbValueLen);
5764 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5765 cbBufSize += cbValueLen;
5768 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5770 *pcbEnumValues = cbBufSize;
5771 *pnEnumValues = cValues;
5773 if (cbEnumValues < cbBufSize) /* buffer too small */
5775 if (HeapFree (hHeap, 0, lpValue) == 0)
5776 WARN ("HeapFree failed with code %i\n", GetLastError ());
5777 if (HeapFree (hHeap, 0, lpValueName) == 0)
5778 WARN ("HeapFree failed with code %i\n", GetLastError ());
5779 r = RegCloseKey (hkSubKey);
5780 if (r != ERROR_SUCCESS)
5781 WARN ("RegCloseKey returned %i\n", r);
5782 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5783 return ERROR_MORE_DATA;
5786 TRACE ("pass 2: copying all names and values to buffer\n");
5788 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5789 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5791 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5793 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5794 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5795 NULL, &dwType, lpValue, &cbValueLen);
5796 if (ret != ERROR_SUCCESS)
5798 if (HeapFree (hHeap, 0, lpValue) == 0)
5799 WARN ("HeapFree failed with code %i\n", GetLastError ());
5800 if (HeapFree (hHeap, 0, lpValueName) == 0)
5801 WARN ("HeapFree failed with code %i\n", GetLastError ());
5802 r = RegCloseKey (hkSubKey);
5803 if (r != ERROR_SUCCESS)
5804 WARN ("RegCloseKey returned %i\n", r);
5805 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5806 return ret;
5809 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5810 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5811 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5812 pEnumValues += cbValueNameLen;
5814 /* return # of *bytes* (including trailing \0), not # of chars */
5815 ppev[dwIndex].cbValueName = cbValueNameLen;
5817 ppev[dwIndex].dwType = dwType;
5819 memcpy (pEnumValues, lpValue, cbValueLen);
5820 ppev[dwIndex].pData = pEnumValues;
5821 pEnumValues += cbValueLen;
5823 ppev[dwIndex].cbData = cbValueLen;
5825 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5826 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5829 if (HeapFree (hHeap, 0, lpValue) == 0)
5831 ret = GetLastError ();
5832 ERR ("HeapFree failed with code %i\n", ret);
5833 if (HeapFree (hHeap, 0, lpValueName) == 0)
5834 WARN ("HeapFree failed with code %i\n", GetLastError ());
5835 r = RegCloseKey (hkSubKey);
5836 if (r != ERROR_SUCCESS)
5837 WARN ("RegCloseKey returned %i\n", r);
5838 return ret;
5841 if (HeapFree (hHeap, 0, lpValueName) == 0)
5843 ret = GetLastError ();
5844 ERR ("HeapFree failed with code %i\n", ret);
5845 r = RegCloseKey (hkSubKey);
5846 if (r != ERROR_SUCCESS)
5847 WARN ("RegCloseKey returned %i\n", r);
5848 return ret;
5851 ret = RegCloseKey (hkSubKey);
5852 if (ret != ERROR_SUCCESS)
5854 ERR ("RegCloseKey returned %i\n", ret);
5855 return ret;
5858 return ERROR_SUCCESS;
5861 /*******************************************************************************
5862 * EnumPrinterDataExA [WINSPOOL.@]
5864 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5865 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5866 * what Windows 2000 SP1 does.
5869 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5870 LPBYTE pEnumValues, DWORD cbEnumValues,
5871 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5873 INT len;
5874 LPWSTR pKeyNameW;
5875 DWORD ret, dwIndex, dwBufSize;
5876 HANDLE hHeap;
5877 LPSTR pBuffer;
5879 TRACE ("%p %s\n", hPrinter, pKeyName);
5881 if (pKeyName == NULL || *pKeyName == 0)
5882 return ERROR_INVALID_PARAMETER;
5884 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5885 if (len == 0)
5887 ret = GetLastError ();
5888 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5889 return ret;
5892 hHeap = GetProcessHeap ();
5893 if (hHeap == NULL)
5895 ERR ("GetProcessHeap failed\n");
5896 return ERROR_OUTOFMEMORY;
5899 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5900 if (pKeyNameW == NULL)
5902 ERR ("Failed to allocate %i bytes from process heap\n",
5903 (LONG)(len * sizeof (WCHAR)));
5904 return ERROR_OUTOFMEMORY;
5907 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5909 ret = GetLastError ();
5910 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5911 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5912 WARN ("HeapFree failed with code %i\n", GetLastError ());
5913 return ret;
5916 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5917 pcbEnumValues, pnEnumValues);
5918 if (ret != ERROR_SUCCESS)
5920 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5921 WARN ("HeapFree failed with code %i\n", GetLastError ());
5922 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5923 return ret;
5926 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5928 ret = GetLastError ();
5929 ERR ("HeapFree failed with code %i\n", ret);
5930 return ret;
5933 if (*pnEnumValues == 0) /* empty key */
5934 return ERROR_SUCCESS;
5936 dwBufSize = 0;
5937 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5939 PPRINTER_ENUM_VALUESW ppev =
5940 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5942 if (dwBufSize < ppev->cbValueName)
5943 dwBufSize = ppev->cbValueName;
5945 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5946 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5947 dwBufSize = ppev->cbData;
5950 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5952 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5953 if (pBuffer == NULL)
5955 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5956 return ERROR_OUTOFMEMORY;
5959 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5961 PPRINTER_ENUM_VALUESW ppev =
5962 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5964 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5965 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5966 NULL);
5967 if (len == 0)
5969 ret = GetLastError ();
5970 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5971 if (HeapFree (hHeap, 0, pBuffer) == 0)
5972 WARN ("HeapFree failed with code %i\n", GetLastError ());
5973 return ret;
5976 memcpy (ppev->pValueName, pBuffer, len);
5978 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5980 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5981 ppev->dwType != REG_MULTI_SZ)
5982 continue;
5984 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5985 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5986 if (len == 0)
5988 ret = GetLastError ();
5989 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5990 if (HeapFree (hHeap, 0, pBuffer) == 0)
5991 WARN ("HeapFree failed with code %i\n", GetLastError ());
5992 return ret;
5995 memcpy (ppev->pData, pBuffer, len);
5997 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5998 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6001 if (HeapFree (hHeap, 0, pBuffer) == 0)
6003 ret = GetLastError ();
6004 ERR ("HeapFree failed with code %i\n", ret);
6005 return ret;
6008 return ERROR_SUCCESS;
6011 /******************************************************************************
6012 * AbortPrinter (WINSPOOL.@)
6014 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6016 FIXME("(%p), stub!\n", hPrinter);
6017 return TRUE;
6020 /******************************************************************************
6021 * AddPortA (WINSPOOL.@)
6023 * See AddPortW.
6026 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6028 LPWSTR nameW = NULL;
6029 LPWSTR monitorW = NULL;
6030 DWORD len;
6031 BOOL res;
6033 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6035 if (pName) {
6036 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6037 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6038 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6041 if (pMonitorName) {
6042 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6043 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6044 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6046 res = AddPortW(nameW, hWnd, monitorW);
6047 HeapFree(GetProcessHeap(), 0, nameW);
6048 HeapFree(GetProcessHeap(), 0, monitorW);
6049 return res;
6052 /******************************************************************************
6053 * AddPortW (WINSPOOL.@)
6055 * Add a Port for a specific Monitor
6057 * PARAMS
6058 * pName [I] Servername or NULL (local Computer)
6059 * hWnd [I] Handle to parent Window for the Dialog-Box
6060 * pMonitorName [I] Name of the Monitor that manage the Port
6062 * RETURNS
6063 * Success: TRUE
6064 * Failure: FALSE
6067 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6069 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6071 if ((backend == NULL) && !load_backend()) return FALSE;
6073 if (!pMonitorName) {
6074 SetLastError(RPC_X_NULL_REF_POINTER);
6075 return FALSE;
6078 return backend->fpAddPort(pName, hWnd, pMonitorName);
6081 /******************************************************************************
6082 * AddPortExA (WINSPOOL.@)
6084 * See AddPortExW.
6087 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6089 PORT_INFO_2W pi2W;
6090 PORT_INFO_2A * pi2A;
6091 LPWSTR nameW = NULL;
6092 LPWSTR monitorW = NULL;
6093 DWORD len;
6094 BOOL res;
6096 pi2A = (PORT_INFO_2A *) pBuffer;
6098 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6099 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6101 if ((level < 1) || (level > 2)) {
6102 SetLastError(ERROR_INVALID_LEVEL);
6103 return FALSE;
6106 if (!pi2A) {
6107 SetLastError(ERROR_INVALID_PARAMETER);
6108 return FALSE;
6111 if (pName) {
6112 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6113 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6114 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6117 if (pMonitorName) {
6118 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6119 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6120 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6123 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6125 if (pi2A->pPortName) {
6126 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6127 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6128 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6131 if (level > 1) {
6132 if (pi2A->pMonitorName) {
6133 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6134 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6135 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6138 if (pi2A->pDescription) {
6139 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6140 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6141 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6143 pi2W.fPortType = pi2A->fPortType;
6144 pi2W.Reserved = pi2A->Reserved;
6147 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6149 HeapFree(GetProcessHeap(), 0, nameW);
6150 HeapFree(GetProcessHeap(), 0, monitorW);
6151 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6152 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6153 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6154 return res;
6158 /******************************************************************************
6159 * AddPortExW (WINSPOOL.@)
6161 * Add a Port for a specific Monitor, without presenting a user interface
6163 * PARAMS
6164 * pName [I] Servername or NULL (local Computer)
6165 * level [I] Structure-Level (1 or 2) for pBuffer
6166 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6167 * pMonitorName [I] Name of the Monitor that manage the Port
6169 * RETURNS
6170 * Success: TRUE
6171 * Failure: FALSE
6174 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6176 PORT_INFO_2W * pi2;
6178 pi2 = (PORT_INFO_2W *) pBuffer;
6180 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6181 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6182 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6183 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6185 if ((backend == NULL) && !load_backend()) return FALSE;
6187 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6188 SetLastError(ERROR_INVALID_PARAMETER);
6189 return FALSE;
6192 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6195 /******************************************************************************
6196 * AddPrinterConnectionA (WINSPOOL.@)
6198 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6200 FIXME("%s\n", debugstr_a(pName));
6201 return FALSE;
6204 /******************************************************************************
6205 * AddPrinterConnectionW (WINSPOOL.@)
6207 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6209 FIXME("%s\n", debugstr_w(pName));
6210 return FALSE;
6213 /******************************************************************************
6214 * AddPrinterDriverExW (WINSPOOL.@)
6216 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6218 * PARAMS
6219 * pName [I] Servername or NULL (local Computer)
6220 * level [I] Level for the supplied DRIVER_INFO_*W struct
6221 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6222 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6224 * RESULTS
6225 * Success: TRUE
6226 * Failure: FALSE
6229 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6231 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6233 if ((backend == NULL) && !load_backend()) return FALSE;
6235 if (level < 2 || level == 5 || level == 7 || level > 8) {
6236 SetLastError(ERROR_INVALID_LEVEL);
6237 return FALSE;
6240 if (!pDriverInfo) {
6241 SetLastError(ERROR_INVALID_PARAMETER);
6242 return FALSE;
6245 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6248 /******************************************************************************
6249 * AddPrinterDriverExA (WINSPOOL.@)
6251 * See AddPrinterDriverExW.
6254 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6256 DRIVER_INFO_8A *diA;
6257 DRIVER_INFO_8W diW;
6258 LPWSTR nameW = NULL;
6259 DWORD lenA;
6260 DWORD len;
6261 DWORD res = FALSE;
6263 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6265 diA = (DRIVER_INFO_8A *) pDriverInfo;
6266 ZeroMemory(&diW, sizeof(diW));
6268 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6269 SetLastError(ERROR_INVALID_LEVEL);
6270 return FALSE;
6273 if (diA == NULL) {
6274 SetLastError(ERROR_INVALID_PARAMETER);
6275 return FALSE;
6278 /* convert servername to unicode */
6279 if (pName) {
6280 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6281 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6282 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6285 /* common fields */
6286 diW.cVersion = diA->cVersion;
6288 if (diA->pName) {
6289 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6290 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6291 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6294 if (diA->pEnvironment) {
6295 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6296 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6297 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6300 if (diA->pDriverPath) {
6301 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6302 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6303 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6306 if (diA->pDataFile) {
6307 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6308 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6309 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6312 if (diA->pConfigFile) {
6313 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6314 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6315 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6318 if ((Level > 2) && diA->pDependentFiles) {
6319 lenA = multi_sz_lenA(diA->pDependentFiles);
6320 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6321 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6322 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6325 if ((Level > 2) && diA->pMonitorName) {
6326 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6327 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6328 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6331 if ((Level > 3) && diA->pDefaultDataType) {
6332 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6333 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6334 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6337 if ((Level > 3) && diA->pszzPreviousNames) {
6338 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6339 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6340 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6341 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6344 if ((Level > 5) && diA->pszMfgName) {
6345 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6346 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6347 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6350 if ((Level > 5) && diA->pszOEMUrl) {
6351 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6352 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6353 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6356 if ((Level > 5) && diA->pszHardwareID) {
6357 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6358 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6359 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6362 if ((Level > 5) && diA->pszProvider) {
6363 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6364 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6365 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6368 if (Level > 7) {
6369 FIXME("level %u is incomplete\n", Level);
6372 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6373 TRACE("got %u with %u\n", res, GetLastError());
6374 HeapFree(GetProcessHeap(), 0, nameW);
6375 HeapFree(GetProcessHeap(), 0, diW.pName);
6376 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6377 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6378 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6379 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6380 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6381 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6382 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6383 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6384 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6385 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6386 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6387 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6389 TRACE("=> %u with %u\n", res, GetLastError());
6390 return res;
6393 /******************************************************************************
6394 * ConfigurePortA (WINSPOOL.@)
6396 * See ConfigurePortW.
6399 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6401 LPWSTR nameW = NULL;
6402 LPWSTR portW = NULL;
6403 INT len;
6404 DWORD res;
6406 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6408 /* convert servername to unicode */
6409 if (pName) {
6410 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6411 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6412 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6415 /* convert portname to unicode */
6416 if (pPortName) {
6417 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6418 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6419 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6422 res = ConfigurePortW(nameW, hWnd, portW);
6423 HeapFree(GetProcessHeap(), 0, nameW);
6424 HeapFree(GetProcessHeap(), 0, portW);
6425 return res;
6428 /******************************************************************************
6429 * ConfigurePortW (WINSPOOL.@)
6431 * Display the Configuration-Dialog for a specific Port
6433 * PARAMS
6434 * pName [I] Servername or NULL (local Computer)
6435 * hWnd [I] Handle to parent Window for the Dialog-Box
6436 * pPortName [I] Name of the Port, that should be configured
6438 * RETURNS
6439 * Success: TRUE
6440 * Failure: FALSE
6443 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6446 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6448 if ((backend == NULL) && !load_backend()) return FALSE;
6450 if (!pPortName) {
6451 SetLastError(RPC_X_NULL_REF_POINTER);
6452 return FALSE;
6455 return backend->fpConfigurePort(pName, hWnd, pPortName);
6458 /******************************************************************************
6459 * ConnectToPrinterDlg (WINSPOOL.@)
6461 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6463 FIXME("%p %x\n", hWnd, Flags);
6464 return NULL;
6467 /******************************************************************************
6468 * DeletePrinterConnectionA (WINSPOOL.@)
6470 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6472 FIXME("%s\n", debugstr_a(pName));
6473 return TRUE;
6476 /******************************************************************************
6477 * DeletePrinterConnectionW (WINSPOOL.@)
6479 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6481 FIXME("%s\n", debugstr_w(pName));
6482 return TRUE;
6485 /******************************************************************************
6486 * DeletePrinterDriverExW (WINSPOOL.@)
6488 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6489 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6491 HKEY hkey_drivers;
6492 BOOL ret = FALSE;
6494 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6495 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6497 if(pName && pName[0])
6499 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6500 SetLastError(ERROR_INVALID_PARAMETER);
6501 return FALSE;
6504 if(dwDeleteFlag)
6506 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6507 SetLastError(ERROR_INVALID_PARAMETER);
6508 return FALSE;
6511 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6513 if(!hkey_drivers)
6515 ERR("Can't open drivers key\n");
6516 return FALSE;
6519 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6520 ret = TRUE;
6522 RegCloseKey(hkey_drivers);
6524 return ret;
6527 /******************************************************************************
6528 * DeletePrinterDriverExA (WINSPOOL.@)
6530 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6531 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6533 UNICODE_STRING NameW, EnvW, DriverW;
6534 BOOL ret;
6536 asciitounicode(&NameW, pName);
6537 asciitounicode(&EnvW, pEnvironment);
6538 asciitounicode(&DriverW, pDriverName);
6540 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6542 RtlFreeUnicodeString(&DriverW);
6543 RtlFreeUnicodeString(&EnvW);
6544 RtlFreeUnicodeString(&NameW);
6546 return ret;
6549 /******************************************************************************
6550 * DeletePrinterDataExW (WINSPOOL.@)
6552 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6553 LPCWSTR pValueName)
6555 FIXME("%p %s %s\n", hPrinter,
6556 debugstr_w(pKeyName), debugstr_w(pValueName));
6557 return ERROR_INVALID_PARAMETER;
6560 /******************************************************************************
6561 * DeletePrinterDataExA (WINSPOOL.@)
6563 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6564 LPCSTR pValueName)
6566 FIXME("%p %s %s\n", hPrinter,
6567 debugstr_a(pKeyName), debugstr_a(pValueName));
6568 return ERROR_INVALID_PARAMETER;
6571 /******************************************************************************
6572 * DeletePrintProcessorA (WINSPOOL.@)
6574 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6576 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6577 debugstr_a(pPrintProcessorName));
6578 return TRUE;
6581 /******************************************************************************
6582 * DeletePrintProcessorW (WINSPOOL.@)
6584 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6586 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6587 debugstr_w(pPrintProcessorName));
6588 return TRUE;
6591 /******************************************************************************
6592 * DeletePrintProvidorA (WINSPOOL.@)
6594 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6596 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6597 debugstr_a(pPrintProviderName));
6598 return TRUE;
6601 /******************************************************************************
6602 * DeletePrintProvidorW (WINSPOOL.@)
6604 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6606 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6607 debugstr_w(pPrintProviderName));
6608 return TRUE;
6611 /******************************************************************************
6612 * EnumFormsA (WINSPOOL.@)
6614 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6615 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6617 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6618 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6619 return FALSE;
6622 /******************************************************************************
6623 * EnumFormsW (WINSPOOL.@)
6625 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6626 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6628 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6629 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6630 return FALSE;
6633 /*****************************************************************************
6634 * EnumMonitorsA [WINSPOOL.@]
6636 * See EnumMonitorsW.
6639 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6640 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6642 BOOL res;
6643 LPBYTE bufferW = NULL;
6644 LPWSTR nameW = NULL;
6645 DWORD needed = 0;
6646 DWORD numentries = 0;
6647 INT len;
6649 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6650 cbBuf, pcbNeeded, pcReturned);
6652 /* convert servername to unicode */
6653 if (pName) {
6654 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6655 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6656 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6658 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6659 needed = cbBuf * sizeof(WCHAR);
6660 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6661 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6663 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6664 if (pcbNeeded) needed = *pcbNeeded;
6665 /* HeapReAlloc return NULL, when bufferW was NULL */
6666 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6667 HeapAlloc(GetProcessHeap(), 0, needed);
6669 /* Try again with the large Buffer */
6670 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6672 numentries = pcReturned ? *pcReturned : 0;
6673 needed = 0;
6675 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6676 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6678 if (res) {
6679 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6680 DWORD entrysize = 0;
6681 DWORD index;
6682 LPSTR ptr;
6683 LPMONITOR_INFO_2W mi2w;
6684 LPMONITOR_INFO_2A mi2a;
6686 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6687 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6689 /* First pass: calculate the size for all Entries */
6690 mi2w = (LPMONITOR_INFO_2W) bufferW;
6691 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6692 index = 0;
6693 while (index < numentries) {
6694 index++;
6695 needed += entrysize; /* MONITOR_INFO_?A */
6696 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6698 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6699 NULL, 0, NULL, NULL);
6700 if (Level > 1) {
6701 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6702 NULL, 0, NULL, NULL);
6703 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6704 NULL, 0, NULL, NULL);
6706 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6707 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6708 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6711 /* check for errors and quit on failure */
6712 if (cbBuf < needed) {
6713 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6714 res = FALSE;
6715 goto emA_cleanup;
6717 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6718 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6719 cbBuf -= len ; /* free Bytes in the user-Buffer */
6720 mi2w = (LPMONITOR_INFO_2W) bufferW;
6721 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6722 index = 0;
6723 /* Second Pass: Fill the User Buffer (if we have one) */
6724 while ((index < numentries) && pMonitors) {
6725 index++;
6726 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6727 mi2a->pName = ptr;
6728 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6729 ptr, cbBuf , NULL, NULL);
6730 ptr += len;
6731 cbBuf -= len;
6732 if (Level > 1) {
6733 mi2a->pEnvironment = ptr;
6734 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6735 ptr, cbBuf, NULL, NULL);
6736 ptr += len;
6737 cbBuf -= len;
6739 mi2a->pDLLName = ptr;
6740 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6741 ptr, cbBuf, NULL, NULL);
6742 ptr += len;
6743 cbBuf -= len;
6745 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6746 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6747 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6750 emA_cleanup:
6751 if (pcbNeeded) *pcbNeeded = needed;
6752 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6754 HeapFree(GetProcessHeap(), 0, nameW);
6755 HeapFree(GetProcessHeap(), 0, bufferW);
6757 TRACE("returning %d with %d (%d byte for %d entries)\n",
6758 (res), GetLastError(), needed, numentries);
6760 return (res);
6764 /*****************************************************************************
6765 * EnumMonitorsW [WINSPOOL.@]
6767 * Enumerate available Port-Monitors
6769 * PARAMS
6770 * pName [I] Servername or NULL (local Computer)
6771 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6772 * pMonitors [O] PTR to Buffer that receives the Result
6773 * cbBuf [I] Size of Buffer at pMonitors
6774 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6775 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6777 * RETURNS
6778 * Success: TRUE
6779 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6782 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6783 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6786 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6787 cbBuf, pcbNeeded, pcReturned);
6789 if ((backend == NULL) && !load_backend()) return FALSE;
6791 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6792 SetLastError(RPC_X_NULL_REF_POINTER);
6793 return FALSE;
6796 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6799 /******************************************************************************
6800 * SpoolerInit (WINSPOOL.@)
6802 * Initialize the Spooler
6804 * RETURNS
6805 * Success: TRUE
6806 * Failure: FALSE
6808 * NOTES
6809 * The function fails on windows, when the spooler service is not running
6812 BOOL WINAPI SpoolerInit(void)
6815 if ((backend == NULL) && !load_backend()) return FALSE;
6816 return TRUE;
6819 /******************************************************************************
6820 * XcvDataW (WINSPOOL.@)
6822 * Execute commands in the Printmonitor DLL
6824 * PARAMS
6825 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6826 * pszDataName [i] Name of the command to execute
6827 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6828 * cbInputData [i] Size in Bytes of Buffer at pInputData
6829 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6830 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6831 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6832 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6834 * RETURNS
6835 * Success: TRUE
6836 * Failure: FALSE
6838 * NOTES
6839 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6840 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6842 * Minimal List of commands, that a Printmonitor DLL should support:
6844 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6845 *| "AddPort" : Add a Port
6846 *| "DeletePort": Delete a Port
6848 * Many Printmonitors support additional commands. Examples for localspl.dll:
6849 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6850 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6853 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6854 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6855 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6857 opened_printer_t *printer;
6859 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6860 pInputData, cbInputData, pOutputData,
6861 cbOutputData, pcbOutputNeeded, pdwStatus);
6863 if ((backend == NULL) && !load_backend()) return FALSE;
6865 printer = get_opened_printer(hXcv);
6866 if (!printer || (!printer->backend_printer)) {
6867 SetLastError(ERROR_INVALID_HANDLE);
6868 return FALSE;
6871 if (!pcbOutputNeeded) {
6872 SetLastError(ERROR_INVALID_PARAMETER);
6873 return FALSE;
6876 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6877 SetLastError(RPC_X_NULL_REF_POINTER);
6878 return FALSE;
6881 *pcbOutputNeeded = 0;
6883 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6884 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6888 /*****************************************************************************
6889 * EnumPrinterDataA [WINSPOOL.@]
6892 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6893 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6894 DWORD cbData, LPDWORD pcbData )
6896 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6897 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6898 return ERROR_NO_MORE_ITEMS;
6901 /*****************************************************************************
6902 * EnumPrinterDataW [WINSPOOL.@]
6905 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6906 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6907 DWORD cbData, LPDWORD pcbData )
6909 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6910 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6911 return ERROR_NO_MORE_ITEMS;
6914 /*****************************************************************************
6915 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6918 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6919 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6920 LPDWORD pcbNeeded, LPDWORD pcReturned)
6922 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6923 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6924 pcbNeeded, pcReturned);
6925 return FALSE;
6928 /*****************************************************************************
6929 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6932 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6933 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6934 LPDWORD pcbNeeded, LPDWORD pcReturned)
6936 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6937 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6938 pcbNeeded, pcReturned);
6939 return FALSE;
6942 /*****************************************************************************
6943 * EnumPrintProcessorsA [WINSPOOL.@]
6945 * See EnumPrintProcessorsW.
6948 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6949 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6951 BOOL res;
6952 LPBYTE bufferW = NULL;
6953 LPWSTR nameW = NULL;
6954 LPWSTR envW = NULL;
6955 DWORD needed = 0;
6956 DWORD numentries = 0;
6957 INT len;
6959 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6960 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6962 /* convert names to unicode */
6963 if (pName) {
6964 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6965 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6966 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6968 if (pEnvironment) {
6969 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6970 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6971 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6974 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6975 needed = cbBuf * sizeof(WCHAR);
6976 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6977 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6979 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6980 if (pcbNeeded) needed = *pcbNeeded;
6981 /* HeapReAlloc return NULL, when bufferW was NULL */
6982 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6983 HeapAlloc(GetProcessHeap(), 0, needed);
6985 /* Try again with the large Buffer */
6986 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6988 numentries = pcReturned ? *pcReturned : 0;
6989 needed = 0;
6991 if (res) {
6992 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6993 DWORD index;
6994 LPSTR ptr;
6995 PPRINTPROCESSOR_INFO_1W ppiw;
6996 PPRINTPROCESSOR_INFO_1A ppia;
6998 /* First pass: calculate the size for all Entries */
6999 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7000 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7001 index = 0;
7002 while (index < numentries) {
7003 index++;
7004 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7005 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7007 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7008 NULL, 0, NULL, NULL);
7010 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7011 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7014 /* check for errors and quit on failure */
7015 if (cbBuf < needed) {
7016 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7017 res = FALSE;
7018 goto epp_cleanup;
7021 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7022 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7023 cbBuf -= len ; /* free Bytes in the user-Buffer */
7024 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7025 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7026 index = 0;
7027 /* Second Pass: Fill the User Buffer (if we have one) */
7028 while ((index < numentries) && pPPInfo) {
7029 index++;
7030 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7031 ppia->pName = ptr;
7032 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7033 ptr, cbBuf , NULL, NULL);
7034 ptr += len;
7035 cbBuf -= len;
7037 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7038 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7042 epp_cleanup:
7043 if (pcbNeeded) *pcbNeeded = needed;
7044 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7046 HeapFree(GetProcessHeap(), 0, nameW);
7047 HeapFree(GetProcessHeap(), 0, envW);
7048 HeapFree(GetProcessHeap(), 0, bufferW);
7050 TRACE("returning %d with %d (%d byte for %d entries)\n",
7051 (res), GetLastError(), needed, numentries);
7053 return (res);
7056 /*****************************************************************************
7057 * EnumPrintProcessorsW [WINSPOOL.@]
7059 * Enumerate available Print Processors
7061 * PARAMS
7062 * pName [I] Servername or NULL (local Computer)
7063 * pEnvironment [I] Printing-Environment or NULL (Default)
7064 * Level [I] Structure-Level (Only 1 is allowed)
7065 * pPPInfo [O] PTR to Buffer that receives the Result
7066 * cbBuf [I] Size of Buffer at pPPInfo
7067 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7068 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7070 * RETURNS
7071 * Success: TRUE
7072 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7075 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7076 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7079 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7080 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7082 if ((backend == NULL) && !load_backend()) return FALSE;
7084 if (!pcbNeeded || !pcReturned) {
7085 SetLastError(RPC_X_NULL_REF_POINTER);
7086 return FALSE;
7089 if (!pPPInfo && (cbBuf > 0)) {
7090 SetLastError(ERROR_INVALID_USER_BUFFER);
7091 return FALSE;
7094 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7095 cbBuf, pcbNeeded, pcReturned);
7098 /*****************************************************************************
7099 * ExtDeviceMode [WINSPOOL.@]
7102 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7103 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7104 DWORD fMode)
7106 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7107 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7108 debugstr_a(pProfile), fMode);
7109 return -1;
7112 /*****************************************************************************
7113 * FindClosePrinterChangeNotification [WINSPOOL.@]
7116 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7118 FIXME("Stub: %p\n", hChange);
7119 return TRUE;
7122 /*****************************************************************************
7123 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7126 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7127 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7129 FIXME("Stub: %p %x %x %p\n",
7130 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7131 return INVALID_HANDLE_VALUE;
7134 /*****************************************************************************
7135 * FindNextPrinterChangeNotification [WINSPOOL.@]
7138 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7139 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7141 FIXME("Stub: %p %p %p %p\n",
7142 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7143 return FALSE;
7146 /*****************************************************************************
7147 * FreePrinterNotifyInfo [WINSPOOL.@]
7150 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7152 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7153 return TRUE;
7156 /*****************************************************************************
7157 * string_to_buf
7159 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7160 * ansi depending on the unicode parameter.
7162 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7164 if(!str)
7166 *size = 0;
7167 return TRUE;
7170 if(unicode)
7172 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7173 if(*size <= cb)
7175 memcpy(ptr, str, *size);
7176 return TRUE;
7178 return FALSE;
7180 else
7182 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7183 if(*size <= cb)
7185 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7186 return TRUE;
7188 return FALSE;
7192 /*****************************************************************************
7193 * get_job_info_1
7195 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7196 LPDWORD pcbNeeded, BOOL unicode)
7198 DWORD size, left = cbBuf;
7199 BOOL space = (cbBuf > 0);
7200 LPBYTE ptr = buf;
7202 *pcbNeeded = 0;
7204 if(space)
7206 ji1->JobId = job->job_id;
7209 string_to_buf(job->document_title, ptr, left, &size, unicode);
7210 if(space && size <= left)
7212 ji1->pDocument = (LPWSTR)ptr;
7213 ptr += size;
7214 left -= size;
7216 else
7217 space = FALSE;
7218 *pcbNeeded += size;
7220 if (job->printer_name)
7222 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7223 if(space && size <= left)
7225 ji1->pPrinterName = (LPWSTR)ptr;
7226 ptr += size;
7227 left -= size;
7229 else
7230 space = FALSE;
7231 *pcbNeeded += size;
7234 return space;
7237 /*****************************************************************************
7238 * get_job_info_2
7240 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7241 LPDWORD pcbNeeded, BOOL unicode)
7243 DWORD size, left = cbBuf;
7244 DWORD shift;
7245 BOOL space = (cbBuf > 0);
7246 LPBYTE ptr = buf;
7247 LPDEVMODEA dmA = NULL;
7248 LPDEVMODEW devmode;
7250 *pcbNeeded = 0;
7252 if(space)
7254 ji2->JobId = job->job_id;
7257 string_to_buf(job->document_title, ptr, left, &size, unicode);
7258 if(space && size <= left)
7260 ji2->pDocument = (LPWSTR)ptr;
7261 ptr += size;
7262 left -= size;
7264 else
7265 space = FALSE;
7266 *pcbNeeded += size;
7268 if (job->printer_name)
7270 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7271 if(space && size <= left)
7273 ji2->pPrinterName = (LPWSTR)ptr;
7274 ptr += size;
7275 left -= size;
7277 else
7278 space = FALSE;
7279 *pcbNeeded += size;
7282 if (job->devmode)
7284 if (!unicode)
7286 dmA = DEVMODEdupWtoA(job->devmode);
7287 devmode = (LPDEVMODEW) dmA;
7288 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7290 else
7292 devmode = job->devmode;
7293 size = devmode->dmSize + devmode->dmDriverExtra;
7296 if (!devmode)
7297 FIXME("Can't convert DEVMODE W to A\n");
7298 else
7300 /* align DEVMODE to a DWORD boundary */
7301 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7302 size += shift;
7304 if (size <= left)
7306 ptr += shift;
7307 memcpy(ptr, devmode, size-shift);
7308 ji2->pDevMode = (LPDEVMODEW)ptr;
7309 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7310 ptr += size;
7311 left -= size;
7313 else
7314 space = FALSE;
7315 *pcbNeeded +=size;
7319 return space;
7322 /*****************************************************************************
7323 * get_job_info
7325 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7326 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7328 BOOL ret = FALSE;
7329 DWORD needed = 0, size;
7330 job_t *job;
7331 LPBYTE ptr = pJob;
7333 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7335 EnterCriticalSection(&printer_handles_cs);
7336 job = get_job(hPrinter, JobId);
7337 if(!job)
7338 goto end;
7340 switch(Level)
7342 case 1:
7343 size = sizeof(JOB_INFO_1W);
7344 if(cbBuf >= size)
7346 cbBuf -= size;
7347 ptr += size;
7348 memset(pJob, 0, size);
7350 else
7351 cbBuf = 0;
7352 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7353 needed += size;
7354 break;
7356 case 2:
7357 size = sizeof(JOB_INFO_2W);
7358 if(cbBuf >= size)
7360 cbBuf -= size;
7361 ptr += size;
7362 memset(pJob, 0, size);
7364 else
7365 cbBuf = 0;
7366 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7367 needed += size;
7368 break;
7370 case 3:
7371 size = sizeof(JOB_INFO_3);
7372 if(cbBuf >= size)
7374 cbBuf -= size;
7375 memset(pJob, 0, size);
7376 ret = TRUE;
7378 else
7379 cbBuf = 0;
7380 needed = size;
7381 break;
7383 default:
7384 SetLastError(ERROR_INVALID_LEVEL);
7385 goto end;
7387 if(pcbNeeded)
7388 *pcbNeeded = needed;
7389 end:
7390 LeaveCriticalSection(&printer_handles_cs);
7391 return ret;
7394 /*****************************************************************************
7395 * GetJobA [WINSPOOL.@]
7398 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7399 DWORD cbBuf, LPDWORD pcbNeeded)
7401 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7404 /*****************************************************************************
7405 * GetJobW [WINSPOOL.@]
7408 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7409 DWORD cbBuf, LPDWORD pcbNeeded)
7411 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7414 /*****************************************************************************
7415 * schedule_pipe
7417 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7419 #ifdef HAVE_FORK
7420 char *unixname, *cmdA;
7421 DWORD len;
7422 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7423 BOOL ret = FALSE;
7424 char buf[1024];
7425 pid_t pid, wret;
7426 int status;
7428 if(!(unixname = wine_get_unix_file_name(filename)))
7429 return FALSE;
7431 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7432 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7433 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7435 TRACE("printing with: %s\n", cmdA);
7437 if((file_fd = open(unixname, O_RDONLY)) == -1)
7438 goto end;
7440 if (pipe(fds))
7442 ERR("pipe() failed!\n");
7443 goto end;
7446 if ((pid = fork()) == 0)
7448 close(0);
7449 dup2(fds[0], 0);
7450 close(fds[1]);
7452 /* reset signals that we previously set to SIG_IGN */
7453 signal(SIGPIPE, SIG_DFL);
7455 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7456 _exit(1);
7458 else if (pid == -1)
7460 ERR("fork() failed!\n");
7461 goto end;
7464 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7465 write(fds[1], buf, no_read);
7467 close(fds[1]);
7468 fds[1] = -1;
7470 /* reap child */
7471 do {
7472 wret = waitpid(pid, &status, 0);
7473 } while (wret < 0 && errno == EINTR);
7474 if (wret < 0)
7476 ERR("waitpid() failed!\n");
7477 goto end;
7479 if (!WIFEXITED(status) || WEXITSTATUS(status))
7481 ERR("child process failed! %d\n", status);
7482 goto end;
7485 ret = TRUE;
7487 end:
7488 if(file_fd != -1) close(file_fd);
7489 if(fds[0] != -1) close(fds[0]);
7490 if(fds[1] != -1) close(fds[1]);
7492 HeapFree(GetProcessHeap(), 0, cmdA);
7493 HeapFree(GetProcessHeap(), 0, unixname);
7494 return ret;
7495 #else
7496 return FALSE;
7497 #endif
7500 /*****************************************************************************
7501 * schedule_lpr
7503 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7505 WCHAR *cmd;
7506 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7507 BOOL r;
7509 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7510 sprintfW(cmd, fmtW, printer_name);
7512 r = schedule_pipe(cmd, filename);
7514 HeapFree(GetProcessHeap(), 0, cmd);
7515 return r;
7518 /*****************************************************************************
7519 * schedule_cups
7521 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7523 #ifdef SONAME_LIBCUPS
7524 if(pcupsPrintFile)
7526 char *unixname, *queue, *unix_doc_title;
7527 DWORD len;
7528 BOOL ret;
7530 if(!(unixname = wine_get_unix_file_name(filename)))
7531 return FALSE;
7533 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7534 queue = HeapAlloc(GetProcessHeap(), 0, len);
7535 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7537 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7538 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7539 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7541 TRACE("printing via cups\n");
7542 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7543 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7544 HeapFree(GetProcessHeap(), 0, queue);
7545 HeapFree(GetProcessHeap(), 0, unixname);
7546 return ret;
7548 else
7549 #endif
7551 return schedule_lpr(printer_name, filename);
7555 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7557 LPWSTR filename;
7559 switch(msg)
7561 case WM_INITDIALOG:
7562 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7563 return TRUE;
7565 case WM_COMMAND:
7566 if(HIWORD(wparam) == BN_CLICKED)
7568 if(LOWORD(wparam) == IDOK)
7570 HANDLE hf;
7571 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7572 LPWSTR *output;
7574 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7575 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7577 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7579 WCHAR caption[200], message[200];
7580 int mb_ret;
7582 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7583 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7584 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7585 if(mb_ret == IDCANCEL)
7587 HeapFree(GetProcessHeap(), 0, filename);
7588 return TRUE;
7591 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7592 if(hf == INVALID_HANDLE_VALUE)
7594 WCHAR caption[200], message[200];
7596 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7597 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7598 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7599 HeapFree(GetProcessHeap(), 0, filename);
7600 return TRUE;
7602 CloseHandle(hf);
7603 DeleteFileW(filename);
7604 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7605 *output = filename;
7606 EndDialog(hwnd, IDOK);
7607 return TRUE;
7609 if(LOWORD(wparam) == IDCANCEL)
7611 EndDialog(hwnd, IDCANCEL);
7612 return TRUE;
7615 return FALSE;
7617 return FALSE;
7620 /*****************************************************************************
7621 * get_filename
7623 static BOOL get_filename(LPWSTR *filename)
7625 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7626 file_dlg_proc, (LPARAM)filename) == IDOK;
7629 /*****************************************************************************
7630 * schedule_file
7632 static BOOL schedule_file(LPCWSTR filename)
7634 LPWSTR output = NULL;
7636 if(get_filename(&output))
7638 BOOL r;
7639 TRACE("copy to %s\n", debugstr_w(output));
7640 r = CopyFileW(filename, output, FALSE);
7641 HeapFree(GetProcessHeap(), 0, output);
7642 return r;
7644 return FALSE;
7647 /*****************************************************************************
7648 * schedule_unixfile
7650 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7652 int in_fd, out_fd, no_read;
7653 char buf[1024];
7654 BOOL ret = FALSE;
7655 char *unixname, *outputA;
7656 DWORD len;
7658 if(!(unixname = wine_get_unix_file_name(filename)))
7659 return FALSE;
7661 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7662 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7663 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7665 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7666 in_fd = open(unixname, O_RDONLY);
7667 if(out_fd == -1 || in_fd == -1)
7668 goto end;
7670 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7671 write(out_fd, buf, no_read);
7673 ret = TRUE;
7674 end:
7675 if(in_fd != -1) close(in_fd);
7676 if(out_fd != -1) close(out_fd);
7677 HeapFree(GetProcessHeap(), 0, outputA);
7678 HeapFree(GetProcessHeap(), 0, unixname);
7679 return ret;
7682 /*****************************************************************************
7683 * ScheduleJob [WINSPOOL.@]
7686 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7688 opened_printer_t *printer;
7689 BOOL ret = FALSE;
7690 struct list *cursor, *cursor2;
7692 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7693 EnterCriticalSection(&printer_handles_cs);
7694 printer = get_opened_printer(hPrinter);
7695 if(!printer)
7696 goto end;
7698 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7700 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7701 HANDLE hf;
7703 if(job->job_id != dwJobID) continue;
7705 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7706 if(hf != INVALID_HANDLE_VALUE)
7708 PRINTER_INFO_5W *pi5 = NULL;
7709 LPWSTR portname = job->portname;
7710 DWORD needed;
7711 HKEY hkey;
7712 WCHAR output[1024];
7713 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7714 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7716 if (!portname)
7718 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7719 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7720 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7721 portname = pi5->pPortName;
7723 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7724 debugstr_w(portname));
7726 output[0] = 0;
7728 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7729 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7731 DWORD type, count = sizeof(output);
7732 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7733 RegCloseKey(hkey);
7735 if(output[0] == '|')
7737 ret = schedule_pipe(output + 1, job->filename);
7739 else if(output[0])
7741 ret = schedule_unixfile(output, job->filename);
7743 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7745 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7747 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7749 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7751 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7753 ret = schedule_file(job->filename);
7755 else
7757 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7759 HeapFree(GetProcessHeap(), 0, pi5);
7760 CloseHandle(hf);
7761 DeleteFileW(job->filename);
7763 list_remove(cursor);
7764 HeapFree(GetProcessHeap(), 0, job->document_title);
7765 HeapFree(GetProcessHeap(), 0, job->printer_name);
7766 HeapFree(GetProcessHeap(), 0, job->portname);
7767 HeapFree(GetProcessHeap(), 0, job->filename);
7768 HeapFree(GetProcessHeap(), 0, job->devmode);
7769 HeapFree(GetProcessHeap(), 0, job);
7770 break;
7772 end:
7773 LeaveCriticalSection(&printer_handles_cs);
7774 return ret;
7777 /*****************************************************************************
7778 * StartDocDlgA [WINSPOOL.@]
7780 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7782 UNICODE_STRING usBuffer;
7783 DOCINFOW docW;
7784 LPWSTR retW;
7785 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7786 LPSTR ret = NULL;
7788 docW.cbSize = sizeof(docW);
7789 if (doc->lpszDocName)
7791 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7792 if (!(docW.lpszDocName = docnameW)) return NULL;
7794 if (doc->lpszOutput)
7796 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7797 if (!(docW.lpszOutput = outputW)) return NULL;
7799 if (doc->lpszDatatype)
7801 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7802 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7804 docW.fwType = doc->fwType;
7806 retW = StartDocDlgW(hPrinter, &docW);
7808 if(retW)
7810 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7811 ret = HeapAlloc(GetProcessHeap(), 0, len);
7812 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7813 HeapFree(GetProcessHeap(), 0, retW);
7816 HeapFree(GetProcessHeap(), 0, datatypeW);
7817 HeapFree(GetProcessHeap(), 0, outputW);
7818 HeapFree(GetProcessHeap(), 0, docnameW);
7820 return ret;
7823 /*****************************************************************************
7824 * StartDocDlgW [WINSPOOL.@]
7826 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7827 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7828 * port is "FILE:". Also returns the full path if passed a relative path.
7830 * The caller should free the returned string from the process heap.
7832 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7834 LPWSTR ret = NULL;
7835 DWORD len, attr;
7837 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7839 PRINTER_INFO_5W *pi5;
7840 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7841 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7842 return NULL;
7843 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7844 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7845 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7847 HeapFree(GetProcessHeap(), 0, pi5);
7848 return NULL;
7850 HeapFree(GetProcessHeap(), 0, pi5);
7853 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7855 LPWSTR name;
7857 if (get_filename(&name))
7859 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7861 HeapFree(GetProcessHeap(), 0, name);
7862 return NULL;
7864 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7865 GetFullPathNameW(name, len, ret, NULL);
7866 HeapFree(GetProcessHeap(), 0, name);
7868 return ret;
7871 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7872 return NULL;
7874 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7875 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7877 attr = GetFileAttributesW(ret);
7878 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7880 HeapFree(GetProcessHeap(), 0, ret);
7881 ret = NULL;
7883 return ret;