winspool: Remove a FIXME now that we don't ignore the defaults.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob14d4b14382e79893507b808127170ed3f8786e80
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);
1903 if(!phPrinter) {
1904 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1905 SetLastError(ERROR_INVALID_PARAMETER);
1906 return FALSE;
1909 /* Get the unique handle of the printer or Printserver */
1910 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1911 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1912 return (*phPrinter != 0);
1915 /******************************************************************
1916 * AddMonitorA [WINSPOOL.@]
1918 * See AddMonitorW.
1921 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1923 LPWSTR nameW = NULL;
1924 INT len;
1925 BOOL res;
1926 LPMONITOR_INFO_2A mi2a;
1927 MONITOR_INFO_2W mi2w;
1929 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1930 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1931 debugstr_a(mi2a ? mi2a->pName : NULL),
1932 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1933 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1935 if (Level != 2) {
1936 SetLastError(ERROR_INVALID_LEVEL);
1937 return FALSE;
1940 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1941 if (mi2a == NULL) {
1942 return FALSE;
1945 if (pName) {
1946 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1947 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1948 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1951 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1952 if (mi2a->pName) {
1953 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1954 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1955 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1957 if (mi2a->pEnvironment) {
1958 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1959 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1960 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1962 if (mi2a->pDLLName) {
1963 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1964 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1965 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1968 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1970 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1971 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1972 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1974 HeapFree(GetProcessHeap(), 0, nameW);
1975 return (res);
1978 /******************************************************************************
1979 * AddMonitorW [WINSPOOL.@]
1981 * Install a Printmonitor
1983 * PARAMS
1984 * pName [I] Servername or NULL (local Computer)
1985 * Level [I] Structure-Level (Must be 2)
1986 * pMonitors [I] PTR to MONITOR_INFO_2
1988 * RETURNS
1989 * Success: TRUE
1990 * Failure: FALSE
1992 * NOTES
1993 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1996 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1998 LPMONITOR_INFO_2W mi2w;
2000 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2001 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2002 debugstr_w(mi2w ? mi2w->pName : NULL),
2003 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2004 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2006 if ((backend == NULL) && !load_backend()) return FALSE;
2008 if (Level != 2) {
2009 SetLastError(ERROR_INVALID_LEVEL);
2010 return FALSE;
2013 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2014 if (mi2w == NULL) {
2015 return FALSE;
2018 return backend->fpAddMonitor(pName, Level, pMonitors);
2021 /******************************************************************
2022 * DeletePrinterDriverA [WINSPOOL.@]
2025 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2027 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2030 /******************************************************************
2031 * DeletePrinterDriverW [WINSPOOL.@]
2034 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2036 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2039 /******************************************************************
2040 * DeleteMonitorA [WINSPOOL.@]
2042 * See DeleteMonitorW.
2045 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2047 LPWSTR nameW = NULL;
2048 LPWSTR EnvironmentW = NULL;
2049 LPWSTR MonitorNameW = NULL;
2050 BOOL res;
2051 INT len;
2053 if (pName) {
2054 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2055 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2056 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2059 if (pEnvironment) {
2060 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2061 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2062 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2064 if (pMonitorName) {
2065 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2066 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2067 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2070 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2072 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2073 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2074 HeapFree(GetProcessHeap(), 0, nameW);
2075 return (res);
2078 /******************************************************************
2079 * DeleteMonitorW [WINSPOOL.@]
2081 * Delete a specific Printmonitor from a Printing-Environment
2083 * PARAMS
2084 * pName [I] Servername or NULL (local Computer)
2085 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2086 * pMonitorName [I] Name of the Monitor, that should be deleted
2088 * RETURNS
2089 * Success: TRUE
2090 * Failure: FALSE
2092 * NOTES
2093 * pEnvironment is ignored in Windows for the local Computer.
2096 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2099 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2100 debugstr_w(pMonitorName));
2102 if ((backend == NULL) && !load_backend()) return FALSE;
2104 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2108 /******************************************************************
2109 * DeletePortA [WINSPOOL.@]
2111 * See DeletePortW.
2114 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2116 LPWSTR nameW = NULL;
2117 LPWSTR portW = NULL;
2118 INT len;
2119 DWORD res;
2121 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2123 /* convert servername to unicode */
2124 if (pName) {
2125 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2126 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2127 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2130 /* convert portname to unicode */
2131 if (pPortName) {
2132 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2133 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2134 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2137 res = DeletePortW(nameW, hWnd, portW);
2138 HeapFree(GetProcessHeap(), 0, nameW);
2139 HeapFree(GetProcessHeap(), 0, portW);
2140 return res;
2143 /******************************************************************
2144 * DeletePortW [WINSPOOL.@]
2146 * Delete a specific Port
2148 * PARAMS
2149 * pName [I] Servername or NULL (local Computer)
2150 * hWnd [I] Handle to parent Window for the Dialog-Box
2151 * pPortName [I] Name of the Port, that should be deleted
2153 * RETURNS
2154 * Success: TRUE
2155 * Failure: FALSE
2158 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2160 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2162 if ((backend == NULL) && !load_backend()) return FALSE;
2164 if (!pPortName) {
2165 SetLastError(RPC_X_NULL_REF_POINTER);
2166 return FALSE;
2169 return backend->fpDeletePort(pName, hWnd, pPortName);
2172 /******************************************************************************
2173 * SetPrinterW [WINSPOOL.@]
2175 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2177 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2178 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2179 return FALSE;
2182 /******************************************************************************
2183 * WritePrinter [WINSPOOL.@]
2185 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2187 opened_printer_t *printer;
2188 BOOL ret = FALSE;
2190 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2192 EnterCriticalSection(&printer_handles_cs);
2193 printer = get_opened_printer(hPrinter);
2194 if(!printer)
2196 SetLastError(ERROR_INVALID_HANDLE);
2197 goto end;
2200 if(!printer->doc)
2202 SetLastError(ERROR_SPL_NO_STARTDOC);
2203 goto end;
2206 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2207 end:
2208 LeaveCriticalSection(&printer_handles_cs);
2209 return ret;
2212 /*****************************************************************************
2213 * AddFormA [WINSPOOL.@]
2215 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2217 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2218 return 1;
2221 /*****************************************************************************
2222 * AddFormW [WINSPOOL.@]
2224 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2226 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2227 return 1;
2230 /*****************************************************************************
2231 * AddJobA [WINSPOOL.@]
2233 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2235 BOOL ret;
2236 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2237 DWORD needed;
2239 if(Level != 1) {
2240 SetLastError(ERROR_INVALID_LEVEL);
2241 return FALSE;
2244 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2246 if(ret) {
2247 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2248 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2249 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2250 if(*pcbNeeded > cbBuf) {
2251 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2252 ret = FALSE;
2253 } else {
2254 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2255 addjobA->JobId = addjobW->JobId;
2256 addjobA->Path = (char *)(addjobA + 1);
2257 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2260 return ret;
2263 /*****************************************************************************
2264 * AddJobW [WINSPOOL.@]
2266 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2268 opened_printer_t *printer;
2269 job_t *job;
2270 BOOL ret = FALSE;
2271 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2272 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2273 WCHAR path[MAX_PATH], filename[MAX_PATH];
2274 DWORD len;
2275 ADDJOB_INFO_1W *addjob;
2277 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2279 EnterCriticalSection(&printer_handles_cs);
2281 printer = get_opened_printer(hPrinter);
2283 if(!printer) {
2284 SetLastError(ERROR_INVALID_HANDLE);
2285 goto end;
2288 if(Level != 1) {
2289 SetLastError(ERROR_INVALID_LEVEL);
2290 goto end;
2293 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2294 if(!job)
2295 goto end;
2297 job->job_id = InterlockedIncrement(&next_job_id);
2299 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2300 if(path[len - 1] != '\\')
2301 path[len++] = '\\';
2302 memcpy(path + len, spool_path, sizeof(spool_path));
2303 sprintfW(filename, fmtW, path, job->job_id);
2305 len = strlenW(filename);
2306 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2307 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2308 job->portname = NULL;
2309 job->document_title = strdupW(default_doc_title);
2310 job->printer_name = strdupW(printer->name);
2311 job->devmode = dup_devmode( printer->devmode );
2312 list_add_tail(&printer->queue->jobs, &job->entry);
2314 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2315 if(*pcbNeeded <= cbBuf) {
2316 addjob = (ADDJOB_INFO_1W*)pData;
2317 addjob->JobId = job->job_id;
2318 addjob->Path = (WCHAR *)(addjob + 1);
2319 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2320 ret = TRUE;
2321 } else
2322 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2324 end:
2325 LeaveCriticalSection(&printer_handles_cs);
2326 return ret;
2329 /*****************************************************************************
2330 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2332 * Return the PATH for the Print-Processors
2334 * See GetPrintProcessorDirectoryW.
2338 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2339 DWORD level, LPBYTE Info,
2340 DWORD cbBuf, LPDWORD pcbNeeded)
2342 LPWSTR serverW = NULL;
2343 LPWSTR envW = NULL;
2344 BOOL ret;
2345 INT len;
2347 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2348 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2351 if (server) {
2352 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2353 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2354 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2357 if (env) {
2358 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2359 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2360 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2363 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2364 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2366 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2367 cbBuf, pcbNeeded);
2369 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2370 cbBuf, NULL, NULL) > 0;
2373 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2374 HeapFree(GetProcessHeap(), 0, envW);
2375 HeapFree(GetProcessHeap(), 0, serverW);
2376 return ret;
2379 /*****************************************************************************
2380 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2382 * Return the PATH for the Print-Processors
2384 * PARAMS
2385 * server [I] Servername (NT only) or NULL (local Computer)
2386 * env [I] Printing-Environment (see below) or NULL (Default)
2387 * level [I] Structure-Level (must be 1)
2388 * Info [O] PTR to Buffer that receives the Result
2389 * cbBuf [I] Size of Buffer at "Info"
2390 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2391 * required for the Buffer at "Info"
2393 * RETURNS
2394 * Success: TRUE and in pcbNeeded the Bytes used in Info
2395 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2396 * if cbBuf is too small
2398 * Native Values returned in Info on Success:
2399 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2400 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2401 *| win9x(Windows 4.0): "%winsysdir%"
2403 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2405 * BUGS
2406 * Only NULL or "" is supported for server
2409 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2410 DWORD level, LPBYTE Info,
2411 DWORD cbBuf, LPDWORD pcbNeeded)
2414 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2415 Info, cbBuf, pcbNeeded);
2417 if ((backend == NULL) && !load_backend()) return FALSE;
2419 if (level != 1) {
2420 /* (Level != 1) is ignored in win9x */
2421 SetLastError(ERROR_INVALID_LEVEL);
2422 return FALSE;
2425 if (pcbNeeded == NULL) {
2426 /* (pcbNeeded == NULL) is ignored in win9x */
2427 SetLastError(RPC_X_NULL_REF_POINTER);
2428 return FALSE;
2431 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2434 /*****************************************************************************
2435 * WINSPOOL_OpenDriverReg [internal]
2437 * opens the registry for the printer drivers depending on the given input
2438 * variable pEnvironment
2440 * RETURNS:
2441 * the opened hkey on success
2442 * NULL on error
2444 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2446 HKEY retval = NULL;
2447 LPWSTR buffer;
2448 const printenv_t * env;
2450 TRACE("(%s)\n", debugstr_w(pEnvironment));
2452 env = validate_envW(pEnvironment);
2453 if (!env) return NULL;
2455 buffer = HeapAlloc( GetProcessHeap(), 0,
2456 (strlenW(DriversW) + strlenW(env->envname) +
2457 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2458 if(buffer) {
2459 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2460 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2461 HeapFree(GetProcessHeap(), 0, buffer);
2463 return retval;
2466 /*****************************************************************************
2467 * set_devices_and_printerports [internal]
2469 * set the [Devices] and [PrinterPorts] entries for a printer.
2472 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2474 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2475 WCHAR *devline;
2476 HKEY hkey;
2478 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2480 /* FIXME: the driver must change to "winspool" */
2481 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2482 if (devline) {
2483 lstrcpyW(devline, driver_nt);
2484 lstrcatW(devline, commaW);
2485 lstrcatW(devline, pi->pPortName);
2487 TRACE("using %s\n", debugstr_w(devline));
2488 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2489 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2490 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2491 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2492 RegCloseKey(hkey);
2495 lstrcatW(devline, timeout_15_45);
2496 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2497 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2498 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2499 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2500 RegCloseKey(hkey);
2502 HeapFree(GetProcessHeap(), 0, devline);
2506 /*****************************************************************************
2507 * AddPrinterW [WINSPOOL.@]
2509 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2511 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2512 LPDEVMODEA dmA;
2513 LPDEVMODEW dmW;
2514 HANDLE retval;
2515 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2516 LONG size;
2517 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2518 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2519 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2520 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2521 statusW[] = {'S','t','a','t','u','s',0},
2522 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2524 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2526 if(pName != NULL) {
2527 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2528 SetLastError(ERROR_INVALID_PARAMETER);
2529 return 0;
2531 if(Level != 2) {
2532 ERR("Level = %d, unsupported!\n", Level);
2533 SetLastError(ERROR_INVALID_LEVEL);
2534 return 0;
2536 if(!pPrinter) {
2537 SetLastError(ERROR_INVALID_PARAMETER);
2538 return 0;
2540 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2541 ERROR_SUCCESS) {
2542 ERR("Can't create Printers key\n");
2543 return 0;
2545 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2546 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2547 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2548 RegCloseKey(hkeyPrinter);
2549 RegCloseKey(hkeyPrinters);
2550 return 0;
2552 RegCloseKey(hkeyPrinter);
2554 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2555 if(!hkeyDrivers) {
2556 ERR("Can't create Drivers key\n");
2557 RegCloseKey(hkeyPrinters);
2558 return 0;
2560 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2561 ERROR_SUCCESS) {
2562 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2563 RegCloseKey(hkeyPrinters);
2564 RegCloseKey(hkeyDrivers);
2565 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2566 return 0;
2568 RegCloseKey(hkeyDriver);
2569 RegCloseKey(hkeyDrivers);
2571 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2572 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2573 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2574 RegCloseKey(hkeyPrinters);
2575 return 0;
2578 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2579 ERROR_SUCCESS) {
2580 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2581 SetLastError(ERROR_INVALID_PRINTER_NAME);
2582 RegCloseKey(hkeyPrinters);
2583 return 0;
2586 set_devices_and_printerports(pi);
2587 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2588 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2589 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2591 /* See if we can load the driver. We may need the devmode structure anyway
2593 * FIXME:
2594 * Note that DocumentPropertiesW will briefly try to open the printer we
2595 * just create to find a DEVMODEA struct (it will use the WINEPS default
2596 * one in case it is not there, so we are ok).
2598 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2600 if(size < 0) {
2601 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2602 size = sizeof(DEVMODEW);
2604 if(pi->pDevMode)
2605 dmW = pi->pDevMode;
2606 else
2608 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2609 dmW->dmSize = size;
2610 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2612 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2613 HeapFree(GetProcessHeap(),0,dmW);
2614 dmW=NULL;
2616 else
2618 /* set devmode to printer name */
2619 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2623 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2624 and we support these drivers. NT writes DEVMODEW so somehow
2625 we'll need to distinguish between these when we support NT
2626 drivers */
2627 if (dmW)
2629 dmA = DEVMODEdupWtoA(dmW);
2630 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2631 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2632 HeapFree(GetProcessHeap(), 0, dmA);
2633 if(!pi->pDevMode)
2634 HeapFree(GetProcessHeap(), 0, dmW);
2636 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2637 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2638 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2639 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2641 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2642 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2643 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2644 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2645 (LPBYTE)&pi->Priority, sizeof(DWORD));
2646 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2647 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2648 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2649 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2650 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2651 (LPBYTE)&pi->Status, sizeof(DWORD));
2652 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2653 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2655 RegCloseKey(hkeyPrinter);
2656 RegCloseKey(hkeyPrinters);
2657 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2658 ERR("OpenPrinter failing\n");
2659 return 0;
2661 return retval;
2664 /*****************************************************************************
2665 * AddPrinterA [WINSPOOL.@]
2667 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2669 UNICODE_STRING pNameW;
2670 PWSTR pwstrNameW;
2671 PRINTER_INFO_2W *piW;
2672 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2673 HANDLE ret;
2675 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2676 if(Level != 2) {
2677 ERR("Level = %d, unsupported!\n", Level);
2678 SetLastError(ERROR_INVALID_LEVEL);
2679 return 0;
2681 pwstrNameW = asciitounicode(&pNameW,pName);
2682 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2684 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2686 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2687 RtlFreeUnicodeString(&pNameW);
2688 return ret;
2692 /*****************************************************************************
2693 * ClosePrinter [WINSPOOL.@]
2695 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2697 UINT_PTR i = (UINT_PTR)hPrinter;
2698 opened_printer_t *printer = NULL;
2699 BOOL ret = FALSE;
2701 TRACE("(%p)\n", hPrinter);
2703 EnterCriticalSection(&printer_handles_cs);
2705 if ((i > 0) && (i <= nb_printer_handles))
2706 printer = printer_handles[i - 1];
2709 if(printer)
2711 struct list *cursor, *cursor2;
2713 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2715 if (printer->backend_printer) {
2716 backend->fpClosePrinter(printer->backend_printer);
2719 if(printer->doc)
2720 EndDocPrinter(hPrinter);
2722 if(InterlockedDecrement(&printer->queue->ref) == 0)
2724 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2726 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2727 ScheduleJob(hPrinter, job->job_id);
2729 HeapFree(GetProcessHeap(), 0, printer->queue);
2732 free_printer_entry( printer );
2733 printer_handles[i - 1] = NULL;
2734 ret = TRUE;
2736 LeaveCriticalSection(&printer_handles_cs);
2737 return ret;
2740 /*****************************************************************************
2741 * DeleteFormA [WINSPOOL.@]
2743 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2745 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2746 return 1;
2749 /*****************************************************************************
2750 * DeleteFormW [WINSPOOL.@]
2752 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2754 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2755 return 1;
2758 /*****************************************************************************
2759 * DeletePrinter [WINSPOOL.@]
2761 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2763 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2764 HKEY hkeyPrinters, hkey;
2766 if(!lpNameW) {
2767 SetLastError(ERROR_INVALID_HANDLE);
2768 return FALSE;
2770 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2771 RegDeleteTreeW(hkeyPrinters, lpNameW);
2772 RegCloseKey(hkeyPrinters);
2774 WriteProfileStringW(devicesW, lpNameW, NULL);
2775 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2777 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2778 RegDeleteValueW(hkey, lpNameW);
2779 RegCloseKey(hkey);
2782 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2783 RegDeleteValueW(hkey, lpNameW);
2784 RegCloseKey(hkey);
2786 return TRUE;
2789 /*****************************************************************************
2790 * SetPrinterA [WINSPOOL.@]
2792 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2793 DWORD Command)
2795 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2796 return FALSE;
2799 /*****************************************************************************
2800 * SetJobA [WINSPOOL.@]
2802 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2803 LPBYTE pJob, DWORD Command)
2805 BOOL ret;
2806 LPBYTE JobW;
2807 UNICODE_STRING usBuffer;
2809 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2811 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2812 are all ignored by SetJob, so we don't bother copying them */
2813 switch(Level)
2815 case 0:
2816 JobW = NULL;
2817 break;
2818 case 1:
2820 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2821 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2823 JobW = (LPBYTE)info1W;
2824 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2825 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2826 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2827 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2828 info1W->Status = info1A->Status;
2829 info1W->Priority = info1A->Priority;
2830 info1W->Position = info1A->Position;
2831 info1W->PagesPrinted = info1A->PagesPrinted;
2832 break;
2834 case 2:
2836 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2837 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2839 JobW = (LPBYTE)info2W;
2840 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2841 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2842 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2843 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2844 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2845 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2846 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2847 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2848 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2849 info2W->Status = info2A->Status;
2850 info2W->Priority = info2A->Priority;
2851 info2W->Position = info2A->Position;
2852 info2W->StartTime = info2A->StartTime;
2853 info2W->UntilTime = info2A->UntilTime;
2854 info2W->PagesPrinted = info2A->PagesPrinted;
2855 break;
2857 case 3:
2858 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2859 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2860 break;
2861 default:
2862 SetLastError(ERROR_INVALID_LEVEL);
2863 return FALSE;
2866 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2868 switch(Level)
2870 case 1:
2872 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2873 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2874 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2875 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2876 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2877 break;
2879 case 2:
2881 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2882 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2883 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2884 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2885 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2886 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2887 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2888 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2889 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2890 break;
2893 HeapFree(GetProcessHeap(), 0, JobW);
2895 return ret;
2898 /*****************************************************************************
2899 * SetJobW [WINSPOOL.@]
2901 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2902 LPBYTE pJob, DWORD Command)
2904 BOOL ret = FALSE;
2905 job_t *job;
2907 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2908 FIXME("Ignoring everything other than document title\n");
2910 EnterCriticalSection(&printer_handles_cs);
2911 job = get_job(hPrinter, JobId);
2912 if(!job)
2913 goto end;
2915 switch(Level)
2917 case 0:
2918 break;
2919 case 1:
2921 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2922 HeapFree(GetProcessHeap(), 0, job->document_title);
2923 job->document_title = strdupW(info1->pDocument);
2924 break;
2926 case 2:
2928 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2929 HeapFree(GetProcessHeap(), 0, job->document_title);
2930 job->document_title = strdupW(info2->pDocument);
2931 HeapFree(GetProcessHeap(), 0, job->devmode);
2932 job->devmode = dup_devmode( info2->pDevMode );
2933 break;
2935 case 3:
2936 break;
2937 default:
2938 SetLastError(ERROR_INVALID_LEVEL);
2939 goto end;
2941 ret = TRUE;
2942 end:
2943 LeaveCriticalSection(&printer_handles_cs);
2944 return ret;
2947 /*****************************************************************************
2948 * EndDocPrinter [WINSPOOL.@]
2950 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2952 opened_printer_t *printer;
2953 BOOL ret = FALSE;
2954 TRACE("(%p)\n", hPrinter);
2956 EnterCriticalSection(&printer_handles_cs);
2958 printer = get_opened_printer(hPrinter);
2959 if(!printer)
2961 SetLastError(ERROR_INVALID_HANDLE);
2962 goto end;
2965 if(!printer->doc)
2967 SetLastError(ERROR_SPL_NO_STARTDOC);
2968 goto end;
2971 CloseHandle(printer->doc->hf);
2972 ScheduleJob(hPrinter, printer->doc->job_id);
2973 HeapFree(GetProcessHeap(), 0, printer->doc);
2974 printer->doc = NULL;
2975 ret = TRUE;
2976 end:
2977 LeaveCriticalSection(&printer_handles_cs);
2978 return ret;
2981 /*****************************************************************************
2982 * EndPagePrinter [WINSPOOL.@]
2984 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2986 FIXME("(%p): stub\n", hPrinter);
2987 return TRUE;
2990 /*****************************************************************************
2991 * StartDocPrinterA [WINSPOOL.@]
2993 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2995 UNICODE_STRING usBuffer;
2996 DOC_INFO_2W doc2W;
2997 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2998 DWORD ret;
3000 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3001 or one (DOC_INFO_3) extra DWORDs */
3003 switch(Level) {
3004 case 2:
3005 doc2W.JobId = doc2->JobId;
3006 /* fall through */
3007 case 3:
3008 doc2W.dwMode = doc2->dwMode;
3009 /* fall through */
3010 case 1:
3011 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3012 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3013 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3014 break;
3016 default:
3017 SetLastError(ERROR_INVALID_LEVEL);
3018 return FALSE;
3021 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3023 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3024 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3025 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3027 return ret;
3030 /*****************************************************************************
3031 * StartDocPrinterW [WINSPOOL.@]
3033 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3035 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3036 opened_printer_t *printer;
3037 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3038 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3039 JOB_INFO_1W job_info;
3040 DWORD needed, ret = 0;
3041 HANDLE hf;
3042 WCHAR *filename;
3043 job_t *job;
3045 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3046 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3047 debugstr_w(doc->pDatatype));
3049 if(Level < 1 || Level > 3)
3051 SetLastError(ERROR_INVALID_LEVEL);
3052 return 0;
3055 EnterCriticalSection(&printer_handles_cs);
3056 printer = get_opened_printer(hPrinter);
3057 if(!printer)
3059 SetLastError(ERROR_INVALID_HANDLE);
3060 goto end;
3063 if(printer->doc)
3065 SetLastError(ERROR_INVALID_PRINTER_STATE);
3066 goto end;
3069 /* Even if we're printing to a file we still add a print job, we'll
3070 just ignore the spool file name */
3072 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3074 ERR("AddJob failed gle %u\n", GetLastError());
3075 goto end;
3078 /* use pOutputFile only, when it is a real filename */
3079 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3080 filename = doc->pOutputFile;
3081 else
3082 filename = addjob->Path;
3084 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3085 if(hf == INVALID_HANDLE_VALUE)
3086 goto end;
3088 memset(&job_info, 0, sizeof(job_info));
3089 job_info.pDocument = doc->pDocName;
3090 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3092 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3093 printer->doc->hf = hf;
3094 ret = printer->doc->job_id = addjob->JobId;
3095 job = get_job(hPrinter, ret);
3096 job->portname = strdupW(doc->pOutputFile);
3098 end:
3099 LeaveCriticalSection(&printer_handles_cs);
3101 return ret;
3104 /*****************************************************************************
3105 * StartPagePrinter [WINSPOOL.@]
3107 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3109 FIXME("(%p): stub\n", hPrinter);
3110 return TRUE;
3113 /*****************************************************************************
3114 * GetFormA [WINSPOOL.@]
3116 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3117 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3119 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3120 Level,pForm,cbBuf,pcbNeeded);
3121 return FALSE;
3124 /*****************************************************************************
3125 * GetFormW [WINSPOOL.@]
3127 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3128 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3130 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3131 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3132 return FALSE;
3135 /*****************************************************************************
3136 * SetFormA [WINSPOOL.@]
3138 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3139 LPBYTE pForm)
3141 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3142 return FALSE;
3145 /*****************************************************************************
3146 * SetFormW [WINSPOOL.@]
3148 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3149 LPBYTE pForm)
3151 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3152 return FALSE;
3155 /*****************************************************************************
3156 * ReadPrinter [WINSPOOL.@]
3158 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3159 LPDWORD pNoBytesRead)
3161 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3162 return FALSE;
3165 /*****************************************************************************
3166 * ResetPrinterA [WINSPOOL.@]
3168 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3170 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3171 return FALSE;
3174 /*****************************************************************************
3175 * ResetPrinterW [WINSPOOL.@]
3177 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3179 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3180 return FALSE;
3183 /*****************************************************************************
3184 * WINSPOOL_GetDWORDFromReg
3186 * Return DWORD associated with ValueName from hkey.
3188 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3190 DWORD sz = sizeof(DWORD), type, value = 0;
3191 LONG ret;
3193 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3195 if(ret != ERROR_SUCCESS) {
3196 WARN("Got ret = %d on name %s\n", ret, ValueName);
3197 return 0;
3199 if(type != REG_DWORD) {
3200 ERR("Got type %d\n", type);
3201 return 0;
3203 return value;
3207 /*****************************************************************************
3208 * get_filename_from_reg [internal]
3210 * Get ValueName from hkey storing result in out
3211 * when the Value in the registry has only a filename, use driverdir as prefix
3212 * outlen is space left in out
3213 * String is stored either as unicode or ascii
3217 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3218 LPBYTE out, DWORD outlen, LPDWORD needed)
3220 WCHAR filename[MAX_PATH];
3221 DWORD size;
3222 DWORD type;
3223 LONG ret;
3224 LPWSTR buffer = filename;
3225 LPWSTR ptr;
3227 *needed = 0;
3228 size = sizeof(filename);
3229 buffer[0] = '\0';
3230 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3231 if (ret == ERROR_MORE_DATA) {
3232 TRACE("need dynamic buffer: %u\n", size);
3233 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3234 if (!buffer) {
3235 /* No Memory is bad */
3236 return FALSE;
3238 buffer[0] = '\0';
3239 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3242 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3243 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3244 return FALSE;
3247 ptr = buffer;
3248 while (ptr) {
3249 /* do we have a full path ? */
3250 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3251 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3253 if (!ret) {
3254 /* we must build the full Path */
3255 *needed += dirlen;
3256 if ((out) && (outlen > dirlen)) {
3257 lstrcpyW((LPWSTR)out, driverdir);
3258 out += dirlen;
3259 outlen -= dirlen;
3261 else
3262 out = NULL;
3265 /* write the filename */
3266 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3267 if ((out) && (outlen >= size)) {
3268 lstrcpyW((LPWSTR)out, ptr);
3269 out += size;
3270 outlen -= size;
3272 else
3273 out = NULL;
3274 *needed += size;
3275 ptr += lstrlenW(ptr)+1;
3276 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3279 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3281 /* write the multisz-termination */
3282 if (type == REG_MULTI_SZ) {
3283 size = sizeof(WCHAR);
3285 *needed += size;
3286 if (out && (outlen >= size)) {
3287 memset (out, 0, size);
3290 return TRUE;
3293 /*****************************************************************************
3294 * WINSPOOL_GetStringFromReg
3296 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3297 * String is stored as unicode.
3299 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3300 DWORD buflen, DWORD *needed)
3302 DWORD sz = buflen, type;
3303 LONG ret;
3305 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3306 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3307 WARN("Got ret = %d\n", ret);
3308 *needed = 0;
3309 return FALSE;
3311 /* add space for terminating '\0' */
3312 sz += sizeof(WCHAR);
3313 *needed = sz;
3315 if (ptr)
3316 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3318 return TRUE;
3321 /*****************************************************************************
3322 * WINSPOOL_GetDefaultDevMode
3324 * Get a default DevMode values for wineps.
3325 * FIXME - use ppd.
3328 static void WINSPOOL_GetDefaultDevMode(
3329 LPBYTE ptr,
3330 DWORD buflen, DWORD *needed)
3332 DEVMODEW dm;
3333 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3335 /* fill default DEVMODE - should be read from ppd... */
3336 ZeroMemory( &dm, sizeof(dm) );
3337 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3338 dm.dmSpecVersion = DM_SPECVERSION;
3339 dm.dmDriverVersion = 1;
3340 dm.dmSize = sizeof(DEVMODEW);
3341 dm.dmDriverExtra = 0;
3342 dm.dmFields =
3343 DM_ORIENTATION | DM_PAPERSIZE |
3344 DM_PAPERLENGTH | DM_PAPERWIDTH |
3345 DM_SCALE |
3346 DM_COPIES |
3347 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3348 DM_YRESOLUTION | DM_TTOPTION;
3350 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3351 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3352 dm.u1.s1.dmPaperLength = 2970;
3353 dm.u1.s1.dmPaperWidth = 2100;
3355 dm.u1.s1.dmScale = 100;
3356 dm.u1.s1.dmCopies = 1;
3357 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3358 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3359 /* dm.dmColor */
3360 /* dm.dmDuplex */
3361 dm.dmYResolution = 300; /* 300dpi */
3362 dm.dmTTOption = DMTT_BITMAP;
3363 /* dm.dmCollate */
3364 /* dm.dmFormName */
3365 /* dm.dmLogPixels */
3366 /* dm.dmBitsPerPel */
3367 /* dm.dmPelsWidth */
3368 /* dm.dmPelsHeight */
3369 /* dm.u2.dmDisplayFlags */
3370 /* dm.dmDisplayFrequency */
3371 /* dm.dmICMMethod */
3372 /* dm.dmICMIntent */
3373 /* dm.dmMediaType */
3374 /* dm.dmDitherType */
3375 /* dm.dmReserved1 */
3376 /* dm.dmReserved2 */
3377 /* dm.dmPanningWidth */
3378 /* dm.dmPanningHeight */
3380 if(buflen >= sizeof(DEVMODEW))
3381 memcpy(ptr, &dm, sizeof(DEVMODEW));
3382 *needed = sizeof(DEVMODEW);
3385 /*****************************************************************************
3386 * WINSPOOL_GetDevModeFromReg
3388 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3389 * DevMode is stored either as unicode or ascii.
3391 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3392 LPBYTE ptr,
3393 DWORD buflen, DWORD *needed)
3395 DWORD sz = buflen, type;
3396 LONG ret;
3398 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3399 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3400 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3401 if (sz < sizeof(DEVMODEA))
3403 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3404 return FALSE;
3406 /* ensures that dmSize is not erratically bogus if registry is invalid */
3407 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3408 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3409 sz += (CCHDEVICENAME + CCHFORMNAME);
3410 if (ptr && (buflen >= sz)) {
3411 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3412 memcpy(ptr, dmW, sz);
3413 HeapFree(GetProcessHeap(),0,dmW);
3415 *needed = sz;
3416 return TRUE;
3419 /*********************************************************************
3420 * WINSPOOL_GetPrinter_1
3422 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3424 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3425 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3427 DWORD size, left = cbBuf;
3428 BOOL space = (cbBuf > 0);
3429 LPBYTE ptr = buf;
3431 *pcbNeeded = 0;
3433 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3434 if(space && size <= left) {
3435 pi1->pName = (LPWSTR)ptr;
3436 ptr += size;
3437 left -= size;
3438 } else
3439 space = FALSE;
3440 *pcbNeeded += size;
3443 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3444 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3445 if(space && size <= left) {
3446 pi1->pDescription = (LPWSTR)ptr;
3447 ptr += size;
3448 left -= size;
3449 } else
3450 space = FALSE;
3451 *pcbNeeded += size;
3454 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3455 if(space && size <= left) {
3456 pi1->pComment = (LPWSTR)ptr;
3457 ptr += size;
3458 left -= size;
3459 } else
3460 space = FALSE;
3461 *pcbNeeded += size;
3464 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3466 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3467 memset(pi1, 0, sizeof(*pi1));
3469 return space;
3471 /*********************************************************************
3472 * WINSPOOL_GetPrinter_2
3474 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3476 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3477 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3479 DWORD size, left = cbBuf;
3480 BOOL space = (cbBuf > 0);
3481 LPBYTE ptr = buf;
3483 *pcbNeeded = 0;
3485 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3486 if(space && size <= left) {
3487 pi2->pPrinterName = (LPWSTR)ptr;
3488 ptr += size;
3489 left -= size;
3490 } else
3491 space = FALSE;
3492 *pcbNeeded += size;
3494 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3495 if(space && size <= left) {
3496 pi2->pShareName = (LPWSTR)ptr;
3497 ptr += size;
3498 left -= size;
3499 } else
3500 space = FALSE;
3501 *pcbNeeded += size;
3503 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3504 if(space && size <= left) {
3505 pi2->pPortName = (LPWSTR)ptr;
3506 ptr += size;
3507 left -= size;
3508 } else
3509 space = FALSE;
3510 *pcbNeeded += size;
3512 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3513 if(space && size <= left) {
3514 pi2->pDriverName = (LPWSTR)ptr;
3515 ptr += size;
3516 left -= size;
3517 } else
3518 space = FALSE;
3519 *pcbNeeded += size;
3521 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3522 if(space && size <= left) {
3523 pi2->pComment = (LPWSTR)ptr;
3524 ptr += size;
3525 left -= size;
3526 } else
3527 space = FALSE;
3528 *pcbNeeded += size;
3530 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3531 if(space && size <= left) {
3532 pi2->pLocation = (LPWSTR)ptr;
3533 ptr += size;
3534 left -= size;
3535 } else
3536 space = FALSE;
3537 *pcbNeeded += size;
3539 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3540 if(space && size <= left) {
3541 pi2->pDevMode = (LPDEVMODEW)ptr;
3542 ptr += size;
3543 left -= size;
3544 } else
3545 space = FALSE;
3546 *pcbNeeded += size;
3548 else
3550 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3551 if(space && size <= left) {
3552 pi2->pDevMode = (LPDEVMODEW)ptr;
3553 ptr += size;
3554 left -= size;
3555 } else
3556 space = FALSE;
3557 *pcbNeeded += size;
3559 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3560 if(space && size <= left) {
3561 pi2->pSepFile = (LPWSTR)ptr;
3562 ptr += size;
3563 left -= size;
3564 } else
3565 space = FALSE;
3566 *pcbNeeded += size;
3568 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3569 if(space && size <= left) {
3570 pi2->pPrintProcessor = (LPWSTR)ptr;
3571 ptr += size;
3572 left -= size;
3573 } else
3574 space = FALSE;
3575 *pcbNeeded += size;
3577 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3578 if(space && size <= left) {
3579 pi2->pDatatype = (LPWSTR)ptr;
3580 ptr += size;
3581 left -= size;
3582 } else
3583 space = FALSE;
3584 *pcbNeeded += size;
3586 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3587 if(space && size <= left) {
3588 pi2->pParameters = (LPWSTR)ptr;
3589 ptr += size;
3590 left -= size;
3591 } else
3592 space = FALSE;
3593 *pcbNeeded += size;
3595 if(pi2) {
3596 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3597 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3598 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3599 "Default Priority");
3600 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3601 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3604 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3605 memset(pi2, 0, sizeof(*pi2));
3607 return space;
3610 /*********************************************************************
3611 * WINSPOOL_GetPrinter_4
3613 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3615 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3616 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3618 DWORD size, left = cbBuf;
3619 BOOL space = (cbBuf > 0);
3620 LPBYTE ptr = buf;
3622 *pcbNeeded = 0;
3624 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3625 if(space && size <= left) {
3626 pi4->pPrinterName = (LPWSTR)ptr;
3627 ptr += size;
3628 left -= size;
3629 } else
3630 space = FALSE;
3631 *pcbNeeded += size;
3633 if(pi4) {
3634 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3637 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3638 memset(pi4, 0, sizeof(*pi4));
3640 return space;
3643 /*********************************************************************
3644 * WINSPOOL_GetPrinter_5
3646 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3648 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3649 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3651 DWORD size, left = cbBuf;
3652 BOOL space = (cbBuf > 0);
3653 LPBYTE ptr = buf;
3655 *pcbNeeded = 0;
3657 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3658 if(space && size <= left) {
3659 pi5->pPrinterName = (LPWSTR)ptr;
3660 ptr += size;
3661 left -= size;
3662 } else
3663 space = FALSE;
3664 *pcbNeeded += size;
3666 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3667 if(space && size <= left) {
3668 pi5->pPortName = (LPWSTR)ptr;
3669 ptr += size;
3670 left -= size;
3671 } else
3672 space = FALSE;
3673 *pcbNeeded += size;
3675 if(pi5) {
3676 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3677 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3678 "dnsTimeout");
3679 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3680 "txTimeout");
3683 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3684 memset(pi5, 0, sizeof(*pi5));
3686 return space;
3689 /*********************************************************************
3690 * WINSPOOL_GetPrinter_7
3692 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3694 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3695 DWORD cbBuf, LPDWORD pcbNeeded)
3697 DWORD size, left = cbBuf;
3698 BOOL space = (cbBuf > 0);
3699 LPBYTE ptr = buf;
3701 *pcbNeeded = 0;
3703 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3705 ptr = NULL;
3706 size = sizeof(pi7->pszObjectGUID);
3708 if (space && size <= left) {
3709 pi7->pszObjectGUID = (LPWSTR)ptr;
3710 ptr += size;
3711 left -= size;
3712 } else
3713 space = FALSE;
3714 *pcbNeeded += size;
3715 if (pi7) {
3716 /* We do not have a Directory Service */
3717 pi7->dwAction = DSPRINT_UNPUBLISH;
3720 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3721 memset(pi7, 0, sizeof(*pi7));
3723 return space;
3726 /*********************************************************************
3727 * WINSPOOL_GetPrinter_9
3729 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3731 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3732 DWORD cbBuf, LPDWORD pcbNeeded)
3734 DWORD size;
3735 BOOL space = (cbBuf > 0);
3737 *pcbNeeded = 0;
3739 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3740 if(space && size <= cbBuf) {
3741 pi9->pDevMode = (LPDEVMODEW)buf;
3742 } else
3743 space = FALSE;
3744 *pcbNeeded += size;
3746 else
3748 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3749 if(space && size <= cbBuf) {
3750 pi9->pDevMode = (LPDEVMODEW)buf;
3751 } else
3752 space = FALSE;
3753 *pcbNeeded += size;
3756 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3757 memset(pi9, 0, sizeof(*pi9));
3759 return space;
3762 /*****************************************************************************
3763 * GetPrinterW [WINSPOOL.@]
3765 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3766 DWORD cbBuf, LPDWORD pcbNeeded)
3768 LPCWSTR name;
3769 DWORD size, needed = 0;
3770 LPBYTE ptr = NULL;
3771 HKEY hkeyPrinter, hkeyPrinters;
3772 BOOL ret;
3774 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3776 if (!(name = get_opened_printer_name(hPrinter))) {
3777 SetLastError(ERROR_INVALID_HANDLE);
3778 return FALSE;
3781 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3782 ERROR_SUCCESS) {
3783 ERR("Can't create Printers key\n");
3784 return FALSE;
3786 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3788 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3789 RegCloseKey(hkeyPrinters);
3790 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3791 return FALSE;
3794 switch(Level) {
3795 case 2:
3797 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3799 size = sizeof(PRINTER_INFO_2W);
3800 if(size <= cbBuf) {
3801 ptr = pPrinter + size;
3802 cbBuf -= size;
3803 memset(pPrinter, 0, size);
3804 } else {
3805 pi2 = NULL;
3806 cbBuf = 0;
3808 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3809 needed += size;
3810 break;
3813 case 4:
3815 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3817 size = sizeof(PRINTER_INFO_4W);
3818 if(size <= cbBuf) {
3819 ptr = pPrinter + size;
3820 cbBuf -= size;
3821 memset(pPrinter, 0, size);
3822 } else {
3823 pi4 = NULL;
3824 cbBuf = 0;
3826 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3827 needed += size;
3828 break;
3832 case 5:
3834 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3836 size = sizeof(PRINTER_INFO_5W);
3837 if(size <= cbBuf) {
3838 ptr = pPrinter + size;
3839 cbBuf -= size;
3840 memset(pPrinter, 0, size);
3841 } else {
3842 pi5 = NULL;
3843 cbBuf = 0;
3846 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3847 needed += size;
3848 break;
3852 case 6:
3854 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3856 size = sizeof(PRINTER_INFO_6);
3857 if (size <= cbBuf) {
3858 /* FIXME: We do not update the status yet */
3859 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3860 ret = TRUE;
3861 } else {
3862 ret = FALSE;
3865 needed += size;
3866 break;
3869 case 7:
3871 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3873 size = sizeof(PRINTER_INFO_7W);
3874 if (size <= cbBuf) {
3875 ptr = pPrinter + size;
3876 cbBuf -= size;
3877 memset(pPrinter, 0, size);
3878 } else {
3879 pi7 = NULL;
3880 cbBuf = 0;
3883 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3884 needed += size;
3885 break;
3889 case 9:
3891 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3893 size = sizeof(PRINTER_INFO_9W);
3894 if(size <= cbBuf) {
3895 ptr = pPrinter + size;
3896 cbBuf -= size;
3897 memset(pPrinter, 0, size);
3898 } else {
3899 pi9 = NULL;
3900 cbBuf = 0;
3903 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3904 needed += size;
3905 break;
3909 default:
3910 FIXME("Unimplemented level %d\n", Level);
3911 SetLastError(ERROR_INVALID_LEVEL);
3912 RegCloseKey(hkeyPrinters);
3913 RegCloseKey(hkeyPrinter);
3914 return FALSE;
3917 RegCloseKey(hkeyPrinter);
3918 RegCloseKey(hkeyPrinters);
3920 TRACE("returning %d needed = %d\n", ret, needed);
3921 if(pcbNeeded) *pcbNeeded = needed;
3922 if(!ret)
3923 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3924 return ret;
3927 /*****************************************************************************
3928 * GetPrinterA [WINSPOOL.@]
3930 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3931 DWORD cbBuf, LPDWORD pcbNeeded)
3933 BOOL ret;
3934 LPBYTE buf = NULL;
3936 if (cbBuf)
3937 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3939 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3940 if (ret)
3941 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3942 HeapFree(GetProcessHeap(), 0, buf);
3944 return ret;
3947 /*****************************************************************************
3948 * WINSPOOL_EnumPrintersW
3950 * Implementation of EnumPrintersW
3952 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3953 DWORD dwLevel, LPBYTE lpbPrinters,
3954 DWORD cbBuf, LPDWORD lpdwNeeded,
3955 LPDWORD lpdwReturned)
3958 HKEY hkeyPrinters, hkeyPrinter;
3959 WCHAR PrinterName[255];
3960 DWORD needed = 0, number = 0;
3961 DWORD used, i, left;
3962 PBYTE pi, buf;
3964 if(lpbPrinters)
3965 memset(lpbPrinters, 0, cbBuf);
3966 if(lpdwReturned)
3967 *lpdwReturned = 0;
3968 if(lpdwNeeded)
3969 *lpdwNeeded = 0;
3971 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3972 if(dwType == PRINTER_ENUM_DEFAULT)
3973 return TRUE;
3975 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3976 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3977 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3978 if (!dwType) {
3979 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3980 return TRUE;
3985 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3986 FIXME("dwType = %08x\n", dwType);
3987 SetLastError(ERROR_INVALID_FLAGS);
3988 return FALSE;
3991 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3992 ERROR_SUCCESS) {
3993 ERR("Can't create Printers key\n");
3994 return FALSE;
3997 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3998 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3999 RegCloseKey(hkeyPrinters);
4000 ERR("Can't query Printers key\n");
4001 return FALSE;
4003 TRACE("Found %d printers\n", number);
4005 switch(dwLevel) {
4006 case 1:
4007 used = number * sizeof(PRINTER_INFO_1W);
4008 break;
4009 case 2:
4010 used = number * sizeof(PRINTER_INFO_2W);
4011 break;
4012 case 4:
4013 used = number * sizeof(PRINTER_INFO_4W);
4014 break;
4015 case 5:
4016 used = number * sizeof(PRINTER_INFO_5W);
4017 break;
4019 default:
4020 SetLastError(ERROR_INVALID_LEVEL);
4021 RegCloseKey(hkeyPrinters);
4022 return FALSE;
4024 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4026 for(i = 0; i < number; i++) {
4027 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4028 ERROR_SUCCESS) {
4029 ERR("Can't enum key number %d\n", i);
4030 RegCloseKey(hkeyPrinters);
4031 return FALSE;
4033 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4034 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4035 ERROR_SUCCESS) {
4036 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4037 RegCloseKey(hkeyPrinters);
4038 return FALSE;
4041 if(cbBuf > used) {
4042 buf = lpbPrinters + used;
4043 left = cbBuf - used;
4044 } else {
4045 buf = NULL;
4046 left = 0;
4049 switch(dwLevel) {
4050 case 1:
4051 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4052 left, &needed);
4053 used += needed;
4054 if(pi) pi += sizeof(PRINTER_INFO_1W);
4055 break;
4056 case 2:
4057 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4058 left, &needed);
4059 used += needed;
4060 if(pi) pi += sizeof(PRINTER_INFO_2W);
4061 break;
4062 case 4:
4063 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4064 left, &needed);
4065 used += needed;
4066 if(pi) pi += sizeof(PRINTER_INFO_4W);
4067 break;
4068 case 5:
4069 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4070 left, &needed);
4071 used += needed;
4072 if(pi) pi += sizeof(PRINTER_INFO_5W);
4073 break;
4074 default:
4075 ERR("Shouldn't be here!\n");
4076 RegCloseKey(hkeyPrinter);
4077 RegCloseKey(hkeyPrinters);
4078 return FALSE;
4080 RegCloseKey(hkeyPrinter);
4082 RegCloseKey(hkeyPrinters);
4084 if(lpdwNeeded)
4085 *lpdwNeeded = used;
4087 if(used > cbBuf) {
4088 if(lpbPrinters)
4089 memset(lpbPrinters, 0, cbBuf);
4090 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4091 return FALSE;
4093 if(lpdwReturned)
4094 *lpdwReturned = number;
4095 SetLastError(ERROR_SUCCESS);
4096 return TRUE;
4100 /******************************************************************
4101 * EnumPrintersW [WINSPOOL.@]
4103 * Enumerates the available printers, print servers and print
4104 * providers, depending on the specified flags, name and level.
4106 * RETURNS:
4108 * If level is set to 1:
4109 * Returns an array of PRINTER_INFO_1 data structures in the
4110 * lpbPrinters buffer.
4112 * If level is set to 2:
4113 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4114 * Returns an array of PRINTER_INFO_2 data structures in the
4115 * lpbPrinters buffer. Note that according to MSDN also an
4116 * OpenPrinter should be performed on every remote printer.
4118 * If level is set to 4 (officially WinNT only):
4119 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4120 * Fast: Only the registry is queried to retrieve printer names,
4121 * no connection to the driver is made.
4122 * Returns an array of PRINTER_INFO_4 data structures in the
4123 * lpbPrinters buffer.
4125 * If level is set to 5 (officially WinNT4/Win9x only):
4126 * Fast: Only the registry is queried to retrieve printer names,
4127 * no connection to the driver is made.
4128 * Returns an array of PRINTER_INFO_5 data structures in the
4129 * lpbPrinters buffer.
4131 * If level set to 3 or 6+:
4132 * returns zero (failure!)
4134 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4135 * for information.
4137 * BUGS:
4138 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4139 * - Only levels 2, 4 and 5 are implemented at the moment.
4140 * - 16-bit printer drivers are not enumerated.
4141 * - Returned amount of bytes used/needed does not match the real Windoze
4142 * implementation (as in this implementation, all strings are part
4143 * of the buffer, whereas Win32 keeps them somewhere else)
4144 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4146 * NOTE:
4147 * - In a regular Wine installation, no registry settings for printers
4148 * exist, which makes this function return an empty list.
4150 BOOL WINAPI EnumPrintersW(
4151 DWORD dwType, /* [in] Types of print objects to enumerate */
4152 LPWSTR lpszName, /* [in] name of objects to enumerate */
4153 DWORD dwLevel, /* [in] type of printer info structure */
4154 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4155 DWORD cbBuf, /* [in] max size of buffer in bytes */
4156 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4157 LPDWORD lpdwReturned /* [out] number of entries returned */
4160 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4161 lpdwNeeded, lpdwReturned);
4164 /******************************************************************
4165 * EnumPrintersA [WINSPOOL.@]
4167 * See EnumPrintersW
4170 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4171 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4173 BOOL ret;
4174 UNICODE_STRING pNameU;
4175 LPWSTR pNameW;
4176 LPBYTE pPrintersW;
4178 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4179 pPrinters, cbBuf, pcbNeeded, pcReturned);
4181 pNameW = asciitounicode(&pNameU, pName);
4183 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4184 MS Office need this */
4185 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4187 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4189 RtlFreeUnicodeString(&pNameU);
4190 if (ret) {
4191 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4193 HeapFree(GetProcessHeap(), 0, pPrintersW);
4194 return ret;
4197 /*****************************************************************************
4198 * WINSPOOL_GetDriverInfoFromReg [internal]
4200 * Enters the information from the registry into the DRIVER_INFO struct
4202 * RETURNS
4203 * zero if the printer driver does not exist in the registry
4204 * (only if Level > 1) otherwise nonzero
4206 static BOOL WINSPOOL_GetDriverInfoFromReg(
4207 HKEY hkeyDrivers,
4208 LPWSTR DriverName,
4209 const printenv_t * env,
4210 DWORD Level,
4211 LPBYTE ptr, /* DRIVER_INFO */
4212 LPBYTE pDriverStrings, /* strings buffer */
4213 DWORD cbBuf, /* size of string buffer */
4214 LPDWORD pcbNeeded) /* space needed for str. */
4216 DWORD size, tmp;
4217 HKEY hkeyDriver;
4218 WCHAR driverdir[MAX_PATH];
4219 DWORD dirlen;
4220 LPBYTE strPtr = pDriverStrings;
4221 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4223 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4224 debugstr_w(DriverName), env,
4225 Level, di, pDriverStrings, cbBuf);
4227 if (di) ZeroMemory(di, di_sizeof[Level]);
4229 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4230 if (*pcbNeeded <= cbBuf)
4231 strcpyW((LPWSTR)strPtr, DriverName);
4233 /* pName for level 1 has a different offset! */
4234 if (Level == 1) {
4235 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4236 return TRUE;
4239 /* .cVersion and .pName for level > 1 */
4240 if (di) {
4241 di->cVersion = env->driverversion;
4242 di->pName = (LPWSTR) strPtr;
4243 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4246 /* Reserve Space for the largest subdir and a Backslash*/
4247 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4248 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4249 /* Should never Fail */
4250 return FALSE;
4252 lstrcatW(driverdir, env->versionsubdir);
4253 lstrcatW(driverdir, backslashW);
4255 /* dirlen must not include the terminating zero */
4256 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4258 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4259 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4260 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4261 return FALSE;
4264 /* pEnvironment */
4265 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4267 *pcbNeeded += size;
4268 if (*pcbNeeded <= cbBuf) {
4269 lstrcpyW((LPWSTR)strPtr, env->envname);
4270 if (di) di->pEnvironment = (LPWSTR)strPtr;
4271 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4274 /* .pDriverPath is the Graphics rendering engine.
4275 The full Path is required to avoid a crash in some apps */
4276 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4277 *pcbNeeded += size;
4278 if (*pcbNeeded <= cbBuf)
4279 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4281 if (di) di->pDriverPath = (LPWSTR)strPtr;
4282 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4285 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4286 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4287 *pcbNeeded += size;
4288 if (*pcbNeeded <= cbBuf)
4289 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4291 if (di) di->pDataFile = (LPWSTR)strPtr;
4292 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4295 /* .pConfigFile is the Driver user Interface */
4296 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4297 *pcbNeeded += size;
4298 if (*pcbNeeded <= cbBuf)
4299 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4301 if (di) di->pConfigFile = (LPWSTR)strPtr;
4302 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4305 if (Level == 2 ) {
4306 RegCloseKey(hkeyDriver);
4307 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4308 return TRUE;
4311 if (Level == 5 ) {
4312 RegCloseKey(hkeyDriver);
4313 FIXME("level 5: incomplete\n");
4314 return TRUE;
4317 /* .pHelpFile */
4318 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4319 *pcbNeeded += size;
4320 if (*pcbNeeded <= cbBuf)
4321 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4323 if (di) di->pHelpFile = (LPWSTR)strPtr;
4324 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4327 /* .pDependentFiles */
4328 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4329 *pcbNeeded += size;
4330 if (*pcbNeeded <= cbBuf)
4331 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4333 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4334 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4336 else if (GetVersion() & 0x80000000) {
4337 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4338 size = 2 * sizeof(WCHAR);
4339 *pcbNeeded += size;
4340 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4342 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4343 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4346 /* .pMonitorName is the optional Language Monitor */
4347 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4348 *pcbNeeded += size;
4349 if (*pcbNeeded <= cbBuf)
4350 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4352 if (di) di->pMonitorName = (LPWSTR)strPtr;
4353 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4356 /* .pDefaultDataType */
4357 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4358 *pcbNeeded += size;
4359 if(*pcbNeeded <= cbBuf)
4360 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4362 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4363 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4366 if (Level == 3 ) {
4367 RegCloseKey(hkeyDriver);
4368 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4369 return TRUE;
4372 /* .pszzPreviousNames */
4373 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4374 *pcbNeeded += size;
4375 if(*pcbNeeded <= cbBuf)
4376 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4378 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4379 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4382 if (Level == 4 ) {
4383 RegCloseKey(hkeyDriver);
4384 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4385 return TRUE;
4388 /* support is missing, but not important enough for a FIXME */
4389 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4391 /* .pszMfgName */
4392 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4393 *pcbNeeded += size;
4394 if(*pcbNeeded <= cbBuf)
4395 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4397 if (di) di->pszMfgName = (LPWSTR)strPtr;
4398 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4401 /* .pszOEMUrl */
4402 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4403 *pcbNeeded += size;
4404 if(*pcbNeeded <= cbBuf)
4405 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4407 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4408 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4411 /* .pszHardwareID */
4412 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4413 *pcbNeeded += size;
4414 if(*pcbNeeded <= cbBuf)
4415 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4417 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4418 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4421 /* .pszProvider */
4422 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4423 *pcbNeeded += size;
4424 if(*pcbNeeded <= cbBuf)
4425 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4427 if (di) di->pszProvider = (LPWSTR)strPtr;
4428 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4431 if (Level == 6 ) {
4432 RegCloseKey(hkeyDriver);
4433 return TRUE;
4436 /* support is missing, but not important enough for a FIXME */
4437 TRACE("level 8: incomplete\n");
4439 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4440 RegCloseKey(hkeyDriver);
4441 return TRUE;
4444 /*****************************************************************************
4445 * GetPrinterDriverW [WINSPOOL.@]
4447 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4448 DWORD Level, LPBYTE pDriverInfo,
4449 DWORD cbBuf, LPDWORD pcbNeeded)
4451 LPCWSTR name;
4452 WCHAR DriverName[100];
4453 DWORD ret, type, size, needed = 0;
4454 LPBYTE ptr = NULL;
4455 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4456 const printenv_t * env;
4458 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4459 Level,pDriverInfo,cbBuf, pcbNeeded);
4461 if (cbBuf > 0)
4462 ZeroMemory(pDriverInfo, cbBuf);
4464 if (!(name = get_opened_printer_name(hPrinter))) {
4465 SetLastError(ERROR_INVALID_HANDLE);
4466 return FALSE;
4469 if (Level < 1 || Level == 7 || Level > 8) {
4470 SetLastError(ERROR_INVALID_LEVEL);
4471 return FALSE;
4474 env = validate_envW(pEnvironment);
4475 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4477 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4478 ERROR_SUCCESS) {
4479 ERR("Can't create Printers key\n");
4480 return FALSE;
4482 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4483 != ERROR_SUCCESS) {
4484 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4485 RegCloseKey(hkeyPrinters);
4486 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4487 return FALSE;
4489 size = sizeof(DriverName);
4490 DriverName[0] = 0;
4491 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4492 (LPBYTE)DriverName, &size);
4493 RegCloseKey(hkeyPrinter);
4494 RegCloseKey(hkeyPrinters);
4495 if(ret != ERROR_SUCCESS) {
4496 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4497 return FALSE;
4500 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4501 if(!hkeyDrivers) {
4502 ERR("Can't create Drivers key\n");
4503 return FALSE;
4506 size = di_sizeof[Level];
4507 if ((size <= cbBuf) && pDriverInfo)
4508 ptr = pDriverInfo + size;
4510 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4511 env, Level, pDriverInfo, ptr,
4512 (cbBuf < size) ? 0 : cbBuf - size,
4513 &needed)) {
4514 RegCloseKey(hkeyDrivers);
4515 return FALSE;
4518 RegCloseKey(hkeyDrivers);
4520 if(pcbNeeded) *pcbNeeded = size + needed;
4521 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4522 if(cbBuf >= size + needed) return TRUE;
4523 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4524 return FALSE;
4527 /*****************************************************************************
4528 * GetPrinterDriverA [WINSPOOL.@]
4530 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4531 DWORD Level, LPBYTE pDriverInfo,
4532 DWORD cbBuf, LPDWORD pcbNeeded)
4534 BOOL ret;
4535 UNICODE_STRING pEnvW;
4536 PWSTR pwstrEnvW;
4537 LPBYTE buf = NULL;
4539 if (cbBuf)
4541 ZeroMemory(pDriverInfo, cbBuf);
4542 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4545 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4546 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4547 cbBuf, pcbNeeded);
4548 if (ret)
4549 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4551 HeapFree(GetProcessHeap(), 0, buf);
4553 RtlFreeUnicodeString(&pEnvW);
4554 return ret;
4557 /*****************************************************************************
4558 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4560 * Return the PATH for the Printer-Drivers (UNICODE)
4562 * PARAMS
4563 * pName [I] Servername (NT only) or NULL (local Computer)
4564 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4565 * Level [I] Structure-Level (must be 1)
4566 * pDriverDirectory [O] PTR to Buffer that receives the Result
4567 * cbBuf [I] Size of Buffer at pDriverDirectory
4568 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4569 * required for pDriverDirectory
4571 * RETURNS
4572 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4573 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4574 * if cbBuf is too small
4576 * Native Values returned in pDriverDirectory on Success:
4577 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4578 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4579 *| win9x(Windows 4.0): "%winsysdir%"
4581 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4583 * FIXME
4584 *- Only NULL or "" is supported for pName
4587 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4588 DWORD Level, LPBYTE pDriverDirectory,
4589 DWORD cbBuf, LPDWORD pcbNeeded)
4591 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4592 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4594 if ((backend == NULL) && !load_backend()) return FALSE;
4596 if (Level != 1) {
4597 /* (Level != 1) is ignored in win9x */
4598 SetLastError(ERROR_INVALID_LEVEL);
4599 return FALSE;
4601 if (pcbNeeded == NULL) {
4602 /* (pcbNeeded == NULL) is ignored in win9x */
4603 SetLastError(RPC_X_NULL_REF_POINTER);
4604 return FALSE;
4607 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4608 pDriverDirectory, cbBuf, pcbNeeded);
4613 /*****************************************************************************
4614 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4616 * Return the PATH for the Printer-Drivers (ANSI)
4618 * See GetPrinterDriverDirectoryW.
4620 * NOTES
4621 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4624 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4625 DWORD Level, LPBYTE pDriverDirectory,
4626 DWORD cbBuf, LPDWORD pcbNeeded)
4628 UNICODE_STRING nameW, environmentW;
4629 BOOL ret;
4630 DWORD pcbNeededW;
4631 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4632 WCHAR *driverDirectoryW = NULL;
4634 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4635 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4637 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4639 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4640 else nameW.Buffer = NULL;
4641 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4642 else environmentW.Buffer = NULL;
4644 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4645 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4646 if (ret) {
4647 DWORD needed;
4648 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4649 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4650 if(pcbNeeded)
4651 *pcbNeeded = needed;
4652 ret = (needed <= cbBuf) ? TRUE : FALSE;
4653 } else
4654 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4656 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4658 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4659 RtlFreeUnicodeString(&environmentW);
4660 RtlFreeUnicodeString(&nameW);
4662 return ret;
4665 /*****************************************************************************
4666 * AddPrinterDriverA [WINSPOOL.@]
4668 * See AddPrinterDriverW.
4671 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4673 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4674 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4677 /******************************************************************************
4678 * AddPrinterDriverW (WINSPOOL.@)
4680 * Install a Printer Driver
4682 * PARAMS
4683 * pName [I] Servername or NULL (local Computer)
4684 * level [I] Level for the supplied DRIVER_INFO_*W struct
4685 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4687 * RESULTS
4688 * Success: TRUE
4689 * Failure: FALSE
4692 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4694 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4695 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4698 /*****************************************************************************
4699 * AddPrintProcessorA [WINSPOOL.@]
4701 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4702 LPSTR pPrintProcessorName)
4704 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4705 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4706 return FALSE;
4709 /*****************************************************************************
4710 * AddPrintProcessorW [WINSPOOL.@]
4712 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4713 LPWSTR pPrintProcessorName)
4715 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4716 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4717 return TRUE;
4720 /*****************************************************************************
4721 * AddPrintProvidorA [WINSPOOL.@]
4723 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4725 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4726 return FALSE;
4729 /*****************************************************************************
4730 * AddPrintProvidorW [WINSPOOL.@]
4732 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4734 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4735 return FALSE;
4738 /*****************************************************************************
4739 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4741 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4742 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4744 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4745 pDevModeOutput, pDevModeInput);
4746 return 0;
4749 /*****************************************************************************
4750 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4752 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4753 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4755 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4756 pDevModeOutput, pDevModeInput);
4757 return 0;
4760 /*****************************************************************************
4761 * PrinterProperties [WINSPOOL.@]
4763 * Displays a dialog to set the properties of the printer.
4765 * RETURNS
4766 * nonzero on success or zero on failure
4768 * BUGS
4769 * implemented as stub only
4771 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4772 HANDLE hPrinter /* [in] handle to printer object */
4774 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4775 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4776 return FALSE;
4779 /*****************************************************************************
4780 * EnumJobsA [WINSPOOL.@]
4783 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4784 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4785 LPDWORD pcReturned)
4787 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4788 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4790 if(pcbNeeded) *pcbNeeded = 0;
4791 if(pcReturned) *pcReturned = 0;
4792 return FALSE;
4796 /*****************************************************************************
4797 * EnumJobsW [WINSPOOL.@]
4800 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4801 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4802 LPDWORD pcReturned)
4804 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4805 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4807 if(pcbNeeded) *pcbNeeded = 0;
4808 if(pcReturned) *pcReturned = 0;
4809 return FALSE;
4812 /*****************************************************************************
4813 * WINSPOOL_EnumPrinterDrivers [internal]
4815 * Delivers information about all printer drivers installed on the
4816 * localhost or a given server
4818 * RETURNS
4819 * nonzero on success or zero on failure. If the buffer for the returned
4820 * information is too small the function will return an error
4822 * BUGS
4823 * - only implemented for localhost, foreign hosts will return an error
4825 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4826 DWORD Level, LPBYTE pDriverInfo,
4827 DWORD driver_index,
4828 DWORD cbBuf, LPDWORD pcbNeeded,
4829 LPDWORD pcFound, DWORD data_offset)
4831 { HKEY hkeyDrivers;
4832 DWORD i, size = 0;
4833 const printenv_t * env;
4835 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4836 debugstr_w(pName), debugstr_w(pEnvironment),
4837 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4839 env = validate_envW(pEnvironment);
4840 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4842 *pcFound = 0;
4844 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4845 if(!hkeyDrivers) {
4846 ERR("Can't open Drivers key\n");
4847 return FALSE;
4850 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4851 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4852 RegCloseKey(hkeyDrivers);
4853 ERR("Can't query Drivers key\n");
4854 return FALSE;
4856 TRACE("Found %d Drivers\n", *pcFound);
4858 /* get size of single struct
4859 * unicode and ascii structure have the same size
4861 size = di_sizeof[Level];
4863 if (data_offset == 0)
4864 data_offset = size * (*pcFound);
4865 *pcbNeeded = data_offset;
4867 for( i = 0; i < *pcFound; i++) {
4868 WCHAR DriverNameW[255];
4869 PBYTE table_ptr = NULL;
4870 PBYTE data_ptr = NULL;
4871 DWORD needed = 0;
4873 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4874 != ERROR_SUCCESS) {
4875 ERR("Can't enum key number %d\n", i);
4876 RegCloseKey(hkeyDrivers);
4877 return FALSE;
4880 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4881 table_ptr = pDriverInfo + (driver_index + i) * size;
4882 if (pDriverInfo && *pcbNeeded <= cbBuf)
4883 data_ptr = pDriverInfo + *pcbNeeded;
4885 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4886 env, Level, table_ptr, data_ptr,
4887 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4888 &needed)) {
4889 RegCloseKey(hkeyDrivers);
4890 return FALSE;
4893 *pcbNeeded += needed;
4896 RegCloseKey(hkeyDrivers);
4898 if(cbBuf < *pcbNeeded){
4899 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4900 return FALSE;
4903 return TRUE;
4906 /*****************************************************************************
4907 * EnumPrinterDriversW [WINSPOOL.@]
4909 * see function EnumPrinterDrivers for RETURNS, BUGS
4911 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4912 LPBYTE pDriverInfo, DWORD cbBuf,
4913 LPDWORD pcbNeeded, LPDWORD pcReturned)
4915 static const WCHAR allW[] = {'a','l','l',0};
4916 BOOL ret;
4917 DWORD found;
4919 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4921 SetLastError(RPC_X_NULL_REF_POINTER);
4922 return FALSE;
4925 /* check for local drivers */
4926 if((pName) && (pName[0])) {
4927 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4928 SetLastError(ERROR_ACCESS_DENIED);
4929 return FALSE;
4932 /* check input parameter */
4933 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4934 SetLastError(ERROR_INVALID_LEVEL);
4935 return FALSE;
4938 if(pDriverInfo && cbBuf > 0)
4939 memset( pDriverInfo, 0, cbBuf);
4941 /* Exception: pull all printers */
4942 if (pEnvironment && !strcmpW(pEnvironment, allW))
4944 DWORD i, needed, bufsize = cbBuf;
4945 DWORD total_needed = 0;
4946 DWORD total_found = 0;
4947 DWORD data_offset;
4949 /* Precompute the overall total; we need this to know
4950 where pointers end and data begins (i.e. data_offset) */
4951 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4953 needed = found = 0;
4954 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4955 NULL, 0, 0, &needed, &found, 0);
4956 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4957 total_needed += needed;
4958 total_found += found;
4961 data_offset = di_sizeof[Level] * total_found;
4963 *pcReturned = 0;
4964 *pcbNeeded = 0;
4965 total_found = 0;
4966 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4968 needed = found = 0;
4969 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4970 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4971 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4972 else if (ret)
4973 *pcReturned += found;
4974 *pcbNeeded = needed;
4975 data_offset = needed;
4976 total_found += found;
4978 return ret;
4981 /* Normal behavior */
4982 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4983 0, cbBuf, pcbNeeded, &found, 0);
4984 if (ret)
4985 *pcReturned = found;
4987 return ret;
4990 /*****************************************************************************
4991 * EnumPrinterDriversA [WINSPOOL.@]
4993 * see function EnumPrinterDrivers for RETURNS, BUGS
4995 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4996 LPBYTE pDriverInfo, DWORD cbBuf,
4997 LPDWORD pcbNeeded, LPDWORD pcReturned)
4999 BOOL ret;
5000 UNICODE_STRING pNameW, pEnvironmentW;
5001 PWSTR pwstrNameW, pwstrEnvironmentW;
5002 LPBYTE buf = NULL;
5004 if (cbBuf)
5005 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5007 pwstrNameW = asciitounicode(&pNameW, pName);
5008 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5010 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5011 buf, cbBuf, pcbNeeded, pcReturned);
5012 if (ret)
5013 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5015 HeapFree(GetProcessHeap(), 0, buf);
5017 RtlFreeUnicodeString(&pNameW);
5018 RtlFreeUnicodeString(&pEnvironmentW);
5020 return ret;
5023 /******************************************************************************
5024 * EnumPortsA (WINSPOOL.@)
5026 * See EnumPortsW.
5029 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5030 LPDWORD pcbNeeded, LPDWORD pcReturned)
5032 BOOL res;
5033 LPBYTE bufferW = NULL;
5034 LPWSTR nameW = NULL;
5035 DWORD needed = 0;
5036 DWORD numentries = 0;
5037 INT len;
5039 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5040 cbBuf, pcbNeeded, pcReturned);
5042 /* convert servername to unicode */
5043 if (pName) {
5044 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5045 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5046 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5048 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5049 needed = cbBuf * sizeof(WCHAR);
5050 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5051 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5053 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5054 if (pcbNeeded) needed = *pcbNeeded;
5055 /* HeapReAlloc return NULL, when bufferW was NULL */
5056 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5057 HeapAlloc(GetProcessHeap(), 0, needed);
5059 /* Try again with the large Buffer */
5060 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5062 needed = pcbNeeded ? *pcbNeeded : 0;
5063 numentries = pcReturned ? *pcReturned : 0;
5066 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5067 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5069 if (res) {
5070 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5071 DWORD entrysize = 0;
5072 DWORD index;
5073 LPSTR ptr;
5074 LPPORT_INFO_2W pi2w;
5075 LPPORT_INFO_2A pi2a;
5077 needed = 0;
5078 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5080 /* First pass: calculate the size for all Entries */
5081 pi2w = (LPPORT_INFO_2W) bufferW;
5082 pi2a = (LPPORT_INFO_2A) pPorts;
5083 index = 0;
5084 while (index < numentries) {
5085 index++;
5086 needed += entrysize; /* PORT_INFO_?A */
5087 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5089 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5090 NULL, 0, NULL, NULL);
5091 if (Level > 1) {
5092 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5093 NULL, 0, NULL, NULL);
5094 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5095 NULL, 0, NULL, NULL);
5097 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5098 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5099 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5102 /* check for errors and quit on failure */
5103 if (cbBuf < needed) {
5104 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5105 res = FALSE;
5106 goto cleanup;
5108 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5109 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5110 cbBuf -= len ; /* free Bytes in the user-Buffer */
5111 pi2w = (LPPORT_INFO_2W) bufferW;
5112 pi2a = (LPPORT_INFO_2A) pPorts;
5113 index = 0;
5114 /* Second Pass: Fill the User Buffer (if we have one) */
5115 while ((index < numentries) && pPorts) {
5116 index++;
5117 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5118 pi2a->pPortName = ptr;
5119 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5120 ptr, cbBuf , NULL, NULL);
5121 ptr += len;
5122 cbBuf -= len;
5123 if (Level > 1) {
5124 pi2a->pMonitorName = ptr;
5125 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5126 ptr, cbBuf, NULL, NULL);
5127 ptr += len;
5128 cbBuf -= len;
5130 pi2a->pDescription = ptr;
5131 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5132 ptr, cbBuf, NULL, NULL);
5133 ptr += len;
5134 cbBuf -= len;
5136 pi2a->fPortType = pi2w->fPortType;
5137 pi2a->Reserved = 0; /* documented: "must be zero" */
5140 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5141 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5142 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5146 cleanup:
5147 if (pcbNeeded) *pcbNeeded = needed;
5148 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5150 HeapFree(GetProcessHeap(), 0, nameW);
5151 HeapFree(GetProcessHeap(), 0, bufferW);
5153 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5154 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5156 return (res);
5160 /******************************************************************************
5161 * EnumPortsW (WINSPOOL.@)
5163 * Enumerate available Ports
5165 * PARAMS
5166 * pName [I] Servername or NULL (local Computer)
5167 * Level [I] Structure-Level (1 or 2)
5168 * pPorts [O] PTR to Buffer that receives the Result
5169 * cbBuf [I] Size of Buffer at pPorts
5170 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5171 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5173 * RETURNS
5174 * Success: TRUE
5175 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5178 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5181 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5182 cbBuf, pcbNeeded, pcReturned);
5184 if ((backend == NULL) && !load_backend()) return FALSE;
5186 /* Level is not checked in win9x */
5187 if (!Level || (Level > 2)) {
5188 WARN("level (%d) is ignored in win9x\n", Level);
5189 SetLastError(ERROR_INVALID_LEVEL);
5190 return FALSE;
5192 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5193 SetLastError(RPC_X_NULL_REF_POINTER);
5194 return FALSE;
5197 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5200 /******************************************************************************
5201 * GetDefaultPrinterW (WINSPOOL.@)
5203 * FIXME
5204 * This function must read the value from data 'device' of key
5205 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5207 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5209 BOOL retval = TRUE;
5210 DWORD insize, len;
5211 WCHAR *buffer, *ptr;
5213 if (!namesize)
5215 SetLastError(ERROR_INVALID_PARAMETER);
5216 return FALSE;
5219 /* make the buffer big enough for the stuff from the profile/registry,
5220 * the content must fit into the local buffer to compute the correct
5221 * size even if the extern buffer is too small or not given.
5222 * (20 for ,driver,port) */
5223 insize = *namesize;
5224 len = max(100, (insize + 20));
5225 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5227 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5229 SetLastError (ERROR_FILE_NOT_FOUND);
5230 retval = FALSE;
5231 goto end;
5233 TRACE("%s\n", debugstr_w(buffer));
5235 if ((ptr = strchrW(buffer, ',')) == NULL)
5237 SetLastError(ERROR_INVALID_NAME);
5238 retval = FALSE;
5239 goto end;
5242 *ptr = 0;
5243 *namesize = strlenW(buffer) + 1;
5244 if(!name || (*namesize > insize))
5246 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5247 retval = FALSE;
5248 goto end;
5250 strcpyW(name, buffer);
5252 end:
5253 HeapFree( GetProcessHeap(), 0, buffer);
5254 return retval;
5258 /******************************************************************************
5259 * GetDefaultPrinterA (WINSPOOL.@)
5261 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5263 BOOL retval = TRUE;
5264 DWORD insize = 0;
5265 WCHAR *bufferW = NULL;
5267 if (!namesize)
5269 SetLastError(ERROR_INVALID_PARAMETER);
5270 return FALSE;
5273 if(name && *namesize) {
5274 insize = *namesize;
5275 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5278 if(!GetDefaultPrinterW( bufferW, namesize)) {
5279 retval = FALSE;
5280 goto end;
5283 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5284 NULL, NULL);
5285 if (!*namesize)
5287 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5288 retval = FALSE;
5290 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5292 end:
5293 HeapFree( GetProcessHeap(), 0, bufferW);
5294 return retval;
5298 /******************************************************************************
5299 * SetDefaultPrinterW (WINSPOOL.204)
5301 * Set the Name of the Default Printer
5303 * PARAMS
5304 * pszPrinter [I] Name of the Printer or NULL
5306 * RETURNS
5307 * Success: True
5308 * Failure: FALSE
5310 * NOTES
5311 * When the Parameter is NULL or points to an Empty String and
5312 * a Default Printer was already present, then this Function changes nothing.
5313 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5314 * the First enumerated local Printer is used.
5317 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5319 WCHAR default_printer[MAX_PATH];
5320 LPWSTR buffer = NULL;
5321 HKEY hreg;
5322 DWORD size;
5323 DWORD namelen;
5324 LONG lres;
5326 TRACE("(%s)\n", debugstr_w(pszPrinter));
5327 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5329 default_printer[0] = '\0';
5330 size = sizeof(default_printer)/sizeof(WCHAR);
5332 /* if we have a default Printer, do nothing. */
5333 if (GetDefaultPrinterW(default_printer, &size))
5334 return TRUE;
5336 pszPrinter = NULL;
5337 /* we have no default Printer: search local Printers and use the first */
5338 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5340 default_printer[0] = '\0';
5341 size = sizeof(default_printer)/sizeof(WCHAR);
5342 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5344 pszPrinter = default_printer;
5345 TRACE("using %s\n", debugstr_w(pszPrinter));
5347 RegCloseKey(hreg);
5350 if (pszPrinter == NULL) {
5351 TRACE("no local printer found\n");
5352 SetLastError(ERROR_FILE_NOT_FOUND);
5353 return FALSE;
5357 /* "pszPrinter" is never empty or NULL here. */
5358 namelen = lstrlenW(pszPrinter);
5359 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5360 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5361 if (!buffer ||
5362 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5363 HeapFree(GetProcessHeap(), 0, buffer);
5364 SetLastError(ERROR_FILE_NOT_FOUND);
5365 return FALSE;
5368 /* read the devices entry for the printer (driver,port) to build the string for the
5369 default device entry (printer,driver,port) */
5370 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5371 buffer[namelen] = ',';
5372 namelen++; /* move index to the start of the driver */
5374 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5375 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5376 if (!lres) {
5377 TRACE("set device to %s\n", debugstr_w(buffer));
5379 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5380 TRACE("failed to set the device entry: %d\n", GetLastError());
5381 lres = ERROR_INVALID_PRINTER_NAME;
5384 /* remove the next section, when INIFileMapping is implemented */
5386 HKEY hdev;
5387 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5388 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5389 RegCloseKey(hdev);
5393 else
5395 if (lres != ERROR_FILE_NOT_FOUND)
5396 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5398 SetLastError(ERROR_INVALID_PRINTER_NAME);
5401 RegCloseKey(hreg);
5402 HeapFree(GetProcessHeap(), 0, buffer);
5403 return (lres == ERROR_SUCCESS);
5406 /******************************************************************************
5407 * SetDefaultPrinterA (WINSPOOL.202)
5409 * See SetDefaultPrinterW.
5412 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5414 LPWSTR bufferW = NULL;
5415 BOOL res;
5417 TRACE("(%s)\n", debugstr_a(pszPrinter));
5418 if(pszPrinter) {
5419 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5420 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5421 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5423 res = SetDefaultPrinterW(bufferW);
5424 HeapFree(GetProcessHeap(), 0, bufferW);
5425 return res;
5428 /******************************************************************************
5429 * SetPrinterDataExA (WINSPOOL.@)
5431 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5432 LPCSTR pValueName, DWORD Type,
5433 LPBYTE pData, DWORD cbData)
5435 HKEY hkeyPrinter, hkeySubkey;
5436 DWORD ret;
5438 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5439 debugstr_a(pValueName), Type, pData, cbData);
5441 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5442 != ERROR_SUCCESS)
5443 return ret;
5445 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5446 != ERROR_SUCCESS) {
5447 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5448 RegCloseKey(hkeyPrinter);
5449 return ret;
5451 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5452 RegCloseKey(hkeySubkey);
5453 RegCloseKey(hkeyPrinter);
5454 return ret;
5457 /******************************************************************************
5458 * SetPrinterDataExW (WINSPOOL.@)
5460 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5461 LPCWSTR pValueName, DWORD Type,
5462 LPBYTE pData, DWORD cbData)
5464 HKEY hkeyPrinter, hkeySubkey;
5465 DWORD ret;
5467 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5468 debugstr_w(pValueName), Type, pData, cbData);
5470 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5471 != ERROR_SUCCESS)
5472 return ret;
5474 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5475 != ERROR_SUCCESS) {
5476 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5477 RegCloseKey(hkeyPrinter);
5478 return ret;
5480 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5481 RegCloseKey(hkeySubkey);
5482 RegCloseKey(hkeyPrinter);
5483 return ret;
5486 /******************************************************************************
5487 * SetPrinterDataA (WINSPOOL.@)
5489 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5490 LPBYTE pData, DWORD cbData)
5492 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5493 pData, cbData);
5496 /******************************************************************************
5497 * SetPrinterDataW (WINSPOOL.@)
5499 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5500 LPBYTE pData, DWORD cbData)
5502 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5503 pData, cbData);
5506 /******************************************************************************
5507 * GetPrinterDataExA (WINSPOOL.@)
5509 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5510 LPCSTR pValueName, LPDWORD pType,
5511 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5513 opened_printer_t *printer;
5514 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5515 DWORD ret;
5517 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5518 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5520 printer = get_opened_printer(hPrinter);
5521 if(!printer) return ERROR_INVALID_HANDLE;
5523 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5524 if (ret) return ret;
5526 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5528 if (printer->name) {
5530 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5531 if (ret) {
5532 RegCloseKey(hkeyPrinters);
5533 return ret;
5535 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5536 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5537 RegCloseKey(hkeyPrinter);
5538 RegCloseKey(hkeyPrinters);
5539 return ret;
5542 *pcbNeeded = nSize;
5543 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5544 0, pType, pData, pcbNeeded);
5546 if (!ret && !pData) ret = ERROR_MORE_DATA;
5548 RegCloseKey(hkeySubkey);
5549 RegCloseKey(hkeyPrinter);
5550 RegCloseKey(hkeyPrinters);
5552 TRACE("--> %d\n", ret);
5553 return ret;
5556 /******************************************************************************
5557 * GetPrinterDataExW (WINSPOOL.@)
5559 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5560 LPCWSTR pValueName, LPDWORD pType,
5561 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5563 opened_printer_t *printer;
5564 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5565 DWORD ret;
5567 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5568 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5570 printer = get_opened_printer(hPrinter);
5571 if(!printer) return ERROR_INVALID_HANDLE;
5573 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5574 if (ret) return ret;
5576 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5578 if (printer->name) {
5580 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5581 if (ret) {
5582 RegCloseKey(hkeyPrinters);
5583 return ret;
5585 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5586 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5587 RegCloseKey(hkeyPrinter);
5588 RegCloseKey(hkeyPrinters);
5589 return ret;
5592 *pcbNeeded = nSize;
5593 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5594 0, pType, pData, pcbNeeded);
5596 if (!ret && !pData) ret = ERROR_MORE_DATA;
5598 RegCloseKey(hkeySubkey);
5599 RegCloseKey(hkeyPrinter);
5600 RegCloseKey(hkeyPrinters);
5602 TRACE("--> %d\n", ret);
5603 return ret;
5606 /******************************************************************************
5607 * GetPrinterDataA (WINSPOOL.@)
5609 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5610 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5612 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5613 pData, nSize, pcbNeeded);
5616 /******************************************************************************
5617 * GetPrinterDataW (WINSPOOL.@)
5619 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5620 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5622 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5623 pData, nSize, pcbNeeded);
5626 /*******************************************************************************
5627 * EnumPrinterDataExW [WINSPOOL.@]
5629 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5630 LPBYTE pEnumValues, DWORD cbEnumValues,
5631 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5633 HKEY hkPrinter, hkSubKey;
5634 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5635 cbValueNameLen, cbMaxValueLen, cbValueLen,
5636 cbBufSize, dwType;
5637 LPWSTR lpValueName;
5638 HANDLE hHeap;
5639 PBYTE lpValue;
5640 PPRINTER_ENUM_VALUESW ppev;
5642 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5644 if (pKeyName == NULL || *pKeyName == 0)
5645 return ERROR_INVALID_PARAMETER;
5647 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5648 if (ret != ERROR_SUCCESS)
5650 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5651 hPrinter, ret);
5652 return ret;
5655 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5656 if (ret != ERROR_SUCCESS)
5658 r = RegCloseKey (hkPrinter);
5659 if (r != ERROR_SUCCESS)
5660 WARN ("RegCloseKey returned %i\n", r);
5661 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5662 debugstr_w (pKeyName), ret);
5663 return ret;
5666 ret = RegCloseKey (hkPrinter);
5667 if (ret != ERROR_SUCCESS)
5669 ERR ("RegCloseKey returned %i\n", ret);
5670 r = RegCloseKey (hkSubKey);
5671 if (r != ERROR_SUCCESS)
5672 WARN ("RegCloseKey returned %i\n", r);
5673 return ret;
5676 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5677 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5678 if (ret != ERROR_SUCCESS)
5680 r = RegCloseKey (hkSubKey);
5681 if (r != ERROR_SUCCESS)
5682 WARN ("RegCloseKey returned %i\n", r);
5683 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5684 return ret;
5687 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5688 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5690 if (cValues == 0) /* empty key */
5692 r = RegCloseKey (hkSubKey);
5693 if (r != ERROR_SUCCESS)
5694 WARN ("RegCloseKey returned %i\n", r);
5695 *pcbEnumValues = *pnEnumValues = 0;
5696 return ERROR_SUCCESS;
5699 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5701 hHeap = GetProcessHeap ();
5702 if (hHeap == NULL)
5704 ERR ("GetProcessHeap failed\n");
5705 r = RegCloseKey (hkSubKey);
5706 if (r != ERROR_SUCCESS)
5707 WARN ("RegCloseKey returned %i\n", r);
5708 return ERROR_OUTOFMEMORY;
5711 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5712 if (lpValueName == NULL)
5714 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5715 r = RegCloseKey (hkSubKey);
5716 if (r != ERROR_SUCCESS)
5717 WARN ("RegCloseKey returned %i\n", r);
5718 return ERROR_OUTOFMEMORY;
5721 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5722 if (lpValue == NULL)
5724 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5725 if (HeapFree (hHeap, 0, lpValueName) == 0)
5726 WARN ("HeapFree failed with code %i\n", GetLastError ());
5727 r = RegCloseKey (hkSubKey);
5728 if (r != ERROR_SUCCESS)
5729 WARN ("RegCloseKey returned %i\n", r);
5730 return ERROR_OUTOFMEMORY;
5733 TRACE ("pass 1: calculating buffer required for all names and values\n");
5735 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5737 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5739 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5741 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5742 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5743 NULL, NULL, lpValue, &cbValueLen);
5744 if (ret != ERROR_SUCCESS)
5746 if (HeapFree (hHeap, 0, lpValue) == 0)
5747 WARN ("HeapFree failed with code %i\n", GetLastError ());
5748 if (HeapFree (hHeap, 0, lpValueName) == 0)
5749 WARN ("HeapFree failed with code %i\n", GetLastError ());
5750 r = RegCloseKey (hkSubKey);
5751 if (r != ERROR_SUCCESS)
5752 WARN ("RegCloseKey returned %i\n", r);
5753 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5754 return ret;
5757 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5758 debugstr_w (lpValueName), dwIndex,
5759 cbValueNameLen + 1, cbValueLen);
5761 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5762 cbBufSize += cbValueLen;
5765 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5767 *pcbEnumValues = cbBufSize;
5768 *pnEnumValues = cValues;
5770 if (cbEnumValues < cbBufSize) /* buffer too small */
5772 if (HeapFree (hHeap, 0, lpValue) == 0)
5773 WARN ("HeapFree failed with code %i\n", GetLastError ());
5774 if (HeapFree (hHeap, 0, lpValueName) == 0)
5775 WARN ("HeapFree failed with code %i\n", GetLastError ());
5776 r = RegCloseKey (hkSubKey);
5777 if (r != ERROR_SUCCESS)
5778 WARN ("RegCloseKey returned %i\n", r);
5779 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5780 return ERROR_MORE_DATA;
5783 TRACE ("pass 2: copying all names and values to buffer\n");
5785 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5786 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5788 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5790 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5791 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5792 NULL, &dwType, lpValue, &cbValueLen);
5793 if (ret != ERROR_SUCCESS)
5795 if (HeapFree (hHeap, 0, lpValue) == 0)
5796 WARN ("HeapFree failed with code %i\n", GetLastError ());
5797 if (HeapFree (hHeap, 0, lpValueName) == 0)
5798 WARN ("HeapFree failed with code %i\n", GetLastError ());
5799 r = RegCloseKey (hkSubKey);
5800 if (r != ERROR_SUCCESS)
5801 WARN ("RegCloseKey returned %i\n", r);
5802 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5803 return ret;
5806 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5807 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5808 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5809 pEnumValues += cbValueNameLen;
5811 /* return # of *bytes* (including trailing \0), not # of chars */
5812 ppev[dwIndex].cbValueName = cbValueNameLen;
5814 ppev[dwIndex].dwType = dwType;
5816 memcpy (pEnumValues, lpValue, cbValueLen);
5817 ppev[dwIndex].pData = pEnumValues;
5818 pEnumValues += cbValueLen;
5820 ppev[dwIndex].cbData = cbValueLen;
5822 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5823 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5826 if (HeapFree (hHeap, 0, lpValue) == 0)
5828 ret = GetLastError ();
5829 ERR ("HeapFree failed with code %i\n", ret);
5830 if (HeapFree (hHeap, 0, lpValueName) == 0)
5831 WARN ("HeapFree failed with code %i\n", GetLastError ());
5832 r = RegCloseKey (hkSubKey);
5833 if (r != ERROR_SUCCESS)
5834 WARN ("RegCloseKey returned %i\n", r);
5835 return ret;
5838 if (HeapFree (hHeap, 0, lpValueName) == 0)
5840 ret = GetLastError ();
5841 ERR ("HeapFree failed with code %i\n", ret);
5842 r = RegCloseKey (hkSubKey);
5843 if (r != ERROR_SUCCESS)
5844 WARN ("RegCloseKey returned %i\n", r);
5845 return ret;
5848 ret = RegCloseKey (hkSubKey);
5849 if (ret != ERROR_SUCCESS)
5851 ERR ("RegCloseKey returned %i\n", ret);
5852 return ret;
5855 return ERROR_SUCCESS;
5858 /*******************************************************************************
5859 * EnumPrinterDataExA [WINSPOOL.@]
5861 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5862 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5863 * what Windows 2000 SP1 does.
5866 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5867 LPBYTE pEnumValues, DWORD cbEnumValues,
5868 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5870 INT len;
5871 LPWSTR pKeyNameW;
5872 DWORD ret, dwIndex, dwBufSize;
5873 HANDLE hHeap;
5874 LPSTR pBuffer;
5876 TRACE ("%p %s\n", hPrinter, pKeyName);
5878 if (pKeyName == NULL || *pKeyName == 0)
5879 return ERROR_INVALID_PARAMETER;
5881 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5882 if (len == 0)
5884 ret = GetLastError ();
5885 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5886 return ret;
5889 hHeap = GetProcessHeap ();
5890 if (hHeap == NULL)
5892 ERR ("GetProcessHeap failed\n");
5893 return ERROR_OUTOFMEMORY;
5896 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5897 if (pKeyNameW == NULL)
5899 ERR ("Failed to allocate %i bytes from process heap\n",
5900 (LONG)(len * sizeof (WCHAR)));
5901 return ERROR_OUTOFMEMORY;
5904 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5906 ret = GetLastError ();
5907 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5908 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5909 WARN ("HeapFree failed with code %i\n", GetLastError ());
5910 return ret;
5913 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5914 pcbEnumValues, pnEnumValues);
5915 if (ret != ERROR_SUCCESS)
5917 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5918 WARN ("HeapFree failed with code %i\n", GetLastError ());
5919 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5920 return ret;
5923 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5925 ret = GetLastError ();
5926 ERR ("HeapFree failed with code %i\n", ret);
5927 return ret;
5930 if (*pnEnumValues == 0) /* empty key */
5931 return ERROR_SUCCESS;
5933 dwBufSize = 0;
5934 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5936 PPRINTER_ENUM_VALUESW ppev =
5937 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5939 if (dwBufSize < ppev->cbValueName)
5940 dwBufSize = ppev->cbValueName;
5942 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5943 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5944 dwBufSize = ppev->cbData;
5947 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5949 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5950 if (pBuffer == NULL)
5952 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5953 return ERROR_OUTOFMEMORY;
5956 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5958 PPRINTER_ENUM_VALUESW ppev =
5959 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5961 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5962 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5963 NULL);
5964 if (len == 0)
5966 ret = GetLastError ();
5967 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5968 if (HeapFree (hHeap, 0, pBuffer) == 0)
5969 WARN ("HeapFree failed with code %i\n", GetLastError ());
5970 return ret;
5973 memcpy (ppev->pValueName, pBuffer, len);
5975 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5977 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5978 ppev->dwType != REG_MULTI_SZ)
5979 continue;
5981 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5982 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5983 if (len == 0)
5985 ret = GetLastError ();
5986 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5987 if (HeapFree (hHeap, 0, pBuffer) == 0)
5988 WARN ("HeapFree failed with code %i\n", GetLastError ());
5989 return ret;
5992 memcpy (ppev->pData, pBuffer, len);
5994 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5995 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5998 if (HeapFree (hHeap, 0, pBuffer) == 0)
6000 ret = GetLastError ();
6001 ERR ("HeapFree failed with code %i\n", ret);
6002 return ret;
6005 return ERROR_SUCCESS;
6008 /******************************************************************************
6009 * AbortPrinter (WINSPOOL.@)
6011 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6013 FIXME("(%p), stub!\n", hPrinter);
6014 return TRUE;
6017 /******************************************************************************
6018 * AddPortA (WINSPOOL.@)
6020 * See AddPortW.
6023 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6025 LPWSTR nameW = NULL;
6026 LPWSTR monitorW = NULL;
6027 DWORD len;
6028 BOOL res;
6030 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6032 if (pName) {
6033 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6034 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6035 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6038 if (pMonitorName) {
6039 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6040 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6041 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6043 res = AddPortW(nameW, hWnd, monitorW);
6044 HeapFree(GetProcessHeap(), 0, nameW);
6045 HeapFree(GetProcessHeap(), 0, monitorW);
6046 return res;
6049 /******************************************************************************
6050 * AddPortW (WINSPOOL.@)
6052 * Add a Port for a specific Monitor
6054 * PARAMS
6055 * pName [I] Servername or NULL (local Computer)
6056 * hWnd [I] Handle to parent Window for the Dialog-Box
6057 * pMonitorName [I] Name of the Monitor that manage the Port
6059 * RETURNS
6060 * Success: TRUE
6061 * Failure: FALSE
6064 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6066 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6068 if ((backend == NULL) && !load_backend()) return FALSE;
6070 if (!pMonitorName) {
6071 SetLastError(RPC_X_NULL_REF_POINTER);
6072 return FALSE;
6075 return backend->fpAddPort(pName, hWnd, pMonitorName);
6078 /******************************************************************************
6079 * AddPortExA (WINSPOOL.@)
6081 * See AddPortExW.
6084 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6086 PORT_INFO_2W pi2W;
6087 PORT_INFO_2A * pi2A;
6088 LPWSTR nameW = NULL;
6089 LPWSTR monitorW = NULL;
6090 DWORD len;
6091 BOOL res;
6093 pi2A = (PORT_INFO_2A *) pBuffer;
6095 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6096 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6098 if ((level < 1) || (level > 2)) {
6099 SetLastError(ERROR_INVALID_LEVEL);
6100 return FALSE;
6103 if (!pi2A) {
6104 SetLastError(ERROR_INVALID_PARAMETER);
6105 return FALSE;
6108 if (pName) {
6109 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6110 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6111 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6114 if (pMonitorName) {
6115 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6116 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6117 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6120 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6122 if (pi2A->pPortName) {
6123 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6124 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6125 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6128 if (level > 1) {
6129 if (pi2A->pMonitorName) {
6130 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6131 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6132 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6135 if (pi2A->pDescription) {
6136 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6137 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6138 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6140 pi2W.fPortType = pi2A->fPortType;
6141 pi2W.Reserved = pi2A->Reserved;
6144 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6146 HeapFree(GetProcessHeap(), 0, nameW);
6147 HeapFree(GetProcessHeap(), 0, monitorW);
6148 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6149 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6150 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6151 return res;
6155 /******************************************************************************
6156 * AddPortExW (WINSPOOL.@)
6158 * Add a Port for a specific Monitor, without presenting a user interface
6160 * PARAMS
6161 * pName [I] Servername or NULL (local Computer)
6162 * level [I] Structure-Level (1 or 2) for pBuffer
6163 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6164 * pMonitorName [I] Name of the Monitor that manage the Port
6166 * RETURNS
6167 * Success: TRUE
6168 * Failure: FALSE
6171 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6173 PORT_INFO_2W * pi2;
6175 pi2 = (PORT_INFO_2W *) pBuffer;
6177 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6178 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6179 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6180 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6182 if ((backend == NULL) && !load_backend()) return FALSE;
6184 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6185 SetLastError(ERROR_INVALID_PARAMETER);
6186 return FALSE;
6189 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6192 /******************************************************************************
6193 * AddPrinterConnectionA (WINSPOOL.@)
6195 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6197 FIXME("%s\n", debugstr_a(pName));
6198 return FALSE;
6201 /******************************************************************************
6202 * AddPrinterConnectionW (WINSPOOL.@)
6204 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6206 FIXME("%s\n", debugstr_w(pName));
6207 return FALSE;
6210 /******************************************************************************
6211 * AddPrinterDriverExW (WINSPOOL.@)
6213 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6215 * PARAMS
6216 * pName [I] Servername or NULL (local Computer)
6217 * level [I] Level for the supplied DRIVER_INFO_*W struct
6218 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6219 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6221 * RESULTS
6222 * Success: TRUE
6223 * Failure: FALSE
6226 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6228 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6230 if ((backend == NULL) && !load_backend()) return FALSE;
6232 if (level < 2 || level == 5 || level == 7 || level > 8) {
6233 SetLastError(ERROR_INVALID_LEVEL);
6234 return FALSE;
6237 if (!pDriverInfo) {
6238 SetLastError(ERROR_INVALID_PARAMETER);
6239 return FALSE;
6242 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6245 /******************************************************************************
6246 * AddPrinterDriverExA (WINSPOOL.@)
6248 * See AddPrinterDriverExW.
6251 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6253 DRIVER_INFO_8A *diA;
6254 DRIVER_INFO_8W diW;
6255 LPWSTR nameW = NULL;
6256 DWORD lenA;
6257 DWORD len;
6258 DWORD res = FALSE;
6260 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6262 diA = (DRIVER_INFO_8A *) pDriverInfo;
6263 ZeroMemory(&diW, sizeof(diW));
6265 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6266 SetLastError(ERROR_INVALID_LEVEL);
6267 return FALSE;
6270 if (diA == NULL) {
6271 SetLastError(ERROR_INVALID_PARAMETER);
6272 return FALSE;
6275 /* convert servername to unicode */
6276 if (pName) {
6277 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6278 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6279 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6282 /* common fields */
6283 diW.cVersion = diA->cVersion;
6285 if (diA->pName) {
6286 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6287 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6288 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6291 if (diA->pEnvironment) {
6292 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6293 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6294 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6297 if (diA->pDriverPath) {
6298 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6299 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6300 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6303 if (diA->pDataFile) {
6304 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6305 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6306 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6309 if (diA->pConfigFile) {
6310 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6311 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6312 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6315 if ((Level > 2) && diA->pDependentFiles) {
6316 lenA = multi_sz_lenA(diA->pDependentFiles);
6317 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6318 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6319 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6322 if ((Level > 2) && diA->pMonitorName) {
6323 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6324 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6325 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6328 if ((Level > 3) && diA->pDefaultDataType) {
6329 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6330 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6331 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6334 if ((Level > 3) && diA->pszzPreviousNames) {
6335 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6336 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6337 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6338 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6341 if ((Level > 5) && diA->pszMfgName) {
6342 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6343 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6344 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6347 if ((Level > 5) && diA->pszOEMUrl) {
6348 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6349 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6350 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6353 if ((Level > 5) && diA->pszHardwareID) {
6354 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6355 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6356 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6359 if ((Level > 5) && diA->pszProvider) {
6360 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6361 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6362 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6365 if (Level > 7) {
6366 FIXME("level %u is incomplete\n", Level);
6369 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6370 TRACE("got %u with %u\n", res, GetLastError());
6371 HeapFree(GetProcessHeap(), 0, nameW);
6372 HeapFree(GetProcessHeap(), 0, diW.pName);
6373 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6374 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6375 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6376 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6377 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6378 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6379 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6380 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6381 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6382 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6383 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6384 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6386 TRACE("=> %u with %u\n", res, GetLastError());
6387 return res;
6390 /******************************************************************************
6391 * ConfigurePortA (WINSPOOL.@)
6393 * See ConfigurePortW.
6396 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6398 LPWSTR nameW = NULL;
6399 LPWSTR portW = NULL;
6400 INT len;
6401 DWORD res;
6403 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6405 /* convert servername to unicode */
6406 if (pName) {
6407 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6408 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6409 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6412 /* convert portname to unicode */
6413 if (pPortName) {
6414 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6415 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6416 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6419 res = ConfigurePortW(nameW, hWnd, portW);
6420 HeapFree(GetProcessHeap(), 0, nameW);
6421 HeapFree(GetProcessHeap(), 0, portW);
6422 return res;
6425 /******************************************************************************
6426 * ConfigurePortW (WINSPOOL.@)
6428 * Display the Configuration-Dialog for a specific Port
6430 * PARAMS
6431 * pName [I] Servername or NULL (local Computer)
6432 * hWnd [I] Handle to parent Window for the Dialog-Box
6433 * pPortName [I] Name of the Port, that should be configured
6435 * RETURNS
6436 * Success: TRUE
6437 * Failure: FALSE
6440 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6443 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6445 if ((backend == NULL) && !load_backend()) return FALSE;
6447 if (!pPortName) {
6448 SetLastError(RPC_X_NULL_REF_POINTER);
6449 return FALSE;
6452 return backend->fpConfigurePort(pName, hWnd, pPortName);
6455 /******************************************************************************
6456 * ConnectToPrinterDlg (WINSPOOL.@)
6458 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6460 FIXME("%p %x\n", hWnd, Flags);
6461 return NULL;
6464 /******************************************************************************
6465 * DeletePrinterConnectionA (WINSPOOL.@)
6467 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6469 FIXME("%s\n", debugstr_a(pName));
6470 return TRUE;
6473 /******************************************************************************
6474 * DeletePrinterConnectionW (WINSPOOL.@)
6476 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6478 FIXME("%s\n", debugstr_w(pName));
6479 return TRUE;
6482 /******************************************************************************
6483 * DeletePrinterDriverExW (WINSPOOL.@)
6485 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6486 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6488 HKEY hkey_drivers;
6489 BOOL ret = FALSE;
6491 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6492 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6494 if(pName && pName[0])
6496 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6497 SetLastError(ERROR_INVALID_PARAMETER);
6498 return FALSE;
6501 if(dwDeleteFlag)
6503 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6504 SetLastError(ERROR_INVALID_PARAMETER);
6505 return FALSE;
6508 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6510 if(!hkey_drivers)
6512 ERR("Can't open drivers key\n");
6513 return FALSE;
6516 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6517 ret = TRUE;
6519 RegCloseKey(hkey_drivers);
6521 return ret;
6524 /******************************************************************************
6525 * DeletePrinterDriverExA (WINSPOOL.@)
6527 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6528 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6530 UNICODE_STRING NameW, EnvW, DriverW;
6531 BOOL ret;
6533 asciitounicode(&NameW, pName);
6534 asciitounicode(&EnvW, pEnvironment);
6535 asciitounicode(&DriverW, pDriverName);
6537 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6539 RtlFreeUnicodeString(&DriverW);
6540 RtlFreeUnicodeString(&EnvW);
6541 RtlFreeUnicodeString(&NameW);
6543 return ret;
6546 /******************************************************************************
6547 * DeletePrinterDataExW (WINSPOOL.@)
6549 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6550 LPCWSTR pValueName)
6552 FIXME("%p %s %s\n", hPrinter,
6553 debugstr_w(pKeyName), debugstr_w(pValueName));
6554 return ERROR_INVALID_PARAMETER;
6557 /******************************************************************************
6558 * DeletePrinterDataExA (WINSPOOL.@)
6560 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6561 LPCSTR pValueName)
6563 FIXME("%p %s %s\n", hPrinter,
6564 debugstr_a(pKeyName), debugstr_a(pValueName));
6565 return ERROR_INVALID_PARAMETER;
6568 /******************************************************************************
6569 * DeletePrintProcessorA (WINSPOOL.@)
6571 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6573 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6574 debugstr_a(pPrintProcessorName));
6575 return TRUE;
6578 /******************************************************************************
6579 * DeletePrintProcessorW (WINSPOOL.@)
6581 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6583 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6584 debugstr_w(pPrintProcessorName));
6585 return TRUE;
6588 /******************************************************************************
6589 * DeletePrintProvidorA (WINSPOOL.@)
6591 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6593 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6594 debugstr_a(pPrintProviderName));
6595 return TRUE;
6598 /******************************************************************************
6599 * DeletePrintProvidorW (WINSPOOL.@)
6601 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6603 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6604 debugstr_w(pPrintProviderName));
6605 return TRUE;
6608 /******************************************************************************
6609 * EnumFormsA (WINSPOOL.@)
6611 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6612 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6614 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6615 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6616 return FALSE;
6619 /******************************************************************************
6620 * EnumFormsW (WINSPOOL.@)
6622 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6623 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6625 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6626 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6627 return FALSE;
6630 /*****************************************************************************
6631 * EnumMonitorsA [WINSPOOL.@]
6633 * See EnumMonitorsW.
6636 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6637 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6639 BOOL res;
6640 LPBYTE bufferW = NULL;
6641 LPWSTR nameW = NULL;
6642 DWORD needed = 0;
6643 DWORD numentries = 0;
6644 INT len;
6646 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6647 cbBuf, pcbNeeded, pcReturned);
6649 /* convert servername to unicode */
6650 if (pName) {
6651 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6652 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6653 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6655 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6656 needed = cbBuf * sizeof(WCHAR);
6657 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6658 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6660 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6661 if (pcbNeeded) needed = *pcbNeeded;
6662 /* HeapReAlloc return NULL, when bufferW was NULL */
6663 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6664 HeapAlloc(GetProcessHeap(), 0, needed);
6666 /* Try again with the large Buffer */
6667 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6669 numentries = pcReturned ? *pcReturned : 0;
6670 needed = 0;
6672 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6673 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6675 if (res) {
6676 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6677 DWORD entrysize = 0;
6678 DWORD index;
6679 LPSTR ptr;
6680 LPMONITOR_INFO_2W mi2w;
6681 LPMONITOR_INFO_2A mi2a;
6683 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6684 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6686 /* First pass: calculate the size for all Entries */
6687 mi2w = (LPMONITOR_INFO_2W) bufferW;
6688 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6689 index = 0;
6690 while (index < numentries) {
6691 index++;
6692 needed += entrysize; /* MONITOR_INFO_?A */
6693 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6695 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6696 NULL, 0, NULL, NULL);
6697 if (Level > 1) {
6698 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6699 NULL, 0, NULL, NULL);
6700 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6701 NULL, 0, NULL, NULL);
6703 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6704 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6705 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6708 /* check for errors and quit on failure */
6709 if (cbBuf < needed) {
6710 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6711 res = FALSE;
6712 goto emA_cleanup;
6714 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6715 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6716 cbBuf -= len ; /* free Bytes in the user-Buffer */
6717 mi2w = (LPMONITOR_INFO_2W) bufferW;
6718 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6719 index = 0;
6720 /* Second Pass: Fill the User Buffer (if we have one) */
6721 while ((index < numentries) && pMonitors) {
6722 index++;
6723 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6724 mi2a->pName = ptr;
6725 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6726 ptr, cbBuf , NULL, NULL);
6727 ptr += len;
6728 cbBuf -= len;
6729 if (Level > 1) {
6730 mi2a->pEnvironment = ptr;
6731 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6732 ptr, cbBuf, NULL, NULL);
6733 ptr += len;
6734 cbBuf -= len;
6736 mi2a->pDLLName = ptr;
6737 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6738 ptr, cbBuf, NULL, NULL);
6739 ptr += len;
6740 cbBuf -= len;
6742 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6743 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6744 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6747 emA_cleanup:
6748 if (pcbNeeded) *pcbNeeded = needed;
6749 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6751 HeapFree(GetProcessHeap(), 0, nameW);
6752 HeapFree(GetProcessHeap(), 0, bufferW);
6754 TRACE("returning %d with %d (%d byte for %d entries)\n",
6755 (res), GetLastError(), needed, numentries);
6757 return (res);
6761 /*****************************************************************************
6762 * EnumMonitorsW [WINSPOOL.@]
6764 * Enumerate available Port-Monitors
6766 * PARAMS
6767 * pName [I] Servername or NULL (local Computer)
6768 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6769 * pMonitors [O] PTR to Buffer that receives the Result
6770 * cbBuf [I] Size of Buffer at pMonitors
6771 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6772 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6774 * RETURNS
6775 * Success: TRUE
6776 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6779 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6780 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6783 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6784 cbBuf, pcbNeeded, pcReturned);
6786 if ((backend == NULL) && !load_backend()) return FALSE;
6788 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6789 SetLastError(RPC_X_NULL_REF_POINTER);
6790 return FALSE;
6793 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6796 /******************************************************************************
6797 * SpoolerInit (WINSPOOL.@)
6799 * Initialize the Spooler
6801 * RETURNS
6802 * Success: TRUE
6803 * Failure: FALSE
6805 * NOTES
6806 * The function fails on windows, when the spooler service is not running
6809 BOOL WINAPI SpoolerInit(void)
6812 if ((backend == NULL) && !load_backend()) return FALSE;
6813 return TRUE;
6816 /******************************************************************************
6817 * XcvDataW (WINSPOOL.@)
6819 * Execute commands in the Printmonitor DLL
6821 * PARAMS
6822 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6823 * pszDataName [i] Name of the command to execute
6824 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6825 * cbInputData [i] Size in Bytes of Buffer at pInputData
6826 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6827 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6828 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6829 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6831 * RETURNS
6832 * Success: TRUE
6833 * Failure: FALSE
6835 * NOTES
6836 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6837 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6839 * Minimal List of commands, that a Printmonitor DLL should support:
6841 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6842 *| "AddPort" : Add a Port
6843 *| "DeletePort": Delete a Port
6845 * Many Printmonitors support additional commands. Examples for localspl.dll:
6846 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6847 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6850 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6851 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6852 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6854 opened_printer_t *printer;
6856 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6857 pInputData, cbInputData, pOutputData,
6858 cbOutputData, pcbOutputNeeded, pdwStatus);
6860 if ((backend == NULL) && !load_backend()) return FALSE;
6862 printer = get_opened_printer(hXcv);
6863 if (!printer || (!printer->backend_printer)) {
6864 SetLastError(ERROR_INVALID_HANDLE);
6865 return FALSE;
6868 if (!pcbOutputNeeded) {
6869 SetLastError(ERROR_INVALID_PARAMETER);
6870 return FALSE;
6873 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6874 SetLastError(RPC_X_NULL_REF_POINTER);
6875 return FALSE;
6878 *pcbOutputNeeded = 0;
6880 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6881 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6885 /*****************************************************************************
6886 * EnumPrinterDataA [WINSPOOL.@]
6889 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6890 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6891 DWORD cbData, LPDWORD pcbData )
6893 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6894 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6895 return ERROR_NO_MORE_ITEMS;
6898 /*****************************************************************************
6899 * EnumPrinterDataW [WINSPOOL.@]
6902 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6903 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6904 DWORD cbData, LPDWORD pcbData )
6906 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6907 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6908 return ERROR_NO_MORE_ITEMS;
6911 /*****************************************************************************
6912 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6915 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6916 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6917 LPDWORD pcbNeeded, LPDWORD pcReturned)
6919 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6920 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6921 pcbNeeded, pcReturned);
6922 return FALSE;
6925 /*****************************************************************************
6926 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6929 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6930 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6931 LPDWORD pcbNeeded, LPDWORD pcReturned)
6933 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6934 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6935 pcbNeeded, pcReturned);
6936 return FALSE;
6939 /*****************************************************************************
6940 * EnumPrintProcessorsA [WINSPOOL.@]
6942 * See EnumPrintProcessorsW.
6945 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6946 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6948 BOOL res;
6949 LPBYTE bufferW = NULL;
6950 LPWSTR nameW = NULL;
6951 LPWSTR envW = NULL;
6952 DWORD needed = 0;
6953 DWORD numentries = 0;
6954 INT len;
6956 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6957 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6959 /* convert names to unicode */
6960 if (pName) {
6961 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6962 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6963 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6965 if (pEnvironment) {
6966 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6967 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6968 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6971 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6972 needed = cbBuf * sizeof(WCHAR);
6973 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6974 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6976 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6977 if (pcbNeeded) needed = *pcbNeeded;
6978 /* HeapReAlloc return NULL, when bufferW was NULL */
6979 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6980 HeapAlloc(GetProcessHeap(), 0, needed);
6982 /* Try again with the large Buffer */
6983 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6985 numentries = pcReturned ? *pcReturned : 0;
6986 needed = 0;
6988 if (res) {
6989 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6990 DWORD index;
6991 LPSTR ptr;
6992 PPRINTPROCESSOR_INFO_1W ppiw;
6993 PPRINTPROCESSOR_INFO_1A ppia;
6995 /* First pass: calculate the size for all Entries */
6996 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6997 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6998 index = 0;
6999 while (index < numentries) {
7000 index++;
7001 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7002 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7004 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7005 NULL, 0, NULL, NULL);
7007 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7008 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7011 /* check for errors and quit on failure */
7012 if (cbBuf < needed) {
7013 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7014 res = FALSE;
7015 goto epp_cleanup;
7018 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7019 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7020 cbBuf -= len ; /* free Bytes in the user-Buffer */
7021 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7022 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7023 index = 0;
7024 /* Second Pass: Fill the User Buffer (if we have one) */
7025 while ((index < numentries) && pPPInfo) {
7026 index++;
7027 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7028 ppia->pName = ptr;
7029 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7030 ptr, cbBuf , NULL, NULL);
7031 ptr += len;
7032 cbBuf -= len;
7034 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7035 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7039 epp_cleanup:
7040 if (pcbNeeded) *pcbNeeded = needed;
7041 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7043 HeapFree(GetProcessHeap(), 0, nameW);
7044 HeapFree(GetProcessHeap(), 0, envW);
7045 HeapFree(GetProcessHeap(), 0, bufferW);
7047 TRACE("returning %d with %d (%d byte for %d entries)\n",
7048 (res), GetLastError(), needed, numentries);
7050 return (res);
7053 /*****************************************************************************
7054 * EnumPrintProcessorsW [WINSPOOL.@]
7056 * Enumerate available Print Processors
7058 * PARAMS
7059 * pName [I] Servername or NULL (local Computer)
7060 * pEnvironment [I] Printing-Environment or NULL (Default)
7061 * Level [I] Structure-Level (Only 1 is allowed)
7062 * pPPInfo [O] PTR to Buffer that receives the Result
7063 * cbBuf [I] Size of Buffer at pPPInfo
7064 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7065 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7067 * RETURNS
7068 * Success: TRUE
7069 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7072 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7073 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7076 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7077 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7079 if ((backend == NULL) && !load_backend()) return FALSE;
7081 if (!pcbNeeded || !pcReturned) {
7082 SetLastError(RPC_X_NULL_REF_POINTER);
7083 return FALSE;
7086 if (!pPPInfo && (cbBuf > 0)) {
7087 SetLastError(ERROR_INVALID_USER_BUFFER);
7088 return FALSE;
7091 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7092 cbBuf, pcbNeeded, pcReturned);
7095 /*****************************************************************************
7096 * ExtDeviceMode [WINSPOOL.@]
7099 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7100 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7101 DWORD fMode)
7103 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7104 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7105 debugstr_a(pProfile), fMode);
7106 return -1;
7109 /*****************************************************************************
7110 * FindClosePrinterChangeNotification [WINSPOOL.@]
7113 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7115 FIXME("Stub: %p\n", hChange);
7116 return TRUE;
7119 /*****************************************************************************
7120 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7123 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7124 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7126 FIXME("Stub: %p %x %x %p\n",
7127 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7128 return INVALID_HANDLE_VALUE;
7131 /*****************************************************************************
7132 * FindNextPrinterChangeNotification [WINSPOOL.@]
7135 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7136 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7138 FIXME("Stub: %p %p %p %p\n",
7139 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7140 return FALSE;
7143 /*****************************************************************************
7144 * FreePrinterNotifyInfo [WINSPOOL.@]
7147 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7149 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7150 return TRUE;
7153 /*****************************************************************************
7154 * string_to_buf
7156 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7157 * ansi depending on the unicode parameter.
7159 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7161 if(!str)
7163 *size = 0;
7164 return TRUE;
7167 if(unicode)
7169 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7170 if(*size <= cb)
7172 memcpy(ptr, str, *size);
7173 return TRUE;
7175 return FALSE;
7177 else
7179 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7180 if(*size <= cb)
7182 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7183 return TRUE;
7185 return FALSE;
7189 /*****************************************************************************
7190 * get_job_info_1
7192 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7193 LPDWORD pcbNeeded, BOOL unicode)
7195 DWORD size, left = cbBuf;
7196 BOOL space = (cbBuf > 0);
7197 LPBYTE ptr = buf;
7199 *pcbNeeded = 0;
7201 if(space)
7203 ji1->JobId = job->job_id;
7206 string_to_buf(job->document_title, ptr, left, &size, unicode);
7207 if(space && size <= left)
7209 ji1->pDocument = (LPWSTR)ptr;
7210 ptr += size;
7211 left -= size;
7213 else
7214 space = FALSE;
7215 *pcbNeeded += size;
7217 if (job->printer_name)
7219 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7220 if(space && size <= left)
7222 ji1->pPrinterName = (LPWSTR)ptr;
7223 ptr += size;
7224 left -= size;
7226 else
7227 space = FALSE;
7228 *pcbNeeded += size;
7231 return space;
7234 /*****************************************************************************
7235 * get_job_info_2
7237 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7238 LPDWORD pcbNeeded, BOOL unicode)
7240 DWORD size, left = cbBuf;
7241 DWORD shift;
7242 BOOL space = (cbBuf > 0);
7243 LPBYTE ptr = buf;
7244 LPDEVMODEA dmA = NULL;
7245 LPDEVMODEW devmode;
7247 *pcbNeeded = 0;
7249 if(space)
7251 ji2->JobId = job->job_id;
7254 string_to_buf(job->document_title, ptr, left, &size, unicode);
7255 if(space && size <= left)
7257 ji2->pDocument = (LPWSTR)ptr;
7258 ptr += size;
7259 left -= size;
7261 else
7262 space = FALSE;
7263 *pcbNeeded += size;
7265 if (job->printer_name)
7267 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7268 if(space && size <= left)
7270 ji2->pPrinterName = (LPWSTR)ptr;
7271 ptr += size;
7272 left -= size;
7274 else
7275 space = FALSE;
7276 *pcbNeeded += size;
7279 if (job->devmode)
7281 if (!unicode)
7283 dmA = DEVMODEdupWtoA(job->devmode);
7284 devmode = (LPDEVMODEW) dmA;
7285 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7287 else
7289 devmode = job->devmode;
7290 size = devmode->dmSize + devmode->dmDriverExtra;
7293 if (!devmode)
7294 FIXME("Can't convert DEVMODE W to A\n");
7295 else
7297 /* align DEVMODE to a DWORD boundary */
7298 shift = (4 - (*pcbNeeded & 3)) & 3;
7299 size += shift;
7301 if (size <= left)
7303 ptr += shift;
7304 memcpy(ptr, devmode, size-shift);
7305 ji2->pDevMode = (LPDEVMODEW)ptr;
7306 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7307 ptr += size-shift;
7308 left -= size;
7310 else
7311 space = FALSE;
7312 *pcbNeeded +=size;
7316 return space;
7319 /*****************************************************************************
7320 * get_job_info
7322 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7323 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7325 BOOL ret = FALSE;
7326 DWORD needed = 0, size;
7327 job_t *job;
7328 LPBYTE ptr = pJob;
7330 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7332 EnterCriticalSection(&printer_handles_cs);
7333 job = get_job(hPrinter, JobId);
7334 if(!job)
7335 goto end;
7337 switch(Level)
7339 case 1:
7340 size = sizeof(JOB_INFO_1W);
7341 if(cbBuf >= size)
7343 cbBuf -= size;
7344 ptr += size;
7345 memset(pJob, 0, size);
7347 else
7348 cbBuf = 0;
7349 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7350 needed += size;
7351 break;
7353 case 2:
7354 size = sizeof(JOB_INFO_2W);
7355 if(cbBuf >= size)
7357 cbBuf -= size;
7358 ptr += size;
7359 memset(pJob, 0, size);
7361 else
7362 cbBuf = 0;
7363 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7364 needed += size;
7365 break;
7367 case 3:
7368 size = sizeof(JOB_INFO_3);
7369 if(cbBuf >= size)
7371 cbBuf -= size;
7372 memset(pJob, 0, size);
7373 ret = TRUE;
7375 else
7376 cbBuf = 0;
7377 needed = size;
7378 break;
7380 default:
7381 SetLastError(ERROR_INVALID_LEVEL);
7382 goto end;
7384 if(pcbNeeded)
7385 *pcbNeeded = needed;
7386 end:
7387 LeaveCriticalSection(&printer_handles_cs);
7388 return ret;
7391 /*****************************************************************************
7392 * GetJobA [WINSPOOL.@]
7395 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7396 DWORD cbBuf, LPDWORD pcbNeeded)
7398 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7401 /*****************************************************************************
7402 * GetJobW [WINSPOOL.@]
7405 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7406 DWORD cbBuf, LPDWORD pcbNeeded)
7408 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7411 /*****************************************************************************
7412 * schedule_pipe
7414 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7416 #ifdef HAVE_FORK
7417 char *unixname, *cmdA;
7418 DWORD len;
7419 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7420 BOOL ret = FALSE;
7421 char buf[1024];
7422 pid_t pid, wret;
7423 int status;
7425 if(!(unixname = wine_get_unix_file_name(filename)))
7426 return FALSE;
7428 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7429 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7430 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7432 TRACE("printing with: %s\n", cmdA);
7434 if((file_fd = open(unixname, O_RDONLY)) == -1)
7435 goto end;
7437 if (pipe(fds))
7439 ERR("pipe() failed!\n");
7440 goto end;
7443 if ((pid = fork()) == 0)
7445 close(0);
7446 dup2(fds[0], 0);
7447 close(fds[1]);
7449 /* reset signals that we previously set to SIG_IGN */
7450 signal(SIGPIPE, SIG_DFL);
7452 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7453 _exit(1);
7455 else if (pid == -1)
7457 ERR("fork() failed!\n");
7458 goto end;
7461 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7462 write(fds[1], buf, no_read);
7464 close(fds[1]);
7465 fds[1] = -1;
7467 /* reap child */
7468 do {
7469 wret = waitpid(pid, &status, 0);
7470 } while (wret < 0 && errno == EINTR);
7471 if (wret < 0)
7473 ERR("waitpid() failed!\n");
7474 goto end;
7476 if (!WIFEXITED(status) || WEXITSTATUS(status))
7478 ERR("child process failed! %d\n", status);
7479 goto end;
7482 ret = TRUE;
7484 end:
7485 if(file_fd != -1) close(file_fd);
7486 if(fds[0] != -1) close(fds[0]);
7487 if(fds[1] != -1) close(fds[1]);
7489 HeapFree(GetProcessHeap(), 0, cmdA);
7490 HeapFree(GetProcessHeap(), 0, unixname);
7491 return ret;
7492 #else
7493 return FALSE;
7494 #endif
7497 /*****************************************************************************
7498 * schedule_lpr
7500 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7502 WCHAR *cmd;
7503 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7504 BOOL r;
7506 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7507 sprintfW(cmd, fmtW, printer_name);
7509 r = schedule_pipe(cmd, filename);
7511 HeapFree(GetProcessHeap(), 0, cmd);
7512 return r;
7515 /*****************************************************************************
7516 * schedule_cups
7518 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7520 #ifdef SONAME_LIBCUPS
7521 if(pcupsPrintFile)
7523 char *unixname, *queue, *unix_doc_title;
7524 DWORD len;
7525 BOOL ret;
7527 if(!(unixname = wine_get_unix_file_name(filename)))
7528 return FALSE;
7530 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7531 queue = HeapAlloc(GetProcessHeap(), 0, len);
7532 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7534 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7535 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7536 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7538 TRACE("printing via cups\n");
7539 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7540 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7541 HeapFree(GetProcessHeap(), 0, queue);
7542 HeapFree(GetProcessHeap(), 0, unixname);
7543 return ret;
7545 else
7546 #endif
7548 return schedule_lpr(printer_name, filename);
7552 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7554 LPWSTR filename;
7556 switch(msg)
7558 case WM_INITDIALOG:
7559 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7560 return TRUE;
7562 case WM_COMMAND:
7563 if(HIWORD(wparam) == BN_CLICKED)
7565 if(LOWORD(wparam) == IDOK)
7567 HANDLE hf;
7568 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7569 LPWSTR *output;
7571 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7572 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7574 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7576 WCHAR caption[200], message[200];
7577 int mb_ret;
7579 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7580 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7581 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7582 if(mb_ret == IDCANCEL)
7584 HeapFree(GetProcessHeap(), 0, filename);
7585 return TRUE;
7588 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7589 if(hf == INVALID_HANDLE_VALUE)
7591 WCHAR caption[200], message[200];
7593 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7594 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7595 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7596 HeapFree(GetProcessHeap(), 0, filename);
7597 return TRUE;
7599 CloseHandle(hf);
7600 DeleteFileW(filename);
7601 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7602 *output = filename;
7603 EndDialog(hwnd, IDOK);
7604 return TRUE;
7606 if(LOWORD(wparam) == IDCANCEL)
7608 EndDialog(hwnd, IDCANCEL);
7609 return TRUE;
7612 return FALSE;
7614 return FALSE;
7617 /*****************************************************************************
7618 * get_filename
7620 static BOOL get_filename(LPWSTR *filename)
7622 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7623 file_dlg_proc, (LPARAM)filename) == IDOK;
7626 /*****************************************************************************
7627 * schedule_file
7629 static BOOL schedule_file(LPCWSTR filename)
7631 LPWSTR output = NULL;
7633 if(get_filename(&output))
7635 BOOL r;
7636 TRACE("copy to %s\n", debugstr_w(output));
7637 r = CopyFileW(filename, output, FALSE);
7638 HeapFree(GetProcessHeap(), 0, output);
7639 return r;
7641 return FALSE;
7644 /*****************************************************************************
7645 * schedule_unixfile
7647 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7649 int in_fd, out_fd, no_read;
7650 char buf[1024];
7651 BOOL ret = FALSE;
7652 char *unixname, *outputA;
7653 DWORD len;
7655 if(!(unixname = wine_get_unix_file_name(filename)))
7656 return FALSE;
7658 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7659 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7660 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7662 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7663 in_fd = open(unixname, O_RDONLY);
7664 if(out_fd == -1 || in_fd == -1)
7665 goto end;
7667 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7668 write(out_fd, buf, no_read);
7670 ret = TRUE;
7671 end:
7672 if(in_fd != -1) close(in_fd);
7673 if(out_fd != -1) close(out_fd);
7674 HeapFree(GetProcessHeap(), 0, outputA);
7675 HeapFree(GetProcessHeap(), 0, unixname);
7676 return ret;
7679 /*****************************************************************************
7680 * ScheduleJob [WINSPOOL.@]
7683 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7685 opened_printer_t *printer;
7686 BOOL ret = FALSE;
7687 struct list *cursor, *cursor2;
7689 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7690 EnterCriticalSection(&printer_handles_cs);
7691 printer = get_opened_printer(hPrinter);
7692 if(!printer)
7693 goto end;
7695 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7697 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7698 HANDLE hf;
7700 if(job->job_id != dwJobID) continue;
7702 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7703 if(hf != INVALID_HANDLE_VALUE)
7705 PRINTER_INFO_5W *pi5 = NULL;
7706 LPWSTR portname = job->portname;
7707 DWORD needed;
7708 HKEY hkey;
7709 WCHAR output[1024];
7710 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7711 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7713 if (!portname)
7715 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7716 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7717 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7718 portname = pi5->pPortName;
7720 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7721 debugstr_w(portname));
7723 output[0] = 0;
7725 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7726 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7728 DWORD type, count = sizeof(output);
7729 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7730 RegCloseKey(hkey);
7732 if(output[0] == '|')
7734 ret = schedule_pipe(output + 1, job->filename);
7736 else if(output[0])
7738 ret = schedule_unixfile(output, job->filename);
7740 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7742 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7744 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7746 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7748 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7750 ret = schedule_file(job->filename);
7752 else
7754 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7756 HeapFree(GetProcessHeap(), 0, pi5);
7757 CloseHandle(hf);
7758 DeleteFileW(job->filename);
7760 list_remove(cursor);
7761 HeapFree(GetProcessHeap(), 0, job->document_title);
7762 HeapFree(GetProcessHeap(), 0, job->printer_name);
7763 HeapFree(GetProcessHeap(), 0, job->portname);
7764 HeapFree(GetProcessHeap(), 0, job->filename);
7765 HeapFree(GetProcessHeap(), 0, job->devmode);
7766 HeapFree(GetProcessHeap(), 0, job);
7767 break;
7769 end:
7770 LeaveCriticalSection(&printer_handles_cs);
7771 return ret;
7774 /*****************************************************************************
7775 * StartDocDlgA [WINSPOOL.@]
7777 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7779 UNICODE_STRING usBuffer;
7780 DOCINFOW docW;
7781 LPWSTR retW;
7782 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7783 LPSTR ret = NULL;
7785 docW.cbSize = sizeof(docW);
7786 if (doc->lpszDocName)
7788 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7789 if (!(docW.lpszDocName = docnameW)) return NULL;
7791 if (doc->lpszOutput)
7793 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7794 if (!(docW.lpszOutput = outputW)) return NULL;
7796 if (doc->lpszDatatype)
7798 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7799 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7801 docW.fwType = doc->fwType;
7803 retW = StartDocDlgW(hPrinter, &docW);
7805 if(retW)
7807 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7808 ret = HeapAlloc(GetProcessHeap(), 0, len);
7809 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7810 HeapFree(GetProcessHeap(), 0, retW);
7813 HeapFree(GetProcessHeap(), 0, datatypeW);
7814 HeapFree(GetProcessHeap(), 0, outputW);
7815 HeapFree(GetProcessHeap(), 0, docnameW);
7817 return ret;
7820 /*****************************************************************************
7821 * StartDocDlgW [WINSPOOL.@]
7823 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7824 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7825 * port is "FILE:". Also returns the full path if passed a relative path.
7827 * The caller should free the returned string from the process heap.
7829 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7831 LPWSTR ret = NULL;
7832 DWORD len, attr;
7834 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7836 PRINTER_INFO_5W *pi5;
7837 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7838 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7839 return NULL;
7840 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7841 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7842 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7844 HeapFree(GetProcessHeap(), 0, pi5);
7845 return NULL;
7847 HeapFree(GetProcessHeap(), 0, pi5);
7850 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7852 LPWSTR name;
7854 if (get_filename(&name))
7856 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7858 HeapFree(GetProcessHeap(), 0, name);
7859 return NULL;
7861 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7862 GetFullPathNameW(name, len, ret, NULL);
7863 HeapFree(GetProcessHeap(), 0, name);
7865 return ret;
7868 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7869 return NULL;
7871 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7872 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7874 attr = GetFileAttributesW(ret);
7875 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7877 HeapFree(GetProcessHeap(), 0, ret);
7878 ret = NULL;
7880 return ret;