include: Added macros for __uuidof emulation based on C++ templates.
[wine/wine-gecko.git] / dlls / winspool.drv / info.c
blob5201e30451ad8bc8c4644b2da8e7f2a8e7b7717f
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 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #include <signal.h>
40 #ifdef HAVE_CUPS_CUPS_H
41 # include <cups/cups.h>
42 #endif
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
46 #include "wine/library.h"
47 #include "windef.h"
48 #include "winbase.h"
49 #include "winuser.h"
50 #include "winerror.h"
51 #include "winreg.h"
52 #include "wingdi.h"
53 #include "winspool.h"
54 #include "winternl.h"
55 #include "wine/windef16.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
58 #include "wine/list.h"
59 #include "winnls.h"
61 #include "ddk/winsplp.h"
62 #include "wspool.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
66 /* ############################### */
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
77 /* ############################### */
79 typedef struct {
80 DWORD job_id;
81 HANDLE hf;
82 } started_doc_t;
84 typedef struct {
85 struct list jobs;
86 LONG ref;
87 } jobqueue_t;
89 typedef struct {
90 LPWSTR name;
91 LPWSTR printername;
92 HANDLE backend_printer;
93 jobqueue_t *queue;
94 started_doc_t *doc;
95 } opened_printer_t;
97 typedef struct {
98 struct list entry;
99 DWORD job_id;
100 WCHAR *filename;
101 WCHAR *portname;
102 WCHAR *document_title;
103 WCHAR *printer_name;
104 LPDEVMODEW devmode;
105 } job_t;
108 typedef struct {
109 LPCWSTR envname;
110 LPCWSTR subdir;
111 DWORD driverversion;
112 LPCWSTR versionregpath;
113 LPCWSTR versionsubdir;
114 } printenv_t;
116 /* ############################### */
118 static opened_printer_t **printer_handles;
119 static UINT nb_printer_handles;
120 static LONG next_job_id = 1;
122 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
123 WORD fwCapability, LPSTR lpszOutput,
124 LPDEVMODEA lpdm );
125 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
126 LPSTR lpszDevice, LPSTR lpszPort,
127 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
128 DWORD fwMode );
130 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'c','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
135 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
137 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
138 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
139 'C','o','n','t','r','o','l','\\',
140 'P','r','i','n','t','\\',
141 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
145 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
146 'M','i','c','r','o','s','o','f','t','\\',
147 'W','i','n','d','o','w','s',' ','N','T','\\',
148 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
149 'W','i','n','d','o','w','s',0};
151 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
152 'M','i','c','r','o','s','o','f','t','\\',
153 'W','i','n','d','o','w','s',' ','N','T','\\',
154 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'D','e','v','i','c','e','s',0};
157 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
158 'M','i','c','r','o','s','o','f','t','\\',
159 'W','i','n','d','o','w','s',' ','N','T','\\',
160 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
161 'P','o','r','t','s',0};
163 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
164 'M','i','c','r','o','s','o','f','t','\\',
165 'W','i','n','d','o','w','s',' ','N','T','\\',
166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
167 'P','r','i','n','t','e','r','P','o','r','t','s',0};
169 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
170 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
171 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
172 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
173 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
174 static const WCHAR subdir_x64W[] = {'x','6','4',0};
175 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
176 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
177 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
178 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
179 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
181 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
182 static const WCHAR backslashW[] = {'\\',0};
183 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
184 'i','o','n',' ','F','i','l','e',0};
185 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
186 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
187 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
188 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
189 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
190 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
191 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
192 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
193 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
194 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
195 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
196 static const WCHAR NameW[] = {'N','a','m','e',0};
197 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
198 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
199 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
200 static const WCHAR PortW[] = {'P','o','r','t',0};
201 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
202 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
203 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
204 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
205 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
206 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
207 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
208 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
209 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
210 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
211 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
212 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
213 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
214 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
215 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
216 static WCHAR rawW[] = {'R','A','W',0};
217 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
218 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
219 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
220 static const WCHAR commaW[] = {',',0};
221 static WCHAR emptyStringW[] = {0};
223 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
225 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
226 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
227 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
229 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
230 'D','o','c','u','m','e','n','t',0};
232 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
233 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
234 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
235 0, sizeof(DRIVER_INFO_8W)};
238 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
239 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
240 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
241 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
242 sizeof(PRINTER_INFO_9W)};
244 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
245 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
246 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
248 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
250 /******************************************************************
251 * validate the user-supplied printing-environment [internal]
253 * PARAMS
254 * env [I] PTR to Environment-String or NULL
256 * RETURNS
257 * Failure: NULL
258 * Success: PTR to printenv_t
260 * NOTES
261 * An empty string is handled the same way as NULL.
262 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
266 static const printenv_t * validate_envW(LPCWSTR env)
268 const printenv_t *result = NULL;
269 unsigned int i;
271 TRACE("testing %s\n", debugstr_w(env));
272 if (env && env[0])
274 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
276 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
278 result = all_printenv[i];
279 break;
283 if (result == NULL) {
284 FIXME("unsupported Environment: %s\n", debugstr_w(env));
285 SetLastError(ERROR_INVALID_ENVIRONMENT);
287 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
289 else
291 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
293 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
295 return result;
299 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
300 if passed a NULL string. This returns NULLs to the result.
302 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
304 if ( (src) )
306 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
307 return usBufferPtr->Buffer;
309 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
310 return NULL;
313 static LPWSTR strdupW(LPCWSTR p)
315 LPWSTR ret;
316 DWORD len;
318 if(!p) return NULL;
319 len = (strlenW(p) + 1) * sizeof(WCHAR);
320 ret = HeapAlloc(GetProcessHeap(), 0, len);
321 memcpy(ret, p, len);
322 return ret;
325 static LPSTR strdupWtoA( LPCWSTR str )
327 LPSTR ret;
328 INT len;
330 if (!str) return NULL;
331 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
332 ret = HeapAlloc( GetProcessHeap(), 0, len );
333 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
334 return ret;
337 /******************************************************************
338 * verify, that the filename is a local file
341 static inline BOOL is_local_file(LPWSTR name)
343 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
346 /* ################################ */
348 static int multi_sz_lenA(const char *str)
350 const char *ptr = str;
351 if(!str) return 0;
354 ptr += lstrlenA(ptr) + 1;
355 } while(*ptr);
357 return ptr - str + 1;
360 static void
361 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
362 char qbuf[200];
364 /* If forcing, or no profile string entry for device yet, set the entry
366 * The always change entry if not WINEPS yet is discussable.
368 if (force ||
369 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
370 !strcmp(qbuf,"*") ||
371 !strstr(qbuf,"WINEPS.DRV")
373 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
374 HKEY hkey;
376 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
377 WriteProfileStringA("windows","device",buf);
378 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
379 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
380 RegCloseKey(hkey);
382 HeapFree(GetProcessHeap(),0,buf);
386 static BOOL add_printer_driver(WCHAR *name)
388 DRIVER_INFO_3W di3;
390 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
391 di3.cVersion = 3;
392 di3.pName = name;
393 di3.pEnvironment = envname_x86W;
394 di3.pDriverPath = driver_nt;
395 di3.pDataFile = generic_ppdW;
396 di3.pConfigFile = driver_nt;
397 di3.pDefaultDataType = rawW;
399 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
400 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
402 di3.cVersion = 0;
403 di3.pEnvironment = envname_win40W;
404 di3.pDriverPath = driver_9x;
405 di3.pConfigFile = driver_9x;
406 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
407 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
409 return TRUE;
412 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
413 return FALSE;
416 #ifdef SONAME_LIBCUPS
417 static typeof(cupsFreeDests) *pcupsFreeDests;
418 static typeof(cupsGetDests) *pcupsGetDests;
419 static typeof(cupsGetPPD) *pcupsGetPPD;
420 static typeof(cupsPrintFile) *pcupsPrintFile;
421 static void *cupshandle;
423 static BOOL CUPS_LoadPrinters(void)
425 int i, nrofdests;
426 BOOL hadprinter = FALSE, haddefault = FALSE;
427 cups_dest_t *dests;
428 PRINTER_INFO_2W pi2;
429 WCHAR *port;
430 HKEY hkeyPrinter, hkeyPrinters;
431 char loaderror[256];
432 WCHAR nameW[MAX_PATH];
434 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
435 if (!cupshandle) {
436 TRACE("%s\n", loaderror);
437 return FALSE;
439 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
441 #define DYNCUPS(x) \
442 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
443 if (!p##x) return FALSE;
445 DYNCUPS(cupsFreeDests);
446 DYNCUPS(cupsGetPPD);
447 DYNCUPS(cupsGetDests);
448 DYNCUPS(cupsPrintFile);
449 #undef DYNCUPS
451 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
452 ERROR_SUCCESS) {
453 ERR("Can't create Printers key\n");
454 return FALSE;
457 nrofdests = pcupsGetDests(&dests);
458 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
459 for (i=0;i<nrofdests;i++) {
460 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
462 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
463 lstrcpyW(port, CUPS_Port);
464 lstrcatW(port, nameW);
466 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
467 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
468 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
469 and continue */
470 TRACE("Printer already exists\n");
471 /* overwrite old LPR:* port */
472 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
473 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
474 RegCloseKey(hkeyPrinter);
475 } else {
476 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
477 ' ','u','s','i','n','g',' ','C','U','P','S',0};
479 add_printer_driver(nameW);
481 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
482 pi2.pPrinterName = nameW;
483 pi2.pDatatype = rawW;
484 pi2.pPrintProcessor = WinPrintW;
485 pi2.pDriverName = nameW;
486 pi2.pComment = comment_cups;
487 pi2.pLocation = emptyStringW;
488 pi2.pPortName = port;
489 pi2.pParameters = emptyStringW;
490 pi2.pShareName = emptyStringW;
491 pi2.pSepFile = emptyStringW;
493 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
494 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
495 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
498 HeapFree(GetProcessHeap(),0,port);
500 hadprinter = TRUE;
501 if (dests[i].is_default) {
502 SetDefaultPrinterW(nameW);
503 haddefault = TRUE;
506 if (hadprinter & !haddefault) {
507 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
508 SetDefaultPrinterW(nameW);
510 pcupsFreeDests(nrofdests, dests);
511 RegCloseKey(hkeyPrinters);
512 return hadprinter;
514 #endif
516 static BOOL
517 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
518 PRINTER_INFO_2A pinfo2a;
519 char *e,*s,*name,*prettyname,*devname;
520 BOOL ret = FALSE, set_default = FALSE;
521 char *port = NULL, *env_default;
522 HKEY hkeyPrinter, hkeyPrinters;
523 WCHAR devnameW[MAX_PATH];
525 while (isspace(*pent)) pent++;
526 s = strchr(pent,':');
527 if(s) *s='\0';
528 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
529 strcpy(name,pent);
530 if(s) {
531 *s=':';
532 pent = s;
533 } else
534 pent = "";
536 TRACE("name=%s entry=%s\n",name, pent);
538 if(ispunct(*name)) { /* a tc entry, not a real printer */
539 TRACE("skipping tc entry\n");
540 goto end;
543 if(strstr(pent,":server")) { /* server only version so skip */
544 TRACE("skipping server entry\n");
545 goto end;
548 /* Determine whether this is a postscript printer. */
550 ret = TRUE;
551 env_default = getenv("PRINTER");
552 prettyname = name;
553 /* Get longest name, usually the one at the right for later display. */
554 while((s=strchr(prettyname,'|'))) {
555 *s = '\0';
556 e = s;
557 while(isspace(*--e)) *e = '\0';
558 TRACE("\t%s\n", debugstr_a(prettyname));
559 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
560 for(prettyname = s+1; isspace(*prettyname); prettyname++)
563 e = prettyname + strlen(prettyname);
564 while(isspace(*--e)) *e = '\0';
565 TRACE("\t%s\n", debugstr_a(prettyname));
566 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
568 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
569 * if it is too long, we use it as comment below. */
570 devname = prettyname;
571 if (strlen(devname)>=CCHDEVICENAME-1)
572 devname = name;
573 if (strlen(devname)>=CCHDEVICENAME-1) {
574 ret = FALSE;
575 goto end;
578 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
579 sprintf(port,"LPR:%s",name);
581 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
582 ERROR_SUCCESS) {
583 ERR("Can't create Printers key\n");
584 ret = FALSE;
585 goto end;
588 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
590 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
591 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
592 and continue */
593 TRACE("Printer already exists\n");
594 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
595 RegCloseKey(hkeyPrinter);
596 } else {
597 static CHAR data_type[] = "RAW",
598 print_proc[] = "WinPrint",
599 comment[] = "WINEPS Printer using LPR",
600 params[] = "<parameters?>",
601 share_name[] = "<share name?>",
602 sep_file[] = "<sep file?>";
604 add_printer_driver(devnameW);
606 memset(&pinfo2a,0,sizeof(pinfo2a));
607 pinfo2a.pPrinterName = devname;
608 pinfo2a.pDatatype = data_type;
609 pinfo2a.pPrintProcessor = print_proc;
610 pinfo2a.pDriverName = devname;
611 pinfo2a.pComment = comment;
612 pinfo2a.pLocation = prettyname;
613 pinfo2a.pPortName = port;
614 pinfo2a.pParameters = params;
615 pinfo2a.pShareName = share_name;
616 pinfo2a.pSepFile = sep_file;
618 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
619 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
620 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
623 RegCloseKey(hkeyPrinters);
625 if (isfirst || set_default)
626 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
628 end:
629 HeapFree(GetProcessHeap(), 0, port);
630 HeapFree(GetProcessHeap(), 0, name);
631 return ret;
634 static BOOL
635 PRINTCAP_LoadPrinters(void) {
636 BOOL hadprinter = FALSE;
637 char buf[200];
638 FILE *f;
639 char *pent = NULL;
640 BOOL had_bash = FALSE;
642 f = fopen("/etc/printcap","r");
643 if (!f)
644 return FALSE;
646 while(fgets(buf,sizeof(buf),f)) {
647 char *start, *end;
649 end=strchr(buf,'\n');
650 if (end) *end='\0';
652 start = buf;
653 while(isspace(*start)) start++;
654 if(*start == '#' || *start == '\0')
655 continue;
657 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
658 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
659 HeapFree(GetProcessHeap(),0,pent);
660 pent = NULL;
663 if (end && *--end == '\\') {
664 *end = '\0';
665 had_bash = TRUE;
666 } else
667 had_bash = FALSE;
669 if (pent) {
670 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
671 strcat(pent,start);
672 } else {
673 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
674 strcpy(pent,start);
678 if(pent) {
679 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
680 HeapFree(GetProcessHeap(),0,pent);
682 fclose(f);
683 return hadprinter;
686 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
688 if (value)
689 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
690 (lstrlenW(value) + 1) * sizeof(WCHAR));
691 else
692 return ERROR_FILE_NOT_FOUND;
695 /******************************************************************
696 * get_servername_from_name (internal)
698 * for an external server, a copy of the serverpart from the full name is returned
701 static LPWSTR get_servername_from_name(LPCWSTR name)
703 LPWSTR server;
704 LPWSTR ptr;
705 WCHAR buffer[MAX_PATH];
706 DWORD len;
708 if (name == NULL) return NULL;
709 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
711 server = strdupW(&name[2]); /* skip over both backslash */
712 if (server == NULL) return NULL;
714 /* strip '\' and the printername */
715 ptr = strchrW(server, '\\');
716 if (ptr) ptr[0] = '\0';
718 TRACE("found %s\n", debugstr_w(server));
720 len = sizeof(buffer)/sizeof(buffer[0]);
721 if (GetComputerNameW(buffer, &len)) {
722 if (lstrcmpW(buffer, server) == 0) {
723 /* The requested Servername is our computername */
724 HeapFree(GetProcessHeap(), 0, server);
725 return NULL;
728 return server;
731 /******************************************************************
732 * get_basename_from_name (internal)
734 * skip over the serverpart from the full name
737 static LPCWSTR get_basename_from_name(LPCWSTR name)
739 if (name == NULL) return NULL;
740 if ((name[0] == '\\') && (name[1] == '\\')) {
741 /* skip over the servername and search for the following '\' */
742 name = strchrW(&name[2], '\\');
743 if ((name) && (name[1])) {
744 /* found a separator ('\') followed by a name:
745 skip over the separator and return the rest */
746 name++;
748 else
750 /* no basename present (we found only a servername) */
751 return NULL;
754 return name;
757 /******************************************************************
758 * get_opened_printer_entry
759 * Get the first place empty in the opened printer table
761 * ToDo:
762 * - pDefault is ignored
764 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
766 UINT_PTR handle = nb_printer_handles, i;
767 jobqueue_t *queue = NULL;
768 opened_printer_t *printer = NULL;
769 LPWSTR servername;
770 LPCWSTR printername;
772 if ((backend == NULL) && !load_backend()) return NULL;
774 servername = get_servername_from_name(name);
775 if (servername) {
776 FIXME("server %s not supported\n", debugstr_w(servername));
777 HeapFree(GetProcessHeap(), 0, servername);
778 SetLastError(ERROR_INVALID_PRINTER_NAME);
779 return NULL;
782 printername = get_basename_from_name(name);
783 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
785 /* an empty printername is invalid */
786 if (printername && (!printername[0])) {
787 SetLastError(ERROR_INVALID_PARAMETER);
788 return NULL;
791 EnterCriticalSection(&printer_handles_cs);
793 for (i = 0; i < nb_printer_handles; i++)
795 if (!printer_handles[i])
797 if(handle == nb_printer_handles)
798 handle = i;
800 else
802 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
803 queue = printer_handles[i]->queue;
807 if (handle >= nb_printer_handles)
809 opened_printer_t **new_array;
810 if (printer_handles)
811 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
812 (nb_printer_handles + 16) * sizeof(*new_array) );
813 else
814 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
815 (nb_printer_handles + 16) * sizeof(*new_array) );
817 if (!new_array)
819 handle = 0;
820 goto end;
822 printer_handles = new_array;
823 nb_printer_handles += 16;
826 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
828 handle = 0;
829 goto end;
832 /* get a printer handle from the backend */
833 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
834 handle = 0;
835 goto end;
838 /* clone the base name. This is NULL for the printserver */
839 printer->printername = strdupW(printername);
841 /* clone the full name */
842 printer->name = strdupW(name);
843 if (name && (!printer->name)) {
844 handle = 0;
845 goto end;
848 if(queue)
849 printer->queue = queue;
850 else
852 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
853 if (!printer->queue) {
854 handle = 0;
855 goto end;
857 list_init(&printer->queue->jobs);
858 printer->queue->ref = 0;
860 InterlockedIncrement(&printer->queue->ref);
862 printer_handles[handle] = printer;
863 handle++;
864 end:
865 LeaveCriticalSection(&printer_handles_cs);
866 if (!handle && printer) {
867 /* Something failed: Free all resources */
868 HeapFree(GetProcessHeap(), 0, printer->printername);
869 HeapFree(GetProcessHeap(), 0, printer->name);
870 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
871 HeapFree(GetProcessHeap(), 0, printer);
874 return (HANDLE)handle;
877 /******************************************************************
878 * get_opened_printer
879 * Get the pointer to the opened printer referred by the handle
881 static opened_printer_t *get_opened_printer(HANDLE hprn)
883 UINT_PTR idx = (UINT_PTR)hprn;
884 opened_printer_t *ret = NULL;
886 EnterCriticalSection(&printer_handles_cs);
888 if ((idx > 0) && (idx <= nb_printer_handles)) {
889 ret = printer_handles[idx - 1];
891 LeaveCriticalSection(&printer_handles_cs);
892 return ret;
895 /******************************************************************
896 * get_opened_printer_name
897 * Get the pointer to the opened printer name referred by the handle
899 static LPCWSTR get_opened_printer_name(HANDLE hprn)
901 opened_printer_t *printer = get_opened_printer(hprn);
902 if(!printer) return NULL;
903 return printer->name;
906 /******************************************************************
907 * WINSPOOL_GetOpenedPrinterRegKey
910 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
912 LPCWSTR name = get_opened_printer_name(hPrinter);
913 DWORD ret;
914 HKEY hkeyPrinters;
916 if(!name) return ERROR_INVALID_HANDLE;
918 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
919 ERROR_SUCCESS)
920 return ret;
922 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
924 ERR("Can't find opened printer %s in registry\n",
925 debugstr_w(name));
926 RegCloseKey(hkeyPrinters);
927 return ERROR_INVALID_PRINTER_NAME; /* ? */
929 RegCloseKey(hkeyPrinters);
930 return ERROR_SUCCESS;
933 void WINSPOOL_LoadSystemPrinters(void)
935 HKEY hkey, hkeyPrinters;
936 HANDLE hprn;
937 DWORD needed, num, i;
938 WCHAR PrinterName[256];
939 BOOL done = FALSE;
941 /* This ensures that all printer entries have a valid Name value. If causes
942 problems later if they don't. If one is found to be missed we create one
943 and set it equal to the name of the key */
944 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
945 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
946 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
947 for(i = 0; i < num; i++) {
948 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
949 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
950 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
951 set_reg_szW(hkey, NameW, PrinterName);
953 RegCloseKey(hkey);
958 RegCloseKey(hkeyPrinters);
961 /* We want to avoid calling AddPrinter on printers as much as
962 possible, because on cups printers this will (eventually) lead
963 to a call to cupsGetPPD which takes forever, even with non-cups
964 printers AddPrinter takes a while. So we'll tag all printers that
965 were automatically added last time around, if they still exist
966 we'll leave them be otherwise we'll delete them. */
967 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
968 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
969 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
970 for(i = 0; i < num; i++) {
971 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
972 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
973 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
974 DWORD dw = 1;
975 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
976 RegCloseKey(hkey);
978 ClosePrinter(hprn);
983 HeapFree(GetProcessHeap(), 0, pi);
987 #ifdef SONAME_LIBCUPS
988 done = CUPS_LoadPrinters();
989 #endif
991 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
992 PRINTCAP_LoadPrinters();
994 /* Now enumerate the list again and delete any printers that are still tagged */
995 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
996 if(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 BOOL delete_driver = FALSE;
1003 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1004 DWORD dw, type, size = sizeof(dw);
1005 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1006 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1007 DeletePrinter(hprn);
1008 delete_driver = TRUE;
1010 RegCloseKey(hkey);
1012 ClosePrinter(hprn);
1013 if(delete_driver)
1014 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1019 HeapFree(GetProcessHeap(), 0, pi);
1022 return;
1026 /******************************************************************
1027 * get_job
1029 * Get the pointer to the specified job.
1030 * Should hold the printer_handles_cs before calling.
1032 static job_t *get_job(HANDLE hprn, DWORD JobId)
1034 opened_printer_t *printer = get_opened_printer(hprn);
1035 job_t *job;
1037 if(!printer) return NULL;
1038 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1040 if(job->job_id == JobId)
1041 return job;
1043 return NULL;
1046 /***********************************************************
1047 * DEVMODEcpyAtoW
1049 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1051 BOOL Formname;
1052 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1053 DWORD size;
1055 Formname = (dmA->dmSize > off_formname);
1056 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1057 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1058 dmW->dmDeviceName, CCHDEVICENAME);
1059 if(!Formname) {
1060 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1061 dmA->dmSize - CCHDEVICENAME);
1062 } else {
1063 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1064 off_formname - CCHDEVICENAME);
1065 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1066 dmW->dmFormName, CCHFORMNAME);
1067 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1068 (off_formname + CCHFORMNAME));
1070 dmW->dmSize = size;
1071 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1072 dmA->dmDriverExtra);
1073 return dmW;
1076 /***********************************************************
1077 * DEVMODEdupWtoA
1078 * Creates an ansi copy of supplied devmode
1080 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1082 LPDEVMODEA dmA;
1083 DWORD size;
1085 if (!dmW) return NULL;
1086 size = dmW->dmSize - CCHDEVICENAME -
1087 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1089 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1090 if (!dmA) return NULL;
1092 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1093 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1095 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1096 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1097 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1099 else
1101 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1102 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1103 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1104 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1106 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1109 dmA->dmSize = size;
1110 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1111 return dmA;
1114 /******************************************************************
1115 * convert_printerinfo_W_to_A [internal]
1118 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1119 DWORD level, DWORD outlen, DWORD numentries)
1121 DWORD id = 0;
1122 LPSTR ptr;
1123 INT len;
1125 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1127 len = pi_sizeof[level] * numentries;
1128 ptr = (LPSTR) out + len;
1129 outlen -= len;
1131 /* copy the numbers of all PRINTER_INFO_* first */
1132 memcpy(out, pPrintersW, len);
1134 while (id < numentries) {
1135 switch (level) {
1136 case 1:
1138 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1139 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1141 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1142 if (piW->pDescription) {
1143 piA->pDescription = ptr;
1144 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1145 ptr, outlen, NULL, NULL);
1146 ptr += len;
1147 outlen -= len;
1149 if (piW->pName) {
1150 piA->pName = ptr;
1151 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1152 ptr, outlen, NULL, NULL);
1153 ptr += len;
1154 outlen -= len;
1156 if (piW->pComment) {
1157 piA->pComment = ptr;
1158 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1159 ptr, outlen, NULL, NULL);
1160 ptr += len;
1161 outlen -= len;
1163 break;
1166 case 2:
1168 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1169 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1170 LPDEVMODEA dmA;
1172 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1173 if (piW->pServerName) {
1174 piA->pServerName = ptr;
1175 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1176 ptr, outlen, NULL, NULL);
1177 ptr += len;
1178 outlen -= len;
1180 if (piW->pPrinterName) {
1181 piA->pPrinterName = ptr;
1182 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1183 ptr, outlen, NULL, NULL);
1184 ptr += len;
1185 outlen -= len;
1187 if (piW->pShareName) {
1188 piA->pShareName = ptr;
1189 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1190 ptr, outlen, NULL, NULL);
1191 ptr += len;
1192 outlen -= len;
1194 if (piW->pPortName) {
1195 piA->pPortName = ptr;
1196 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1197 ptr, outlen, NULL, NULL);
1198 ptr += len;
1199 outlen -= len;
1201 if (piW->pDriverName) {
1202 piA->pDriverName = ptr;
1203 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1204 ptr, outlen, NULL, NULL);
1205 ptr += len;
1206 outlen -= len;
1208 if (piW->pComment) {
1209 piA->pComment = ptr;
1210 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1211 ptr, outlen, NULL, NULL);
1212 ptr += len;
1213 outlen -= len;
1215 if (piW->pLocation) {
1216 piA->pLocation = ptr;
1217 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1218 ptr, outlen, NULL, NULL);
1219 ptr += len;
1220 outlen -= len;
1223 dmA = DEVMODEdupWtoA(piW->pDevMode);
1224 if (dmA) {
1225 /* align DEVMODEA to a DWORD boundary */
1226 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1227 ptr += len;
1228 outlen -= len;
1230 piA->pDevMode = (LPDEVMODEA) ptr;
1231 len = dmA->dmSize + dmA->dmDriverExtra;
1232 memcpy(ptr, dmA, len);
1233 HeapFree(GetProcessHeap(), 0, dmA);
1235 ptr += len;
1236 outlen -= len;
1239 if (piW->pSepFile) {
1240 piA->pSepFile = ptr;
1241 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1242 ptr, outlen, NULL, NULL);
1243 ptr += len;
1244 outlen -= len;
1246 if (piW->pPrintProcessor) {
1247 piA->pPrintProcessor = ptr;
1248 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1249 ptr, outlen, NULL, NULL);
1250 ptr += len;
1251 outlen -= len;
1253 if (piW->pDatatype) {
1254 piA->pDatatype = ptr;
1255 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1256 ptr, outlen, NULL, NULL);
1257 ptr += len;
1258 outlen -= len;
1260 if (piW->pParameters) {
1261 piA->pParameters = ptr;
1262 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1263 ptr, outlen, NULL, NULL);
1264 ptr += len;
1265 outlen -= len;
1267 if (piW->pSecurityDescriptor) {
1268 piA->pSecurityDescriptor = NULL;
1269 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1271 break;
1274 case 4:
1276 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1277 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1279 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1281 if (piW->pPrinterName) {
1282 piA->pPrinterName = ptr;
1283 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1284 ptr, outlen, NULL, NULL);
1285 ptr += len;
1286 outlen -= len;
1288 if (piW->pServerName) {
1289 piA->pServerName = ptr;
1290 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1291 ptr, outlen, NULL, NULL);
1292 ptr += len;
1293 outlen -= len;
1295 break;
1298 case 5:
1300 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1301 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1303 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1305 if (piW->pPrinterName) {
1306 piA->pPrinterName = ptr;
1307 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1308 ptr, outlen, NULL, NULL);
1309 ptr += len;
1310 outlen -= len;
1312 if (piW->pPortName) {
1313 piA->pPortName = ptr;
1314 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1315 ptr, outlen, NULL, NULL);
1316 ptr += len;
1317 outlen -= len;
1319 break;
1322 case 6: /* 6A and 6W are the same structure */
1323 break;
1325 case 7:
1327 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1328 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1330 TRACE("(%u) #%u\n", level, id);
1331 if (piW->pszObjectGUID) {
1332 piA->pszObjectGUID = ptr;
1333 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1334 ptr, outlen, NULL, NULL);
1335 ptr += len;
1336 outlen -= len;
1338 break;
1341 case 9:
1343 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1344 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1345 LPDEVMODEA dmA;
1347 TRACE("(%u) #%u\n", level, id);
1348 dmA = DEVMODEdupWtoA(piW->pDevMode);
1349 if (dmA) {
1350 /* align DEVMODEA to a DWORD boundary */
1351 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1352 ptr += len;
1353 outlen -= len;
1355 piA->pDevMode = (LPDEVMODEA) ptr;
1356 len = dmA->dmSize + dmA->dmDriverExtra;
1357 memcpy(ptr, dmA, len);
1358 HeapFree(GetProcessHeap(), 0, dmA);
1360 ptr += len;
1361 outlen -= len;
1364 break;
1367 default:
1368 FIXME("for level %u\n", level);
1370 pPrintersW += pi_sizeof[level];
1371 out += pi_sizeof[level];
1372 id++;
1376 /******************************************************************
1377 * convert_driverinfo_W_to_A [internal]
1380 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1381 DWORD level, DWORD outlen, DWORD numentries)
1383 DWORD id = 0;
1384 LPSTR ptr;
1385 INT len;
1387 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1389 len = di_sizeof[level] * numentries;
1390 ptr = (LPSTR) out + len;
1391 outlen -= len;
1393 /* copy the numbers of all PRINTER_INFO_* first */
1394 memcpy(out, pDriversW, len);
1396 #define COPY_STRING(fld) \
1397 { if (diW->fld){ \
1398 diA->fld = ptr; \
1399 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1400 ptr += len; outlen -= len;\
1402 #define COPY_MULTIZ_STRING(fld) \
1403 { LPWSTR p = diW->fld; if (p){ \
1404 diA->fld = ptr; \
1405 do {\
1406 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1407 ptr += len; outlen -= len; p += len;\
1409 while(len > 1 && outlen > 0); \
1412 while (id < numentries)
1414 switch (level)
1416 case 1:
1418 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1419 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1421 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1423 COPY_STRING(pName);
1424 break;
1426 case 2:
1428 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1429 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1431 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1433 COPY_STRING(pName);
1434 COPY_STRING(pEnvironment);
1435 COPY_STRING(pDriverPath);
1436 COPY_STRING(pDataFile);
1437 COPY_STRING(pConfigFile);
1438 break;
1440 case 3:
1442 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1443 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1445 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1447 COPY_STRING(pName);
1448 COPY_STRING(pEnvironment);
1449 COPY_STRING(pDriverPath);
1450 COPY_STRING(pDataFile);
1451 COPY_STRING(pConfigFile);
1452 COPY_STRING(pHelpFile);
1453 COPY_MULTIZ_STRING(pDependentFiles);
1454 COPY_STRING(pMonitorName);
1455 COPY_STRING(pDefaultDataType);
1456 break;
1458 case 4:
1460 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1461 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1463 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1465 COPY_STRING(pName);
1466 COPY_STRING(pEnvironment);
1467 COPY_STRING(pDriverPath);
1468 COPY_STRING(pDataFile);
1469 COPY_STRING(pConfigFile);
1470 COPY_STRING(pHelpFile);
1471 COPY_MULTIZ_STRING(pDependentFiles);
1472 COPY_STRING(pMonitorName);
1473 COPY_STRING(pDefaultDataType);
1474 COPY_MULTIZ_STRING(pszzPreviousNames);
1475 break;
1477 case 5:
1479 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1480 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1482 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1484 COPY_STRING(pName);
1485 COPY_STRING(pEnvironment);
1486 COPY_STRING(pDriverPath);
1487 COPY_STRING(pDataFile);
1488 COPY_STRING(pConfigFile);
1489 break;
1491 case 6:
1493 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1494 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1496 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1498 COPY_STRING(pName);
1499 COPY_STRING(pEnvironment);
1500 COPY_STRING(pDriverPath);
1501 COPY_STRING(pDataFile);
1502 COPY_STRING(pConfigFile);
1503 COPY_STRING(pHelpFile);
1504 COPY_MULTIZ_STRING(pDependentFiles);
1505 COPY_STRING(pMonitorName);
1506 COPY_STRING(pDefaultDataType);
1507 COPY_MULTIZ_STRING(pszzPreviousNames);
1508 COPY_STRING(pszMfgName);
1509 COPY_STRING(pszOEMUrl);
1510 COPY_STRING(pszHardwareID);
1511 COPY_STRING(pszProvider);
1512 break;
1514 case 8:
1516 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1517 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1519 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1521 COPY_STRING(pName);
1522 COPY_STRING(pEnvironment);
1523 COPY_STRING(pDriverPath);
1524 COPY_STRING(pDataFile);
1525 COPY_STRING(pConfigFile);
1526 COPY_STRING(pHelpFile);
1527 COPY_MULTIZ_STRING(pDependentFiles);
1528 COPY_STRING(pMonitorName);
1529 COPY_STRING(pDefaultDataType);
1530 COPY_MULTIZ_STRING(pszzPreviousNames);
1531 COPY_STRING(pszMfgName);
1532 COPY_STRING(pszOEMUrl);
1533 COPY_STRING(pszHardwareID);
1534 COPY_STRING(pszProvider);
1535 COPY_STRING(pszPrintProcessor);
1536 COPY_STRING(pszVendorSetup);
1537 COPY_MULTIZ_STRING(pszzColorProfiles);
1538 COPY_STRING(pszInfPath);
1539 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1540 break;
1544 default:
1545 FIXME("for level %u\n", level);
1548 pDriversW += di_sizeof[level];
1549 out += di_sizeof[level];
1550 id++;
1553 #undef COPY_STRING
1554 #undef COPY_MULTIZ_STRING
1558 /***********************************************************
1559 * PRINTER_INFO_2AtoW
1560 * Creates a unicode copy of PRINTER_INFO_2A on heap
1562 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1564 LPPRINTER_INFO_2W piW;
1565 UNICODE_STRING usBuffer;
1567 if(!piA) return NULL;
1568 piW = HeapAlloc(heap, 0, sizeof(*piW));
1569 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1571 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1572 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1573 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1574 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1575 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1576 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1577 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1578 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1579 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1580 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1581 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1582 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1583 return piW;
1586 /***********************************************************
1587 * FREE_PRINTER_INFO_2W
1588 * Free PRINTER_INFO_2W and all strings
1590 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1592 if(!piW) return;
1594 HeapFree(heap,0,piW->pServerName);
1595 HeapFree(heap,0,piW->pPrinterName);
1596 HeapFree(heap,0,piW->pShareName);
1597 HeapFree(heap,0,piW->pPortName);
1598 HeapFree(heap,0,piW->pDriverName);
1599 HeapFree(heap,0,piW->pComment);
1600 HeapFree(heap,0,piW->pLocation);
1601 HeapFree(heap,0,piW->pDevMode);
1602 HeapFree(heap,0,piW->pSepFile);
1603 HeapFree(heap,0,piW->pPrintProcessor);
1604 HeapFree(heap,0,piW->pDatatype);
1605 HeapFree(heap,0,piW->pParameters);
1606 HeapFree(heap,0,piW);
1607 return;
1610 /******************************************************************
1611 * DeviceCapabilities [WINSPOOL.@]
1612 * DeviceCapabilitiesA [WINSPOOL.@]
1615 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1616 LPSTR pOutput, LPDEVMODEA lpdm)
1618 INT ret;
1620 if (!GDI_CallDeviceCapabilities16)
1622 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1623 (LPCSTR)104 );
1624 if (!GDI_CallDeviceCapabilities16) return -1;
1626 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1628 /* If DC_PAPERSIZE map POINT16s to POINTs */
1629 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1630 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1631 POINT *pt = (POINT *)pOutput;
1632 INT i;
1633 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1634 for(i = 0; i < ret; i++, pt++)
1636 pt->x = tmp[i].x;
1637 pt->y = tmp[i].y;
1639 HeapFree( GetProcessHeap(), 0, tmp );
1641 return ret;
1645 /*****************************************************************************
1646 * DeviceCapabilitiesW [WINSPOOL.@]
1648 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1651 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1652 WORD fwCapability, LPWSTR pOutput,
1653 const DEVMODEW *pDevMode)
1655 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1656 LPSTR pDeviceA = strdupWtoA(pDevice);
1657 LPSTR pPortA = strdupWtoA(pPort);
1658 INT ret;
1660 if(pOutput && (fwCapability == DC_BINNAMES ||
1661 fwCapability == DC_FILEDEPENDENCIES ||
1662 fwCapability == DC_PAPERNAMES)) {
1663 /* These need A -> W translation */
1664 INT size = 0, i;
1665 LPSTR pOutputA;
1666 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1667 dmA);
1668 if(ret == -1)
1669 return ret;
1670 switch(fwCapability) {
1671 case DC_BINNAMES:
1672 size = 24;
1673 break;
1674 case DC_PAPERNAMES:
1675 case DC_FILEDEPENDENCIES:
1676 size = 64;
1677 break;
1679 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1680 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1681 dmA);
1682 for(i = 0; i < ret; i++)
1683 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1684 pOutput + (i * size), size);
1685 HeapFree(GetProcessHeap(), 0, pOutputA);
1686 } else {
1687 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1688 (LPSTR)pOutput, dmA);
1690 HeapFree(GetProcessHeap(),0,pPortA);
1691 HeapFree(GetProcessHeap(),0,pDeviceA);
1692 HeapFree(GetProcessHeap(),0,dmA);
1693 return ret;
1696 /******************************************************************
1697 * DocumentPropertiesA [WINSPOOL.@]
1699 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1701 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1702 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1703 LPDEVMODEA pDevModeInput,DWORD fMode )
1705 LPSTR lpName = pDeviceName;
1706 static CHAR port[] = "LPT1:";
1707 LONG ret;
1709 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1710 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1713 if(!pDeviceName) {
1714 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1715 if(!lpNameW) {
1716 ERR("no name from hPrinter?\n");
1717 SetLastError(ERROR_INVALID_HANDLE);
1718 return -1;
1720 lpName = strdupWtoA(lpNameW);
1723 if (!GDI_CallExtDeviceMode16)
1725 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1726 (LPCSTR)102 );
1727 if (!GDI_CallExtDeviceMode16) {
1728 ERR("No CallExtDeviceMode16?\n");
1729 return -1;
1732 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1733 pDevModeInput, NULL, fMode);
1735 if(!pDeviceName)
1736 HeapFree(GetProcessHeap(),0,lpName);
1737 return ret;
1741 /*****************************************************************************
1742 * DocumentPropertiesW (WINSPOOL.@)
1744 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1746 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1747 LPWSTR pDeviceName,
1748 LPDEVMODEW pDevModeOutput,
1749 LPDEVMODEW pDevModeInput, DWORD fMode)
1752 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1753 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1754 LPDEVMODEA pDevModeOutputA = NULL;
1755 LONG ret;
1757 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1758 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1759 fMode);
1760 if(pDevModeOutput) {
1761 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1762 if(ret < 0) return ret;
1763 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1765 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1766 pDevModeInputA, fMode);
1767 if(pDevModeOutput) {
1768 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1769 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1771 if(fMode == 0 && ret > 0)
1772 ret += (CCHDEVICENAME + CCHFORMNAME);
1773 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1774 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1775 return ret;
1778 /*****************************************************************************
1779 * IsValidDevmodeA [WINSPOOL.@]
1781 * Validate a DEVMODE structure and fix errors if possible.
1784 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1786 FIXME("(%p,%ld): stub\n", pDevMode, size);
1788 if(!pDevMode)
1789 return FALSE;
1791 return TRUE;
1794 /*****************************************************************************
1795 * IsValidDevmodeW [WINSPOOL.@]
1797 * Validate a DEVMODE structure and fix errors if possible.
1800 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1802 FIXME("(%p,%ld): stub\n", pDevMode, size);
1804 if(!pDevMode)
1805 return FALSE;
1807 return TRUE;
1810 /******************************************************************
1811 * OpenPrinterA [WINSPOOL.@]
1813 * See OpenPrinterW.
1816 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1817 LPPRINTER_DEFAULTSA pDefault)
1819 UNICODE_STRING lpPrinterNameW;
1820 UNICODE_STRING usBuffer;
1821 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1822 PWSTR pwstrPrinterNameW;
1823 BOOL ret;
1825 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1827 if(pDefault) {
1828 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1829 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1830 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1831 pDefaultW = &DefaultW;
1833 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1834 if(pDefault) {
1835 RtlFreeUnicodeString(&usBuffer);
1836 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1838 RtlFreeUnicodeString(&lpPrinterNameW);
1839 return ret;
1842 /******************************************************************
1843 * OpenPrinterW [WINSPOOL.@]
1845 * Open a Printer / Printserver or a Printer-Object
1847 * PARAMS
1848 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1849 * phPrinter [O] The resulting Handle is stored here
1850 * pDefault [I] PTR to Default Printer Settings or NULL
1852 * RETURNS
1853 * Success: TRUE
1854 * Failure: FALSE
1856 * NOTES
1857 * lpPrinterName is one of:
1858 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1859 *| Printer: "PrinterName"
1860 *| Printer-Object: "PrinterName,Job xxx"
1861 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1862 *| XcvPort: "Servername,XcvPort PortName"
1864 * BUGS
1865 *| Printer-Object not supported
1866 *| pDefaults is ignored
1869 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1872 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1873 if (pDefault) {
1874 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1875 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1878 if(!phPrinter) {
1879 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1880 SetLastError(ERROR_INVALID_PARAMETER);
1881 return FALSE;
1884 /* Get the unique handle of the printer or Printserver */
1885 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1886 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1887 return (*phPrinter != 0);
1890 /******************************************************************
1891 * AddMonitorA [WINSPOOL.@]
1893 * See AddMonitorW.
1896 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1898 LPWSTR nameW = NULL;
1899 INT len;
1900 BOOL res;
1901 LPMONITOR_INFO_2A mi2a;
1902 MONITOR_INFO_2W mi2w;
1904 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1905 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1906 debugstr_a(mi2a ? mi2a->pName : NULL),
1907 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1908 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1910 if (Level != 2) {
1911 SetLastError(ERROR_INVALID_LEVEL);
1912 return FALSE;
1915 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1916 if (mi2a == NULL) {
1917 return FALSE;
1920 if (pName) {
1921 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1922 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1923 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1926 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1927 if (mi2a->pName) {
1928 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1929 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1930 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1932 if (mi2a->pEnvironment) {
1933 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1934 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1935 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1937 if (mi2a->pDLLName) {
1938 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1939 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1940 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1943 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1945 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1946 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1947 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1949 HeapFree(GetProcessHeap(), 0, nameW);
1950 return (res);
1953 /******************************************************************************
1954 * AddMonitorW [WINSPOOL.@]
1956 * Install a Printmonitor
1958 * PARAMS
1959 * pName [I] Servername or NULL (local Computer)
1960 * Level [I] Structure-Level (Must be 2)
1961 * pMonitors [I] PTR to MONITOR_INFO_2
1963 * RETURNS
1964 * Success: TRUE
1965 * Failure: FALSE
1967 * NOTES
1968 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1971 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1973 LPMONITOR_INFO_2W mi2w;
1975 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1976 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1977 debugstr_w(mi2w ? mi2w->pName : NULL),
1978 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1979 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1981 if ((backend == NULL) && !load_backend()) return FALSE;
1983 if (Level != 2) {
1984 SetLastError(ERROR_INVALID_LEVEL);
1985 return FALSE;
1988 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1989 if (mi2w == NULL) {
1990 return FALSE;
1993 return backend->fpAddMonitor(pName, Level, pMonitors);
1996 /******************************************************************
1997 * DeletePrinterDriverA [WINSPOOL.@]
2000 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2002 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2005 /******************************************************************
2006 * DeletePrinterDriverW [WINSPOOL.@]
2009 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2011 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2014 /******************************************************************
2015 * DeleteMonitorA [WINSPOOL.@]
2017 * See DeleteMonitorW.
2020 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2022 LPWSTR nameW = NULL;
2023 LPWSTR EnvironmentW = NULL;
2024 LPWSTR MonitorNameW = NULL;
2025 BOOL res;
2026 INT len;
2028 if (pName) {
2029 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2030 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2031 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2034 if (pEnvironment) {
2035 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2036 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2037 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2039 if (pMonitorName) {
2040 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2041 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2045 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2047 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2048 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2049 HeapFree(GetProcessHeap(), 0, nameW);
2050 return (res);
2053 /******************************************************************
2054 * DeleteMonitorW [WINSPOOL.@]
2056 * Delete a specific Printmonitor from a Printing-Environment
2058 * PARAMS
2059 * pName [I] Servername or NULL (local Computer)
2060 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2061 * pMonitorName [I] Name of the Monitor, that should be deleted
2063 * RETURNS
2064 * Success: TRUE
2065 * Failure: FALSE
2067 * NOTES
2068 * pEnvironment is ignored in Windows for the local Computer.
2071 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2074 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2075 debugstr_w(pMonitorName));
2077 if ((backend == NULL) && !load_backend()) return FALSE;
2079 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2083 /******************************************************************
2084 * DeletePortA [WINSPOOL.@]
2086 * See DeletePortW.
2089 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2091 LPWSTR nameW = NULL;
2092 LPWSTR portW = NULL;
2093 INT len;
2094 DWORD res;
2096 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2098 /* convert servername to unicode */
2099 if (pName) {
2100 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2101 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2102 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2105 /* convert portname to unicode */
2106 if (pPortName) {
2107 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2108 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2109 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2112 res = DeletePortW(nameW, hWnd, portW);
2113 HeapFree(GetProcessHeap(), 0, nameW);
2114 HeapFree(GetProcessHeap(), 0, portW);
2115 return res;
2118 /******************************************************************
2119 * DeletePortW [WINSPOOL.@]
2121 * Delete a specific Port
2123 * PARAMS
2124 * pName [I] Servername or NULL (local Computer)
2125 * hWnd [I] Handle to parent Window for the Dialog-Box
2126 * pPortName [I] Name of the Port, that should be deleted
2128 * RETURNS
2129 * Success: TRUE
2130 * Failure: FALSE
2133 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2135 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2137 if ((backend == NULL) && !load_backend()) return FALSE;
2139 if (!pPortName) {
2140 SetLastError(RPC_X_NULL_REF_POINTER);
2141 return FALSE;
2144 return backend->fpDeletePort(pName, hWnd, pPortName);
2147 /******************************************************************************
2148 * SetPrinterW [WINSPOOL.@]
2150 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2152 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2153 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2154 return FALSE;
2157 /******************************************************************************
2158 * WritePrinter [WINSPOOL.@]
2160 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2162 opened_printer_t *printer;
2163 BOOL ret = FALSE;
2165 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2167 EnterCriticalSection(&printer_handles_cs);
2168 printer = get_opened_printer(hPrinter);
2169 if(!printer)
2171 SetLastError(ERROR_INVALID_HANDLE);
2172 goto end;
2175 if(!printer->doc)
2177 SetLastError(ERROR_SPL_NO_STARTDOC);
2178 goto end;
2181 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2182 end:
2183 LeaveCriticalSection(&printer_handles_cs);
2184 return ret;
2187 /*****************************************************************************
2188 * AddFormA [WINSPOOL.@]
2190 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2192 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2193 return 1;
2196 /*****************************************************************************
2197 * AddFormW [WINSPOOL.@]
2199 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2201 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2202 return 1;
2205 /*****************************************************************************
2206 * AddJobA [WINSPOOL.@]
2208 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2210 BOOL ret;
2211 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2212 DWORD needed;
2214 if(Level != 1) {
2215 SetLastError(ERROR_INVALID_LEVEL);
2216 return FALSE;
2219 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2221 if(ret) {
2222 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2223 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2224 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2225 if(*pcbNeeded > cbBuf) {
2226 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2227 ret = FALSE;
2228 } else {
2229 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2230 addjobA->JobId = addjobW->JobId;
2231 addjobA->Path = (char *)(addjobA + 1);
2232 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2235 return ret;
2238 /*****************************************************************************
2239 * AddJobW [WINSPOOL.@]
2241 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2243 opened_printer_t *printer;
2244 job_t *job;
2245 BOOL ret = FALSE;
2246 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2247 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2248 WCHAR path[MAX_PATH], filename[MAX_PATH];
2249 DWORD len;
2250 ADDJOB_INFO_1W *addjob;
2252 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2254 EnterCriticalSection(&printer_handles_cs);
2256 printer = get_opened_printer(hPrinter);
2258 if(!printer) {
2259 SetLastError(ERROR_INVALID_HANDLE);
2260 goto end;
2263 if(Level != 1) {
2264 SetLastError(ERROR_INVALID_LEVEL);
2265 goto end;
2268 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2269 if(!job)
2270 goto end;
2272 job->job_id = InterlockedIncrement(&next_job_id);
2274 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2275 if(path[len - 1] != '\\')
2276 path[len++] = '\\';
2277 memcpy(path + len, spool_path, sizeof(spool_path));
2278 sprintfW(filename, fmtW, path, job->job_id);
2280 len = strlenW(filename);
2281 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2282 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2283 job->document_title = strdupW(default_doc_title);
2284 job->printer_name = strdupW(printer->name);
2285 job->devmode = NULL;
2286 list_add_tail(&printer->queue->jobs, &job->entry);
2288 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2289 if(*pcbNeeded <= cbBuf) {
2290 addjob = (ADDJOB_INFO_1W*)pData;
2291 addjob->JobId = job->job_id;
2292 addjob->Path = (WCHAR *)(addjob + 1);
2293 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2294 ret = TRUE;
2295 } else
2296 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2298 end:
2299 LeaveCriticalSection(&printer_handles_cs);
2300 return ret;
2303 /*****************************************************************************
2304 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2306 * Return the PATH for the Print-Processors
2308 * See GetPrintProcessorDirectoryW.
2312 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2313 DWORD level, LPBYTE Info,
2314 DWORD cbBuf, LPDWORD pcbNeeded)
2316 LPWSTR serverW = NULL;
2317 LPWSTR envW = NULL;
2318 BOOL ret;
2319 INT len;
2321 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2322 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2325 if (server) {
2326 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2327 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2328 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2331 if (env) {
2332 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2333 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2334 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2337 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2338 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2340 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2341 cbBuf, pcbNeeded);
2343 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2344 cbBuf, NULL, NULL) > 0;
2347 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2348 HeapFree(GetProcessHeap(), 0, envW);
2349 HeapFree(GetProcessHeap(), 0, serverW);
2350 return ret;
2353 /*****************************************************************************
2354 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2356 * Return the PATH for the Print-Processors
2358 * PARAMS
2359 * server [I] Servername (NT only) or NULL (local Computer)
2360 * env [I] Printing-Environment (see below) or NULL (Default)
2361 * level [I] Structure-Level (must be 1)
2362 * Info [O] PTR to Buffer that receives the Result
2363 * cbBuf [I] Size of Buffer at "Info"
2364 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2365 * required for the Buffer at "Info"
2367 * RETURNS
2368 * Success: TRUE and in pcbNeeded the Bytes used in Info
2369 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2370 * if cbBuf is too small
2372 * Native Values returned in Info on Success:
2373 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2374 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2375 *| win9x(Windows 4.0): "%winsysdir%"
2377 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2379 * BUGS
2380 * Only NULL or "" is supported for server
2383 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2384 DWORD level, LPBYTE Info,
2385 DWORD cbBuf, LPDWORD pcbNeeded)
2388 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2389 Info, cbBuf, pcbNeeded);
2391 if ((backend == NULL) && !load_backend()) return FALSE;
2393 if (level != 1) {
2394 /* (Level != 1) is ignored in win9x */
2395 SetLastError(ERROR_INVALID_LEVEL);
2396 return FALSE;
2399 if (pcbNeeded == NULL) {
2400 /* (pcbNeeded == NULL) is ignored in win9x */
2401 SetLastError(RPC_X_NULL_REF_POINTER);
2402 return FALSE;
2405 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2408 /*****************************************************************************
2409 * WINSPOOL_OpenDriverReg [internal]
2411 * opens the registry for the printer drivers depending on the given input
2412 * variable pEnvironment
2414 * RETURNS:
2415 * the opened hkey on success
2416 * NULL on error
2418 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2420 HKEY retval = NULL;
2421 LPWSTR buffer;
2422 const printenv_t * env;
2424 TRACE("(%s)\n", debugstr_w(pEnvironment));
2426 env = validate_envW(pEnvironment);
2427 if (!env) return NULL;
2429 buffer = HeapAlloc( GetProcessHeap(), 0,
2430 (strlenW(DriversW) + strlenW(env->envname) +
2431 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2432 if(buffer) {
2433 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2434 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2435 HeapFree(GetProcessHeap(), 0, buffer);
2437 return retval;
2440 /*****************************************************************************
2441 * set_devices_and_printerports [internal]
2443 * set the [Devices] and [PrinterPorts] entries for a printer.
2446 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2448 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2449 WCHAR *devline;
2450 HKEY hkey;
2452 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2454 /* FIXME: the driver must change to "winspool" */
2455 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2456 if (devline) {
2457 lstrcpyW(devline, driver_nt);
2458 lstrcatW(devline, commaW);
2459 lstrcatW(devline, pi->pPortName);
2461 TRACE("using %s\n", debugstr_w(devline));
2462 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2463 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2464 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2465 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2466 RegCloseKey(hkey);
2469 lstrcatW(devline, timeout_15_45);
2470 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2471 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2472 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2473 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2474 RegCloseKey(hkey);
2476 HeapFree(GetProcessHeap(), 0, devline);
2480 /*****************************************************************************
2481 * AddPrinterW [WINSPOOL.@]
2483 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2485 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2486 LPDEVMODEA dmA;
2487 LPDEVMODEW dmW;
2488 HANDLE retval;
2489 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2490 LONG size;
2491 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2492 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2493 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2494 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2495 statusW[] = {'S','t','a','t','u','s',0},
2496 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2498 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2500 if(pName != NULL) {
2501 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2502 SetLastError(ERROR_INVALID_PARAMETER);
2503 return 0;
2505 if(Level != 2) {
2506 ERR("Level = %d, unsupported!\n", Level);
2507 SetLastError(ERROR_INVALID_LEVEL);
2508 return 0;
2510 if(!pPrinter) {
2511 SetLastError(ERROR_INVALID_PARAMETER);
2512 return 0;
2514 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2515 ERROR_SUCCESS) {
2516 ERR("Can't create Printers key\n");
2517 return 0;
2519 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2520 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2521 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2522 RegCloseKey(hkeyPrinter);
2523 RegCloseKey(hkeyPrinters);
2524 return 0;
2526 RegCloseKey(hkeyPrinter);
2528 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2529 if(!hkeyDrivers) {
2530 ERR("Can't create Drivers key\n");
2531 RegCloseKey(hkeyPrinters);
2532 return 0;
2534 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2535 ERROR_SUCCESS) {
2536 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2537 RegCloseKey(hkeyPrinters);
2538 RegCloseKey(hkeyDrivers);
2539 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2540 return 0;
2542 RegCloseKey(hkeyDriver);
2543 RegCloseKey(hkeyDrivers);
2545 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2546 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2547 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2548 RegCloseKey(hkeyPrinters);
2549 return 0;
2552 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2553 ERROR_SUCCESS) {
2554 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2555 SetLastError(ERROR_INVALID_PRINTER_NAME);
2556 RegCloseKey(hkeyPrinters);
2557 return 0;
2560 set_devices_and_printerports(pi);
2561 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2562 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2563 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2565 /* See if we can load the driver. We may need the devmode structure anyway
2567 * FIXME:
2568 * Note that DocumentPropertiesW will briefly try to open the printer we
2569 * just create to find a DEVMODEA struct (it will use the WINEPS default
2570 * one in case it is not there, so we are ok).
2572 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2574 if(size < 0) {
2575 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2576 size = sizeof(DEVMODEW);
2578 if(pi->pDevMode)
2579 dmW = pi->pDevMode;
2580 else
2582 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2583 dmW->dmSize = size;
2584 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2586 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2587 HeapFree(GetProcessHeap(),0,dmW);
2588 dmW=NULL;
2590 else
2592 /* set devmode to printer name */
2593 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2597 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2598 and we support these drivers. NT writes DEVMODEW so somehow
2599 we'll need to distinguish between these when we support NT
2600 drivers */
2601 if (dmW)
2603 dmA = DEVMODEdupWtoA(dmW);
2604 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2605 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2606 HeapFree(GetProcessHeap(), 0, dmA);
2607 if(!pi->pDevMode)
2608 HeapFree(GetProcessHeap(), 0, dmW);
2610 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2611 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2612 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2613 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2615 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2616 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2617 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2618 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2619 (LPBYTE)&pi->Priority, sizeof(DWORD));
2620 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2621 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2622 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2623 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2624 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2625 (LPBYTE)&pi->Status, sizeof(DWORD));
2626 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2627 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2629 RegCloseKey(hkeyPrinter);
2630 RegCloseKey(hkeyPrinters);
2631 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2632 ERR("OpenPrinter failing\n");
2633 return 0;
2635 return retval;
2638 /*****************************************************************************
2639 * AddPrinterA [WINSPOOL.@]
2641 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2643 UNICODE_STRING pNameW;
2644 PWSTR pwstrNameW;
2645 PRINTER_INFO_2W *piW;
2646 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2647 HANDLE ret;
2649 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2650 if(Level != 2) {
2651 ERR("Level = %d, unsupported!\n", Level);
2652 SetLastError(ERROR_INVALID_LEVEL);
2653 return 0;
2655 pwstrNameW = asciitounicode(&pNameW,pName);
2656 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2658 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2660 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2661 RtlFreeUnicodeString(&pNameW);
2662 return ret;
2666 /*****************************************************************************
2667 * ClosePrinter [WINSPOOL.@]
2669 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2671 UINT_PTR i = (UINT_PTR)hPrinter;
2672 opened_printer_t *printer = NULL;
2673 BOOL ret = FALSE;
2675 TRACE("(%p)\n", hPrinter);
2677 EnterCriticalSection(&printer_handles_cs);
2679 if ((i > 0) && (i <= nb_printer_handles))
2680 printer = printer_handles[i - 1];
2683 if(printer)
2685 struct list *cursor, *cursor2;
2687 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2689 if (printer->backend_printer) {
2690 backend->fpClosePrinter(printer->backend_printer);
2693 if(printer->doc)
2694 EndDocPrinter(hPrinter);
2696 if(InterlockedDecrement(&printer->queue->ref) == 0)
2698 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2700 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2701 ScheduleJob(hPrinter, job->job_id);
2703 HeapFree(GetProcessHeap(), 0, printer->queue);
2706 HeapFree(GetProcessHeap(), 0, printer->printername);
2707 HeapFree(GetProcessHeap(), 0, printer->name);
2708 HeapFree(GetProcessHeap(), 0, printer);
2709 printer_handles[i - 1] = NULL;
2710 ret = TRUE;
2712 LeaveCriticalSection(&printer_handles_cs);
2713 return ret;
2716 /*****************************************************************************
2717 * DeleteFormA [WINSPOOL.@]
2719 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2721 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2722 return 1;
2725 /*****************************************************************************
2726 * DeleteFormW [WINSPOOL.@]
2728 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2730 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2731 return 1;
2734 /*****************************************************************************
2735 * DeletePrinter [WINSPOOL.@]
2737 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2739 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2740 HKEY hkeyPrinters, hkey;
2742 if(!lpNameW) {
2743 SetLastError(ERROR_INVALID_HANDLE);
2744 return FALSE;
2746 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2747 RegDeleteTreeW(hkeyPrinters, lpNameW);
2748 RegCloseKey(hkeyPrinters);
2750 WriteProfileStringW(devicesW, lpNameW, NULL);
2751 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2753 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2754 RegDeleteValueW(hkey, lpNameW);
2755 RegCloseKey(hkey);
2758 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2759 RegDeleteValueW(hkey, lpNameW);
2760 RegCloseKey(hkey);
2762 return TRUE;
2765 /*****************************************************************************
2766 * SetPrinterA [WINSPOOL.@]
2768 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2769 DWORD Command)
2771 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2772 return FALSE;
2775 /*****************************************************************************
2776 * SetJobA [WINSPOOL.@]
2778 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2779 LPBYTE pJob, DWORD Command)
2781 BOOL ret;
2782 LPBYTE JobW;
2783 UNICODE_STRING usBuffer;
2785 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2787 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2788 are all ignored by SetJob, so we don't bother copying them */
2789 switch(Level)
2791 case 0:
2792 JobW = NULL;
2793 break;
2794 case 1:
2796 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2797 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2799 JobW = (LPBYTE)info1W;
2800 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2801 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2802 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2803 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2804 info1W->Status = info1A->Status;
2805 info1W->Priority = info1A->Priority;
2806 info1W->Position = info1A->Position;
2807 info1W->PagesPrinted = info1A->PagesPrinted;
2808 break;
2810 case 2:
2812 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2813 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2815 JobW = (LPBYTE)info2W;
2816 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2817 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2818 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2819 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2820 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2821 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2822 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2823 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2824 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2825 info2W->Status = info2A->Status;
2826 info2W->Priority = info2A->Priority;
2827 info2W->Position = info2A->Position;
2828 info2W->StartTime = info2A->StartTime;
2829 info2W->UntilTime = info2A->UntilTime;
2830 info2W->PagesPrinted = info2A->PagesPrinted;
2831 break;
2833 case 3:
2834 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2835 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2836 break;
2837 default:
2838 SetLastError(ERROR_INVALID_LEVEL);
2839 return FALSE;
2842 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2844 switch(Level)
2846 case 1:
2848 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2849 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2850 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2851 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2852 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2853 break;
2855 case 2:
2857 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2858 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2859 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2860 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2861 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2862 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2863 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2864 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2865 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2866 break;
2869 HeapFree(GetProcessHeap(), 0, JobW);
2871 return ret;
2874 /*****************************************************************************
2875 * SetJobW [WINSPOOL.@]
2877 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2878 LPBYTE pJob, DWORD Command)
2880 BOOL ret = FALSE;
2881 job_t *job;
2882 DWORD size;
2884 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2885 FIXME("Ignoring everything other than document title\n");
2887 EnterCriticalSection(&printer_handles_cs);
2888 job = get_job(hPrinter, JobId);
2889 if(!job)
2890 goto end;
2892 switch(Level)
2894 case 0:
2895 break;
2896 case 1:
2898 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2899 HeapFree(GetProcessHeap(), 0, job->document_title);
2900 job->document_title = strdupW(info1->pDocument);
2901 break;
2903 case 2:
2905 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2906 HeapFree(GetProcessHeap(), 0, job->document_title);
2907 job->document_title = strdupW(info2->pDocument);
2908 HeapFree(GetProcessHeap(), 0, job->devmode);
2909 if (info2->pDevMode)
2911 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2912 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2913 memcpy(job->devmode, info2->pDevMode, size);
2915 else
2916 job->devmode = NULL;
2917 break;
2919 case 3:
2920 break;
2921 default:
2922 SetLastError(ERROR_INVALID_LEVEL);
2923 goto end;
2925 ret = TRUE;
2926 end:
2927 LeaveCriticalSection(&printer_handles_cs);
2928 return ret;
2931 /*****************************************************************************
2932 * EndDocPrinter [WINSPOOL.@]
2934 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2936 opened_printer_t *printer;
2937 BOOL ret = FALSE;
2938 TRACE("(%p)\n", hPrinter);
2940 EnterCriticalSection(&printer_handles_cs);
2942 printer = get_opened_printer(hPrinter);
2943 if(!printer)
2945 SetLastError(ERROR_INVALID_HANDLE);
2946 goto end;
2949 if(!printer->doc)
2951 SetLastError(ERROR_SPL_NO_STARTDOC);
2952 goto end;
2955 CloseHandle(printer->doc->hf);
2956 ScheduleJob(hPrinter, printer->doc->job_id);
2957 HeapFree(GetProcessHeap(), 0, printer->doc);
2958 printer->doc = NULL;
2959 ret = TRUE;
2960 end:
2961 LeaveCriticalSection(&printer_handles_cs);
2962 return ret;
2965 /*****************************************************************************
2966 * EndPagePrinter [WINSPOOL.@]
2968 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2970 FIXME("(%p): stub\n", hPrinter);
2971 return TRUE;
2974 /*****************************************************************************
2975 * StartDocPrinterA [WINSPOOL.@]
2977 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2979 UNICODE_STRING usBuffer;
2980 DOC_INFO_2W doc2W;
2981 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2982 DWORD ret;
2984 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2985 or one (DOC_INFO_3) extra DWORDs */
2987 switch(Level) {
2988 case 2:
2989 doc2W.JobId = doc2->JobId;
2990 /* fall through */
2991 case 3:
2992 doc2W.dwMode = doc2->dwMode;
2993 /* fall through */
2994 case 1:
2995 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2996 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2997 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2998 break;
3000 default:
3001 SetLastError(ERROR_INVALID_LEVEL);
3002 return FALSE;
3005 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3007 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3008 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3009 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3011 return ret;
3014 /*****************************************************************************
3015 * StartDocPrinterW [WINSPOOL.@]
3017 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3019 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3020 opened_printer_t *printer;
3021 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3022 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3023 JOB_INFO_1W job_info;
3024 DWORD needed, ret = 0;
3025 HANDLE hf;
3026 WCHAR *filename;
3027 job_t *job;
3029 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3030 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3031 debugstr_w(doc->pDatatype));
3033 if(Level < 1 || Level > 3)
3035 SetLastError(ERROR_INVALID_LEVEL);
3036 return 0;
3039 EnterCriticalSection(&printer_handles_cs);
3040 printer = get_opened_printer(hPrinter);
3041 if(!printer)
3043 SetLastError(ERROR_INVALID_HANDLE);
3044 goto end;
3047 if(printer->doc)
3049 SetLastError(ERROR_INVALID_PRINTER_STATE);
3050 goto end;
3053 /* Even if we're printing to a file we still add a print job, we'll
3054 just ignore the spool file name */
3056 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3058 ERR("AddJob failed gle %u\n", GetLastError());
3059 goto end;
3062 /* use pOutputFile only, when it is a real filename */
3063 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3064 filename = doc->pOutputFile;
3065 else
3066 filename = addjob->Path;
3068 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3069 if(hf == INVALID_HANDLE_VALUE)
3070 goto end;
3072 memset(&job_info, 0, sizeof(job_info));
3073 job_info.pDocument = doc->pDocName;
3074 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3076 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3077 printer->doc->hf = hf;
3078 ret = printer->doc->job_id = addjob->JobId;
3079 job = get_job(hPrinter, ret);
3080 job->portname = strdupW(doc->pOutputFile);
3082 end:
3083 LeaveCriticalSection(&printer_handles_cs);
3085 return ret;
3088 /*****************************************************************************
3089 * StartPagePrinter [WINSPOOL.@]
3091 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3093 FIXME("(%p): stub\n", hPrinter);
3094 return TRUE;
3097 /*****************************************************************************
3098 * GetFormA [WINSPOOL.@]
3100 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3101 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3103 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3104 Level,pForm,cbBuf,pcbNeeded);
3105 return FALSE;
3108 /*****************************************************************************
3109 * GetFormW [WINSPOOL.@]
3111 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3112 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3114 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3115 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3116 return FALSE;
3119 /*****************************************************************************
3120 * SetFormA [WINSPOOL.@]
3122 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3123 LPBYTE pForm)
3125 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3126 return FALSE;
3129 /*****************************************************************************
3130 * SetFormW [WINSPOOL.@]
3132 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3133 LPBYTE pForm)
3135 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3136 return FALSE;
3139 /*****************************************************************************
3140 * ReadPrinter [WINSPOOL.@]
3142 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3143 LPDWORD pNoBytesRead)
3145 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3146 return FALSE;
3149 /*****************************************************************************
3150 * ResetPrinterA [WINSPOOL.@]
3152 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3154 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3155 return FALSE;
3158 /*****************************************************************************
3159 * ResetPrinterW [WINSPOOL.@]
3161 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3163 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3164 return FALSE;
3167 /*****************************************************************************
3168 * WINSPOOL_GetDWORDFromReg
3170 * Return DWORD associated with ValueName from hkey.
3172 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3174 DWORD sz = sizeof(DWORD), type, value = 0;
3175 LONG ret;
3177 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3179 if(ret != ERROR_SUCCESS) {
3180 WARN("Got ret = %d on name %s\n", ret, ValueName);
3181 return 0;
3183 if(type != REG_DWORD) {
3184 ERR("Got type %d\n", type);
3185 return 0;
3187 return value;
3191 /*****************************************************************************
3192 * get_filename_from_reg [internal]
3194 * Get ValueName from hkey storing result in out
3195 * when the Value in the registry has only a filename, use driverdir as prefix
3196 * outlen is space left in out
3197 * String is stored either as unicode or ascii
3201 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3202 LPBYTE out, DWORD outlen, LPDWORD needed)
3204 WCHAR filename[MAX_PATH];
3205 DWORD size;
3206 DWORD type;
3207 LONG ret;
3208 LPWSTR buffer = filename;
3209 LPWSTR ptr;
3211 *needed = 0;
3212 size = sizeof(filename);
3213 buffer[0] = '\0';
3214 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3215 if (ret == ERROR_MORE_DATA) {
3216 TRACE("need dynamic buffer: %u\n", size);
3217 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3218 if (!buffer) {
3219 /* No Memory is bad */
3220 return FALSE;
3222 buffer[0] = '\0';
3223 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3226 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3227 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3228 return FALSE;
3231 ptr = buffer;
3232 while (ptr) {
3233 /* do we have a full path ? */
3234 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3235 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3237 if (!ret) {
3238 /* we must build the full Path */
3239 *needed += dirlen;
3240 if ((out) && (outlen > dirlen)) {
3241 lstrcpyW((LPWSTR)out, driverdir);
3242 out += dirlen;
3243 outlen -= dirlen;
3245 else
3246 out = NULL;
3249 /* write the filename */
3250 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3251 if ((out) && (outlen >= size)) {
3252 lstrcpyW((LPWSTR)out, ptr);
3253 out += size;
3254 outlen -= size;
3256 else
3257 out = NULL;
3258 *needed += size;
3259 ptr += lstrlenW(ptr)+1;
3260 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3263 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3265 /* write the multisz-termination */
3266 if (type == REG_MULTI_SZ) {
3267 size = sizeof(WCHAR);
3269 *needed += size;
3270 if (out && (outlen >= size)) {
3271 memset (out, 0, size);
3274 return TRUE;
3277 /*****************************************************************************
3278 * WINSPOOL_GetStringFromReg
3280 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3281 * String is stored as unicode.
3283 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3284 DWORD buflen, DWORD *needed)
3286 DWORD sz = buflen, type;
3287 LONG ret;
3289 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3290 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3291 WARN("Got ret = %d\n", ret);
3292 *needed = 0;
3293 return FALSE;
3295 /* add space for terminating '\0' */
3296 sz += sizeof(WCHAR);
3297 *needed = sz;
3299 if (ptr)
3300 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3302 return TRUE;
3305 /*****************************************************************************
3306 * WINSPOOL_GetDefaultDevMode
3308 * Get a default DevMode values for wineps.
3309 * FIXME - use ppd.
3312 static void WINSPOOL_GetDefaultDevMode(
3313 LPBYTE ptr,
3314 DWORD buflen, DWORD *needed)
3316 DEVMODEW dm;
3317 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3319 /* fill default DEVMODE - should be read from ppd... */
3320 ZeroMemory( &dm, sizeof(dm) );
3321 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3322 dm.dmSpecVersion = DM_SPECVERSION;
3323 dm.dmDriverVersion = 1;
3324 dm.dmSize = sizeof(DEVMODEW);
3325 dm.dmDriverExtra = 0;
3326 dm.dmFields =
3327 DM_ORIENTATION | DM_PAPERSIZE |
3328 DM_PAPERLENGTH | DM_PAPERWIDTH |
3329 DM_SCALE |
3330 DM_COPIES |
3331 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3332 DM_YRESOLUTION | DM_TTOPTION;
3334 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3335 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3336 dm.u1.s1.dmPaperLength = 2970;
3337 dm.u1.s1.dmPaperWidth = 2100;
3339 dm.u1.s1.dmScale = 100;
3340 dm.u1.s1.dmCopies = 1;
3341 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3342 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3343 /* dm.dmColor */
3344 /* dm.dmDuplex */
3345 dm.dmYResolution = 300; /* 300dpi */
3346 dm.dmTTOption = DMTT_BITMAP;
3347 /* dm.dmCollate */
3348 /* dm.dmFormName */
3349 /* dm.dmLogPixels */
3350 /* dm.dmBitsPerPel */
3351 /* dm.dmPelsWidth */
3352 /* dm.dmPelsHeight */
3353 /* dm.u2.dmDisplayFlags */
3354 /* dm.dmDisplayFrequency */
3355 /* dm.dmICMMethod */
3356 /* dm.dmICMIntent */
3357 /* dm.dmMediaType */
3358 /* dm.dmDitherType */
3359 /* dm.dmReserved1 */
3360 /* dm.dmReserved2 */
3361 /* dm.dmPanningWidth */
3362 /* dm.dmPanningHeight */
3364 if(buflen >= sizeof(DEVMODEW))
3365 memcpy(ptr, &dm, sizeof(DEVMODEW));
3366 *needed = sizeof(DEVMODEW);
3369 /*****************************************************************************
3370 * WINSPOOL_GetDevModeFromReg
3372 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3373 * DevMode is stored either as unicode or ascii.
3375 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3376 LPBYTE ptr,
3377 DWORD buflen, DWORD *needed)
3379 DWORD sz = buflen, type;
3380 LONG ret;
3382 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3383 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3384 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3385 if (sz < sizeof(DEVMODEA))
3387 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3388 return FALSE;
3390 /* ensures that dmSize is not erratically bogus if registry is invalid */
3391 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3392 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3393 sz += (CCHDEVICENAME + CCHFORMNAME);
3394 if (ptr && (buflen >= sz)) {
3395 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3396 memcpy(ptr, dmW, sz);
3397 HeapFree(GetProcessHeap(),0,dmW);
3399 *needed = sz;
3400 return TRUE;
3403 /*********************************************************************
3404 * WINSPOOL_GetPrinter_1
3406 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3408 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3409 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3411 DWORD size, left = cbBuf;
3412 BOOL space = (cbBuf > 0);
3413 LPBYTE ptr = buf;
3415 *pcbNeeded = 0;
3417 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3418 if(space && size <= left) {
3419 pi1->pName = (LPWSTR)ptr;
3420 ptr += size;
3421 left -= size;
3422 } else
3423 space = FALSE;
3424 *pcbNeeded += size;
3427 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3428 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3429 if(space && size <= left) {
3430 pi1->pDescription = (LPWSTR)ptr;
3431 ptr += size;
3432 left -= size;
3433 } else
3434 space = FALSE;
3435 *pcbNeeded += size;
3438 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3439 if(space && size <= left) {
3440 pi1->pComment = (LPWSTR)ptr;
3441 ptr += size;
3442 left -= size;
3443 } else
3444 space = FALSE;
3445 *pcbNeeded += size;
3448 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3450 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3451 memset(pi1, 0, sizeof(*pi1));
3453 return space;
3455 /*********************************************************************
3456 * WINSPOOL_GetPrinter_2
3458 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3460 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3461 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3463 DWORD size, left = cbBuf;
3464 BOOL space = (cbBuf > 0);
3465 LPBYTE ptr = buf;
3467 *pcbNeeded = 0;
3469 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3470 if(space && size <= left) {
3471 pi2->pPrinterName = (LPWSTR)ptr;
3472 ptr += size;
3473 left -= size;
3474 } else
3475 space = FALSE;
3476 *pcbNeeded += size;
3478 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3479 if(space && size <= left) {
3480 pi2->pShareName = (LPWSTR)ptr;
3481 ptr += size;
3482 left -= size;
3483 } else
3484 space = FALSE;
3485 *pcbNeeded += size;
3487 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3488 if(space && size <= left) {
3489 pi2->pPortName = (LPWSTR)ptr;
3490 ptr += size;
3491 left -= size;
3492 } else
3493 space = FALSE;
3494 *pcbNeeded += size;
3496 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3497 if(space && size <= left) {
3498 pi2->pDriverName = (LPWSTR)ptr;
3499 ptr += size;
3500 left -= size;
3501 } else
3502 space = FALSE;
3503 *pcbNeeded += size;
3505 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3506 if(space && size <= left) {
3507 pi2->pComment = (LPWSTR)ptr;
3508 ptr += size;
3509 left -= size;
3510 } else
3511 space = FALSE;
3512 *pcbNeeded += size;
3514 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3515 if(space && size <= left) {
3516 pi2->pLocation = (LPWSTR)ptr;
3517 ptr += size;
3518 left -= size;
3519 } else
3520 space = FALSE;
3521 *pcbNeeded += size;
3523 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3524 if(space && size <= left) {
3525 pi2->pDevMode = (LPDEVMODEW)ptr;
3526 ptr += size;
3527 left -= size;
3528 } else
3529 space = FALSE;
3530 *pcbNeeded += size;
3532 else
3534 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3535 if(space && size <= left) {
3536 pi2->pDevMode = (LPDEVMODEW)ptr;
3537 ptr += size;
3538 left -= size;
3539 } else
3540 space = FALSE;
3541 *pcbNeeded += size;
3543 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3544 if(space && size <= left) {
3545 pi2->pSepFile = (LPWSTR)ptr;
3546 ptr += size;
3547 left -= size;
3548 } else
3549 space = FALSE;
3550 *pcbNeeded += size;
3552 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3553 if(space && size <= left) {
3554 pi2->pPrintProcessor = (LPWSTR)ptr;
3555 ptr += size;
3556 left -= size;
3557 } else
3558 space = FALSE;
3559 *pcbNeeded += size;
3561 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3562 if(space && size <= left) {
3563 pi2->pDatatype = (LPWSTR)ptr;
3564 ptr += size;
3565 left -= size;
3566 } else
3567 space = FALSE;
3568 *pcbNeeded += size;
3570 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3571 if(space && size <= left) {
3572 pi2->pParameters = (LPWSTR)ptr;
3573 ptr += size;
3574 left -= size;
3575 } else
3576 space = FALSE;
3577 *pcbNeeded += size;
3579 if(pi2) {
3580 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3581 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3582 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3583 "Default Priority");
3584 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3585 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3588 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3589 memset(pi2, 0, sizeof(*pi2));
3591 return space;
3594 /*********************************************************************
3595 * WINSPOOL_GetPrinter_4
3597 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3599 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3600 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3602 DWORD size, left = cbBuf;
3603 BOOL space = (cbBuf > 0);
3604 LPBYTE ptr = buf;
3606 *pcbNeeded = 0;
3608 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3609 if(space && size <= left) {
3610 pi4->pPrinterName = (LPWSTR)ptr;
3611 ptr += size;
3612 left -= size;
3613 } else
3614 space = FALSE;
3615 *pcbNeeded += size;
3617 if(pi4) {
3618 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3621 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3622 memset(pi4, 0, sizeof(*pi4));
3624 return space;
3627 /*********************************************************************
3628 * WINSPOOL_GetPrinter_5
3630 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3632 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3633 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3635 DWORD size, left = cbBuf;
3636 BOOL space = (cbBuf > 0);
3637 LPBYTE ptr = buf;
3639 *pcbNeeded = 0;
3641 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3642 if(space && size <= left) {
3643 pi5->pPrinterName = (LPWSTR)ptr;
3644 ptr += size;
3645 left -= size;
3646 } else
3647 space = FALSE;
3648 *pcbNeeded += size;
3650 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3651 if(space && size <= left) {
3652 pi5->pPortName = (LPWSTR)ptr;
3653 ptr += size;
3654 left -= size;
3655 } else
3656 space = FALSE;
3657 *pcbNeeded += size;
3659 if(pi5) {
3660 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3661 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3662 "dnsTimeout");
3663 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3664 "txTimeout");
3667 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3668 memset(pi5, 0, sizeof(*pi5));
3670 return space;
3673 /*********************************************************************
3674 * WINSPOOL_GetPrinter_7
3676 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3678 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3679 DWORD cbBuf, LPDWORD pcbNeeded)
3681 DWORD size, left = cbBuf;
3682 BOOL space = (cbBuf > 0);
3683 LPBYTE ptr = buf;
3685 *pcbNeeded = 0;
3687 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3689 ptr = NULL;
3690 size = sizeof(pi7->pszObjectGUID);
3692 if (space && size <= left) {
3693 pi7->pszObjectGUID = (LPWSTR)ptr;
3694 ptr += size;
3695 left -= size;
3696 } else
3697 space = FALSE;
3698 *pcbNeeded += size;
3699 if (pi7) {
3700 /* We do not have a Directory Service */
3701 pi7->dwAction = DSPRINT_UNPUBLISH;
3704 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3705 memset(pi7, 0, sizeof(*pi7));
3707 return space;
3710 /*********************************************************************
3711 * WINSPOOL_GetPrinter_9
3713 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3715 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3716 DWORD cbBuf, LPDWORD pcbNeeded)
3718 DWORD size;
3719 BOOL space = (cbBuf > 0);
3721 *pcbNeeded = 0;
3723 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3724 if(space && size <= cbBuf) {
3725 pi9->pDevMode = (LPDEVMODEW)buf;
3726 } else
3727 space = FALSE;
3728 *pcbNeeded += size;
3730 else
3732 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3733 if(space && size <= cbBuf) {
3734 pi9->pDevMode = (LPDEVMODEW)buf;
3735 } else
3736 space = FALSE;
3737 *pcbNeeded += size;
3740 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3741 memset(pi9, 0, sizeof(*pi9));
3743 return space;
3746 /*****************************************************************************
3747 * GetPrinterW [WINSPOOL.@]
3749 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3750 DWORD cbBuf, LPDWORD pcbNeeded)
3752 LPCWSTR name;
3753 DWORD size, needed = 0;
3754 LPBYTE ptr = NULL;
3755 HKEY hkeyPrinter, hkeyPrinters;
3756 BOOL ret;
3758 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3760 if (!(name = get_opened_printer_name(hPrinter))) {
3761 SetLastError(ERROR_INVALID_HANDLE);
3762 return FALSE;
3765 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3766 ERROR_SUCCESS) {
3767 ERR("Can't create Printers key\n");
3768 return FALSE;
3770 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3772 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3773 RegCloseKey(hkeyPrinters);
3774 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3775 return FALSE;
3778 switch(Level) {
3779 case 2:
3781 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3783 size = sizeof(PRINTER_INFO_2W);
3784 if(size <= cbBuf) {
3785 ptr = pPrinter + size;
3786 cbBuf -= size;
3787 memset(pPrinter, 0, size);
3788 } else {
3789 pi2 = NULL;
3790 cbBuf = 0;
3792 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3793 needed += size;
3794 break;
3797 case 4:
3799 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3801 size = sizeof(PRINTER_INFO_4W);
3802 if(size <= cbBuf) {
3803 ptr = pPrinter + size;
3804 cbBuf -= size;
3805 memset(pPrinter, 0, size);
3806 } else {
3807 pi4 = NULL;
3808 cbBuf = 0;
3810 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3811 needed += size;
3812 break;
3816 case 5:
3818 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3820 size = sizeof(PRINTER_INFO_5W);
3821 if(size <= cbBuf) {
3822 ptr = pPrinter + size;
3823 cbBuf -= size;
3824 memset(pPrinter, 0, size);
3825 } else {
3826 pi5 = NULL;
3827 cbBuf = 0;
3830 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3831 needed += size;
3832 break;
3836 case 6:
3838 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3840 size = sizeof(PRINTER_INFO_6);
3841 if (size <= cbBuf) {
3842 /* FIXME: We do not update the status yet */
3843 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3844 ret = TRUE;
3845 } else {
3846 ret = FALSE;
3849 needed += size;
3850 break;
3853 case 7:
3855 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3857 size = sizeof(PRINTER_INFO_7W);
3858 if (size <= cbBuf) {
3859 ptr = pPrinter + size;
3860 cbBuf -= size;
3861 memset(pPrinter, 0, size);
3862 } else {
3863 pi7 = NULL;
3864 cbBuf = 0;
3867 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3868 needed += size;
3869 break;
3873 case 9:
3875 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3877 size = sizeof(PRINTER_INFO_9W);
3878 if(size <= cbBuf) {
3879 ptr = pPrinter + size;
3880 cbBuf -= size;
3881 memset(pPrinter, 0, size);
3882 } else {
3883 pi9 = NULL;
3884 cbBuf = 0;
3887 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3888 needed += size;
3889 break;
3893 default:
3894 FIXME("Unimplemented level %d\n", Level);
3895 SetLastError(ERROR_INVALID_LEVEL);
3896 RegCloseKey(hkeyPrinters);
3897 RegCloseKey(hkeyPrinter);
3898 return FALSE;
3901 RegCloseKey(hkeyPrinter);
3902 RegCloseKey(hkeyPrinters);
3904 TRACE("returning %d needed = %d\n", ret, needed);
3905 if(pcbNeeded) *pcbNeeded = needed;
3906 if(!ret)
3907 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3908 return ret;
3911 /*****************************************************************************
3912 * GetPrinterA [WINSPOOL.@]
3914 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3915 DWORD cbBuf, LPDWORD pcbNeeded)
3917 BOOL ret;
3918 LPBYTE buf = NULL;
3920 if (cbBuf)
3921 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3923 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3924 if (ret)
3925 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3926 HeapFree(GetProcessHeap(), 0, buf);
3928 return ret;
3931 /*****************************************************************************
3932 * WINSPOOL_EnumPrintersW
3934 * Implementation of EnumPrintersW
3936 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3937 DWORD dwLevel, LPBYTE lpbPrinters,
3938 DWORD cbBuf, LPDWORD lpdwNeeded,
3939 LPDWORD lpdwReturned)
3942 HKEY hkeyPrinters, hkeyPrinter;
3943 WCHAR PrinterName[255];
3944 DWORD needed = 0, number = 0;
3945 DWORD used, i, left;
3946 PBYTE pi, buf;
3948 if(lpbPrinters)
3949 memset(lpbPrinters, 0, cbBuf);
3950 if(lpdwReturned)
3951 *lpdwReturned = 0;
3952 if(lpdwNeeded)
3953 *lpdwNeeded = 0;
3955 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3956 if(dwType == PRINTER_ENUM_DEFAULT)
3957 return TRUE;
3959 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3960 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3961 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3962 if (!dwType) {
3963 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3964 return TRUE;
3969 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3970 FIXME("dwType = %08x\n", dwType);
3971 SetLastError(ERROR_INVALID_FLAGS);
3972 return FALSE;
3975 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3976 ERROR_SUCCESS) {
3977 ERR("Can't create Printers key\n");
3978 return FALSE;
3981 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3982 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3983 RegCloseKey(hkeyPrinters);
3984 ERR("Can't query Printers key\n");
3985 return FALSE;
3987 TRACE("Found %d printers\n", number);
3989 switch(dwLevel) {
3990 case 1:
3991 used = number * sizeof(PRINTER_INFO_1W);
3992 break;
3993 case 2:
3994 used = number * sizeof(PRINTER_INFO_2W);
3995 break;
3996 case 4:
3997 used = number * sizeof(PRINTER_INFO_4W);
3998 break;
3999 case 5:
4000 used = number * sizeof(PRINTER_INFO_5W);
4001 break;
4003 default:
4004 SetLastError(ERROR_INVALID_LEVEL);
4005 RegCloseKey(hkeyPrinters);
4006 return FALSE;
4008 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4010 for(i = 0; i < number; i++) {
4011 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4012 ERROR_SUCCESS) {
4013 ERR("Can't enum key number %d\n", i);
4014 RegCloseKey(hkeyPrinters);
4015 return FALSE;
4017 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4018 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4019 ERROR_SUCCESS) {
4020 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4021 RegCloseKey(hkeyPrinters);
4022 return FALSE;
4025 if(cbBuf > used) {
4026 buf = lpbPrinters + used;
4027 left = cbBuf - used;
4028 } else {
4029 buf = NULL;
4030 left = 0;
4033 switch(dwLevel) {
4034 case 1:
4035 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4036 left, &needed);
4037 used += needed;
4038 if(pi) pi += sizeof(PRINTER_INFO_1W);
4039 break;
4040 case 2:
4041 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4042 left, &needed);
4043 used += needed;
4044 if(pi) pi += sizeof(PRINTER_INFO_2W);
4045 break;
4046 case 4:
4047 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4048 left, &needed);
4049 used += needed;
4050 if(pi) pi += sizeof(PRINTER_INFO_4W);
4051 break;
4052 case 5:
4053 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4054 left, &needed);
4055 used += needed;
4056 if(pi) pi += sizeof(PRINTER_INFO_5W);
4057 break;
4058 default:
4059 ERR("Shouldn't be here!\n");
4060 RegCloseKey(hkeyPrinter);
4061 RegCloseKey(hkeyPrinters);
4062 return FALSE;
4064 RegCloseKey(hkeyPrinter);
4066 RegCloseKey(hkeyPrinters);
4068 if(lpdwNeeded)
4069 *lpdwNeeded = used;
4071 if(used > cbBuf) {
4072 if(lpbPrinters)
4073 memset(lpbPrinters, 0, cbBuf);
4074 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4075 return FALSE;
4077 if(lpdwReturned)
4078 *lpdwReturned = number;
4079 SetLastError(ERROR_SUCCESS);
4080 return TRUE;
4084 /******************************************************************
4085 * EnumPrintersW [WINSPOOL.@]
4087 * Enumerates the available printers, print servers and print
4088 * providers, depending on the specified flags, name and level.
4090 * RETURNS:
4092 * If level is set to 1:
4093 * Returns an array of PRINTER_INFO_1 data structures in the
4094 * lpbPrinters buffer.
4096 * If level is set to 2:
4097 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4098 * Returns an array of PRINTER_INFO_2 data structures in the
4099 * lpbPrinters buffer. Note that according to MSDN also an
4100 * OpenPrinter should be performed on every remote printer.
4102 * If level is set to 4 (officially WinNT only):
4103 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4104 * Fast: Only the registry is queried to retrieve printer names,
4105 * no connection to the driver is made.
4106 * Returns an array of PRINTER_INFO_4 data structures in the
4107 * lpbPrinters buffer.
4109 * If level is set to 5 (officially WinNT4/Win9x only):
4110 * Fast: Only the registry is queried to retrieve printer names,
4111 * no connection to the driver is made.
4112 * Returns an array of PRINTER_INFO_5 data structures in the
4113 * lpbPrinters buffer.
4115 * If level set to 3 or 6+:
4116 * returns zero (failure!)
4118 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4119 * for information.
4121 * BUGS:
4122 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4123 * - Only levels 2, 4 and 5 are implemented at the moment.
4124 * - 16-bit printer drivers are not enumerated.
4125 * - Returned amount of bytes used/needed does not match the real Windoze
4126 * implementation (as in this implementation, all strings are part
4127 * of the buffer, whereas Win32 keeps them somewhere else)
4128 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4130 * NOTE:
4131 * - In a regular Wine installation, no registry settings for printers
4132 * exist, which makes this function return an empty list.
4134 BOOL WINAPI EnumPrintersW(
4135 DWORD dwType, /* [in] Types of print objects to enumerate */
4136 LPWSTR lpszName, /* [in] name of objects to enumerate */
4137 DWORD dwLevel, /* [in] type of printer info structure */
4138 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4139 DWORD cbBuf, /* [in] max size of buffer in bytes */
4140 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4141 LPDWORD lpdwReturned /* [out] number of entries returned */
4144 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4145 lpdwNeeded, lpdwReturned);
4148 /******************************************************************
4149 * EnumPrintersA [WINSPOOL.@]
4151 * See EnumPrintersW
4154 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4155 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4157 BOOL ret;
4158 UNICODE_STRING pNameU;
4159 LPWSTR pNameW;
4160 LPBYTE pPrintersW;
4162 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4163 pPrinters, cbBuf, pcbNeeded, pcReturned);
4165 pNameW = asciitounicode(&pNameU, pName);
4167 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4168 MS Office need this */
4169 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4171 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4173 RtlFreeUnicodeString(&pNameU);
4174 if (ret) {
4175 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4177 HeapFree(GetProcessHeap(), 0, pPrintersW);
4178 return ret;
4181 /*****************************************************************************
4182 * WINSPOOL_GetDriverInfoFromReg [internal]
4184 * Enters the information from the registry into the DRIVER_INFO struct
4186 * RETURNS
4187 * zero if the printer driver does not exist in the registry
4188 * (only if Level > 1) otherwise nonzero
4190 static BOOL WINSPOOL_GetDriverInfoFromReg(
4191 HKEY hkeyDrivers,
4192 LPWSTR DriverName,
4193 const printenv_t * env,
4194 DWORD Level,
4195 LPBYTE ptr, /* DRIVER_INFO */
4196 LPBYTE pDriverStrings, /* strings buffer */
4197 DWORD cbBuf, /* size of string buffer */
4198 LPDWORD pcbNeeded) /* space needed for str. */
4200 DWORD size, tmp;
4201 HKEY hkeyDriver;
4202 WCHAR driverdir[MAX_PATH];
4203 DWORD dirlen;
4204 LPBYTE strPtr = pDriverStrings;
4205 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4207 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4208 debugstr_w(DriverName), env,
4209 Level, di, pDriverStrings, cbBuf);
4211 if (di) ZeroMemory(di, di_sizeof[Level]);
4213 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4214 if (*pcbNeeded <= cbBuf)
4215 strcpyW((LPWSTR)strPtr, DriverName);
4217 /* pName for level 1 has a different offset! */
4218 if (Level == 1) {
4219 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4220 return TRUE;
4223 /* .cVersion and .pName for level > 1 */
4224 if (di) {
4225 di->cVersion = env->driverversion;
4226 di->pName = (LPWSTR) strPtr;
4227 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4230 /* Reserve Space for the largest subdir and a Backslash*/
4231 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4232 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4233 /* Should never Fail */
4234 return FALSE;
4236 lstrcatW(driverdir, env->versionsubdir);
4237 lstrcatW(driverdir, backslashW);
4239 /* dirlen must not include the terminating zero */
4240 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4242 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4243 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4244 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4245 return FALSE;
4248 /* pEnvironment */
4249 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4251 *pcbNeeded += size;
4252 if (*pcbNeeded <= cbBuf) {
4253 lstrcpyW((LPWSTR)strPtr, env->envname);
4254 if (di) di->pEnvironment = (LPWSTR)strPtr;
4255 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4258 /* .pDriverPath is the Graphics rendering engine.
4259 The full Path is required to avoid a crash in some apps */
4260 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4261 *pcbNeeded += size;
4262 if (*pcbNeeded <= cbBuf)
4263 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4265 if (di) di->pDriverPath = (LPWSTR)strPtr;
4266 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4269 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4270 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4271 *pcbNeeded += size;
4272 if (*pcbNeeded <= cbBuf)
4273 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4275 if (di) di->pDataFile = (LPWSTR)strPtr;
4276 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4279 /* .pConfigFile is the Driver user Interface */
4280 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4281 *pcbNeeded += size;
4282 if (*pcbNeeded <= cbBuf)
4283 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4285 if (di) di->pConfigFile = (LPWSTR)strPtr;
4286 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4289 if (Level == 2 ) {
4290 RegCloseKey(hkeyDriver);
4291 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4292 return TRUE;
4295 if (Level == 5 ) {
4296 RegCloseKey(hkeyDriver);
4297 FIXME("level 5: incomplete\n");
4298 return TRUE;
4301 /* .pHelpFile */
4302 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4303 *pcbNeeded += size;
4304 if (*pcbNeeded <= cbBuf)
4305 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4307 if (di) di->pHelpFile = (LPWSTR)strPtr;
4308 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4311 /* .pDependentFiles */
4312 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4313 *pcbNeeded += size;
4314 if (*pcbNeeded <= cbBuf)
4315 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4317 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4318 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4320 else if (GetVersion() & 0x80000000) {
4321 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4322 size = 2 * sizeof(WCHAR);
4323 *pcbNeeded += size;
4324 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4326 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4327 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4330 /* .pMonitorName is the optional Language Monitor */
4331 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4332 *pcbNeeded += size;
4333 if (*pcbNeeded <= cbBuf)
4334 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4336 if (di) di->pMonitorName = (LPWSTR)strPtr;
4337 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4340 /* .pDefaultDataType */
4341 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4342 *pcbNeeded += size;
4343 if(*pcbNeeded <= cbBuf)
4344 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4346 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4347 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4350 if (Level == 3 ) {
4351 RegCloseKey(hkeyDriver);
4352 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4353 return TRUE;
4356 /* .pszzPreviousNames */
4357 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4358 *pcbNeeded += size;
4359 if(*pcbNeeded <= cbBuf)
4360 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4362 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4363 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4366 if (Level == 4 ) {
4367 RegCloseKey(hkeyDriver);
4368 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4369 return TRUE;
4372 /* support is missing, but not important enough for a FIXME */
4373 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4375 /* .pszMfgName */
4376 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4377 *pcbNeeded += size;
4378 if(*pcbNeeded <= cbBuf)
4379 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4381 if (di) di->pszMfgName = (LPWSTR)strPtr;
4382 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4385 /* .pszOEMUrl */
4386 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4387 *pcbNeeded += size;
4388 if(*pcbNeeded <= cbBuf)
4389 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4391 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4392 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4395 /* .pszHardwareID */
4396 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4397 *pcbNeeded += size;
4398 if(*pcbNeeded <= cbBuf)
4399 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4401 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4402 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4405 /* .pszProvider */
4406 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4407 *pcbNeeded += size;
4408 if(*pcbNeeded <= cbBuf)
4409 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4411 if (di) di->pszProvider = (LPWSTR)strPtr;
4412 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4415 if (Level == 6 ) {
4416 RegCloseKey(hkeyDriver);
4417 return TRUE;
4420 /* support is missing, but not important enough for a FIXME */
4421 TRACE("level 8: incomplete\n");
4423 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4424 RegCloseKey(hkeyDriver);
4425 return TRUE;
4428 /*****************************************************************************
4429 * GetPrinterDriverW [WINSPOOL.@]
4431 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4432 DWORD Level, LPBYTE pDriverInfo,
4433 DWORD cbBuf, LPDWORD pcbNeeded)
4435 LPCWSTR name;
4436 WCHAR DriverName[100];
4437 DWORD ret, type, size, needed = 0;
4438 LPBYTE ptr = NULL;
4439 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4440 const printenv_t * env;
4442 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4443 Level,pDriverInfo,cbBuf, pcbNeeded);
4445 if (cbBuf > 0)
4446 ZeroMemory(pDriverInfo, cbBuf);
4448 if (!(name = get_opened_printer_name(hPrinter))) {
4449 SetLastError(ERROR_INVALID_HANDLE);
4450 return FALSE;
4453 if (Level < 1 || Level == 7 || Level > 8) {
4454 SetLastError(ERROR_INVALID_LEVEL);
4455 return FALSE;
4458 env = validate_envW(pEnvironment);
4459 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4461 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4462 ERROR_SUCCESS) {
4463 ERR("Can't create Printers key\n");
4464 return FALSE;
4466 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4467 != ERROR_SUCCESS) {
4468 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4469 RegCloseKey(hkeyPrinters);
4470 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4471 return FALSE;
4473 size = sizeof(DriverName);
4474 DriverName[0] = 0;
4475 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4476 (LPBYTE)DriverName, &size);
4477 RegCloseKey(hkeyPrinter);
4478 RegCloseKey(hkeyPrinters);
4479 if(ret != ERROR_SUCCESS) {
4480 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4481 return FALSE;
4484 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4485 if(!hkeyDrivers) {
4486 ERR("Can't create Drivers key\n");
4487 return FALSE;
4490 size = di_sizeof[Level];
4491 if ((size <= cbBuf) && pDriverInfo)
4492 ptr = pDriverInfo + size;
4494 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4495 env, Level, pDriverInfo, ptr,
4496 (cbBuf < size) ? 0 : cbBuf - size,
4497 &needed)) {
4498 RegCloseKey(hkeyDrivers);
4499 return FALSE;
4502 RegCloseKey(hkeyDrivers);
4504 if(pcbNeeded) *pcbNeeded = size + needed;
4505 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4506 if(cbBuf >= size + needed) return TRUE;
4507 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4508 return FALSE;
4511 /*****************************************************************************
4512 * GetPrinterDriverA [WINSPOOL.@]
4514 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4515 DWORD Level, LPBYTE pDriverInfo,
4516 DWORD cbBuf, LPDWORD pcbNeeded)
4518 BOOL ret;
4519 UNICODE_STRING pEnvW;
4520 PWSTR pwstrEnvW;
4521 LPBYTE buf = NULL;
4523 if (cbBuf)
4525 ZeroMemory(pDriverInfo, cbBuf);
4526 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4529 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4530 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4531 cbBuf, pcbNeeded);
4532 if (ret)
4533 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4535 HeapFree(GetProcessHeap(), 0, buf);
4537 RtlFreeUnicodeString(&pEnvW);
4538 return ret;
4541 /*****************************************************************************
4542 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4544 * Return the PATH for the Printer-Drivers (UNICODE)
4546 * PARAMS
4547 * pName [I] Servername (NT only) or NULL (local Computer)
4548 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4549 * Level [I] Structure-Level (must be 1)
4550 * pDriverDirectory [O] PTR to Buffer that receives the Result
4551 * cbBuf [I] Size of Buffer at pDriverDirectory
4552 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4553 * required for pDriverDirectory
4555 * RETURNS
4556 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4557 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4558 * if cbBuf is too small
4560 * Native Values returned in pDriverDirectory on Success:
4561 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4562 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4563 *| win9x(Windows 4.0): "%winsysdir%"
4565 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4567 * FIXME
4568 *- Only NULL or "" is supported for pName
4571 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4572 DWORD Level, LPBYTE pDriverDirectory,
4573 DWORD cbBuf, LPDWORD pcbNeeded)
4575 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4576 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4578 if ((backend == NULL) && !load_backend()) return FALSE;
4580 if (Level != 1) {
4581 /* (Level != 1) is ignored in win9x */
4582 SetLastError(ERROR_INVALID_LEVEL);
4583 return FALSE;
4585 if (pcbNeeded == NULL) {
4586 /* (pcbNeeded == NULL) is ignored in win9x */
4587 SetLastError(RPC_X_NULL_REF_POINTER);
4588 return FALSE;
4591 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4592 pDriverDirectory, cbBuf, pcbNeeded);
4597 /*****************************************************************************
4598 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4600 * Return the PATH for the Printer-Drivers (ANSI)
4602 * See GetPrinterDriverDirectoryW.
4604 * NOTES
4605 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4608 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4609 DWORD Level, LPBYTE pDriverDirectory,
4610 DWORD cbBuf, LPDWORD pcbNeeded)
4612 UNICODE_STRING nameW, environmentW;
4613 BOOL ret;
4614 DWORD pcbNeededW;
4615 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4616 WCHAR *driverDirectoryW = NULL;
4618 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4619 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4621 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4623 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4624 else nameW.Buffer = NULL;
4625 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4626 else environmentW.Buffer = NULL;
4628 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4629 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4630 if (ret) {
4631 DWORD needed;
4632 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4633 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4634 if(pcbNeeded)
4635 *pcbNeeded = needed;
4636 ret = (needed <= cbBuf) ? TRUE : FALSE;
4637 } else
4638 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4640 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4642 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4643 RtlFreeUnicodeString(&environmentW);
4644 RtlFreeUnicodeString(&nameW);
4646 return ret;
4649 /*****************************************************************************
4650 * AddPrinterDriverA [WINSPOOL.@]
4652 * See AddPrinterDriverW.
4655 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4657 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4658 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4661 /******************************************************************************
4662 * AddPrinterDriverW (WINSPOOL.@)
4664 * Install a Printer Driver
4666 * PARAMS
4667 * pName [I] Servername or NULL (local Computer)
4668 * level [I] Level for the supplied DRIVER_INFO_*W struct
4669 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4671 * RESULTS
4672 * Success: TRUE
4673 * Failure: FALSE
4676 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4678 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4679 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4682 /*****************************************************************************
4683 * AddPrintProcessorA [WINSPOOL.@]
4685 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4686 LPSTR pPrintProcessorName)
4688 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4689 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4690 return FALSE;
4693 /*****************************************************************************
4694 * AddPrintProcessorW [WINSPOOL.@]
4696 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4697 LPWSTR pPrintProcessorName)
4699 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4700 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4701 return TRUE;
4704 /*****************************************************************************
4705 * AddPrintProvidorA [WINSPOOL.@]
4707 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4709 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4710 return FALSE;
4713 /*****************************************************************************
4714 * AddPrintProvidorW [WINSPOOL.@]
4716 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4718 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4719 return FALSE;
4722 /*****************************************************************************
4723 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4725 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4726 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4728 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4729 pDevModeOutput, pDevModeInput);
4730 return 0;
4733 /*****************************************************************************
4734 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4736 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4737 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4739 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4740 pDevModeOutput, pDevModeInput);
4741 return 0;
4744 /*****************************************************************************
4745 * PrinterProperties [WINSPOOL.@]
4747 * Displays a dialog to set the properties of the printer.
4749 * RETURNS
4750 * nonzero on success or zero on failure
4752 * BUGS
4753 * implemented as stub only
4755 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4756 HANDLE hPrinter /* [in] handle to printer object */
4758 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4759 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4760 return FALSE;
4763 /*****************************************************************************
4764 * EnumJobsA [WINSPOOL.@]
4767 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4768 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4769 LPDWORD pcReturned)
4771 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4772 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4774 if(pcbNeeded) *pcbNeeded = 0;
4775 if(pcReturned) *pcReturned = 0;
4776 return FALSE;
4780 /*****************************************************************************
4781 * EnumJobsW [WINSPOOL.@]
4784 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4785 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4786 LPDWORD pcReturned)
4788 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4789 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4791 if(pcbNeeded) *pcbNeeded = 0;
4792 if(pcReturned) *pcReturned = 0;
4793 return FALSE;
4796 /*****************************************************************************
4797 * WINSPOOL_EnumPrinterDrivers [internal]
4799 * Delivers information about all printer drivers installed on the
4800 * localhost or a given server
4802 * RETURNS
4803 * nonzero on success or zero on failure. If the buffer for the returned
4804 * information is too small the function will return an error
4806 * BUGS
4807 * - only implemented for localhost, foreign hosts will return an error
4809 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4810 DWORD Level, LPBYTE pDriverInfo,
4811 DWORD driver_index,
4812 DWORD cbBuf, LPDWORD pcbNeeded,
4813 LPDWORD pcFound, DWORD data_offset)
4815 { HKEY hkeyDrivers;
4816 DWORD i, size = 0;
4817 const printenv_t * env;
4819 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4820 debugstr_w(pName), debugstr_w(pEnvironment),
4821 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4823 env = validate_envW(pEnvironment);
4824 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4826 *pcFound = 0;
4828 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4829 if(!hkeyDrivers) {
4830 ERR("Can't open Drivers key\n");
4831 return FALSE;
4834 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4835 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4836 RegCloseKey(hkeyDrivers);
4837 ERR("Can't query Drivers key\n");
4838 return FALSE;
4840 TRACE("Found %d Drivers\n", *pcFound);
4842 /* get size of single struct
4843 * unicode and ascii structure have the same size
4845 size = di_sizeof[Level];
4847 if (data_offset == 0)
4848 data_offset = size * (*pcFound);
4849 *pcbNeeded = data_offset;
4851 for( i = 0; i < *pcFound; i++) {
4852 WCHAR DriverNameW[255];
4853 PBYTE table_ptr = NULL;
4854 PBYTE data_ptr = NULL;
4855 DWORD needed = 0;
4857 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4858 != ERROR_SUCCESS) {
4859 ERR("Can't enum key number %d\n", i);
4860 RegCloseKey(hkeyDrivers);
4861 return FALSE;
4864 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4865 table_ptr = pDriverInfo + (driver_index + i) * size;
4866 if (pDriverInfo && *pcbNeeded <= cbBuf)
4867 data_ptr = pDriverInfo + *pcbNeeded;
4869 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4870 env, Level, table_ptr, data_ptr,
4871 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4872 &needed)) {
4873 RegCloseKey(hkeyDrivers);
4874 return FALSE;
4877 *pcbNeeded += needed;
4880 RegCloseKey(hkeyDrivers);
4882 if(cbBuf < *pcbNeeded){
4883 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4884 return FALSE;
4887 return TRUE;
4890 /*****************************************************************************
4891 * EnumPrinterDriversW [WINSPOOL.@]
4893 * see function EnumPrinterDrivers for RETURNS, BUGS
4895 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4896 LPBYTE pDriverInfo, DWORD cbBuf,
4897 LPDWORD pcbNeeded, LPDWORD pcReturned)
4899 static const WCHAR allW[] = {'a','l','l',0};
4900 BOOL ret;
4901 DWORD found;
4903 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4905 SetLastError(RPC_X_NULL_REF_POINTER);
4906 return FALSE;
4909 /* check for local drivers */
4910 if((pName) && (pName[0])) {
4911 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4912 SetLastError(ERROR_ACCESS_DENIED);
4913 return FALSE;
4916 /* check input parameter */
4917 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4918 SetLastError(ERROR_INVALID_LEVEL);
4919 return FALSE;
4922 if(pDriverInfo && cbBuf > 0)
4923 memset( pDriverInfo, 0, cbBuf);
4925 /* Exception: pull all printers */
4926 if (pEnvironment && !strcmpW(pEnvironment, allW))
4928 DWORD i, needed, bufsize = cbBuf;
4929 DWORD total_needed = 0;
4930 DWORD total_found = 0;
4931 DWORD data_offset;
4933 /* Precompute the overall total; we need this to know
4934 where pointers end and data begins (i.e. data_offset) */
4935 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4937 needed = found = 0;
4938 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4939 NULL, 0, 0, &needed, &found, 0);
4940 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4941 total_needed += needed;
4942 total_found += found;
4945 data_offset = di_sizeof[Level] * total_found;
4947 *pcReturned = 0;
4948 *pcbNeeded = 0;
4949 total_found = 0;
4950 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4952 needed = found = 0;
4953 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4954 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4955 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4956 else if (ret)
4957 *pcReturned += found;
4958 *pcbNeeded = needed;
4959 data_offset = needed;
4960 total_found += found;
4962 return ret;
4965 /* Normal behavior */
4966 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4967 0, cbBuf, pcbNeeded, &found, 0);
4968 if (ret)
4969 *pcReturned = found;
4971 return ret;
4974 /*****************************************************************************
4975 * EnumPrinterDriversA [WINSPOOL.@]
4977 * see function EnumPrinterDrivers for RETURNS, BUGS
4979 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4980 LPBYTE pDriverInfo, DWORD cbBuf,
4981 LPDWORD pcbNeeded, LPDWORD pcReturned)
4983 BOOL ret;
4984 UNICODE_STRING pNameW, pEnvironmentW;
4985 PWSTR pwstrNameW, pwstrEnvironmentW;
4986 LPBYTE buf = NULL;
4988 if (cbBuf)
4989 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4991 pwstrNameW = asciitounicode(&pNameW, pName);
4992 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4994 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4995 buf, cbBuf, pcbNeeded, pcReturned);
4996 if (ret)
4997 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4999 HeapFree(GetProcessHeap(), 0, buf);
5001 RtlFreeUnicodeString(&pNameW);
5002 RtlFreeUnicodeString(&pEnvironmentW);
5004 return ret;
5007 /******************************************************************************
5008 * EnumPortsA (WINSPOOL.@)
5010 * See EnumPortsW.
5013 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5014 LPDWORD pcbNeeded, LPDWORD pcReturned)
5016 BOOL res;
5017 LPBYTE bufferW = NULL;
5018 LPWSTR nameW = NULL;
5019 DWORD needed = 0;
5020 DWORD numentries = 0;
5021 INT len;
5023 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5024 cbBuf, pcbNeeded, pcReturned);
5026 /* convert servername to unicode */
5027 if (pName) {
5028 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5029 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5030 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5032 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5033 needed = cbBuf * sizeof(WCHAR);
5034 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5035 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5037 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5038 if (pcbNeeded) needed = *pcbNeeded;
5039 /* HeapReAlloc return NULL, when bufferW was NULL */
5040 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5041 HeapAlloc(GetProcessHeap(), 0, needed);
5043 /* Try again with the large Buffer */
5044 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5046 needed = pcbNeeded ? *pcbNeeded : 0;
5047 numentries = pcReturned ? *pcReturned : 0;
5050 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5051 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5053 if (res) {
5054 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5055 DWORD entrysize = 0;
5056 DWORD index;
5057 LPSTR ptr;
5058 LPPORT_INFO_2W pi2w;
5059 LPPORT_INFO_2A pi2a;
5061 needed = 0;
5062 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5064 /* First pass: calculate the size for all Entries */
5065 pi2w = (LPPORT_INFO_2W) bufferW;
5066 pi2a = (LPPORT_INFO_2A) pPorts;
5067 index = 0;
5068 while (index < numentries) {
5069 index++;
5070 needed += entrysize; /* PORT_INFO_?A */
5071 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5073 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5074 NULL, 0, NULL, NULL);
5075 if (Level > 1) {
5076 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5077 NULL, 0, NULL, NULL);
5078 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5079 NULL, 0, NULL, NULL);
5081 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5082 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5083 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5086 /* check for errors and quit on failure */
5087 if (cbBuf < needed) {
5088 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5089 res = FALSE;
5090 goto cleanup;
5092 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5093 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5094 cbBuf -= len ; /* free Bytes in the user-Buffer */
5095 pi2w = (LPPORT_INFO_2W) bufferW;
5096 pi2a = (LPPORT_INFO_2A) pPorts;
5097 index = 0;
5098 /* Second Pass: Fill the User Buffer (if we have one) */
5099 while ((index < numentries) && pPorts) {
5100 index++;
5101 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5102 pi2a->pPortName = ptr;
5103 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5104 ptr, cbBuf , NULL, NULL);
5105 ptr += len;
5106 cbBuf -= len;
5107 if (Level > 1) {
5108 pi2a->pMonitorName = ptr;
5109 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5110 ptr, cbBuf, NULL, NULL);
5111 ptr += len;
5112 cbBuf -= len;
5114 pi2a->pDescription = ptr;
5115 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5116 ptr, cbBuf, NULL, NULL);
5117 ptr += len;
5118 cbBuf -= len;
5120 pi2a->fPortType = pi2w->fPortType;
5121 pi2a->Reserved = 0; /* documented: "must be zero" */
5124 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5125 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5126 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5130 cleanup:
5131 if (pcbNeeded) *pcbNeeded = needed;
5132 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5134 HeapFree(GetProcessHeap(), 0, nameW);
5135 HeapFree(GetProcessHeap(), 0, bufferW);
5137 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5138 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5140 return (res);
5144 /******************************************************************************
5145 * EnumPortsW (WINSPOOL.@)
5147 * Enumerate available Ports
5149 * PARAMS
5150 * pName [I] Servername or NULL (local Computer)
5151 * Level [I] Structure-Level (1 or 2)
5152 * pPorts [O] PTR to Buffer that receives the Result
5153 * cbBuf [I] Size of Buffer at pPorts
5154 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5155 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5157 * RETURNS
5158 * Success: TRUE
5159 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5162 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5165 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5166 cbBuf, pcbNeeded, pcReturned);
5168 if ((backend == NULL) && !load_backend()) return FALSE;
5170 /* Level is not checked in win9x */
5171 if (!Level || (Level > 2)) {
5172 WARN("level (%d) is ignored in win9x\n", Level);
5173 SetLastError(ERROR_INVALID_LEVEL);
5174 return FALSE;
5176 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5177 SetLastError(RPC_X_NULL_REF_POINTER);
5178 return FALSE;
5181 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5184 /******************************************************************************
5185 * GetDefaultPrinterW (WINSPOOL.@)
5187 * FIXME
5188 * This function must read the value from data 'device' of key
5189 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5191 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5193 BOOL retval = TRUE;
5194 DWORD insize, len;
5195 WCHAR *buffer, *ptr;
5197 if (!namesize)
5199 SetLastError(ERROR_INVALID_PARAMETER);
5200 return FALSE;
5203 /* make the buffer big enough for the stuff from the profile/registry,
5204 * the content must fit into the local buffer to compute the correct
5205 * size even if the extern buffer is too small or not given.
5206 * (20 for ,driver,port) */
5207 insize = *namesize;
5208 len = max(100, (insize + 20));
5209 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5211 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5213 SetLastError (ERROR_FILE_NOT_FOUND);
5214 retval = FALSE;
5215 goto end;
5217 TRACE("%s\n", debugstr_w(buffer));
5219 if ((ptr = strchrW(buffer, ',')) == NULL)
5221 SetLastError(ERROR_INVALID_NAME);
5222 retval = FALSE;
5223 goto end;
5226 *ptr = 0;
5227 *namesize = strlenW(buffer) + 1;
5228 if(!name || (*namesize > insize))
5230 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5231 retval = FALSE;
5232 goto end;
5234 strcpyW(name, buffer);
5236 end:
5237 HeapFree( GetProcessHeap(), 0, buffer);
5238 return retval;
5242 /******************************************************************************
5243 * GetDefaultPrinterA (WINSPOOL.@)
5245 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5247 BOOL retval = TRUE;
5248 DWORD insize = 0;
5249 WCHAR *bufferW = NULL;
5251 if (!namesize)
5253 SetLastError(ERROR_INVALID_PARAMETER);
5254 return FALSE;
5257 if(name && *namesize) {
5258 insize = *namesize;
5259 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5262 if(!GetDefaultPrinterW( bufferW, namesize)) {
5263 retval = FALSE;
5264 goto end;
5267 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5268 NULL, NULL);
5269 if (!*namesize)
5271 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5272 retval = FALSE;
5274 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5276 end:
5277 HeapFree( GetProcessHeap(), 0, bufferW);
5278 return retval;
5282 /******************************************************************************
5283 * SetDefaultPrinterW (WINSPOOL.204)
5285 * Set the Name of the Default Printer
5287 * PARAMS
5288 * pszPrinter [I] Name of the Printer or NULL
5290 * RETURNS
5291 * Success: True
5292 * Failure: FALSE
5294 * NOTES
5295 * When the Parameter is NULL or points to an Empty String and
5296 * a Default Printer was already present, then this Function changes nothing.
5297 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5298 * the First enumerated local Printer is used.
5301 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5303 WCHAR default_printer[MAX_PATH];
5304 LPWSTR buffer = NULL;
5305 HKEY hreg;
5306 DWORD size;
5307 DWORD namelen;
5308 LONG lres;
5310 TRACE("(%s)\n", debugstr_w(pszPrinter));
5311 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5313 default_printer[0] = '\0';
5314 size = sizeof(default_printer)/sizeof(WCHAR);
5316 /* if we have a default Printer, do nothing. */
5317 if (GetDefaultPrinterW(default_printer, &size))
5318 return TRUE;
5320 pszPrinter = NULL;
5321 /* we have no default Printer: search local Printers and use the first */
5322 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5324 default_printer[0] = '\0';
5325 size = sizeof(default_printer)/sizeof(WCHAR);
5326 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5328 pszPrinter = default_printer;
5329 TRACE("using %s\n", debugstr_w(pszPrinter));
5331 RegCloseKey(hreg);
5334 if (pszPrinter == NULL) {
5335 TRACE("no local printer found\n");
5336 SetLastError(ERROR_FILE_NOT_FOUND);
5337 return FALSE;
5341 /* "pszPrinter" is never empty or NULL here. */
5342 namelen = lstrlenW(pszPrinter);
5343 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5344 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5345 if (!buffer ||
5346 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5347 HeapFree(GetProcessHeap(), 0, buffer);
5348 SetLastError(ERROR_FILE_NOT_FOUND);
5349 return FALSE;
5352 /* read the devices entry for the printer (driver,port) to build the string for the
5353 default device entry (printer,driver,port) */
5354 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5355 buffer[namelen] = ',';
5356 namelen++; /* move index to the start of the driver */
5358 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5359 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5360 if (!lres) {
5361 TRACE("set device to %s\n", debugstr_w(buffer));
5363 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5364 TRACE("failed to set the device entry: %d\n", GetLastError());
5365 lres = ERROR_INVALID_PRINTER_NAME;
5368 /* remove the next section, when INIFileMapping is implemented */
5370 HKEY hdev;
5371 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5372 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5373 RegCloseKey(hdev);
5377 else
5379 if (lres != ERROR_FILE_NOT_FOUND)
5380 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5382 SetLastError(ERROR_INVALID_PRINTER_NAME);
5385 RegCloseKey(hreg);
5386 HeapFree(GetProcessHeap(), 0, buffer);
5387 return (lres == ERROR_SUCCESS);
5390 /******************************************************************************
5391 * SetDefaultPrinterA (WINSPOOL.202)
5393 * See SetDefaultPrinterW.
5396 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5398 LPWSTR bufferW = NULL;
5399 BOOL res;
5401 TRACE("(%s)\n", debugstr_a(pszPrinter));
5402 if(pszPrinter) {
5403 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5404 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5405 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5407 res = SetDefaultPrinterW(bufferW);
5408 HeapFree(GetProcessHeap(), 0, bufferW);
5409 return res;
5412 /******************************************************************************
5413 * SetPrinterDataExA (WINSPOOL.@)
5415 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5416 LPCSTR pValueName, DWORD Type,
5417 LPBYTE pData, DWORD cbData)
5419 HKEY hkeyPrinter, hkeySubkey;
5420 DWORD ret;
5422 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5423 debugstr_a(pValueName), Type, pData, cbData);
5425 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5426 != ERROR_SUCCESS)
5427 return ret;
5429 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5430 != ERROR_SUCCESS) {
5431 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5432 RegCloseKey(hkeyPrinter);
5433 return ret;
5435 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5436 RegCloseKey(hkeySubkey);
5437 RegCloseKey(hkeyPrinter);
5438 return ret;
5441 /******************************************************************************
5442 * SetPrinterDataExW (WINSPOOL.@)
5444 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5445 LPCWSTR pValueName, DWORD Type,
5446 LPBYTE pData, DWORD cbData)
5448 HKEY hkeyPrinter, hkeySubkey;
5449 DWORD ret;
5451 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5452 debugstr_w(pValueName), Type, pData, cbData);
5454 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5455 != ERROR_SUCCESS)
5456 return ret;
5458 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5459 != ERROR_SUCCESS) {
5460 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5461 RegCloseKey(hkeyPrinter);
5462 return ret;
5464 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5465 RegCloseKey(hkeySubkey);
5466 RegCloseKey(hkeyPrinter);
5467 return ret;
5470 /******************************************************************************
5471 * SetPrinterDataA (WINSPOOL.@)
5473 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5474 LPBYTE pData, DWORD cbData)
5476 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5477 pData, cbData);
5480 /******************************************************************************
5481 * SetPrinterDataW (WINSPOOL.@)
5483 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5484 LPBYTE pData, DWORD cbData)
5486 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5487 pData, cbData);
5490 /******************************************************************************
5491 * GetPrinterDataExA (WINSPOOL.@)
5493 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5494 LPCSTR pValueName, LPDWORD pType,
5495 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5497 opened_printer_t *printer;
5498 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5499 DWORD ret;
5501 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5502 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5504 printer = get_opened_printer(hPrinter);
5505 if(!printer) return ERROR_INVALID_HANDLE;
5507 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5508 if (ret) return ret;
5510 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5512 if (printer->name) {
5514 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5515 if (ret) {
5516 RegCloseKey(hkeyPrinters);
5517 return ret;
5519 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5520 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5521 RegCloseKey(hkeyPrinter);
5522 RegCloseKey(hkeyPrinters);
5523 return ret;
5526 *pcbNeeded = nSize;
5527 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5528 0, pType, pData, pcbNeeded);
5530 if (!ret && !pData) ret = ERROR_MORE_DATA;
5532 RegCloseKey(hkeySubkey);
5533 RegCloseKey(hkeyPrinter);
5534 RegCloseKey(hkeyPrinters);
5536 TRACE("--> %d\n", ret);
5537 return ret;
5540 /******************************************************************************
5541 * GetPrinterDataExW (WINSPOOL.@)
5543 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5544 LPCWSTR pValueName, LPDWORD pType,
5545 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5547 opened_printer_t *printer;
5548 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5549 DWORD ret;
5551 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5552 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5554 printer = get_opened_printer(hPrinter);
5555 if(!printer) return ERROR_INVALID_HANDLE;
5557 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5558 if (ret) return ret;
5560 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5562 if (printer->name) {
5564 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5565 if (ret) {
5566 RegCloseKey(hkeyPrinters);
5567 return ret;
5569 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5570 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5571 RegCloseKey(hkeyPrinter);
5572 RegCloseKey(hkeyPrinters);
5573 return ret;
5576 *pcbNeeded = nSize;
5577 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5578 0, pType, pData, pcbNeeded);
5580 if (!ret && !pData) ret = ERROR_MORE_DATA;
5582 RegCloseKey(hkeySubkey);
5583 RegCloseKey(hkeyPrinter);
5584 RegCloseKey(hkeyPrinters);
5586 TRACE("--> %d\n", ret);
5587 return ret;
5590 /******************************************************************************
5591 * GetPrinterDataA (WINSPOOL.@)
5593 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5594 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5596 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5597 pData, nSize, pcbNeeded);
5600 /******************************************************************************
5601 * GetPrinterDataW (WINSPOOL.@)
5603 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5604 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5606 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5607 pData, nSize, pcbNeeded);
5610 /*******************************************************************************
5611 * EnumPrinterDataExW [WINSPOOL.@]
5613 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5614 LPBYTE pEnumValues, DWORD cbEnumValues,
5615 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5617 HKEY hkPrinter, hkSubKey;
5618 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5619 cbValueNameLen, cbMaxValueLen, cbValueLen,
5620 cbBufSize, dwType;
5621 LPWSTR lpValueName;
5622 HANDLE hHeap;
5623 PBYTE lpValue;
5624 PPRINTER_ENUM_VALUESW ppev;
5626 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5628 if (pKeyName == NULL || *pKeyName == 0)
5629 return ERROR_INVALID_PARAMETER;
5631 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5632 if (ret != ERROR_SUCCESS)
5634 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5635 hPrinter, ret);
5636 return ret;
5639 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5640 if (ret != ERROR_SUCCESS)
5642 r = RegCloseKey (hkPrinter);
5643 if (r != ERROR_SUCCESS)
5644 WARN ("RegCloseKey returned %i\n", r);
5645 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5646 debugstr_w (pKeyName), ret);
5647 return ret;
5650 ret = RegCloseKey (hkPrinter);
5651 if (ret != ERROR_SUCCESS)
5653 ERR ("RegCloseKey returned %i\n", ret);
5654 r = RegCloseKey (hkSubKey);
5655 if (r != ERROR_SUCCESS)
5656 WARN ("RegCloseKey returned %i\n", r);
5657 return ret;
5660 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5661 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5662 if (ret != ERROR_SUCCESS)
5664 r = RegCloseKey (hkSubKey);
5665 if (r != ERROR_SUCCESS)
5666 WARN ("RegCloseKey returned %i\n", r);
5667 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5668 return ret;
5671 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5672 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5674 if (cValues == 0) /* empty key */
5676 r = RegCloseKey (hkSubKey);
5677 if (r != ERROR_SUCCESS)
5678 WARN ("RegCloseKey returned %i\n", r);
5679 *pcbEnumValues = *pnEnumValues = 0;
5680 return ERROR_SUCCESS;
5683 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5685 hHeap = GetProcessHeap ();
5686 if (hHeap == NULL)
5688 ERR ("GetProcessHeap failed\n");
5689 r = RegCloseKey (hkSubKey);
5690 if (r != ERROR_SUCCESS)
5691 WARN ("RegCloseKey returned %i\n", r);
5692 return ERROR_OUTOFMEMORY;
5695 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5696 if (lpValueName == NULL)
5698 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5699 r = RegCloseKey (hkSubKey);
5700 if (r != ERROR_SUCCESS)
5701 WARN ("RegCloseKey returned %i\n", r);
5702 return ERROR_OUTOFMEMORY;
5705 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5706 if (lpValue == NULL)
5708 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5709 if (HeapFree (hHeap, 0, lpValueName) == 0)
5710 WARN ("HeapFree failed with code %i\n", GetLastError ());
5711 r = RegCloseKey (hkSubKey);
5712 if (r != ERROR_SUCCESS)
5713 WARN ("RegCloseKey returned %i\n", r);
5714 return ERROR_OUTOFMEMORY;
5717 TRACE ("pass 1: calculating buffer required for all names and values\n");
5719 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5721 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5723 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5725 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5726 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5727 NULL, NULL, lpValue, &cbValueLen);
5728 if (ret != ERROR_SUCCESS)
5730 if (HeapFree (hHeap, 0, lpValue) == 0)
5731 WARN ("HeapFree failed with code %i\n", GetLastError ());
5732 if (HeapFree (hHeap, 0, lpValueName) == 0)
5733 WARN ("HeapFree failed with code %i\n", GetLastError ());
5734 r = RegCloseKey (hkSubKey);
5735 if (r != ERROR_SUCCESS)
5736 WARN ("RegCloseKey returned %i\n", r);
5737 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5738 return ret;
5741 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5742 debugstr_w (lpValueName), dwIndex,
5743 cbValueNameLen + 1, cbValueLen);
5745 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5746 cbBufSize += cbValueLen;
5749 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5751 *pcbEnumValues = cbBufSize;
5752 *pnEnumValues = cValues;
5754 if (cbEnumValues < cbBufSize) /* buffer too small */
5756 if (HeapFree (hHeap, 0, lpValue) == 0)
5757 WARN ("HeapFree failed with code %i\n", GetLastError ());
5758 if (HeapFree (hHeap, 0, lpValueName) == 0)
5759 WARN ("HeapFree failed with code %i\n", GetLastError ());
5760 r = RegCloseKey (hkSubKey);
5761 if (r != ERROR_SUCCESS)
5762 WARN ("RegCloseKey returned %i\n", r);
5763 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5764 return ERROR_MORE_DATA;
5767 TRACE ("pass 2: copying all names and values to buffer\n");
5769 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5770 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5772 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5774 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5775 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5776 NULL, &dwType, lpValue, &cbValueLen);
5777 if (ret != ERROR_SUCCESS)
5779 if (HeapFree (hHeap, 0, lpValue) == 0)
5780 WARN ("HeapFree failed with code %i\n", GetLastError ());
5781 if (HeapFree (hHeap, 0, lpValueName) == 0)
5782 WARN ("HeapFree failed with code %i\n", GetLastError ());
5783 r = RegCloseKey (hkSubKey);
5784 if (r != ERROR_SUCCESS)
5785 WARN ("RegCloseKey returned %i\n", r);
5786 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5787 return ret;
5790 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5791 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5792 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5793 pEnumValues += cbValueNameLen;
5795 /* return # of *bytes* (including trailing \0), not # of chars */
5796 ppev[dwIndex].cbValueName = cbValueNameLen;
5798 ppev[dwIndex].dwType = dwType;
5800 memcpy (pEnumValues, lpValue, cbValueLen);
5801 ppev[dwIndex].pData = pEnumValues;
5802 pEnumValues += cbValueLen;
5804 ppev[dwIndex].cbData = cbValueLen;
5806 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5807 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5810 if (HeapFree (hHeap, 0, lpValue) == 0)
5812 ret = GetLastError ();
5813 ERR ("HeapFree failed with code %i\n", ret);
5814 if (HeapFree (hHeap, 0, lpValueName) == 0)
5815 WARN ("HeapFree failed with code %i\n", GetLastError ());
5816 r = RegCloseKey (hkSubKey);
5817 if (r != ERROR_SUCCESS)
5818 WARN ("RegCloseKey returned %i\n", r);
5819 return ret;
5822 if (HeapFree (hHeap, 0, lpValueName) == 0)
5824 ret = GetLastError ();
5825 ERR ("HeapFree failed with code %i\n", ret);
5826 r = RegCloseKey (hkSubKey);
5827 if (r != ERROR_SUCCESS)
5828 WARN ("RegCloseKey returned %i\n", r);
5829 return ret;
5832 ret = RegCloseKey (hkSubKey);
5833 if (ret != ERROR_SUCCESS)
5835 ERR ("RegCloseKey returned %i\n", ret);
5836 return ret;
5839 return ERROR_SUCCESS;
5842 /*******************************************************************************
5843 * EnumPrinterDataExA [WINSPOOL.@]
5845 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5846 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5847 * what Windows 2000 SP1 does.
5850 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5851 LPBYTE pEnumValues, DWORD cbEnumValues,
5852 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5854 INT len;
5855 LPWSTR pKeyNameW;
5856 DWORD ret, dwIndex, dwBufSize;
5857 HANDLE hHeap;
5858 LPSTR pBuffer;
5860 TRACE ("%p %s\n", hPrinter, pKeyName);
5862 if (pKeyName == NULL || *pKeyName == 0)
5863 return ERROR_INVALID_PARAMETER;
5865 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5866 if (len == 0)
5868 ret = GetLastError ();
5869 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5870 return ret;
5873 hHeap = GetProcessHeap ();
5874 if (hHeap == NULL)
5876 ERR ("GetProcessHeap failed\n");
5877 return ERROR_OUTOFMEMORY;
5880 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5881 if (pKeyNameW == NULL)
5883 ERR ("Failed to allocate %i bytes from process heap\n",
5884 (LONG)(len * sizeof (WCHAR)));
5885 return ERROR_OUTOFMEMORY;
5888 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5890 ret = GetLastError ();
5891 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5892 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5893 WARN ("HeapFree failed with code %i\n", GetLastError ());
5894 return ret;
5897 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5898 pcbEnumValues, pnEnumValues);
5899 if (ret != ERROR_SUCCESS)
5901 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5902 WARN ("HeapFree failed with code %i\n", GetLastError ());
5903 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5904 return ret;
5907 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5909 ret = GetLastError ();
5910 ERR ("HeapFree failed with code %i\n", ret);
5911 return ret;
5914 if (*pnEnumValues == 0) /* empty key */
5915 return ERROR_SUCCESS;
5917 dwBufSize = 0;
5918 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5920 PPRINTER_ENUM_VALUESW ppev =
5921 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5923 if (dwBufSize < ppev->cbValueName)
5924 dwBufSize = ppev->cbValueName;
5926 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5927 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5928 dwBufSize = ppev->cbData;
5931 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5933 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5934 if (pBuffer == NULL)
5936 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5937 return ERROR_OUTOFMEMORY;
5940 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5942 PPRINTER_ENUM_VALUESW ppev =
5943 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5945 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5946 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5947 NULL);
5948 if (len == 0)
5950 ret = GetLastError ();
5951 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5952 if (HeapFree (hHeap, 0, pBuffer) == 0)
5953 WARN ("HeapFree failed with code %i\n", GetLastError ());
5954 return ret;
5957 memcpy (ppev->pValueName, pBuffer, len);
5959 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5961 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5962 ppev->dwType != REG_MULTI_SZ)
5963 continue;
5965 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5966 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5967 if (len == 0)
5969 ret = GetLastError ();
5970 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5971 if (HeapFree (hHeap, 0, pBuffer) == 0)
5972 WARN ("HeapFree failed with code %i\n", GetLastError ());
5973 return ret;
5976 memcpy (ppev->pData, pBuffer, len);
5978 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5979 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5982 if (HeapFree (hHeap, 0, pBuffer) == 0)
5984 ret = GetLastError ();
5985 ERR ("HeapFree failed with code %i\n", ret);
5986 return ret;
5989 return ERROR_SUCCESS;
5992 /******************************************************************************
5993 * AbortPrinter (WINSPOOL.@)
5995 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5997 FIXME("(%p), stub!\n", hPrinter);
5998 return TRUE;
6001 /******************************************************************************
6002 * AddPortA (WINSPOOL.@)
6004 * See AddPortW.
6007 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6009 LPWSTR nameW = NULL;
6010 LPWSTR monitorW = NULL;
6011 DWORD len;
6012 BOOL res;
6014 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6016 if (pName) {
6017 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6018 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6019 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6022 if (pMonitorName) {
6023 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6024 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6025 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6027 res = AddPortW(nameW, hWnd, monitorW);
6028 HeapFree(GetProcessHeap(), 0, nameW);
6029 HeapFree(GetProcessHeap(), 0, monitorW);
6030 return res;
6033 /******************************************************************************
6034 * AddPortW (WINSPOOL.@)
6036 * Add a Port for a specific Monitor
6038 * PARAMS
6039 * pName [I] Servername or NULL (local Computer)
6040 * hWnd [I] Handle to parent Window for the Dialog-Box
6041 * pMonitorName [I] Name of the Monitor that manage the Port
6043 * RETURNS
6044 * Success: TRUE
6045 * Failure: FALSE
6048 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6050 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6052 if ((backend == NULL) && !load_backend()) return FALSE;
6054 if (!pMonitorName) {
6055 SetLastError(RPC_X_NULL_REF_POINTER);
6056 return FALSE;
6059 return backend->fpAddPort(pName, hWnd, pMonitorName);
6062 /******************************************************************************
6063 * AddPortExA (WINSPOOL.@)
6065 * See AddPortExW.
6068 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6070 PORT_INFO_2W pi2W;
6071 PORT_INFO_2A * pi2A;
6072 LPWSTR nameW = NULL;
6073 LPWSTR monitorW = NULL;
6074 DWORD len;
6075 BOOL res;
6077 pi2A = (PORT_INFO_2A *) pBuffer;
6079 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6080 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6082 if ((level < 1) || (level > 2)) {
6083 SetLastError(ERROR_INVALID_LEVEL);
6084 return FALSE;
6087 if (!pi2A) {
6088 SetLastError(ERROR_INVALID_PARAMETER);
6089 return FALSE;
6092 if (pName) {
6093 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6094 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6095 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6098 if (pMonitorName) {
6099 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6100 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6101 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6104 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6106 if (pi2A->pPortName) {
6107 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6108 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6109 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6112 if (level > 1) {
6113 if (pi2A->pMonitorName) {
6114 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6115 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6116 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6119 if (pi2A->pDescription) {
6120 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6121 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6122 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6124 pi2W.fPortType = pi2A->fPortType;
6125 pi2W.Reserved = pi2A->Reserved;
6128 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6130 HeapFree(GetProcessHeap(), 0, nameW);
6131 HeapFree(GetProcessHeap(), 0, monitorW);
6132 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6133 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6134 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6135 return res;
6139 /******************************************************************************
6140 * AddPortExW (WINSPOOL.@)
6142 * Add a Port for a specific Monitor, without presenting a user interface
6144 * PARAMS
6145 * pName [I] Servername or NULL (local Computer)
6146 * level [I] Structure-Level (1 or 2) for pBuffer
6147 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6148 * pMonitorName [I] Name of the Monitor that manage the Port
6150 * RETURNS
6151 * Success: TRUE
6152 * Failure: FALSE
6155 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6157 PORT_INFO_2W * pi2;
6159 pi2 = (PORT_INFO_2W *) pBuffer;
6161 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6162 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6163 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6164 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6166 if ((backend == NULL) && !load_backend()) return FALSE;
6168 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6169 SetLastError(ERROR_INVALID_PARAMETER);
6170 return FALSE;
6173 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6176 /******************************************************************************
6177 * AddPrinterConnectionA (WINSPOOL.@)
6179 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6181 FIXME("%s\n", debugstr_a(pName));
6182 return FALSE;
6185 /******************************************************************************
6186 * AddPrinterConnectionW (WINSPOOL.@)
6188 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6190 FIXME("%s\n", debugstr_w(pName));
6191 return FALSE;
6194 /******************************************************************************
6195 * AddPrinterDriverExW (WINSPOOL.@)
6197 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6199 * PARAMS
6200 * pName [I] Servername or NULL (local Computer)
6201 * level [I] Level for the supplied DRIVER_INFO_*W struct
6202 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6203 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6205 * RESULTS
6206 * Success: TRUE
6207 * Failure: FALSE
6210 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6212 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6214 if ((backend == NULL) && !load_backend()) return FALSE;
6216 if (level < 2 || level == 5 || level == 7 || level > 8) {
6217 SetLastError(ERROR_INVALID_LEVEL);
6218 return FALSE;
6221 if (!pDriverInfo) {
6222 SetLastError(ERROR_INVALID_PARAMETER);
6223 return FALSE;
6226 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6229 /******************************************************************************
6230 * AddPrinterDriverExA (WINSPOOL.@)
6232 * See AddPrinterDriverExW.
6235 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6237 DRIVER_INFO_8A *diA;
6238 DRIVER_INFO_8W diW;
6239 LPWSTR nameW = NULL;
6240 DWORD lenA;
6241 DWORD len;
6242 DWORD res = FALSE;
6244 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6246 diA = (DRIVER_INFO_8A *) pDriverInfo;
6247 ZeroMemory(&diW, sizeof(diW));
6249 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6250 SetLastError(ERROR_INVALID_LEVEL);
6251 return FALSE;
6254 if (diA == NULL) {
6255 SetLastError(ERROR_INVALID_PARAMETER);
6256 return FALSE;
6259 /* convert servername to unicode */
6260 if (pName) {
6261 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6262 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6263 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6266 /* common fields */
6267 diW.cVersion = diA->cVersion;
6269 if (diA->pName) {
6270 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6271 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6272 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6275 if (diA->pEnvironment) {
6276 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6277 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6278 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6281 if (diA->pDriverPath) {
6282 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6283 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6284 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6287 if (diA->pDataFile) {
6288 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6289 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6290 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6293 if (diA->pConfigFile) {
6294 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6295 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6296 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6299 if ((Level > 2) && diA->pDependentFiles) {
6300 lenA = multi_sz_lenA(diA->pDependentFiles);
6301 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6302 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6303 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6306 if ((Level > 2) && diA->pMonitorName) {
6307 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6308 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6309 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6312 if ((Level > 3) && diA->pDefaultDataType) {
6313 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6314 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6315 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6318 if ((Level > 3) && diA->pszzPreviousNames) {
6319 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6320 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6321 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6322 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6325 if ((Level > 5) && diA->pszMfgName) {
6326 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6327 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6328 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6331 if ((Level > 5) && diA->pszOEMUrl) {
6332 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6333 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6334 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6337 if ((Level > 5) && diA->pszHardwareID) {
6338 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6339 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6340 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6343 if ((Level > 5) && diA->pszProvider) {
6344 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6345 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6346 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6349 if (Level > 7) {
6350 FIXME("level %u is incomplete\n", Level);
6353 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6354 TRACE("got %u with %u\n", res, GetLastError());
6355 HeapFree(GetProcessHeap(), 0, nameW);
6356 HeapFree(GetProcessHeap(), 0, diW.pName);
6357 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6358 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6359 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6360 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6361 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6362 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6363 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6364 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6365 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6366 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6367 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6368 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6370 TRACE("=> %u with %u\n", res, GetLastError());
6371 return res;
6374 /******************************************************************************
6375 * ConfigurePortA (WINSPOOL.@)
6377 * See ConfigurePortW.
6380 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6382 LPWSTR nameW = NULL;
6383 LPWSTR portW = NULL;
6384 INT len;
6385 DWORD res;
6387 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6389 /* convert servername to unicode */
6390 if (pName) {
6391 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6392 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6393 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6396 /* convert portname to unicode */
6397 if (pPortName) {
6398 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6399 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6400 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6403 res = ConfigurePortW(nameW, hWnd, portW);
6404 HeapFree(GetProcessHeap(), 0, nameW);
6405 HeapFree(GetProcessHeap(), 0, portW);
6406 return res;
6409 /******************************************************************************
6410 * ConfigurePortW (WINSPOOL.@)
6412 * Display the Configuration-Dialog for a specific Port
6414 * PARAMS
6415 * pName [I] Servername or NULL (local Computer)
6416 * hWnd [I] Handle to parent Window for the Dialog-Box
6417 * pPortName [I] Name of the Port, that should be configured
6419 * RETURNS
6420 * Success: TRUE
6421 * Failure: FALSE
6424 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6427 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6429 if ((backend == NULL) && !load_backend()) return FALSE;
6431 if (!pPortName) {
6432 SetLastError(RPC_X_NULL_REF_POINTER);
6433 return FALSE;
6436 return backend->fpConfigurePort(pName, hWnd, pPortName);
6439 /******************************************************************************
6440 * ConnectToPrinterDlg (WINSPOOL.@)
6442 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6444 FIXME("%p %x\n", hWnd, Flags);
6445 return NULL;
6448 /******************************************************************************
6449 * DeletePrinterConnectionA (WINSPOOL.@)
6451 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6453 FIXME("%s\n", debugstr_a(pName));
6454 return TRUE;
6457 /******************************************************************************
6458 * DeletePrinterConnectionW (WINSPOOL.@)
6460 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6462 FIXME("%s\n", debugstr_w(pName));
6463 return TRUE;
6466 /******************************************************************************
6467 * DeletePrinterDriverExW (WINSPOOL.@)
6469 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6470 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6472 HKEY hkey_drivers;
6473 BOOL ret = FALSE;
6475 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6476 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6478 if(pName && pName[0])
6480 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6481 SetLastError(ERROR_INVALID_PARAMETER);
6482 return FALSE;
6485 if(dwDeleteFlag)
6487 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6488 SetLastError(ERROR_INVALID_PARAMETER);
6489 return FALSE;
6492 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6494 if(!hkey_drivers)
6496 ERR("Can't open drivers key\n");
6497 return FALSE;
6500 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6501 ret = TRUE;
6503 RegCloseKey(hkey_drivers);
6505 return ret;
6508 /******************************************************************************
6509 * DeletePrinterDriverExA (WINSPOOL.@)
6511 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6512 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6514 UNICODE_STRING NameW, EnvW, DriverW;
6515 BOOL ret;
6517 asciitounicode(&NameW, pName);
6518 asciitounicode(&EnvW, pEnvironment);
6519 asciitounicode(&DriverW, pDriverName);
6521 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6523 RtlFreeUnicodeString(&DriverW);
6524 RtlFreeUnicodeString(&EnvW);
6525 RtlFreeUnicodeString(&NameW);
6527 return ret;
6530 /******************************************************************************
6531 * DeletePrinterDataExW (WINSPOOL.@)
6533 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6534 LPCWSTR pValueName)
6536 FIXME("%p %s %s\n", hPrinter,
6537 debugstr_w(pKeyName), debugstr_w(pValueName));
6538 return ERROR_INVALID_PARAMETER;
6541 /******************************************************************************
6542 * DeletePrinterDataExA (WINSPOOL.@)
6544 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6545 LPCSTR pValueName)
6547 FIXME("%p %s %s\n", hPrinter,
6548 debugstr_a(pKeyName), debugstr_a(pValueName));
6549 return ERROR_INVALID_PARAMETER;
6552 /******************************************************************************
6553 * DeletePrintProcessorA (WINSPOOL.@)
6555 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6557 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6558 debugstr_a(pPrintProcessorName));
6559 return TRUE;
6562 /******************************************************************************
6563 * DeletePrintProcessorW (WINSPOOL.@)
6565 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6567 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6568 debugstr_w(pPrintProcessorName));
6569 return TRUE;
6572 /******************************************************************************
6573 * DeletePrintProvidorA (WINSPOOL.@)
6575 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6577 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6578 debugstr_a(pPrintProviderName));
6579 return TRUE;
6582 /******************************************************************************
6583 * DeletePrintProvidorW (WINSPOOL.@)
6585 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6587 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6588 debugstr_w(pPrintProviderName));
6589 return TRUE;
6592 /******************************************************************************
6593 * EnumFormsA (WINSPOOL.@)
6595 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6596 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6598 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6599 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6600 return FALSE;
6603 /******************************************************************************
6604 * EnumFormsW (WINSPOOL.@)
6606 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6607 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6609 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6610 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6611 return FALSE;
6614 /*****************************************************************************
6615 * EnumMonitorsA [WINSPOOL.@]
6617 * See EnumMonitorsW.
6620 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6621 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6623 BOOL res;
6624 LPBYTE bufferW = NULL;
6625 LPWSTR nameW = NULL;
6626 DWORD needed = 0;
6627 DWORD numentries = 0;
6628 INT len;
6630 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6631 cbBuf, pcbNeeded, pcReturned);
6633 /* convert servername to unicode */
6634 if (pName) {
6635 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6636 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6637 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6639 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6640 needed = cbBuf * sizeof(WCHAR);
6641 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6642 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6644 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6645 if (pcbNeeded) needed = *pcbNeeded;
6646 /* HeapReAlloc return NULL, when bufferW was NULL */
6647 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6648 HeapAlloc(GetProcessHeap(), 0, needed);
6650 /* Try again with the large Buffer */
6651 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6653 numentries = pcReturned ? *pcReturned : 0;
6654 needed = 0;
6656 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6657 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6659 if (res) {
6660 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6661 DWORD entrysize = 0;
6662 DWORD index;
6663 LPSTR ptr;
6664 LPMONITOR_INFO_2W mi2w;
6665 LPMONITOR_INFO_2A mi2a;
6667 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6668 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6670 /* First pass: calculate the size for all Entries */
6671 mi2w = (LPMONITOR_INFO_2W) bufferW;
6672 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6673 index = 0;
6674 while (index < numentries) {
6675 index++;
6676 needed += entrysize; /* MONITOR_INFO_?A */
6677 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6679 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6680 NULL, 0, NULL, NULL);
6681 if (Level > 1) {
6682 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6683 NULL, 0, NULL, NULL);
6684 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6685 NULL, 0, NULL, NULL);
6687 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6688 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6689 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6692 /* check for errors and quit on failure */
6693 if (cbBuf < needed) {
6694 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6695 res = FALSE;
6696 goto emA_cleanup;
6698 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6699 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6700 cbBuf -= len ; /* free Bytes in the user-Buffer */
6701 mi2w = (LPMONITOR_INFO_2W) bufferW;
6702 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6703 index = 0;
6704 /* Second Pass: Fill the User Buffer (if we have one) */
6705 while ((index < numentries) && pMonitors) {
6706 index++;
6707 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6708 mi2a->pName = ptr;
6709 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6710 ptr, cbBuf , NULL, NULL);
6711 ptr += len;
6712 cbBuf -= len;
6713 if (Level > 1) {
6714 mi2a->pEnvironment = ptr;
6715 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6716 ptr, cbBuf, NULL, NULL);
6717 ptr += len;
6718 cbBuf -= len;
6720 mi2a->pDLLName = ptr;
6721 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6722 ptr, cbBuf, NULL, NULL);
6723 ptr += len;
6724 cbBuf -= len;
6726 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6727 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6728 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6731 emA_cleanup:
6732 if (pcbNeeded) *pcbNeeded = needed;
6733 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6735 HeapFree(GetProcessHeap(), 0, nameW);
6736 HeapFree(GetProcessHeap(), 0, bufferW);
6738 TRACE("returning %d with %d (%d byte for %d entries)\n",
6739 (res), GetLastError(), needed, numentries);
6741 return (res);
6745 /*****************************************************************************
6746 * EnumMonitorsW [WINSPOOL.@]
6748 * Enumerate available Port-Monitors
6750 * PARAMS
6751 * pName [I] Servername or NULL (local Computer)
6752 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6753 * pMonitors [O] PTR to Buffer that receives the Result
6754 * cbBuf [I] Size of Buffer at pMonitors
6755 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6756 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6758 * RETURNS
6759 * Success: TRUE
6760 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6763 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6764 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6767 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6768 cbBuf, pcbNeeded, pcReturned);
6770 if ((backend == NULL) && !load_backend()) return FALSE;
6772 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6773 SetLastError(RPC_X_NULL_REF_POINTER);
6774 return FALSE;
6777 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6780 /******************************************************************************
6781 * SpoolerInit (WINSPOOL.@)
6783 * Initialize the Spooler
6785 * RETURNS
6786 * Success: TRUE
6787 * Failure: FALSE
6789 * NOTES
6790 * The function fails on windows, when the spooler service is not running
6793 BOOL WINAPI SpoolerInit(void)
6796 if ((backend == NULL) && !load_backend()) return FALSE;
6797 return TRUE;
6800 /******************************************************************************
6801 * XcvDataW (WINSPOOL.@)
6803 * Execute commands in the Printmonitor DLL
6805 * PARAMS
6806 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6807 * pszDataName [i] Name of the command to execute
6808 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6809 * cbInputData [i] Size in Bytes of Buffer at pInputData
6810 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6811 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6812 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6813 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6815 * RETURNS
6816 * Success: TRUE
6817 * Failure: FALSE
6819 * NOTES
6820 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6821 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6823 * Minimal List of commands, that a Printmonitor DLL should support:
6825 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6826 *| "AddPort" : Add a Port
6827 *| "DeletePort": Delete a Port
6829 * Many Printmonitors support additional commands. Examples for localspl.dll:
6830 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6831 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6834 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6835 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6836 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6838 opened_printer_t *printer;
6840 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6841 pInputData, cbInputData, pOutputData,
6842 cbOutputData, pcbOutputNeeded, pdwStatus);
6844 if ((backend == NULL) && !load_backend()) return FALSE;
6846 printer = get_opened_printer(hXcv);
6847 if (!printer || (!printer->backend_printer)) {
6848 SetLastError(ERROR_INVALID_HANDLE);
6849 return FALSE;
6852 if (!pcbOutputNeeded) {
6853 SetLastError(ERROR_INVALID_PARAMETER);
6854 return FALSE;
6857 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6858 SetLastError(RPC_X_NULL_REF_POINTER);
6859 return FALSE;
6862 *pcbOutputNeeded = 0;
6864 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6865 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6869 /*****************************************************************************
6870 * EnumPrinterDataA [WINSPOOL.@]
6873 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6874 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6875 DWORD cbData, LPDWORD pcbData )
6877 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6878 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6879 return ERROR_NO_MORE_ITEMS;
6882 /*****************************************************************************
6883 * EnumPrinterDataW [WINSPOOL.@]
6886 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6887 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6888 DWORD cbData, LPDWORD pcbData )
6890 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6891 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6892 return ERROR_NO_MORE_ITEMS;
6895 /*****************************************************************************
6896 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6899 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6900 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6901 LPDWORD pcbNeeded, LPDWORD pcReturned)
6903 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6904 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6905 pcbNeeded, pcReturned);
6906 return FALSE;
6909 /*****************************************************************************
6910 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6913 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6914 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6915 LPDWORD pcbNeeded, LPDWORD pcReturned)
6917 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6918 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6919 pcbNeeded, pcReturned);
6920 return FALSE;
6923 /*****************************************************************************
6924 * EnumPrintProcessorsA [WINSPOOL.@]
6926 * See EnumPrintProcessorsW.
6929 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6930 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6932 BOOL res;
6933 LPBYTE bufferW = NULL;
6934 LPWSTR nameW = NULL;
6935 LPWSTR envW = NULL;
6936 DWORD needed = 0;
6937 DWORD numentries = 0;
6938 INT len;
6940 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6941 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6943 /* convert names to unicode */
6944 if (pName) {
6945 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6946 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6947 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6949 if (pEnvironment) {
6950 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6951 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6952 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6955 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6956 needed = cbBuf * sizeof(WCHAR);
6957 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6958 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6960 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6961 if (pcbNeeded) needed = *pcbNeeded;
6962 /* HeapReAlloc return NULL, when bufferW was NULL */
6963 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6964 HeapAlloc(GetProcessHeap(), 0, needed);
6966 /* Try again with the large Buffer */
6967 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6969 numentries = pcReturned ? *pcReturned : 0;
6970 needed = 0;
6972 if (res) {
6973 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6974 DWORD index;
6975 LPSTR ptr;
6976 PPRINTPROCESSOR_INFO_1W ppiw;
6977 PPRINTPROCESSOR_INFO_1A ppia;
6979 /* First pass: calculate the size for all Entries */
6980 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6981 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6982 index = 0;
6983 while (index < numentries) {
6984 index++;
6985 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6986 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6988 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6989 NULL, 0, NULL, NULL);
6991 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6992 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6995 /* check for errors and quit on failure */
6996 if (cbBuf < needed) {
6997 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6998 res = FALSE;
6999 goto epp_cleanup;
7002 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7003 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7004 cbBuf -= len ; /* free Bytes in the user-Buffer */
7005 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7006 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7007 index = 0;
7008 /* Second Pass: Fill the User Buffer (if we have one) */
7009 while ((index < numentries) && pPPInfo) {
7010 index++;
7011 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7012 ppia->pName = ptr;
7013 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7014 ptr, cbBuf , NULL, NULL);
7015 ptr += len;
7016 cbBuf -= len;
7018 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7019 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7023 epp_cleanup:
7024 if (pcbNeeded) *pcbNeeded = needed;
7025 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7027 HeapFree(GetProcessHeap(), 0, nameW);
7028 HeapFree(GetProcessHeap(), 0, envW);
7029 HeapFree(GetProcessHeap(), 0, bufferW);
7031 TRACE("returning %d with %d (%d byte for %d entries)\n",
7032 (res), GetLastError(), needed, numentries);
7034 return (res);
7037 /*****************************************************************************
7038 * EnumPrintProcessorsW [WINSPOOL.@]
7040 * Enumerate available Print Processors
7042 * PARAMS
7043 * pName [I] Servername or NULL (local Computer)
7044 * pEnvironment [I] Printing-Environment or NULL (Default)
7045 * Level [I] Structure-Level (Only 1 is allowed)
7046 * pPPInfo [O] PTR to Buffer that receives the Result
7047 * cbBuf [I] Size of Buffer at pPPInfo
7048 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7049 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7051 * RETURNS
7052 * Success: TRUE
7053 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7056 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7057 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7060 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7061 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7063 if ((backend == NULL) && !load_backend()) return FALSE;
7065 if (!pcbNeeded || !pcReturned) {
7066 SetLastError(RPC_X_NULL_REF_POINTER);
7067 return FALSE;
7070 if (!pPPInfo && (cbBuf > 0)) {
7071 SetLastError(ERROR_INVALID_USER_BUFFER);
7072 return FALSE;
7075 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7076 cbBuf, pcbNeeded, pcReturned);
7079 /*****************************************************************************
7080 * ExtDeviceMode [WINSPOOL.@]
7083 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7084 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7085 DWORD fMode)
7087 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7088 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7089 debugstr_a(pProfile), fMode);
7090 return -1;
7093 /*****************************************************************************
7094 * FindClosePrinterChangeNotification [WINSPOOL.@]
7097 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7099 FIXME("Stub: %p\n", hChange);
7100 return TRUE;
7103 /*****************************************************************************
7104 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7107 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7108 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7110 FIXME("Stub: %p %x %x %p\n",
7111 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7112 return INVALID_HANDLE_VALUE;
7115 /*****************************************************************************
7116 * FindNextPrinterChangeNotification [WINSPOOL.@]
7119 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7120 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7122 FIXME("Stub: %p %p %p %p\n",
7123 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7124 return FALSE;
7127 /*****************************************************************************
7128 * FreePrinterNotifyInfo [WINSPOOL.@]
7131 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7133 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7134 return TRUE;
7137 /*****************************************************************************
7138 * string_to_buf
7140 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7141 * ansi depending on the unicode parameter.
7143 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7145 if(!str)
7147 *size = 0;
7148 return TRUE;
7151 if(unicode)
7153 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7154 if(*size <= cb)
7156 memcpy(ptr, str, *size);
7157 return TRUE;
7159 return FALSE;
7161 else
7163 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7164 if(*size <= cb)
7166 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7167 return TRUE;
7169 return FALSE;
7173 /*****************************************************************************
7174 * get_job_info_1
7176 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7177 LPDWORD pcbNeeded, BOOL unicode)
7179 DWORD size, left = cbBuf;
7180 BOOL space = (cbBuf > 0);
7181 LPBYTE ptr = buf;
7183 *pcbNeeded = 0;
7185 if(space)
7187 ji1->JobId = job->job_id;
7190 string_to_buf(job->document_title, ptr, left, &size, unicode);
7191 if(space && size <= left)
7193 ji1->pDocument = (LPWSTR)ptr;
7194 ptr += size;
7195 left -= size;
7197 else
7198 space = FALSE;
7199 *pcbNeeded += size;
7201 if (job->printer_name)
7203 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7204 if(space && size <= left)
7206 ji1->pPrinterName = (LPWSTR)ptr;
7207 ptr += size;
7208 left -= size;
7210 else
7211 space = FALSE;
7212 *pcbNeeded += size;
7215 return space;
7218 /*****************************************************************************
7219 * get_job_info_2
7221 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7222 LPDWORD pcbNeeded, BOOL unicode)
7224 DWORD size, left = cbBuf;
7225 DWORD shift;
7226 BOOL space = (cbBuf > 0);
7227 LPBYTE ptr = buf;
7228 LPDEVMODEA dmA = NULL;
7229 LPDEVMODEW devmode;
7231 *pcbNeeded = 0;
7233 if(space)
7235 ji2->JobId = job->job_id;
7238 string_to_buf(job->document_title, ptr, left, &size, unicode);
7239 if(space && size <= left)
7241 ji2->pDocument = (LPWSTR)ptr;
7242 ptr += size;
7243 left -= size;
7245 else
7246 space = FALSE;
7247 *pcbNeeded += size;
7249 if (job->printer_name)
7251 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7252 if(space && size <= left)
7254 ji2->pPrinterName = (LPWSTR)ptr;
7255 ptr += size;
7256 left -= size;
7258 else
7259 space = FALSE;
7260 *pcbNeeded += size;
7263 if (job->devmode)
7265 if (!unicode)
7267 dmA = DEVMODEdupWtoA(job->devmode);
7268 devmode = (LPDEVMODEW) dmA;
7269 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7271 else
7273 devmode = job->devmode;
7274 size = devmode->dmSize + devmode->dmDriverExtra;
7277 if (!devmode)
7278 FIXME("Can't convert DEVMODE W to A\n");
7279 else
7281 /* align DEVMODE to a DWORD boundary */
7282 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7283 size += shift;
7285 if (size <= left)
7287 ptr += shift;
7288 memcpy(ptr, devmode, size-shift);
7289 ji2->pDevMode = (LPDEVMODEW)ptr;
7290 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7291 ptr += size;
7292 left -= size;
7294 else
7295 space = FALSE;
7296 *pcbNeeded +=size;
7300 return space;
7303 /*****************************************************************************
7304 * get_job_info
7306 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7307 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7309 BOOL ret = FALSE;
7310 DWORD needed = 0, size;
7311 job_t *job;
7312 LPBYTE ptr = pJob;
7314 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7316 EnterCriticalSection(&printer_handles_cs);
7317 job = get_job(hPrinter, JobId);
7318 if(!job)
7319 goto end;
7321 switch(Level)
7323 case 1:
7324 size = sizeof(JOB_INFO_1W);
7325 if(cbBuf >= size)
7327 cbBuf -= size;
7328 ptr += size;
7329 memset(pJob, 0, size);
7331 else
7332 cbBuf = 0;
7333 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7334 needed += size;
7335 break;
7337 case 2:
7338 size = sizeof(JOB_INFO_2W);
7339 if(cbBuf >= size)
7341 cbBuf -= size;
7342 ptr += size;
7343 memset(pJob, 0, size);
7345 else
7346 cbBuf = 0;
7347 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7348 needed += size;
7349 break;
7351 case 3:
7352 size = sizeof(JOB_INFO_3);
7353 if(cbBuf >= size)
7355 cbBuf -= size;
7356 memset(pJob, 0, size);
7357 ret = TRUE;
7359 else
7360 cbBuf = 0;
7361 needed = size;
7362 break;
7364 default:
7365 SetLastError(ERROR_INVALID_LEVEL);
7366 goto end;
7368 if(pcbNeeded)
7369 *pcbNeeded = needed;
7370 end:
7371 LeaveCriticalSection(&printer_handles_cs);
7372 return ret;
7375 /*****************************************************************************
7376 * GetJobA [WINSPOOL.@]
7379 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7380 DWORD cbBuf, LPDWORD pcbNeeded)
7382 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7385 /*****************************************************************************
7386 * GetJobW [WINSPOOL.@]
7389 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7390 DWORD cbBuf, LPDWORD pcbNeeded)
7392 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7395 /*****************************************************************************
7396 * schedule_pipe
7398 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7400 #ifdef HAVE_FORK
7401 char *unixname, *cmdA;
7402 DWORD len;
7403 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7404 BOOL ret = FALSE;
7405 char buf[1024];
7407 if(!(unixname = wine_get_unix_file_name(filename)))
7408 return FALSE;
7410 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7411 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7412 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7414 TRACE("printing with: %s\n", cmdA);
7416 if((file_fd = open(unixname, O_RDONLY)) == -1)
7417 goto end;
7419 if (pipe(fds))
7421 ERR("pipe() failed!\n");
7422 goto end;
7425 if (fork() == 0)
7427 close(0);
7428 dup2(fds[0], 0);
7429 close(fds[1]);
7431 /* reset signals that we previously set to SIG_IGN */
7432 signal(SIGPIPE, SIG_DFL);
7433 signal(SIGCHLD, SIG_DFL);
7435 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7436 _exit(1);
7439 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7440 write(fds[1], buf, no_read);
7442 ret = TRUE;
7444 end:
7445 if(file_fd != -1) close(file_fd);
7446 if(fds[0] != -1) close(fds[0]);
7447 if(fds[1] != -1) close(fds[1]);
7449 HeapFree(GetProcessHeap(), 0, cmdA);
7450 HeapFree(GetProcessHeap(), 0, unixname);
7451 return ret;
7452 #else
7453 return FALSE;
7454 #endif
7457 /*****************************************************************************
7458 * schedule_lpr
7460 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7462 WCHAR *cmd;
7463 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7464 BOOL r;
7466 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7467 sprintfW(cmd, fmtW, printer_name);
7469 r = schedule_pipe(cmd, filename);
7471 HeapFree(GetProcessHeap(), 0, cmd);
7472 return r;
7475 /*****************************************************************************
7476 * schedule_cups
7478 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7480 #ifdef SONAME_LIBCUPS
7481 if(pcupsPrintFile)
7483 char *unixname, *queue, *unix_doc_title;
7484 DWORD len;
7485 BOOL ret;
7487 if(!(unixname = wine_get_unix_file_name(filename)))
7488 return FALSE;
7490 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7491 queue = HeapAlloc(GetProcessHeap(), 0, len);
7492 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7494 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7495 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7496 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7498 TRACE("printing via cups\n");
7499 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7500 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7501 HeapFree(GetProcessHeap(), 0, queue);
7502 HeapFree(GetProcessHeap(), 0, unixname);
7503 return ret;
7505 else
7506 #endif
7508 return schedule_lpr(printer_name, filename);
7512 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7514 LPWSTR filename;
7516 switch(msg)
7518 case WM_INITDIALOG:
7519 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7520 return TRUE;
7522 case WM_COMMAND:
7523 if(HIWORD(wparam) == BN_CLICKED)
7525 if(LOWORD(wparam) == IDOK)
7527 HANDLE hf;
7528 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7529 LPWSTR *output;
7531 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7532 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7534 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7536 WCHAR caption[200], message[200];
7537 int mb_ret;
7539 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7540 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7541 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7542 if(mb_ret == IDCANCEL)
7544 HeapFree(GetProcessHeap(), 0, filename);
7545 return TRUE;
7548 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7549 if(hf == INVALID_HANDLE_VALUE)
7551 WCHAR caption[200], message[200];
7553 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7554 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7555 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7556 HeapFree(GetProcessHeap(), 0, filename);
7557 return TRUE;
7559 CloseHandle(hf);
7560 DeleteFileW(filename);
7561 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7562 *output = filename;
7563 EndDialog(hwnd, IDOK);
7564 return TRUE;
7566 if(LOWORD(wparam) == IDCANCEL)
7568 EndDialog(hwnd, IDCANCEL);
7569 return TRUE;
7572 return FALSE;
7574 return FALSE;
7577 /*****************************************************************************
7578 * get_filename
7580 static BOOL get_filename(LPWSTR *filename)
7582 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7583 file_dlg_proc, (LPARAM)filename) == IDOK;
7586 /*****************************************************************************
7587 * schedule_file
7589 static BOOL schedule_file(LPCWSTR filename)
7591 LPWSTR output = NULL;
7593 if(get_filename(&output))
7595 BOOL r;
7596 TRACE("copy to %s\n", debugstr_w(output));
7597 r = CopyFileW(filename, output, FALSE);
7598 HeapFree(GetProcessHeap(), 0, output);
7599 return r;
7601 return FALSE;
7604 /*****************************************************************************
7605 * schedule_unixfile
7607 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7609 int in_fd, out_fd, no_read;
7610 char buf[1024];
7611 BOOL ret = FALSE;
7612 char *unixname, *outputA;
7613 DWORD len;
7615 if(!(unixname = wine_get_unix_file_name(filename)))
7616 return FALSE;
7618 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7619 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7620 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7622 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7623 in_fd = open(unixname, O_RDONLY);
7624 if(out_fd == -1 || in_fd == -1)
7625 goto end;
7627 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7628 write(out_fd, buf, no_read);
7630 ret = TRUE;
7631 end:
7632 if(in_fd != -1) close(in_fd);
7633 if(out_fd != -1) close(out_fd);
7634 HeapFree(GetProcessHeap(), 0, outputA);
7635 HeapFree(GetProcessHeap(), 0, unixname);
7636 return ret;
7639 /*****************************************************************************
7640 * ScheduleJob [WINSPOOL.@]
7643 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7645 opened_printer_t *printer;
7646 BOOL ret = FALSE;
7647 struct list *cursor, *cursor2;
7649 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7650 EnterCriticalSection(&printer_handles_cs);
7651 printer = get_opened_printer(hPrinter);
7652 if(!printer)
7653 goto end;
7655 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7657 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7658 HANDLE hf;
7660 if(job->job_id != dwJobID) continue;
7662 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7663 if(hf != INVALID_HANDLE_VALUE)
7665 PRINTER_INFO_5W *pi5 = NULL;
7666 LPWSTR portname = job->portname;
7667 DWORD needed;
7668 HKEY hkey;
7669 WCHAR output[1024];
7670 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7671 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7673 if (!portname)
7675 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7676 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7677 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7678 portname = pi5->pPortName;
7680 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7681 debugstr_w(portname));
7683 output[0] = 0;
7685 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7686 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7688 DWORD type, count = sizeof(output);
7689 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7690 RegCloseKey(hkey);
7692 if(output[0] == '|')
7694 ret = schedule_pipe(output + 1, job->filename);
7696 else if(output[0])
7698 ret = schedule_unixfile(output, job->filename);
7700 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7702 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7704 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7706 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7708 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7710 ret = schedule_file(job->filename);
7712 else
7714 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7716 HeapFree(GetProcessHeap(), 0, pi5);
7717 CloseHandle(hf);
7718 DeleteFileW(job->filename);
7720 list_remove(cursor);
7721 HeapFree(GetProcessHeap(), 0, job->document_title);
7722 HeapFree(GetProcessHeap(), 0, job->printer_name);
7723 HeapFree(GetProcessHeap(), 0, job->portname);
7724 HeapFree(GetProcessHeap(), 0, job->filename);
7725 HeapFree(GetProcessHeap(), 0, job->devmode);
7726 HeapFree(GetProcessHeap(), 0, job);
7727 break;
7729 end:
7730 LeaveCriticalSection(&printer_handles_cs);
7731 return ret;
7734 /*****************************************************************************
7735 * StartDocDlgA [WINSPOOL.@]
7737 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7739 UNICODE_STRING usBuffer;
7740 DOCINFOW docW;
7741 LPWSTR retW;
7742 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7743 LPSTR ret = NULL;
7745 docW.cbSize = sizeof(docW);
7746 if (doc->lpszDocName)
7748 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7749 if (!(docW.lpszDocName = docnameW)) return NULL;
7751 if (doc->lpszOutput)
7753 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7754 if (!(docW.lpszOutput = outputW)) return NULL;
7756 if (doc->lpszDatatype)
7758 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7759 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7761 docW.fwType = doc->fwType;
7763 retW = StartDocDlgW(hPrinter, &docW);
7765 if(retW)
7767 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7768 ret = HeapAlloc(GetProcessHeap(), 0, len);
7769 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7770 HeapFree(GetProcessHeap(), 0, retW);
7773 HeapFree(GetProcessHeap(), 0, datatypeW);
7774 HeapFree(GetProcessHeap(), 0, outputW);
7775 HeapFree(GetProcessHeap(), 0, docnameW);
7777 return ret;
7780 /*****************************************************************************
7781 * StartDocDlgW [WINSPOOL.@]
7783 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7784 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7785 * port is "FILE:". Also returns the full path if passed a relative path.
7787 * The caller should free the returned string from the process heap.
7789 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7791 LPWSTR ret = NULL;
7792 DWORD len, attr;
7794 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7796 PRINTER_INFO_5W *pi5;
7797 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7798 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7799 return NULL;
7800 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7801 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7802 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7804 HeapFree(GetProcessHeap(), 0, pi5);
7805 return NULL;
7807 HeapFree(GetProcessHeap(), 0, pi5);
7810 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7812 LPWSTR name;
7814 if (get_filename(&name))
7816 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7818 HeapFree(GetProcessHeap(), 0, name);
7819 return NULL;
7821 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7822 GetFullPathNameW(name, len, ret, NULL);
7823 HeapFree(GetProcessHeap(), 0, name);
7825 return ret;
7828 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7829 return NULL;
7831 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7832 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7834 attr = GetFileAttributesW(ret);
7835 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7837 HeapFree(GetProcessHeap(), 0, ret);
7838 ret = NULL;
7840 return ret;