mmdevapi: Add return value which happens on wow64 and pure 64-bit.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob4ffe092944b5a0f1fb1940dda395f1c657fbe42f
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 * OpenPrinterA [WINSPOOL.@]
1781 * See OpenPrinterW.
1784 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1785 LPPRINTER_DEFAULTSA pDefault)
1787 UNICODE_STRING lpPrinterNameW;
1788 UNICODE_STRING usBuffer;
1789 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1790 PWSTR pwstrPrinterNameW;
1791 BOOL ret;
1793 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1795 if(pDefault) {
1796 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1797 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1798 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1799 pDefaultW = &DefaultW;
1801 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1802 if(pDefault) {
1803 RtlFreeUnicodeString(&usBuffer);
1804 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1806 RtlFreeUnicodeString(&lpPrinterNameW);
1807 return ret;
1810 /******************************************************************
1811 * OpenPrinterW [WINSPOOL.@]
1813 * Open a Printer / Printserver or a Printer-Object
1815 * PARAMS
1816 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1817 * phPrinter [O] The resulting Handle is stored here
1818 * pDefault [I] PTR to Default Printer Settings or NULL
1820 * RETURNS
1821 * Success: TRUE
1822 * Failure: FALSE
1824 * NOTES
1825 * lpPrinterName is one of:
1826 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1827 *| Printer: "PrinterName"
1828 *| Printer-Object: "PrinterName,Job xxx"
1829 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1830 *| XcvPort: "Servername,XcvPort PortName"
1832 * BUGS
1833 *| Printer-Object not supported
1834 *| pDefaults is ignored
1837 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1840 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1841 if (pDefault) {
1842 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1843 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1846 if(!phPrinter) {
1847 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1848 SetLastError(ERROR_INVALID_PARAMETER);
1849 return FALSE;
1852 /* Get the unique handle of the printer or Printserver */
1853 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1854 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1855 return (*phPrinter != 0);
1858 /******************************************************************
1859 * AddMonitorA [WINSPOOL.@]
1861 * See AddMonitorW.
1864 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1866 LPWSTR nameW = NULL;
1867 INT len;
1868 BOOL res;
1869 LPMONITOR_INFO_2A mi2a;
1870 MONITOR_INFO_2W mi2w;
1872 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1873 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1874 debugstr_a(mi2a ? mi2a->pName : NULL),
1875 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1876 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1878 if (Level != 2) {
1879 SetLastError(ERROR_INVALID_LEVEL);
1880 return FALSE;
1883 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1884 if (mi2a == NULL) {
1885 return FALSE;
1888 if (pName) {
1889 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1890 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1891 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1894 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1895 if (mi2a->pName) {
1896 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1897 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1898 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1900 if (mi2a->pEnvironment) {
1901 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1902 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1903 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1905 if (mi2a->pDLLName) {
1906 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1907 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1908 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1911 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1913 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1914 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1915 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1917 HeapFree(GetProcessHeap(), 0, nameW);
1918 return (res);
1921 /******************************************************************************
1922 * AddMonitorW [WINSPOOL.@]
1924 * Install a Printmonitor
1926 * PARAMS
1927 * pName [I] Servername or NULL (local Computer)
1928 * Level [I] Structure-Level (Must be 2)
1929 * pMonitors [I] PTR to MONITOR_INFO_2
1931 * RETURNS
1932 * Success: TRUE
1933 * Failure: FALSE
1935 * NOTES
1936 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1939 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1941 LPMONITOR_INFO_2W mi2w;
1943 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1944 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1945 debugstr_w(mi2w ? mi2w->pName : NULL),
1946 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1947 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1949 if ((backend == NULL) && !load_backend()) return FALSE;
1951 if (Level != 2) {
1952 SetLastError(ERROR_INVALID_LEVEL);
1953 return FALSE;
1956 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1957 if (mi2w == NULL) {
1958 return FALSE;
1961 return backend->fpAddMonitor(pName, Level, pMonitors);
1964 /******************************************************************
1965 * DeletePrinterDriverA [WINSPOOL.@]
1968 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1970 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1973 /******************************************************************
1974 * DeletePrinterDriverW [WINSPOOL.@]
1977 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1979 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
1982 /******************************************************************
1983 * DeleteMonitorA [WINSPOOL.@]
1985 * See DeleteMonitorW.
1988 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1990 LPWSTR nameW = NULL;
1991 LPWSTR EnvironmentW = NULL;
1992 LPWSTR MonitorNameW = NULL;
1993 BOOL res;
1994 INT len;
1996 if (pName) {
1997 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1998 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1999 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2002 if (pEnvironment) {
2003 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2004 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2005 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2007 if (pMonitorName) {
2008 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2009 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2010 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2013 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2015 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2016 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2017 HeapFree(GetProcessHeap(), 0, nameW);
2018 return (res);
2021 /******************************************************************
2022 * DeleteMonitorW [WINSPOOL.@]
2024 * Delete a specific Printmonitor from a Printing-Environment
2026 * PARAMS
2027 * pName [I] Servername or NULL (local Computer)
2028 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2029 * pMonitorName [I] Name of the Monitor, that should be deleted
2031 * RETURNS
2032 * Success: TRUE
2033 * Failure: FALSE
2035 * NOTES
2036 * pEnvironment is ignored in Windows for the local Computer.
2039 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2042 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2043 debugstr_w(pMonitorName));
2045 if ((backend == NULL) && !load_backend()) return FALSE;
2047 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2051 /******************************************************************
2052 * DeletePortA [WINSPOOL.@]
2054 * See DeletePortW.
2057 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2059 LPWSTR nameW = NULL;
2060 LPWSTR portW = NULL;
2061 INT len;
2062 DWORD res;
2064 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2066 /* convert servername to unicode */
2067 if (pName) {
2068 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2069 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2070 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2073 /* convert portname to unicode */
2074 if (pPortName) {
2075 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2076 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2077 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2080 res = DeletePortW(nameW, hWnd, portW);
2081 HeapFree(GetProcessHeap(), 0, nameW);
2082 HeapFree(GetProcessHeap(), 0, portW);
2083 return res;
2086 /******************************************************************
2087 * DeletePortW [WINSPOOL.@]
2089 * Delete a specific Port
2091 * PARAMS
2092 * pName [I] Servername or NULL (local Computer)
2093 * hWnd [I] Handle to parent Window for the Dialog-Box
2094 * pPortName [I] Name of the Port, that should be deleted
2096 * RETURNS
2097 * Success: TRUE
2098 * Failure: FALSE
2101 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2103 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2105 if ((backend == NULL) && !load_backend()) return FALSE;
2107 if (!pPortName) {
2108 SetLastError(RPC_X_NULL_REF_POINTER);
2109 return FALSE;
2112 return backend->fpDeletePort(pName, hWnd, pPortName);
2115 /******************************************************************************
2116 * SetPrinterW [WINSPOOL.@]
2118 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2120 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2121 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2122 return FALSE;
2125 /******************************************************************************
2126 * WritePrinter [WINSPOOL.@]
2128 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2130 opened_printer_t *printer;
2131 BOOL ret = FALSE;
2133 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2135 EnterCriticalSection(&printer_handles_cs);
2136 printer = get_opened_printer(hPrinter);
2137 if(!printer)
2139 SetLastError(ERROR_INVALID_HANDLE);
2140 goto end;
2143 if(!printer->doc)
2145 SetLastError(ERROR_SPL_NO_STARTDOC);
2146 goto end;
2149 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2150 end:
2151 LeaveCriticalSection(&printer_handles_cs);
2152 return ret;
2155 /*****************************************************************************
2156 * AddFormA [WINSPOOL.@]
2158 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2160 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2161 return 1;
2164 /*****************************************************************************
2165 * AddFormW [WINSPOOL.@]
2167 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2169 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2170 return 1;
2173 /*****************************************************************************
2174 * AddJobA [WINSPOOL.@]
2176 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2178 BOOL ret;
2179 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2180 DWORD needed;
2182 if(Level != 1) {
2183 SetLastError(ERROR_INVALID_LEVEL);
2184 return FALSE;
2187 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2189 if(ret) {
2190 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2191 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2192 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2193 if(*pcbNeeded > cbBuf) {
2194 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2195 ret = FALSE;
2196 } else {
2197 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2198 addjobA->JobId = addjobW->JobId;
2199 addjobA->Path = (char *)(addjobA + 1);
2200 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2203 return ret;
2206 /*****************************************************************************
2207 * AddJobW [WINSPOOL.@]
2209 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2211 opened_printer_t *printer;
2212 job_t *job;
2213 BOOL ret = FALSE;
2214 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2215 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2216 WCHAR path[MAX_PATH], filename[MAX_PATH];
2217 DWORD len;
2218 ADDJOB_INFO_1W *addjob;
2220 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2222 EnterCriticalSection(&printer_handles_cs);
2224 printer = get_opened_printer(hPrinter);
2226 if(!printer) {
2227 SetLastError(ERROR_INVALID_HANDLE);
2228 goto end;
2231 if(Level != 1) {
2232 SetLastError(ERROR_INVALID_LEVEL);
2233 goto end;
2236 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2237 if(!job)
2238 goto end;
2240 job->job_id = InterlockedIncrement(&next_job_id);
2242 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2243 if(path[len - 1] != '\\')
2244 path[len++] = '\\';
2245 memcpy(path + len, spool_path, sizeof(spool_path));
2246 sprintfW(filename, fmtW, path, job->job_id);
2248 len = strlenW(filename);
2249 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2250 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2251 job->document_title = strdupW(default_doc_title);
2252 job->printer_name = strdupW(printer->name);
2253 job->devmode = NULL;
2254 list_add_tail(&printer->queue->jobs, &job->entry);
2256 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2257 if(*pcbNeeded <= cbBuf) {
2258 addjob = (ADDJOB_INFO_1W*)pData;
2259 addjob->JobId = job->job_id;
2260 addjob->Path = (WCHAR *)(addjob + 1);
2261 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2262 ret = TRUE;
2263 } else
2264 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2266 end:
2267 LeaveCriticalSection(&printer_handles_cs);
2268 return ret;
2271 /*****************************************************************************
2272 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2274 * Return the PATH for the Print-Processors
2276 * See GetPrintProcessorDirectoryW.
2280 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2281 DWORD level, LPBYTE Info,
2282 DWORD cbBuf, LPDWORD pcbNeeded)
2284 LPWSTR serverW = NULL;
2285 LPWSTR envW = NULL;
2286 BOOL ret;
2287 INT len;
2289 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2290 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2293 if (server) {
2294 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2295 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2296 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2299 if (env) {
2300 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2301 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2302 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2305 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2306 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2308 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2309 cbBuf, pcbNeeded);
2311 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2312 cbBuf, NULL, NULL) > 0;
2315 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2316 HeapFree(GetProcessHeap(), 0, envW);
2317 HeapFree(GetProcessHeap(), 0, serverW);
2318 return ret;
2321 /*****************************************************************************
2322 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2324 * Return the PATH for the Print-Processors
2326 * PARAMS
2327 * server [I] Servername (NT only) or NULL (local Computer)
2328 * env [I] Printing-Environment (see below) or NULL (Default)
2329 * level [I] Structure-Level (must be 1)
2330 * Info [O] PTR to Buffer that receives the Result
2331 * cbBuf [I] Size of Buffer at "Info"
2332 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2333 * required for the Buffer at "Info"
2335 * RETURNS
2336 * Success: TRUE and in pcbNeeded the Bytes used in Info
2337 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2338 * if cbBuf is too small
2340 * Native Values returned in Info on Success:
2341 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2342 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2343 *| win9x(Windows 4.0): "%winsysdir%"
2345 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2347 * BUGS
2348 * Only NULL or "" is supported for server
2351 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2352 DWORD level, LPBYTE Info,
2353 DWORD cbBuf, LPDWORD pcbNeeded)
2356 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2357 Info, cbBuf, pcbNeeded);
2359 if ((backend == NULL) && !load_backend()) return FALSE;
2361 if (level != 1) {
2362 /* (Level != 1) is ignored in win9x */
2363 SetLastError(ERROR_INVALID_LEVEL);
2364 return FALSE;
2367 if (pcbNeeded == NULL) {
2368 /* (pcbNeeded == NULL) is ignored in win9x */
2369 SetLastError(RPC_X_NULL_REF_POINTER);
2370 return FALSE;
2373 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2376 /*****************************************************************************
2377 * WINSPOOL_OpenDriverReg [internal]
2379 * opens the registry for the printer drivers depending on the given input
2380 * variable pEnvironment
2382 * RETURNS:
2383 * the opened hkey on success
2384 * NULL on error
2386 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2388 HKEY retval = NULL;
2389 LPWSTR buffer;
2390 const printenv_t * env;
2392 TRACE("(%s)\n", debugstr_w(pEnvironment));
2394 env = validate_envW(pEnvironment);
2395 if (!env) return NULL;
2397 buffer = HeapAlloc( GetProcessHeap(), 0,
2398 (strlenW(DriversW) + strlenW(env->envname) +
2399 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2400 if(buffer) {
2401 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2402 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2403 HeapFree(GetProcessHeap(), 0, buffer);
2405 return retval;
2408 /*****************************************************************************
2409 * set_devices_and_printerports [internal]
2411 * set the [Devices] and [PrinterPorts] entries for a printer.
2414 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2416 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2417 WCHAR *devline;
2418 HKEY hkey;
2420 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2422 /* FIXME: the driver must change to "winspool" */
2423 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2424 if (devline) {
2425 lstrcpyW(devline, driver_nt);
2426 lstrcatW(devline, commaW);
2427 lstrcatW(devline, pi->pPortName);
2429 TRACE("using %s\n", debugstr_w(devline));
2430 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2431 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2432 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2433 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2434 RegCloseKey(hkey);
2437 lstrcatW(devline, timeout_15_45);
2438 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2439 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2440 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2441 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2442 RegCloseKey(hkey);
2444 HeapFree(GetProcessHeap(), 0, devline);
2448 /*****************************************************************************
2449 * AddPrinterW [WINSPOOL.@]
2451 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2453 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2454 LPDEVMODEA dmA;
2455 LPDEVMODEW dmW;
2456 HANDLE retval;
2457 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2458 LONG size;
2459 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2460 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2461 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2462 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2463 statusW[] = {'S','t','a','t','u','s',0},
2464 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2466 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2468 if(pName != NULL) {
2469 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2470 SetLastError(ERROR_INVALID_PARAMETER);
2471 return 0;
2473 if(Level != 2) {
2474 ERR("Level = %d, unsupported!\n", Level);
2475 SetLastError(ERROR_INVALID_LEVEL);
2476 return 0;
2478 if(!pPrinter) {
2479 SetLastError(ERROR_INVALID_PARAMETER);
2480 return 0;
2482 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2483 ERROR_SUCCESS) {
2484 ERR("Can't create Printers key\n");
2485 return 0;
2487 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2488 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2489 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2490 RegCloseKey(hkeyPrinter);
2491 RegCloseKey(hkeyPrinters);
2492 return 0;
2494 RegCloseKey(hkeyPrinter);
2496 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2497 if(!hkeyDrivers) {
2498 ERR("Can't create Drivers key\n");
2499 RegCloseKey(hkeyPrinters);
2500 return 0;
2502 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2503 ERROR_SUCCESS) {
2504 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2505 RegCloseKey(hkeyPrinters);
2506 RegCloseKey(hkeyDrivers);
2507 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2508 return 0;
2510 RegCloseKey(hkeyDriver);
2511 RegCloseKey(hkeyDrivers);
2513 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2514 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2515 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2516 RegCloseKey(hkeyPrinters);
2517 return 0;
2520 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2521 ERROR_SUCCESS) {
2522 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2523 SetLastError(ERROR_INVALID_PRINTER_NAME);
2524 RegCloseKey(hkeyPrinters);
2525 return 0;
2528 set_devices_and_printerports(pi);
2529 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2530 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2531 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2533 /* See if we can load the driver. We may need the devmode structure anyway
2535 * FIXME:
2536 * Note that DocumentPropertiesW will briefly try to open the printer we
2537 * just create to find a DEVMODEA struct (it will use the WINEPS default
2538 * one in case it is not there, so we are ok).
2540 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2542 if(size < 0) {
2543 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2544 size = sizeof(DEVMODEW);
2546 if(pi->pDevMode)
2547 dmW = pi->pDevMode;
2548 else
2550 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2551 dmW->dmSize = size;
2552 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2554 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2555 HeapFree(GetProcessHeap(),0,dmW);
2556 dmW=NULL;
2558 else
2560 /* set devmode to printer name */
2561 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2565 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2566 and we support these drivers. NT writes DEVMODEW so somehow
2567 we'll need to distinguish between these when we support NT
2568 drivers */
2569 if (dmW)
2571 dmA = DEVMODEdupWtoA(dmW);
2572 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2573 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2574 HeapFree(GetProcessHeap(), 0, dmA);
2575 if(!pi->pDevMode)
2576 HeapFree(GetProcessHeap(), 0, dmW);
2578 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2579 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2580 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2581 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2583 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2584 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2585 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2586 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2587 (LPBYTE)&pi->Priority, sizeof(DWORD));
2588 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2589 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2590 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2591 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2592 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2593 (LPBYTE)&pi->Status, sizeof(DWORD));
2594 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2595 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2597 RegCloseKey(hkeyPrinter);
2598 RegCloseKey(hkeyPrinters);
2599 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2600 ERR("OpenPrinter failing\n");
2601 return 0;
2603 return retval;
2606 /*****************************************************************************
2607 * AddPrinterA [WINSPOOL.@]
2609 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2611 UNICODE_STRING pNameW;
2612 PWSTR pwstrNameW;
2613 PRINTER_INFO_2W *piW;
2614 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2615 HANDLE ret;
2617 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2618 if(Level != 2) {
2619 ERR("Level = %d, unsupported!\n", Level);
2620 SetLastError(ERROR_INVALID_LEVEL);
2621 return 0;
2623 pwstrNameW = asciitounicode(&pNameW,pName);
2624 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2626 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2628 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2629 RtlFreeUnicodeString(&pNameW);
2630 return ret;
2634 /*****************************************************************************
2635 * ClosePrinter [WINSPOOL.@]
2637 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2639 UINT_PTR i = (UINT_PTR)hPrinter;
2640 opened_printer_t *printer = NULL;
2641 BOOL ret = FALSE;
2643 TRACE("(%p)\n", hPrinter);
2645 EnterCriticalSection(&printer_handles_cs);
2647 if ((i > 0) && (i <= nb_printer_handles))
2648 printer = printer_handles[i - 1];
2651 if(printer)
2653 struct list *cursor, *cursor2;
2655 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2657 if (printer->backend_printer) {
2658 backend->fpClosePrinter(printer->backend_printer);
2661 if(printer->doc)
2662 EndDocPrinter(hPrinter);
2664 if(InterlockedDecrement(&printer->queue->ref) == 0)
2666 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2668 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2669 ScheduleJob(hPrinter, job->job_id);
2671 HeapFree(GetProcessHeap(), 0, printer->queue);
2674 HeapFree(GetProcessHeap(), 0, printer->printername);
2675 HeapFree(GetProcessHeap(), 0, printer->name);
2676 HeapFree(GetProcessHeap(), 0, printer);
2677 printer_handles[i - 1] = NULL;
2678 ret = TRUE;
2680 LeaveCriticalSection(&printer_handles_cs);
2681 return ret;
2684 /*****************************************************************************
2685 * DeleteFormA [WINSPOOL.@]
2687 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2689 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2690 return 1;
2693 /*****************************************************************************
2694 * DeleteFormW [WINSPOOL.@]
2696 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2698 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2699 return 1;
2702 /*****************************************************************************
2703 * DeletePrinter [WINSPOOL.@]
2705 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2707 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2708 HKEY hkeyPrinters, hkey;
2710 if(!lpNameW) {
2711 SetLastError(ERROR_INVALID_HANDLE);
2712 return FALSE;
2714 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2715 RegDeleteTreeW(hkeyPrinters, lpNameW);
2716 RegCloseKey(hkeyPrinters);
2718 WriteProfileStringW(devicesW, lpNameW, NULL);
2719 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2721 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2722 RegDeleteValueW(hkey, lpNameW);
2723 RegCloseKey(hkey);
2726 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2727 RegDeleteValueW(hkey, lpNameW);
2728 RegCloseKey(hkey);
2730 return TRUE;
2733 /*****************************************************************************
2734 * SetPrinterA [WINSPOOL.@]
2736 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2737 DWORD Command)
2739 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2740 return FALSE;
2743 /*****************************************************************************
2744 * SetJobA [WINSPOOL.@]
2746 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2747 LPBYTE pJob, DWORD Command)
2749 BOOL ret;
2750 LPBYTE JobW;
2751 UNICODE_STRING usBuffer;
2753 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2755 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2756 are all ignored by SetJob, so we don't bother copying them */
2757 switch(Level)
2759 case 0:
2760 JobW = NULL;
2761 break;
2762 case 1:
2764 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2765 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2767 JobW = (LPBYTE)info1W;
2768 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2769 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2770 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2771 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2772 info1W->Status = info1A->Status;
2773 info1W->Priority = info1A->Priority;
2774 info1W->Position = info1A->Position;
2775 info1W->PagesPrinted = info1A->PagesPrinted;
2776 break;
2778 case 2:
2780 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2781 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2783 JobW = (LPBYTE)info2W;
2784 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2785 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2786 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2787 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2788 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2789 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2790 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2791 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2792 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2793 info2W->Status = info2A->Status;
2794 info2W->Priority = info2A->Priority;
2795 info2W->Position = info2A->Position;
2796 info2W->StartTime = info2A->StartTime;
2797 info2W->UntilTime = info2A->UntilTime;
2798 info2W->PagesPrinted = info2A->PagesPrinted;
2799 break;
2801 case 3:
2802 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2803 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2804 break;
2805 default:
2806 SetLastError(ERROR_INVALID_LEVEL);
2807 return FALSE;
2810 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2812 switch(Level)
2814 case 1:
2816 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2817 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2818 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2819 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2820 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2821 break;
2823 case 2:
2825 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2826 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2827 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2828 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2829 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2830 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2831 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2832 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2833 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2834 break;
2837 HeapFree(GetProcessHeap(), 0, JobW);
2839 return ret;
2842 /*****************************************************************************
2843 * SetJobW [WINSPOOL.@]
2845 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2846 LPBYTE pJob, DWORD Command)
2848 BOOL ret = FALSE;
2849 job_t *job;
2850 DWORD size;
2852 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2853 FIXME("Ignoring everything other than document title\n");
2855 EnterCriticalSection(&printer_handles_cs);
2856 job = get_job(hPrinter, JobId);
2857 if(!job)
2858 goto end;
2860 switch(Level)
2862 case 0:
2863 break;
2864 case 1:
2866 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2867 HeapFree(GetProcessHeap(), 0, job->document_title);
2868 job->document_title = strdupW(info1->pDocument);
2869 break;
2871 case 2:
2873 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2874 HeapFree(GetProcessHeap(), 0, job->document_title);
2875 job->document_title = strdupW(info2->pDocument);
2876 HeapFree(GetProcessHeap(), 0, job->devmode);
2877 if (info2->pDevMode)
2879 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2880 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2881 memcpy(job->devmode, info2->pDevMode, size);
2883 else
2884 job->devmode = NULL;
2885 break;
2887 case 3:
2888 break;
2889 default:
2890 SetLastError(ERROR_INVALID_LEVEL);
2891 goto end;
2893 ret = TRUE;
2894 end:
2895 LeaveCriticalSection(&printer_handles_cs);
2896 return ret;
2899 /*****************************************************************************
2900 * EndDocPrinter [WINSPOOL.@]
2902 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2904 opened_printer_t *printer;
2905 BOOL ret = FALSE;
2906 TRACE("(%p)\n", hPrinter);
2908 EnterCriticalSection(&printer_handles_cs);
2910 printer = get_opened_printer(hPrinter);
2911 if(!printer)
2913 SetLastError(ERROR_INVALID_HANDLE);
2914 goto end;
2917 if(!printer->doc)
2919 SetLastError(ERROR_SPL_NO_STARTDOC);
2920 goto end;
2923 CloseHandle(printer->doc->hf);
2924 ScheduleJob(hPrinter, printer->doc->job_id);
2925 HeapFree(GetProcessHeap(), 0, printer->doc);
2926 printer->doc = NULL;
2927 ret = TRUE;
2928 end:
2929 LeaveCriticalSection(&printer_handles_cs);
2930 return ret;
2933 /*****************************************************************************
2934 * EndPagePrinter [WINSPOOL.@]
2936 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2938 FIXME("(%p): stub\n", hPrinter);
2939 return TRUE;
2942 /*****************************************************************************
2943 * StartDocPrinterA [WINSPOOL.@]
2945 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2947 UNICODE_STRING usBuffer;
2948 DOC_INFO_2W doc2W;
2949 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2950 DWORD ret;
2952 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2953 or one (DOC_INFO_3) extra DWORDs */
2955 switch(Level) {
2956 case 2:
2957 doc2W.JobId = doc2->JobId;
2958 /* fall through */
2959 case 3:
2960 doc2W.dwMode = doc2->dwMode;
2961 /* fall through */
2962 case 1:
2963 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2964 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2965 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2966 break;
2968 default:
2969 SetLastError(ERROR_INVALID_LEVEL);
2970 return FALSE;
2973 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2975 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2976 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2977 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2979 return ret;
2982 /*****************************************************************************
2983 * StartDocPrinterW [WINSPOOL.@]
2985 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2987 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2988 opened_printer_t *printer;
2989 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2990 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2991 JOB_INFO_1W job_info;
2992 DWORD needed, ret = 0;
2993 HANDLE hf;
2994 WCHAR *filename;
2995 job_t *job;
2997 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2998 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2999 debugstr_w(doc->pDatatype));
3001 if(Level < 1 || Level > 3)
3003 SetLastError(ERROR_INVALID_LEVEL);
3004 return 0;
3007 EnterCriticalSection(&printer_handles_cs);
3008 printer = get_opened_printer(hPrinter);
3009 if(!printer)
3011 SetLastError(ERROR_INVALID_HANDLE);
3012 goto end;
3015 if(printer->doc)
3017 SetLastError(ERROR_INVALID_PRINTER_STATE);
3018 goto end;
3021 /* Even if we're printing to a file we still add a print job, we'll
3022 just ignore the spool file name */
3024 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3026 ERR("AddJob failed gle %u\n", GetLastError());
3027 goto end;
3030 /* use pOutputFile only, when it is a real filename */
3031 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3032 filename = doc->pOutputFile;
3033 else
3034 filename = addjob->Path;
3036 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3037 if(hf == INVALID_HANDLE_VALUE)
3038 goto end;
3040 memset(&job_info, 0, sizeof(job_info));
3041 job_info.pDocument = doc->pDocName;
3042 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3044 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3045 printer->doc->hf = hf;
3046 ret = printer->doc->job_id = addjob->JobId;
3047 job = get_job(hPrinter, ret);
3048 job->portname = strdupW(doc->pOutputFile);
3050 end:
3051 LeaveCriticalSection(&printer_handles_cs);
3053 return ret;
3056 /*****************************************************************************
3057 * StartPagePrinter [WINSPOOL.@]
3059 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3061 FIXME("(%p): stub\n", hPrinter);
3062 return TRUE;
3065 /*****************************************************************************
3066 * GetFormA [WINSPOOL.@]
3068 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3069 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3071 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3072 Level,pForm,cbBuf,pcbNeeded);
3073 return FALSE;
3076 /*****************************************************************************
3077 * GetFormW [WINSPOOL.@]
3079 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3080 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3082 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3083 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3084 return FALSE;
3087 /*****************************************************************************
3088 * SetFormA [WINSPOOL.@]
3090 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3091 LPBYTE pForm)
3093 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3094 return FALSE;
3097 /*****************************************************************************
3098 * SetFormW [WINSPOOL.@]
3100 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3101 LPBYTE pForm)
3103 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3104 return FALSE;
3107 /*****************************************************************************
3108 * ReadPrinter [WINSPOOL.@]
3110 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3111 LPDWORD pNoBytesRead)
3113 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3114 return FALSE;
3117 /*****************************************************************************
3118 * ResetPrinterA [WINSPOOL.@]
3120 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3122 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3123 return FALSE;
3126 /*****************************************************************************
3127 * ResetPrinterW [WINSPOOL.@]
3129 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3131 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3132 return FALSE;
3135 /*****************************************************************************
3136 * WINSPOOL_GetDWORDFromReg
3138 * Return DWORD associated with ValueName from hkey.
3140 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3142 DWORD sz = sizeof(DWORD), type, value = 0;
3143 LONG ret;
3145 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3147 if(ret != ERROR_SUCCESS) {
3148 WARN("Got ret = %d on name %s\n", ret, ValueName);
3149 return 0;
3151 if(type != REG_DWORD) {
3152 ERR("Got type %d\n", type);
3153 return 0;
3155 return value;
3159 /*****************************************************************************
3160 * get_filename_from_reg [internal]
3162 * Get ValueName from hkey storing result in out
3163 * when the Value in the registry has only a filename, use driverdir as prefix
3164 * outlen is space left in out
3165 * String is stored either as unicode or ascii
3169 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3170 LPBYTE out, DWORD outlen, LPDWORD needed)
3172 WCHAR filename[MAX_PATH];
3173 DWORD size;
3174 DWORD type;
3175 LONG ret;
3176 LPWSTR buffer = filename;
3177 LPWSTR ptr;
3179 *needed = 0;
3180 size = sizeof(filename);
3181 buffer[0] = '\0';
3182 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3183 if (ret == ERROR_MORE_DATA) {
3184 TRACE("need dynamic buffer: %u\n", size);
3185 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3186 if (!buffer) {
3187 /* No Memory is bad */
3188 return FALSE;
3190 buffer[0] = '\0';
3191 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3194 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3195 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3196 return FALSE;
3199 ptr = buffer;
3200 while (ptr) {
3201 /* do we have a full path ? */
3202 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3203 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3205 if (!ret) {
3206 /* we must build the full Path */
3207 *needed += dirlen;
3208 if ((out) && (outlen > dirlen)) {
3209 lstrcpyW((LPWSTR)out, driverdir);
3210 out += dirlen;
3211 outlen -= dirlen;
3213 else
3214 out = NULL;
3217 /* write the filename */
3218 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3219 if ((out) && (outlen >= size)) {
3220 lstrcpyW((LPWSTR)out, ptr);
3221 out += size;
3222 outlen -= size;
3224 else
3225 out = NULL;
3226 *needed += size;
3227 ptr += lstrlenW(ptr)+1;
3228 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3231 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3233 /* write the multisz-termination */
3234 if (type == REG_MULTI_SZ) {
3235 size = sizeof(WCHAR);
3237 *needed += size;
3238 if (out && (outlen >= size)) {
3239 memset (out, 0, size);
3242 return TRUE;
3245 /*****************************************************************************
3246 * WINSPOOL_GetStringFromReg
3248 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3249 * String is stored as unicode.
3251 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3252 DWORD buflen, DWORD *needed)
3254 DWORD sz = buflen, type;
3255 LONG ret;
3257 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3258 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3259 WARN("Got ret = %d\n", ret);
3260 *needed = 0;
3261 return FALSE;
3263 /* add space for terminating '\0' */
3264 sz += sizeof(WCHAR);
3265 *needed = sz;
3267 if (ptr)
3268 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3270 return TRUE;
3273 /*****************************************************************************
3274 * WINSPOOL_GetDefaultDevMode
3276 * Get a default DevMode values for wineps.
3277 * FIXME - use ppd.
3280 static void WINSPOOL_GetDefaultDevMode(
3281 LPBYTE ptr,
3282 DWORD buflen, DWORD *needed)
3284 DEVMODEW dm;
3285 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3287 /* fill default DEVMODE - should be read from ppd... */
3288 ZeroMemory( &dm, sizeof(dm) );
3289 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3290 dm.dmSpecVersion = DM_SPECVERSION;
3291 dm.dmDriverVersion = 1;
3292 dm.dmSize = sizeof(DEVMODEW);
3293 dm.dmDriverExtra = 0;
3294 dm.dmFields =
3295 DM_ORIENTATION | DM_PAPERSIZE |
3296 DM_PAPERLENGTH | DM_PAPERWIDTH |
3297 DM_SCALE |
3298 DM_COPIES |
3299 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3300 DM_YRESOLUTION | DM_TTOPTION;
3302 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3303 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3304 dm.u1.s1.dmPaperLength = 2970;
3305 dm.u1.s1.dmPaperWidth = 2100;
3307 dm.u1.s1.dmScale = 100;
3308 dm.u1.s1.dmCopies = 1;
3309 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3310 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3311 /* dm.dmColor */
3312 /* dm.dmDuplex */
3313 dm.dmYResolution = 300; /* 300dpi */
3314 dm.dmTTOption = DMTT_BITMAP;
3315 /* dm.dmCollate */
3316 /* dm.dmFormName */
3317 /* dm.dmLogPixels */
3318 /* dm.dmBitsPerPel */
3319 /* dm.dmPelsWidth */
3320 /* dm.dmPelsHeight */
3321 /* dm.u2.dmDisplayFlags */
3322 /* dm.dmDisplayFrequency */
3323 /* dm.dmICMMethod */
3324 /* dm.dmICMIntent */
3325 /* dm.dmMediaType */
3326 /* dm.dmDitherType */
3327 /* dm.dmReserved1 */
3328 /* dm.dmReserved2 */
3329 /* dm.dmPanningWidth */
3330 /* dm.dmPanningHeight */
3332 if(buflen >= sizeof(DEVMODEW))
3333 memcpy(ptr, &dm, sizeof(DEVMODEW));
3334 *needed = sizeof(DEVMODEW);
3337 /*****************************************************************************
3338 * WINSPOOL_GetDevModeFromReg
3340 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3341 * DevMode is stored either as unicode or ascii.
3343 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3344 LPBYTE ptr,
3345 DWORD buflen, DWORD *needed)
3347 DWORD sz = buflen, type;
3348 LONG ret;
3350 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3351 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3352 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3353 if (sz < sizeof(DEVMODEA))
3355 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3356 return FALSE;
3358 /* ensures that dmSize is not erratically bogus if registry is invalid */
3359 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3360 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3361 sz += (CCHDEVICENAME + CCHFORMNAME);
3362 if (ptr && (buflen >= sz)) {
3363 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3364 memcpy(ptr, dmW, sz);
3365 HeapFree(GetProcessHeap(),0,dmW);
3367 *needed = sz;
3368 return TRUE;
3371 /*********************************************************************
3372 * WINSPOOL_GetPrinter_1
3374 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3376 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3377 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3379 DWORD size, left = cbBuf;
3380 BOOL space = (cbBuf > 0);
3381 LPBYTE ptr = buf;
3383 *pcbNeeded = 0;
3385 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3386 if(space && size <= left) {
3387 pi1->pName = (LPWSTR)ptr;
3388 ptr += size;
3389 left -= size;
3390 } else
3391 space = FALSE;
3392 *pcbNeeded += size;
3395 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3396 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3397 if(space && size <= left) {
3398 pi1->pDescription = (LPWSTR)ptr;
3399 ptr += size;
3400 left -= size;
3401 } else
3402 space = FALSE;
3403 *pcbNeeded += size;
3406 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3407 if(space && size <= left) {
3408 pi1->pComment = (LPWSTR)ptr;
3409 ptr += size;
3410 left -= size;
3411 } else
3412 space = FALSE;
3413 *pcbNeeded += size;
3416 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3418 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3419 memset(pi1, 0, sizeof(*pi1));
3421 return space;
3423 /*********************************************************************
3424 * WINSPOOL_GetPrinter_2
3426 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3428 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3429 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3431 DWORD size, left = cbBuf;
3432 BOOL space = (cbBuf > 0);
3433 LPBYTE ptr = buf;
3435 *pcbNeeded = 0;
3437 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3438 if(space && size <= left) {
3439 pi2->pPrinterName = (LPWSTR)ptr;
3440 ptr += size;
3441 left -= size;
3442 } else
3443 space = FALSE;
3444 *pcbNeeded += size;
3446 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3447 if(space && size <= left) {
3448 pi2->pShareName = (LPWSTR)ptr;
3449 ptr += size;
3450 left -= size;
3451 } else
3452 space = FALSE;
3453 *pcbNeeded += size;
3455 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3456 if(space && size <= left) {
3457 pi2->pPortName = (LPWSTR)ptr;
3458 ptr += size;
3459 left -= size;
3460 } else
3461 space = FALSE;
3462 *pcbNeeded += size;
3464 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3465 if(space && size <= left) {
3466 pi2->pDriverName = (LPWSTR)ptr;
3467 ptr += size;
3468 left -= size;
3469 } else
3470 space = FALSE;
3471 *pcbNeeded += size;
3473 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3474 if(space && size <= left) {
3475 pi2->pComment = (LPWSTR)ptr;
3476 ptr += size;
3477 left -= size;
3478 } else
3479 space = FALSE;
3480 *pcbNeeded += size;
3482 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3483 if(space && size <= left) {
3484 pi2->pLocation = (LPWSTR)ptr;
3485 ptr += size;
3486 left -= size;
3487 } else
3488 space = FALSE;
3489 *pcbNeeded += size;
3491 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3492 if(space && size <= left) {
3493 pi2->pDevMode = (LPDEVMODEW)ptr;
3494 ptr += size;
3495 left -= size;
3496 } else
3497 space = FALSE;
3498 *pcbNeeded += size;
3500 else
3502 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3503 if(space && size <= left) {
3504 pi2->pDevMode = (LPDEVMODEW)ptr;
3505 ptr += size;
3506 left -= size;
3507 } else
3508 space = FALSE;
3509 *pcbNeeded += size;
3511 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3512 if(space && size <= left) {
3513 pi2->pSepFile = (LPWSTR)ptr;
3514 ptr += size;
3515 left -= size;
3516 } else
3517 space = FALSE;
3518 *pcbNeeded += size;
3520 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3521 if(space && size <= left) {
3522 pi2->pPrintProcessor = (LPWSTR)ptr;
3523 ptr += size;
3524 left -= size;
3525 } else
3526 space = FALSE;
3527 *pcbNeeded += size;
3529 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3530 if(space && size <= left) {
3531 pi2->pDatatype = (LPWSTR)ptr;
3532 ptr += size;
3533 left -= size;
3534 } else
3535 space = FALSE;
3536 *pcbNeeded += size;
3538 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3539 if(space && size <= left) {
3540 pi2->pParameters = (LPWSTR)ptr;
3541 ptr += size;
3542 left -= size;
3543 } else
3544 space = FALSE;
3545 *pcbNeeded += size;
3547 if(pi2) {
3548 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3549 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3550 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3551 "Default Priority");
3552 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3553 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3556 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3557 memset(pi2, 0, sizeof(*pi2));
3559 return space;
3562 /*********************************************************************
3563 * WINSPOOL_GetPrinter_4
3565 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3567 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3568 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3570 DWORD size, left = cbBuf;
3571 BOOL space = (cbBuf > 0);
3572 LPBYTE ptr = buf;
3574 *pcbNeeded = 0;
3576 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3577 if(space && size <= left) {
3578 pi4->pPrinterName = (LPWSTR)ptr;
3579 ptr += size;
3580 left -= size;
3581 } else
3582 space = FALSE;
3583 *pcbNeeded += size;
3585 if(pi4) {
3586 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3589 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3590 memset(pi4, 0, sizeof(*pi4));
3592 return space;
3595 /*********************************************************************
3596 * WINSPOOL_GetPrinter_5
3598 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3600 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3601 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3603 DWORD size, left = cbBuf;
3604 BOOL space = (cbBuf > 0);
3605 LPBYTE ptr = buf;
3607 *pcbNeeded = 0;
3609 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3610 if(space && size <= left) {
3611 pi5->pPrinterName = (LPWSTR)ptr;
3612 ptr += size;
3613 left -= size;
3614 } else
3615 space = FALSE;
3616 *pcbNeeded += size;
3618 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3619 if(space && size <= left) {
3620 pi5->pPortName = (LPWSTR)ptr;
3621 ptr += size;
3622 left -= size;
3623 } else
3624 space = FALSE;
3625 *pcbNeeded += size;
3627 if(pi5) {
3628 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3629 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3630 "dnsTimeout");
3631 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3632 "txTimeout");
3635 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3636 memset(pi5, 0, sizeof(*pi5));
3638 return space;
3641 /*********************************************************************
3642 * WINSPOOL_GetPrinter_7
3644 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3646 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3647 DWORD cbBuf, LPDWORD pcbNeeded)
3649 DWORD size, left = cbBuf;
3650 BOOL space = (cbBuf > 0);
3651 LPBYTE ptr = buf;
3653 *pcbNeeded = 0;
3655 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3657 ptr = NULL;
3658 size = sizeof(pi7->pszObjectGUID);
3660 if (space && size <= left) {
3661 pi7->pszObjectGUID = (LPWSTR)ptr;
3662 ptr += size;
3663 left -= size;
3664 } else
3665 space = FALSE;
3666 *pcbNeeded += size;
3667 if (pi7) {
3668 /* We do not have a Directory Service */
3669 pi7->dwAction = DSPRINT_UNPUBLISH;
3672 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3673 memset(pi7, 0, sizeof(*pi7));
3675 return space;
3678 /*********************************************************************
3679 * WINSPOOL_GetPrinter_9
3681 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3683 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3684 DWORD cbBuf, LPDWORD pcbNeeded)
3686 DWORD size;
3687 BOOL space = (cbBuf > 0);
3689 *pcbNeeded = 0;
3691 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3692 if(space && size <= cbBuf) {
3693 pi9->pDevMode = (LPDEVMODEW)buf;
3694 } else
3695 space = FALSE;
3696 *pcbNeeded += size;
3698 else
3700 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3701 if(space && size <= cbBuf) {
3702 pi9->pDevMode = (LPDEVMODEW)buf;
3703 } else
3704 space = FALSE;
3705 *pcbNeeded += size;
3708 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3709 memset(pi9, 0, sizeof(*pi9));
3711 return space;
3714 /*****************************************************************************
3715 * GetPrinterW [WINSPOOL.@]
3717 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3718 DWORD cbBuf, LPDWORD pcbNeeded)
3720 LPCWSTR name;
3721 DWORD size, needed = 0;
3722 LPBYTE ptr = NULL;
3723 HKEY hkeyPrinter, hkeyPrinters;
3724 BOOL ret;
3726 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3728 if (!(name = get_opened_printer_name(hPrinter))) {
3729 SetLastError(ERROR_INVALID_HANDLE);
3730 return FALSE;
3733 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3734 ERROR_SUCCESS) {
3735 ERR("Can't create Printers key\n");
3736 return FALSE;
3738 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3740 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3741 RegCloseKey(hkeyPrinters);
3742 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3743 return FALSE;
3746 switch(Level) {
3747 case 2:
3749 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3751 size = sizeof(PRINTER_INFO_2W);
3752 if(size <= cbBuf) {
3753 ptr = pPrinter + size;
3754 cbBuf -= size;
3755 memset(pPrinter, 0, size);
3756 } else {
3757 pi2 = NULL;
3758 cbBuf = 0;
3760 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3761 needed += size;
3762 break;
3765 case 4:
3767 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3769 size = sizeof(PRINTER_INFO_4W);
3770 if(size <= cbBuf) {
3771 ptr = pPrinter + size;
3772 cbBuf -= size;
3773 memset(pPrinter, 0, size);
3774 } else {
3775 pi4 = NULL;
3776 cbBuf = 0;
3778 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3779 needed += size;
3780 break;
3784 case 5:
3786 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3788 size = sizeof(PRINTER_INFO_5W);
3789 if(size <= cbBuf) {
3790 ptr = pPrinter + size;
3791 cbBuf -= size;
3792 memset(pPrinter, 0, size);
3793 } else {
3794 pi5 = NULL;
3795 cbBuf = 0;
3798 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3799 needed += size;
3800 break;
3804 case 6:
3806 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3808 size = sizeof(PRINTER_INFO_6);
3809 if (size <= cbBuf) {
3810 /* FIXME: We do not update the status yet */
3811 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3812 ret = TRUE;
3813 } else {
3814 ret = FALSE;
3817 needed += size;
3818 break;
3821 case 7:
3823 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3825 size = sizeof(PRINTER_INFO_7W);
3826 if (size <= cbBuf) {
3827 ptr = pPrinter + size;
3828 cbBuf -= size;
3829 memset(pPrinter, 0, size);
3830 } else {
3831 pi7 = NULL;
3832 cbBuf = 0;
3835 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3836 needed += size;
3837 break;
3841 case 9:
3843 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3845 size = sizeof(PRINTER_INFO_9W);
3846 if(size <= cbBuf) {
3847 ptr = pPrinter + size;
3848 cbBuf -= size;
3849 memset(pPrinter, 0, size);
3850 } else {
3851 pi9 = NULL;
3852 cbBuf = 0;
3855 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3856 needed += size;
3857 break;
3861 default:
3862 FIXME("Unimplemented level %d\n", Level);
3863 SetLastError(ERROR_INVALID_LEVEL);
3864 RegCloseKey(hkeyPrinters);
3865 RegCloseKey(hkeyPrinter);
3866 return FALSE;
3869 RegCloseKey(hkeyPrinter);
3870 RegCloseKey(hkeyPrinters);
3872 TRACE("returning %d needed = %d\n", ret, needed);
3873 if(pcbNeeded) *pcbNeeded = needed;
3874 if(!ret)
3875 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3876 return ret;
3879 /*****************************************************************************
3880 * GetPrinterA [WINSPOOL.@]
3882 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3883 DWORD cbBuf, LPDWORD pcbNeeded)
3885 BOOL ret;
3886 LPBYTE buf = NULL;
3888 if (cbBuf)
3889 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3891 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3892 if (ret)
3893 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3894 HeapFree(GetProcessHeap(), 0, buf);
3896 return ret;
3899 /*****************************************************************************
3900 * WINSPOOL_EnumPrintersW
3902 * Implementation of EnumPrintersW
3904 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3905 DWORD dwLevel, LPBYTE lpbPrinters,
3906 DWORD cbBuf, LPDWORD lpdwNeeded,
3907 LPDWORD lpdwReturned)
3910 HKEY hkeyPrinters, hkeyPrinter;
3911 WCHAR PrinterName[255];
3912 DWORD needed = 0, number = 0;
3913 DWORD used, i, left;
3914 PBYTE pi, buf;
3916 if(lpbPrinters)
3917 memset(lpbPrinters, 0, cbBuf);
3918 if(lpdwReturned)
3919 *lpdwReturned = 0;
3920 if(lpdwNeeded)
3921 *lpdwNeeded = 0;
3923 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3924 if(dwType == PRINTER_ENUM_DEFAULT)
3925 return TRUE;
3927 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3928 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3929 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3930 if (!dwType) {
3931 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3932 return TRUE;
3937 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3938 FIXME("dwType = %08x\n", dwType);
3939 SetLastError(ERROR_INVALID_FLAGS);
3940 return FALSE;
3943 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3944 ERROR_SUCCESS) {
3945 ERR("Can't create Printers key\n");
3946 return FALSE;
3949 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3950 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3951 RegCloseKey(hkeyPrinters);
3952 ERR("Can't query Printers key\n");
3953 return FALSE;
3955 TRACE("Found %d printers\n", number);
3957 switch(dwLevel) {
3958 case 1:
3959 used = number * sizeof(PRINTER_INFO_1W);
3960 break;
3961 case 2:
3962 used = number * sizeof(PRINTER_INFO_2W);
3963 break;
3964 case 4:
3965 used = number * sizeof(PRINTER_INFO_4W);
3966 break;
3967 case 5:
3968 used = number * sizeof(PRINTER_INFO_5W);
3969 break;
3971 default:
3972 SetLastError(ERROR_INVALID_LEVEL);
3973 RegCloseKey(hkeyPrinters);
3974 return FALSE;
3976 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3978 for(i = 0; i < number; i++) {
3979 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3980 ERROR_SUCCESS) {
3981 ERR("Can't enum key number %d\n", i);
3982 RegCloseKey(hkeyPrinters);
3983 return FALSE;
3985 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3986 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3987 ERROR_SUCCESS) {
3988 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3989 RegCloseKey(hkeyPrinters);
3990 return FALSE;
3993 if(cbBuf > used) {
3994 buf = lpbPrinters + used;
3995 left = cbBuf - used;
3996 } else {
3997 buf = NULL;
3998 left = 0;
4001 switch(dwLevel) {
4002 case 1:
4003 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4004 left, &needed);
4005 used += needed;
4006 if(pi) pi += sizeof(PRINTER_INFO_1W);
4007 break;
4008 case 2:
4009 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4010 left, &needed);
4011 used += needed;
4012 if(pi) pi += sizeof(PRINTER_INFO_2W);
4013 break;
4014 case 4:
4015 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4016 left, &needed);
4017 used += needed;
4018 if(pi) pi += sizeof(PRINTER_INFO_4W);
4019 break;
4020 case 5:
4021 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4022 left, &needed);
4023 used += needed;
4024 if(pi) pi += sizeof(PRINTER_INFO_5W);
4025 break;
4026 default:
4027 ERR("Shouldn't be here!\n");
4028 RegCloseKey(hkeyPrinter);
4029 RegCloseKey(hkeyPrinters);
4030 return FALSE;
4032 RegCloseKey(hkeyPrinter);
4034 RegCloseKey(hkeyPrinters);
4036 if(lpdwNeeded)
4037 *lpdwNeeded = used;
4039 if(used > cbBuf) {
4040 if(lpbPrinters)
4041 memset(lpbPrinters, 0, cbBuf);
4042 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4043 return FALSE;
4045 if(lpdwReturned)
4046 *lpdwReturned = number;
4047 SetLastError(ERROR_SUCCESS);
4048 return TRUE;
4052 /******************************************************************
4053 * EnumPrintersW [WINSPOOL.@]
4055 * Enumerates the available printers, print servers and print
4056 * providers, depending on the specified flags, name and level.
4058 * RETURNS:
4060 * If level is set to 1:
4061 * Returns an array of PRINTER_INFO_1 data structures in the
4062 * lpbPrinters buffer.
4064 * If level is set to 2:
4065 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4066 * Returns an array of PRINTER_INFO_2 data structures in the
4067 * lpbPrinters buffer. Note that according to MSDN also an
4068 * OpenPrinter should be performed on every remote printer.
4070 * If level is set to 4 (officially WinNT only):
4071 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4072 * Fast: Only the registry is queried to retrieve printer names,
4073 * no connection to the driver is made.
4074 * Returns an array of PRINTER_INFO_4 data structures in the
4075 * lpbPrinters buffer.
4077 * If level is set to 5 (officially WinNT4/Win9x only):
4078 * Fast: Only the registry is queried to retrieve printer names,
4079 * no connection to the driver is made.
4080 * Returns an array of PRINTER_INFO_5 data structures in the
4081 * lpbPrinters buffer.
4083 * If level set to 3 or 6+:
4084 * returns zero (failure!)
4086 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4087 * for information.
4089 * BUGS:
4090 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4091 * - Only levels 2, 4 and 5 are implemented at the moment.
4092 * - 16-bit printer drivers are not enumerated.
4093 * - Returned amount of bytes used/needed does not match the real Windoze
4094 * implementation (as in this implementation, all strings are part
4095 * of the buffer, whereas Win32 keeps them somewhere else)
4096 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4098 * NOTE:
4099 * - In a regular Wine installation, no registry settings for printers
4100 * exist, which makes this function return an empty list.
4102 BOOL WINAPI EnumPrintersW(
4103 DWORD dwType, /* [in] Types of print objects to enumerate */
4104 LPWSTR lpszName, /* [in] name of objects to enumerate */
4105 DWORD dwLevel, /* [in] type of printer info structure */
4106 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4107 DWORD cbBuf, /* [in] max size of buffer in bytes */
4108 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4109 LPDWORD lpdwReturned /* [out] number of entries returned */
4112 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4113 lpdwNeeded, lpdwReturned);
4116 /******************************************************************
4117 * EnumPrintersA [WINSPOOL.@]
4119 * See EnumPrintersW
4122 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4123 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4125 BOOL ret;
4126 UNICODE_STRING pNameU;
4127 LPWSTR pNameW;
4128 LPBYTE pPrintersW;
4130 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4131 pPrinters, cbBuf, pcbNeeded, pcReturned);
4133 pNameW = asciitounicode(&pNameU, pName);
4135 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4136 MS Office need this */
4137 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4139 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4141 RtlFreeUnicodeString(&pNameU);
4142 if (ret) {
4143 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4145 HeapFree(GetProcessHeap(), 0, pPrintersW);
4146 return ret;
4149 /*****************************************************************************
4150 * WINSPOOL_GetDriverInfoFromReg [internal]
4152 * Enters the information from the registry into the DRIVER_INFO struct
4154 * RETURNS
4155 * zero if the printer driver does not exist in the registry
4156 * (only if Level > 1) otherwise nonzero
4158 static BOOL WINSPOOL_GetDriverInfoFromReg(
4159 HKEY hkeyDrivers,
4160 LPWSTR DriverName,
4161 const printenv_t * env,
4162 DWORD Level,
4163 LPBYTE ptr, /* DRIVER_INFO */
4164 LPBYTE pDriverStrings, /* strings buffer */
4165 DWORD cbBuf, /* size of string buffer */
4166 LPDWORD pcbNeeded) /* space needed for str. */
4168 DWORD size, tmp;
4169 HKEY hkeyDriver;
4170 WCHAR driverdir[MAX_PATH];
4171 DWORD dirlen;
4172 LPBYTE strPtr = pDriverStrings;
4173 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4175 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4176 debugstr_w(DriverName), env,
4177 Level, di, pDriverStrings, cbBuf);
4179 if (di) ZeroMemory(di, di_sizeof[Level]);
4181 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4182 if (*pcbNeeded <= cbBuf)
4183 strcpyW((LPWSTR)strPtr, DriverName);
4185 /* pName for level 1 has a different offset! */
4186 if (Level == 1) {
4187 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4188 return TRUE;
4191 /* .cVersion and .pName for level > 1 */
4192 if (di) {
4193 di->cVersion = env->driverversion;
4194 di->pName = (LPWSTR) strPtr;
4195 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4198 /* Reserve Space for the largest subdir and a Backslash*/
4199 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4200 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4201 /* Should never Fail */
4202 return FALSE;
4204 lstrcatW(driverdir, env->versionsubdir);
4205 lstrcatW(driverdir, backslashW);
4207 /* dirlen must not include the terminating zero */
4208 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4210 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4211 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4212 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4213 return FALSE;
4216 /* pEnvironment */
4217 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4219 *pcbNeeded += size;
4220 if (*pcbNeeded <= cbBuf) {
4221 lstrcpyW((LPWSTR)strPtr, env->envname);
4222 if (di) di->pEnvironment = (LPWSTR)strPtr;
4223 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4226 /* .pDriverPath is the Graphics rendering engine.
4227 The full Path is required to avoid a crash in some apps */
4228 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4229 *pcbNeeded += size;
4230 if (*pcbNeeded <= cbBuf)
4231 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4233 if (di) di->pDriverPath = (LPWSTR)strPtr;
4234 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4237 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4238 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4239 *pcbNeeded += size;
4240 if (*pcbNeeded <= cbBuf)
4241 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4243 if (di) di->pDataFile = (LPWSTR)strPtr;
4244 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4247 /* .pConfigFile is the Driver user Interface */
4248 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4249 *pcbNeeded += size;
4250 if (*pcbNeeded <= cbBuf)
4251 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4253 if (di) di->pConfigFile = (LPWSTR)strPtr;
4254 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4257 if (Level == 2 ) {
4258 RegCloseKey(hkeyDriver);
4259 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4260 return TRUE;
4263 if (Level == 5 ) {
4264 RegCloseKey(hkeyDriver);
4265 FIXME("level 5: incomplete\n");
4266 return TRUE;
4269 /* .pHelpFile */
4270 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4271 *pcbNeeded += size;
4272 if (*pcbNeeded <= cbBuf)
4273 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4275 if (di) di->pHelpFile = (LPWSTR)strPtr;
4276 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4279 /* .pDependentFiles */
4280 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4281 *pcbNeeded += size;
4282 if (*pcbNeeded <= cbBuf)
4283 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4285 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4286 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4288 else if (GetVersion() & 0x80000000) {
4289 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4290 size = 2 * sizeof(WCHAR);
4291 *pcbNeeded += size;
4292 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4294 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4295 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4298 /* .pMonitorName is the optional Language Monitor */
4299 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4300 *pcbNeeded += size;
4301 if (*pcbNeeded <= cbBuf)
4302 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4304 if (di) di->pMonitorName = (LPWSTR)strPtr;
4305 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4308 /* .pDefaultDataType */
4309 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4310 *pcbNeeded += size;
4311 if(*pcbNeeded <= cbBuf)
4312 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4314 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4315 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4318 if (Level == 3 ) {
4319 RegCloseKey(hkeyDriver);
4320 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4321 return TRUE;
4324 /* .pszzPreviousNames */
4325 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4326 *pcbNeeded += size;
4327 if(*pcbNeeded <= cbBuf)
4328 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4330 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4331 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4334 if (Level == 4 ) {
4335 RegCloseKey(hkeyDriver);
4336 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4337 return TRUE;
4340 /* support is missing, but not important enough for a FIXME */
4341 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4343 /* .pszMfgName */
4344 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4345 *pcbNeeded += size;
4346 if(*pcbNeeded <= cbBuf)
4347 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4349 if (di) di->pszMfgName = (LPWSTR)strPtr;
4350 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4353 /* .pszOEMUrl */
4354 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4355 *pcbNeeded += size;
4356 if(*pcbNeeded <= cbBuf)
4357 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4359 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4360 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4363 /* .pszHardwareID */
4364 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4365 *pcbNeeded += size;
4366 if(*pcbNeeded <= cbBuf)
4367 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4369 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4370 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4373 /* .pszProvider */
4374 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4375 *pcbNeeded += size;
4376 if(*pcbNeeded <= cbBuf)
4377 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4379 if (di) di->pszProvider = (LPWSTR)strPtr;
4380 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4383 if (Level == 6 ) {
4384 RegCloseKey(hkeyDriver);
4385 return TRUE;
4388 /* support is missing, but not important enough for a FIXME */
4389 TRACE("level 8: incomplete\n");
4391 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4392 RegCloseKey(hkeyDriver);
4393 return TRUE;
4396 /*****************************************************************************
4397 * GetPrinterDriverW [WINSPOOL.@]
4399 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4400 DWORD Level, LPBYTE pDriverInfo,
4401 DWORD cbBuf, LPDWORD pcbNeeded)
4403 LPCWSTR name;
4404 WCHAR DriverName[100];
4405 DWORD ret, type, size, needed = 0;
4406 LPBYTE ptr = NULL;
4407 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4408 const printenv_t * env;
4410 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4411 Level,pDriverInfo,cbBuf, pcbNeeded);
4413 if (cbBuf > 0)
4414 ZeroMemory(pDriverInfo, cbBuf);
4416 if (!(name = get_opened_printer_name(hPrinter))) {
4417 SetLastError(ERROR_INVALID_HANDLE);
4418 return FALSE;
4421 if (Level < 1 || Level == 7 || Level > 8) {
4422 SetLastError(ERROR_INVALID_LEVEL);
4423 return FALSE;
4426 env = validate_envW(pEnvironment);
4427 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4429 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4430 ERROR_SUCCESS) {
4431 ERR("Can't create Printers key\n");
4432 return FALSE;
4434 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4435 != ERROR_SUCCESS) {
4436 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4437 RegCloseKey(hkeyPrinters);
4438 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4439 return FALSE;
4441 size = sizeof(DriverName);
4442 DriverName[0] = 0;
4443 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4444 (LPBYTE)DriverName, &size);
4445 RegCloseKey(hkeyPrinter);
4446 RegCloseKey(hkeyPrinters);
4447 if(ret != ERROR_SUCCESS) {
4448 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4449 return FALSE;
4452 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4453 if(!hkeyDrivers) {
4454 ERR("Can't create Drivers key\n");
4455 return FALSE;
4458 size = di_sizeof[Level];
4459 if ((size <= cbBuf) && pDriverInfo)
4460 ptr = pDriverInfo + size;
4462 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4463 env, Level, pDriverInfo, ptr,
4464 (cbBuf < size) ? 0 : cbBuf - size,
4465 &needed)) {
4466 RegCloseKey(hkeyDrivers);
4467 return FALSE;
4470 RegCloseKey(hkeyDrivers);
4472 if(pcbNeeded) *pcbNeeded = size + needed;
4473 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4474 if(cbBuf >= size + needed) return TRUE;
4475 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4476 return FALSE;
4479 /*****************************************************************************
4480 * GetPrinterDriverA [WINSPOOL.@]
4482 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4483 DWORD Level, LPBYTE pDriverInfo,
4484 DWORD cbBuf, LPDWORD pcbNeeded)
4486 BOOL ret;
4487 UNICODE_STRING pEnvW;
4488 PWSTR pwstrEnvW;
4489 LPBYTE buf = NULL;
4491 if (cbBuf)
4493 ZeroMemory(pDriverInfo, cbBuf);
4494 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4497 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4498 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4499 cbBuf, pcbNeeded);
4500 if (ret)
4501 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4503 HeapFree(GetProcessHeap(), 0, buf);
4505 RtlFreeUnicodeString(&pEnvW);
4506 return ret;
4509 /*****************************************************************************
4510 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4512 * Return the PATH for the Printer-Drivers (UNICODE)
4514 * PARAMS
4515 * pName [I] Servername (NT only) or NULL (local Computer)
4516 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4517 * Level [I] Structure-Level (must be 1)
4518 * pDriverDirectory [O] PTR to Buffer that receives the Result
4519 * cbBuf [I] Size of Buffer at pDriverDirectory
4520 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4521 * required for pDriverDirectory
4523 * RETURNS
4524 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4525 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4526 * if cbBuf is too small
4528 * Native Values returned in pDriverDirectory on Success:
4529 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4530 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4531 *| win9x(Windows 4.0): "%winsysdir%"
4533 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4535 * FIXME
4536 *- Only NULL or "" is supported for pName
4539 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4540 DWORD Level, LPBYTE pDriverDirectory,
4541 DWORD cbBuf, LPDWORD pcbNeeded)
4543 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4544 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4546 if ((backend == NULL) && !load_backend()) return FALSE;
4548 if (Level != 1) {
4549 /* (Level != 1) is ignored in win9x */
4550 SetLastError(ERROR_INVALID_LEVEL);
4551 return FALSE;
4553 if (pcbNeeded == NULL) {
4554 /* (pcbNeeded == NULL) is ignored in win9x */
4555 SetLastError(RPC_X_NULL_REF_POINTER);
4556 return FALSE;
4559 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4560 pDriverDirectory, cbBuf, pcbNeeded);
4565 /*****************************************************************************
4566 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4568 * Return the PATH for the Printer-Drivers (ANSI)
4570 * See GetPrinterDriverDirectoryW.
4572 * NOTES
4573 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4576 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4577 DWORD Level, LPBYTE pDriverDirectory,
4578 DWORD cbBuf, LPDWORD pcbNeeded)
4580 UNICODE_STRING nameW, environmentW;
4581 BOOL ret;
4582 DWORD pcbNeededW;
4583 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4584 WCHAR *driverDirectoryW = NULL;
4586 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4587 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4589 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4591 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4592 else nameW.Buffer = NULL;
4593 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4594 else environmentW.Buffer = NULL;
4596 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4597 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4598 if (ret) {
4599 DWORD needed;
4600 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4601 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4602 if(pcbNeeded)
4603 *pcbNeeded = needed;
4604 ret = (needed <= cbBuf) ? TRUE : FALSE;
4605 } else
4606 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4608 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4610 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4611 RtlFreeUnicodeString(&environmentW);
4612 RtlFreeUnicodeString(&nameW);
4614 return ret;
4617 /*****************************************************************************
4618 * AddPrinterDriverA [WINSPOOL.@]
4620 * See AddPrinterDriverW.
4623 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4625 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4626 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4629 /******************************************************************************
4630 * AddPrinterDriverW (WINSPOOL.@)
4632 * Install a Printer Driver
4634 * PARAMS
4635 * pName [I] Servername or NULL (local Computer)
4636 * level [I] Level for the supplied DRIVER_INFO_*W struct
4637 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4639 * RESULTS
4640 * Success: TRUE
4641 * Failure: FALSE
4644 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4646 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4647 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4650 /*****************************************************************************
4651 * AddPrintProcessorA [WINSPOOL.@]
4653 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4654 LPSTR pPrintProcessorName)
4656 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4657 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4658 return FALSE;
4661 /*****************************************************************************
4662 * AddPrintProcessorW [WINSPOOL.@]
4664 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4665 LPWSTR pPrintProcessorName)
4667 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4668 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4669 return FALSE;
4672 /*****************************************************************************
4673 * AddPrintProvidorA [WINSPOOL.@]
4675 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4677 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4678 return FALSE;
4681 /*****************************************************************************
4682 * AddPrintProvidorW [WINSPOOL.@]
4684 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4686 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4687 return FALSE;
4690 /*****************************************************************************
4691 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4693 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4694 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4696 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4697 pDevModeOutput, pDevModeInput);
4698 return 0;
4701 /*****************************************************************************
4702 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4704 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4705 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4707 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4708 pDevModeOutput, pDevModeInput);
4709 return 0;
4712 /*****************************************************************************
4713 * PrinterProperties [WINSPOOL.@]
4715 * Displays a dialog to set the properties of the printer.
4717 * RETURNS
4718 * nonzero on success or zero on failure
4720 * BUGS
4721 * implemented as stub only
4723 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4724 HANDLE hPrinter /* [in] handle to printer object */
4726 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4727 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4728 return FALSE;
4731 /*****************************************************************************
4732 * EnumJobsA [WINSPOOL.@]
4735 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4736 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4737 LPDWORD pcReturned)
4739 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4740 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4742 if(pcbNeeded) *pcbNeeded = 0;
4743 if(pcReturned) *pcReturned = 0;
4744 return FALSE;
4748 /*****************************************************************************
4749 * EnumJobsW [WINSPOOL.@]
4752 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4753 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4754 LPDWORD pcReturned)
4756 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4757 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4759 if(pcbNeeded) *pcbNeeded = 0;
4760 if(pcReturned) *pcReturned = 0;
4761 return FALSE;
4764 /*****************************************************************************
4765 * WINSPOOL_EnumPrinterDrivers [internal]
4767 * Delivers information about all printer drivers installed on the
4768 * localhost or a given server
4770 * RETURNS
4771 * nonzero on success or zero on failure. If the buffer for the returned
4772 * information is too small the function will return an error
4774 * BUGS
4775 * - only implemented for localhost, foreign hosts will return an error
4777 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4778 DWORD Level, LPBYTE pDriverInfo,
4779 DWORD driver_index,
4780 DWORD cbBuf, LPDWORD pcbNeeded,
4781 LPDWORD pcFound, DWORD data_offset)
4783 { HKEY hkeyDrivers;
4784 DWORD i, size = 0;
4785 const printenv_t * env;
4787 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4788 debugstr_w(pName), debugstr_w(pEnvironment),
4789 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4791 env = validate_envW(pEnvironment);
4792 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4794 *pcFound = 0;
4796 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4797 if(!hkeyDrivers) {
4798 ERR("Can't open Drivers key\n");
4799 return FALSE;
4802 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4803 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4804 RegCloseKey(hkeyDrivers);
4805 ERR("Can't query Drivers key\n");
4806 return FALSE;
4808 TRACE("Found %d Drivers\n", *pcFound);
4810 /* get size of single struct
4811 * unicode and ascii structure have the same size
4813 size = di_sizeof[Level];
4815 if (data_offset == 0)
4816 data_offset = size * (*pcFound);
4817 *pcbNeeded = data_offset;
4819 for( i = 0; i < *pcFound; i++) {
4820 WCHAR DriverNameW[255];
4821 PBYTE table_ptr = NULL;
4822 PBYTE data_ptr = NULL;
4823 DWORD needed = 0;
4825 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4826 != ERROR_SUCCESS) {
4827 ERR("Can't enum key number %d\n", i);
4828 RegCloseKey(hkeyDrivers);
4829 return FALSE;
4832 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4833 table_ptr = pDriverInfo + (driver_index + i) * size;
4834 if (pDriverInfo && *pcbNeeded <= cbBuf)
4835 data_ptr = pDriverInfo + *pcbNeeded;
4837 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4838 env, Level, table_ptr, data_ptr,
4839 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4840 &needed)) {
4841 RegCloseKey(hkeyDrivers);
4842 return FALSE;
4845 *pcbNeeded += needed;
4848 RegCloseKey(hkeyDrivers);
4850 if(cbBuf < *pcbNeeded){
4851 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4852 return FALSE;
4855 return TRUE;
4858 /*****************************************************************************
4859 * EnumPrinterDriversW [WINSPOOL.@]
4861 * see function EnumPrinterDrivers for RETURNS, BUGS
4863 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4864 LPBYTE pDriverInfo, DWORD cbBuf,
4865 LPDWORD pcbNeeded, LPDWORD pcReturned)
4867 static const WCHAR allW[] = {'a','l','l',0};
4868 BOOL ret;
4869 DWORD found;
4871 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4873 SetLastError(RPC_X_NULL_REF_POINTER);
4874 return FALSE;
4877 /* check for local drivers */
4878 if((pName) && (pName[0])) {
4879 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4880 SetLastError(ERROR_ACCESS_DENIED);
4881 return FALSE;
4884 /* check input parameter */
4885 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4886 SetLastError(ERROR_INVALID_LEVEL);
4887 return FALSE;
4890 if(pDriverInfo && cbBuf > 0)
4891 memset( pDriverInfo, 0, cbBuf);
4893 /* Exception: pull all printers */
4894 if (pEnvironment && !strcmpW(pEnvironment, allW))
4896 DWORD i, needed, bufsize = cbBuf;
4897 DWORD total_needed = 0;
4898 DWORD total_found = 0;
4899 DWORD data_offset;
4901 /* Precompute the overall total; we need this to know
4902 where pointers end and data begins (i.e. data_offset) */
4903 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4905 needed = found = 0;
4906 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4907 NULL, 0, 0, &needed, &found, 0);
4908 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4909 total_needed += needed;
4910 total_found += found;
4913 data_offset = di_sizeof[Level] * total_found;
4915 *pcReturned = 0;
4916 *pcbNeeded = 0;
4917 total_found = 0;
4918 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4920 needed = found = 0;
4921 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4922 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4923 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4924 else if (ret)
4925 *pcReturned += found;
4926 *pcbNeeded = needed;
4927 data_offset = needed;
4928 total_found += found;
4930 return ret;
4933 /* Normal behavior */
4934 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4935 0, cbBuf, pcbNeeded, &found, 0);
4936 if (ret)
4937 *pcReturned = found;
4939 return ret;
4942 /*****************************************************************************
4943 * EnumPrinterDriversA [WINSPOOL.@]
4945 * see function EnumPrinterDrivers for RETURNS, BUGS
4947 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4948 LPBYTE pDriverInfo, DWORD cbBuf,
4949 LPDWORD pcbNeeded, LPDWORD pcReturned)
4951 BOOL ret;
4952 UNICODE_STRING pNameW, pEnvironmentW;
4953 PWSTR pwstrNameW, pwstrEnvironmentW;
4954 LPBYTE buf = NULL;
4956 if (cbBuf)
4957 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4959 pwstrNameW = asciitounicode(&pNameW, pName);
4960 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4962 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4963 buf, cbBuf, pcbNeeded, pcReturned);
4964 if (ret)
4965 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4967 HeapFree(GetProcessHeap(), 0, buf);
4969 RtlFreeUnicodeString(&pNameW);
4970 RtlFreeUnicodeString(&pEnvironmentW);
4972 return ret;
4975 /******************************************************************************
4976 * EnumPortsA (WINSPOOL.@)
4978 * See EnumPortsW.
4981 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4982 LPDWORD pcbNeeded, LPDWORD pcReturned)
4984 BOOL res;
4985 LPBYTE bufferW = NULL;
4986 LPWSTR nameW = NULL;
4987 DWORD needed = 0;
4988 DWORD numentries = 0;
4989 INT len;
4991 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4992 cbBuf, pcbNeeded, pcReturned);
4994 /* convert servername to unicode */
4995 if (pName) {
4996 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4997 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4998 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5000 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5001 needed = cbBuf * sizeof(WCHAR);
5002 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5003 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5005 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5006 if (pcbNeeded) needed = *pcbNeeded;
5007 /* HeapReAlloc return NULL, when bufferW was NULL */
5008 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5009 HeapAlloc(GetProcessHeap(), 0, needed);
5011 /* Try again with the large Buffer */
5012 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5014 needed = pcbNeeded ? *pcbNeeded : 0;
5015 numentries = pcReturned ? *pcReturned : 0;
5018 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5019 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5021 if (res) {
5022 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5023 DWORD entrysize = 0;
5024 DWORD index;
5025 LPSTR ptr;
5026 LPPORT_INFO_2W pi2w;
5027 LPPORT_INFO_2A pi2a;
5029 needed = 0;
5030 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5032 /* First pass: calculate the size for all Entries */
5033 pi2w = (LPPORT_INFO_2W) bufferW;
5034 pi2a = (LPPORT_INFO_2A) pPorts;
5035 index = 0;
5036 while (index < numentries) {
5037 index++;
5038 needed += entrysize; /* PORT_INFO_?A */
5039 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5041 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5042 NULL, 0, NULL, NULL);
5043 if (Level > 1) {
5044 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5045 NULL, 0, NULL, NULL);
5046 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5047 NULL, 0, NULL, NULL);
5049 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5050 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5051 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5054 /* check for errors and quit on failure */
5055 if (cbBuf < needed) {
5056 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5057 res = FALSE;
5058 goto cleanup;
5060 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5061 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5062 cbBuf -= len ; /* free Bytes in the user-Buffer */
5063 pi2w = (LPPORT_INFO_2W) bufferW;
5064 pi2a = (LPPORT_INFO_2A) pPorts;
5065 index = 0;
5066 /* Second Pass: Fill the User Buffer (if we have one) */
5067 while ((index < numentries) && pPorts) {
5068 index++;
5069 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5070 pi2a->pPortName = ptr;
5071 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5072 ptr, cbBuf , NULL, NULL);
5073 ptr += len;
5074 cbBuf -= len;
5075 if (Level > 1) {
5076 pi2a->pMonitorName = ptr;
5077 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5078 ptr, cbBuf, NULL, NULL);
5079 ptr += len;
5080 cbBuf -= len;
5082 pi2a->pDescription = ptr;
5083 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5084 ptr, cbBuf, NULL, NULL);
5085 ptr += len;
5086 cbBuf -= len;
5088 pi2a->fPortType = pi2w->fPortType;
5089 pi2a->Reserved = 0; /* documented: "must be zero" */
5092 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5093 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5094 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5098 cleanup:
5099 if (pcbNeeded) *pcbNeeded = needed;
5100 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5102 HeapFree(GetProcessHeap(), 0, nameW);
5103 HeapFree(GetProcessHeap(), 0, bufferW);
5105 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5106 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5108 return (res);
5112 /******************************************************************************
5113 * EnumPortsW (WINSPOOL.@)
5115 * Enumerate available Ports
5117 * PARAMS
5118 * pName [I] Servername or NULL (local Computer)
5119 * Level [I] Structure-Level (1 or 2)
5120 * pPorts [O] PTR to Buffer that receives the Result
5121 * cbBuf [I] Size of Buffer at pPorts
5122 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5123 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5125 * RETURNS
5126 * Success: TRUE
5127 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5130 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5133 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5134 cbBuf, pcbNeeded, pcReturned);
5136 if ((backend == NULL) && !load_backend()) return FALSE;
5138 /* Level is not checked in win9x */
5139 if (!Level || (Level > 2)) {
5140 WARN("level (%d) is ignored in win9x\n", Level);
5141 SetLastError(ERROR_INVALID_LEVEL);
5142 return FALSE;
5144 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5145 SetLastError(RPC_X_NULL_REF_POINTER);
5146 return FALSE;
5149 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5152 /******************************************************************************
5153 * GetDefaultPrinterW (WINSPOOL.@)
5155 * FIXME
5156 * This function must read the value from data 'device' of key
5157 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5159 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5161 BOOL retval = TRUE;
5162 DWORD insize, len;
5163 WCHAR *buffer, *ptr;
5165 if (!namesize)
5167 SetLastError(ERROR_INVALID_PARAMETER);
5168 return FALSE;
5171 /* make the buffer big enough for the stuff from the profile/registry,
5172 * the content must fit into the local buffer to compute the correct
5173 * size even if the extern buffer is too small or not given.
5174 * (20 for ,driver,port) */
5175 insize = *namesize;
5176 len = max(100, (insize + 20));
5177 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5179 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5181 SetLastError (ERROR_FILE_NOT_FOUND);
5182 retval = FALSE;
5183 goto end;
5185 TRACE("%s\n", debugstr_w(buffer));
5187 if ((ptr = strchrW(buffer, ',')) == NULL)
5189 SetLastError(ERROR_INVALID_NAME);
5190 retval = FALSE;
5191 goto end;
5194 *ptr = 0;
5195 *namesize = strlenW(buffer) + 1;
5196 if(!name || (*namesize > insize))
5198 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5199 retval = FALSE;
5200 goto end;
5202 strcpyW(name, buffer);
5204 end:
5205 HeapFree( GetProcessHeap(), 0, buffer);
5206 return retval;
5210 /******************************************************************************
5211 * GetDefaultPrinterA (WINSPOOL.@)
5213 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5215 BOOL retval = TRUE;
5216 DWORD insize = 0;
5217 WCHAR *bufferW = NULL;
5219 if (!namesize)
5221 SetLastError(ERROR_INVALID_PARAMETER);
5222 return FALSE;
5225 if(name && *namesize) {
5226 insize = *namesize;
5227 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5230 if(!GetDefaultPrinterW( bufferW, namesize)) {
5231 retval = FALSE;
5232 goto end;
5235 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5236 NULL, NULL);
5237 if (!*namesize)
5239 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5240 retval = FALSE;
5242 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5244 end:
5245 HeapFree( GetProcessHeap(), 0, bufferW);
5246 return retval;
5250 /******************************************************************************
5251 * SetDefaultPrinterW (WINSPOOL.204)
5253 * Set the Name of the Default Printer
5255 * PARAMS
5256 * pszPrinter [I] Name of the Printer or NULL
5258 * RETURNS
5259 * Success: True
5260 * Failure: FALSE
5262 * NOTES
5263 * When the Parameter is NULL or points to an Empty String and
5264 * a Default Printer was already present, then this Function changes nothing.
5265 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5266 * the First enumerated local Printer is used.
5269 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5271 WCHAR default_printer[MAX_PATH];
5272 LPWSTR buffer = NULL;
5273 HKEY hreg;
5274 DWORD size;
5275 DWORD namelen;
5276 LONG lres;
5278 TRACE("(%s)\n", debugstr_w(pszPrinter));
5279 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5281 default_printer[0] = '\0';
5282 size = sizeof(default_printer)/sizeof(WCHAR);
5284 /* if we have a default Printer, do nothing. */
5285 if (GetDefaultPrinterW(default_printer, &size))
5286 return TRUE;
5288 pszPrinter = NULL;
5289 /* we have no default Printer: search local Printers and use the first */
5290 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5292 default_printer[0] = '\0';
5293 size = sizeof(default_printer)/sizeof(WCHAR);
5294 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5296 pszPrinter = default_printer;
5297 TRACE("using %s\n", debugstr_w(pszPrinter));
5299 RegCloseKey(hreg);
5302 if (pszPrinter == NULL) {
5303 TRACE("no local printer found\n");
5304 SetLastError(ERROR_FILE_NOT_FOUND);
5305 return FALSE;
5309 /* "pszPrinter" is never empty or NULL here. */
5310 namelen = lstrlenW(pszPrinter);
5311 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5312 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5313 if (!buffer ||
5314 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5315 HeapFree(GetProcessHeap(), 0, buffer);
5316 SetLastError(ERROR_FILE_NOT_FOUND);
5317 return FALSE;
5320 /* read the devices entry for the printer (driver,port) to build the string for the
5321 default device entry (printer,driver,port) */
5322 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5323 buffer[namelen] = ',';
5324 namelen++; /* move index to the start of the driver */
5326 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5327 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5328 if (!lres) {
5329 TRACE("set device to %s\n", debugstr_w(buffer));
5331 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5332 TRACE("failed to set the device entry: %d\n", GetLastError());
5333 lres = ERROR_INVALID_PRINTER_NAME;
5336 /* remove the next section, when INIFileMapping is implemented */
5338 HKEY hdev;
5339 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5340 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5341 RegCloseKey(hdev);
5345 else
5347 if (lres != ERROR_FILE_NOT_FOUND)
5348 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5350 SetLastError(ERROR_INVALID_PRINTER_NAME);
5353 RegCloseKey(hreg);
5354 HeapFree(GetProcessHeap(), 0, buffer);
5355 return (lres == ERROR_SUCCESS);
5358 /******************************************************************************
5359 * SetDefaultPrinterA (WINSPOOL.202)
5361 * See SetDefaultPrinterW.
5364 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5366 LPWSTR bufferW = NULL;
5367 BOOL res;
5369 TRACE("(%s)\n", debugstr_a(pszPrinter));
5370 if(pszPrinter) {
5371 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5372 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5373 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5375 res = SetDefaultPrinterW(bufferW);
5376 HeapFree(GetProcessHeap(), 0, bufferW);
5377 return res;
5380 /******************************************************************************
5381 * SetPrinterDataExA (WINSPOOL.@)
5383 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5384 LPCSTR pValueName, DWORD Type,
5385 LPBYTE pData, DWORD cbData)
5387 HKEY hkeyPrinter, hkeySubkey;
5388 DWORD ret;
5390 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5391 debugstr_a(pValueName), Type, pData, cbData);
5393 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5394 != ERROR_SUCCESS)
5395 return ret;
5397 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5398 != ERROR_SUCCESS) {
5399 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5400 RegCloseKey(hkeyPrinter);
5401 return ret;
5403 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5404 RegCloseKey(hkeySubkey);
5405 RegCloseKey(hkeyPrinter);
5406 return ret;
5409 /******************************************************************************
5410 * SetPrinterDataExW (WINSPOOL.@)
5412 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5413 LPCWSTR pValueName, DWORD Type,
5414 LPBYTE pData, DWORD cbData)
5416 HKEY hkeyPrinter, hkeySubkey;
5417 DWORD ret;
5419 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5420 debugstr_w(pValueName), Type, pData, cbData);
5422 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5423 != ERROR_SUCCESS)
5424 return ret;
5426 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5427 != ERROR_SUCCESS) {
5428 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5429 RegCloseKey(hkeyPrinter);
5430 return ret;
5432 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5433 RegCloseKey(hkeySubkey);
5434 RegCloseKey(hkeyPrinter);
5435 return ret;
5438 /******************************************************************************
5439 * SetPrinterDataA (WINSPOOL.@)
5441 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5442 LPBYTE pData, DWORD cbData)
5444 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5445 pData, cbData);
5448 /******************************************************************************
5449 * SetPrinterDataW (WINSPOOL.@)
5451 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5452 LPBYTE pData, DWORD cbData)
5454 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5455 pData, cbData);
5458 /******************************************************************************
5459 * GetPrinterDataExA (WINSPOOL.@)
5461 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5462 LPCSTR pValueName, LPDWORD pType,
5463 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5465 opened_printer_t *printer;
5466 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5467 DWORD ret;
5469 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5470 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5472 printer = get_opened_printer(hPrinter);
5473 if(!printer) return ERROR_INVALID_HANDLE;
5475 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5476 if (ret) return ret;
5478 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5480 if (printer->name) {
5482 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5483 if (ret) {
5484 RegCloseKey(hkeyPrinters);
5485 return ret;
5487 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5488 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5489 RegCloseKey(hkeyPrinter);
5490 RegCloseKey(hkeyPrinters);
5491 return ret;
5494 *pcbNeeded = nSize;
5495 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5496 0, pType, pData, pcbNeeded);
5498 if (!ret && !pData) ret = ERROR_MORE_DATA;
5500 RegCloseKey(hkeySubkey);
5501 RegCloseKey(hkeyPrinter);
5502 RegCloseKey(hkeyPrinters);
5504 TRACE("--> %d\n", ret);
5505 return ret;
5508 /******************************************************************************
5509 * GetPrinterDataExW (WINSPOOL.@)
5511 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5512 LPCWSTR pValueName, LPDWORD pType,
5513 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5515 opened_printer_t *printer;
5516 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5517 DWORD ret;
5519 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5520 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5522 printer = get_opened_printer(hPrinter);
5523 if(!printer) return ERROR_INVALID_HANDLE;
5525 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5526 if (ret) return ret;
5528 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5530 if (printer->name) {
5532 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5533 if (ret) {
5534 RegCloseKey(hkeyPrinters);
5535 return ret;
5537 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5538 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5539 RegCloseKey(hkeyPrinter);
5540 RegCloseKey(hkeyPrinters);
5541 return ret;
5544 *pcbNeeded = nSize;
5545 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5546 0, pType, pData, pcbNeeded);
5548 if (!ret && !pData) ret = ERROR_MORE_DATA;
5550 RegCloseKey(hkeySubkey);
5551 RegCloseKey(hkeyPrinter);
5552 RegCloseKey(hkeyPrinters);
5554 TRACE("--> %d\n", ret);
5555 return ret;
5558 /******************************************************************************
5559 * GetPrinterDataA (WINSPOOL.@)
5561 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5562 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5564 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5565 pData, nSize, pcbNeeded);
5568 /******************************************************************************
5569 * GetPrinterDataW (WINSPOOL.@)
5571 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5572 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5574 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5575 pData, nSize, pcbNeeded);
5578 /*******************************************************************************
5579 * EnumPrinterDataExW [WINSPOOL.@]
5581 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5582 LPBYTE pEnumValues, DWORD cbEnumValues,
5583 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5585 HKEY hkPrinter, hkSubKey;
5586 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5587 cbValueNameLen, cbMaxValueLen, cbValueLen,
5588 cbBufSize, dwType;
5589 LPWSTR lpValueName;
5590 HANDLE hHeap;
5591 PBYTE lpValue;
5592 PPRINTER_ENUM_VALUESW ppev;
5594 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5596 if (pKeyName == NULL || *pKeyName == 0)
5597 return ERROR_INVALID_PARAMETER;
5599 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5600 if (ret != ERROR_SUCCESS)
5602 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5603 hPrinter, ret);
5604 return ret;
5607 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5608 if (ret != ERROR_SUCCESS)
5610 r = RegCloseKey (hkPrinter);
5611 if (r != ERROR_SUCCESS)
5612 WARN ("RegCloseKey returned %i\n", r);
5613 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5614 debugstr_w (pKeyName), ret);
5615 return ret;
5618 ret = RegCloseKey (hkPrinter);
5619 if (ret != ERROR_SUCCESS)
5621 ERR ("RegCloseKey returned %i\n", ret);
5622 r = RegCloseKey (hkSubKey);
5623 if (r != ERROR_SUCCESS)
5624 WARN ("RegCloseKey returned %i\n", r);
5625 return ret;
5628 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5629 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5630 if (ret != ERROR_SUCCESS)
5632 r = RegCloseKey (hkSubKey);
5633 if (r != ERROR_SUCCESS)
5634 WARN ("RegCloseKey returned %i\n", r);
5635 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5636 return ret;
5639 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5640 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5642 if (cValues == 0) /* empty key */
5644 r = RegCloseKey (hkSubKey);
5645 if (r != ERROR_SUCCESS)
5646 WARN ("RegCloseKey returned %i\n", r);
5647 *pcbEnumValues = *pnEnumValues = 0;
5648 return ERROR_SUCCESS;
5651 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5653 hHeap = GetProcessHeap ();
5654 if (hHeap == NULL)
5656 ERR ("GetProcessHeap failed\n");
5657 r = RegCloseKey (hkSubKey);
5658 if (r != ERROR_SUCCESS)
5659 WARN ("RegCloseKey returned %i\n", r);
5660 return ERROR_OUTOFMEMORY;
5663 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5664 if (lpValueName == NULL)
5666 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5667 r = RegCloseKey (hkSubKey);
5668 if (r != ERROR_SUCCESS)
5669 WARN ("RegCloseKey returned %i\n", r);
5670 return ERROR_OUTOFMEMORY;
5673 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5674 if (lpValue == NULL)
5676 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5677 if (HeapFree (hHeap, 0, lpValueName) == 0)
5678 WARN ("HeapFree failed with code %i\n", GetLastError ());
5679 r = RegCloseKey (hkSubKey);
5680 if (r != ERROR_SUCCESS)
5681 WARN ("RegCloseKey returned %i\n", r);
5682 return ERROR_OUTOFMEMORY;
5685 TRACE ("pass 1: calculating buffer required for all names and values\n");
5687 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5689 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5691 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5693 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5694 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5695 NULL, NULL, lpValue, &cbValueLen);
5696 if (ret != ERROR_SUCCESS)
5698 if (HeapFree (hHeap, 0, lpValue) == 0)
5699 WARN ("HeapFree failed with code %i\n", GetLastError ());
5700 if (HeapFree (hHeap, 0, lpValueName) == 0)
5701 WARN ("HeapFree failed with code %i\n", GetLastError ());
5702 r = RegCloseKey (hkSubKey);
5703 if (r != ERROR_SUCCESS)
5704 WARN ("RegCloseKey returned %i\n", r);
5705 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5706 return ret;
5709 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5710 debugstr_w (lpValueName), dwIndex,
5711 cbValueNameLen + 1, cbValueLen);
5713 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5714 cbBufSize += cbValueLen;
5717 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5719 *pcbEnumValues = cbBufSize;
5720 *pnEnumValues = cValues;
5722 if (cbEnumValues < cbBufSize) /* buffer too small */
5724 if (HeapFree (hHeap, 0, lpValue) == 0)
5725 WARN ("HeapFree failed with code %i\n", GetLastError ());
5726 if (HeapFree (hHeap, 0, lpValueName) == 0)
5727 WARN ("HeapFree failed with code %i\n", GetLastError ());
5728 r = RegCloseKey (hkSubKey);
5729 if (r != ERROR_SUCCESS)
5730 WARN ("RegCloseKey returned %i\n", r);
5731 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5732 return ERROR_MORE_DATA;
5735 TRACE ("pass 2: copying all names and values to buffer\n");
5737 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5738 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5740 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5742 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5743 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5744 NULL, &dwType, lpValue, &cbValueLen);
5745 if (ret != ERROR_SUCCESS)
5747 if (HeapFree (hHeap, 0, lpValue) == 0)
5748 WARN ("HeapFree failed with code %i\n", GetLastError ());
5749 if (HeapFree (hHeap, 0, lpValueName) == 0)
5750 WARN ("HeapFree failed with code %i\n", GetLastError ());
5751 r = RegCloseKey (hkSubKey);
5752 if (r != ERROR_SUCCESS)
5753 WARN ("RegCloseKey returned %i\n", r);
5754 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5755 return ret;
5758 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5759 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5760 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5761 pEnumValues += cbValueNameLen;
5763 /* return # of *bytes* (including trailing \0), not # of chars */
5764 ppev[dwIndex].cbValueName = cbValueNameLen;
5766 ppev[dwIndex].dwType = dwType;
5768 memcpy (pEnumValues, lpValue, cbValueLen);
5769 ppev[dwIndex].pData = pEnumValues;
5770 pEnumValues += cbValueLen;
5772 ppev[dwIndex].cbData = cbValueLen;
5774 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5775 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5778 if (HeapFree (hHeap, 0, lpValue) == 0)
5780 ret = GetLastError ();
5781 ERR ("HeapFree failed with code %i\n", ret);
5782 if (HeapFree (hHeap, 0, lpValueName) == 0)
5783 WARN ("HeapFree failed with code %i\n", GetLastError ());
5784 r = RegCloseKey (hkSubKey);
5785 if (r != ERROR_SUCCESS)
5786 WARN ("RegCloseKey returned %i\n", r);
5787 return ret;
5790 if (HeapFree (hHeap, 0, lpValueName) == 0)
5792 ret = GetLastError ();
5793 ERR ("HeapFree failed with code %i\n", ret);
5794 r = RegCloseKey (hkSubKey);
5795 if (r != ERROR_SUCCESS)
5796 WARN ("RegCloseKey returned %i\n", r);
5797 return ret;
5800 ret = RegCloseKey (hkSubKey);
5801 if (ret != ERROR_SUCCESS)
5803 ERR ("RegCloseKey returned %i\n", ret);
5804 return ret;
5807 return ERROR_SUCCESS;
5810 /*******************************************************************************
5811 * EnumPrinterDataExA [WINSPOOL.@]
5813 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5814 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5815 * what Windows 2000 SP1 does.
5818 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5819 LPBYTE pEnumValues, DWORD cbEnumValues,
5820 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5822 INT len;
5823 LPWSTR pKeyNameW;
5824 DWORD ret, dwIndex, dwBufSize;
5825 HANDLE hHeap;
5826 LPSTR pBuffer;
5828 TRACE ("%p %s\n", hPrinter, pKeyName);
5830 if (pKeyName == NULL || *pKeyName == 0)
5831 return ERROR_INVALID_PARAMETER;
5833 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5834 if (len == 0)
5836 ret = GetLastError ();
5837 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5838 return ret;
5841 hHeap = GetProcessHeap ();
5842 if (hHeap == NULL)
5844 ERR ("GetProcessHeap failed\n");
5845 return ERROR_OUTOFMEMORY;
5848 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5849 if (pKeyNameW == NULL)
5851 ERR ("Failed to allocate %i bytes from process heap\n",
5852 (LONG)(len * sizeof (WCHAR)));
5853 return ERROR_OUTOFMEMORY;
5856 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5858 ret = GetLastError ();
5859 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5860 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5861 WARN ("HeapFree failed with code %i\n", GetLastError ());
5862 return ret;
5865 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5866 pcbEnumValues, pnEnumValues);
5867 if (ret != ERROR_SUCCESS)
5869 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5870 WARN ("HeapFree failed with code %i\n", GetLastError ());
5871 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5872 return ret;
5875 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5877 ret = GetLastError ();
5878 ERR ("HeapFree failed with code %i\n", ret);
5879 return ret;
5882 if (*pnEnumValues == 0) /* empty key */
5883 return ERROR_SUCCESS;
5885 dwBufSize = 0;
5886 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5888 PPRINTER_ENUM_VALUESW ppev =
5889 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5891 if (dwBufSize < ppev->cbValueName)
5892 dwBufSize = ppev->cbValueName;
5894 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5895 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5896 dwBufSize = ppev->cbData;
5899 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5901 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5902 if (pBuffer == NULL)
5904 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5905 return ERROR_OUTOFMEMORY;
5908 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5910 PPRINTER_ENUM_VALUESW ppev =
5911 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5913 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5914 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5915 NULL);
5916 if (len == 0)
5918 ret = GetLastError ();
5919 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5920 if (HeapFree (hHeap, 0, pBuffer) == 0)
5921 WARN ("HeapFree failed with code %i\n", GetLastError ());
5922 return ret;
5925 memcpy (ppev->pValueName, pBuffer, len);
5927 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5929 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5930 ppev->dwType != REG_MULTI_SZ)
5931 continue;
5933 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5934 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5935 if (len == 0)
5937 ret = GetLastError ();
5938 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5939 if (HeapFree (hHeap, 0, pBuffer) == 0)
5940 WARN ("HeapFree failed with code %i\n", GetLastError ());
5941 return ret;
5944 memcpy (ppev->pData, pBuffer, len);
5946 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5947 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5950 if (HeapFree (hHeap, 0, pBuffer) == 0)
5952 ret = GetLastError ();
5953 ERR ("HeapFree failed with code %i\n", ret);
5954 return ret;
5957 return ERROR_SUCCESS;
5960 /******************************************************************************
5961 * AbortPrinter (WINSPOOL.@)
5963 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5965 FIXME("(%p), stub!\n", hPrinter);
5966 return TRUE;
5969 /******************************************************************************
5970 * AddPortA (WINSPOOL.@)
5972 * See AddPortW.
5975 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5977 LPWSTR nameW = NULL;
5978 LPWSTR monitorW = NULL;
5979 DWORD len;
5980 BOOL res;
5982 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5984 if (pName) {
5985 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5986 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5987 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5990 if (pMonitorName) {
5991 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5992 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5993 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5995 res = AddPortW(nameW, hWnd, monitorW);
5996 HeapFree(GetProcessHeap(), 0, nameW);
5997 HeapFree(GetProcessHeap(), 0, monitorW);
5998 return res;
6001 /******************************************************************************
6002 * AddPortW (WINSPOOL.@)
6004 * Add a Port for a specific Monitor
6006 * PARAMS
6007 * pName [I] Servername or NULL (local Computer)
6008 * hWnd [I] Handle to parent Window for the Dialog-Box
6009 * pMonitorName [I] Name of the Monitor that manage the Port
6011 * RETURNS
6012 * Success: TRUE
6013 * Failure: FALSE
6016 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6018 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6020 if ((backend == NULL) && !load_backend()) return FALSE;
6022 if (!pMonitorName) {
6023 SetLastError(RPC_X_NULL_REF_POINTER);
6024 return FALSE;
6027 return backend->fpAddPort(pName, hWnd, pMonitorName);
6030 /******************************************************************************
6031 * AddPortExA (WINSPOOL.@)
6033 * See AddPortExW.
6036 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6038 PORT_INFO_2W pi2W;
6039 PORT_INFO_2A * pi2A;
6040 LPWSTR nameW = NULL;
6041 LPWSTR monitorW = NULL;
6042 DWORD len;
6043 BOOL res;
6045 pi2A = (PORT_INFO_2A *) pBuffer;
6047 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6048 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6050 if ((level < 1) || (level > 2)) {
6051 SetLastError(ERROR_INVALID_LEVEL);
6052 return FALSE;
6055 if (!pi2A) {
6056 SetLastError(ERROR_INVALID_PARAMETER);
6057 return FALSE;
6060 if (pName) {
6061 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6062 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6063 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6066 if (pMonitorName) {
6067 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6068 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6069 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6072 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6074 if (pi2A->pPortName) {
6075 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6076 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6077 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6080 if (level > 1) {
6081 if (pi2A->pMonitorName) {
6082 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6083 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6084 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6087 if (pi2A->pDescription) {
6088 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6089 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6090 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6092 pi2W.fPortType = pi2A->fPortType;
6093 pi2W.Reserved = pi2A->Reserved;
6096 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6098 HeapFree(GetProcessHeap(), 0, nameW);
6099 HeapFree(GetProcessHeap(), 0, monitorW);
6100 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6101 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6102 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6103 return res;
6107 /******************************************************************************
6108 * AddPortExW (WINSPOOL.@)
6110 * Add a Port for a specific Monitor, without presenting a user interface
6112 * PARAMS
6113 * pName [I] Servername or NULL (local Computer)
6114 * level [I] Structure-Level (1 or 2) for pBuffer
6115 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6116 * pMonitorName [I] Name of the Monitor that manage the Port
6118 * RETURNS
6119 * Success: TRUE
6120 * Failure: FALSE
6123 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6125 PORT_INFO_2W * pi2;
6127 pi2 = (PORT_INFO_2W *) pBuffer;
6129 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6130 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6131 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6132 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6134 if ((backend == NULL) && !load_backend()) return FALSE;
6136 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6137 SetLastError(ERROR_INVALID_PARAMETER);
6138 return FALSE;
6141 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6144 /******************************************************************************
6145 * AddPrinterConnectionA (WINSPOOL.@)
6147 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6149 FIXME("%s\n", debugstr_a(pName));
6150 return FALSE;
6153 /******************************************************************************
6154 * AddPrinterConnectionW (WINSPOOL.@)
6156 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6158 FIXME("%s\n", debugstr_w(pName));
6159 return FALSE;
6162 /******************************************************************************
6163 * AddPrinterDriverExW (WINSPOOL.@)
6165 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6167 * PARAMS
6168 * pName [I] Servername or NULL (local Computer)
6169 * level [I] Level for the supplied DRIVER_INFO_*W struct
6170 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6171 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6173 * RESULTS
6174 * Success: TRUE
6175 * Failure: FALSE
6178 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6180 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6182 if ((backend == NULL) && !load_backend()) return FALSE;
6184 if (level < 2 || level == 5 || level == 7 || level > 8) {
6185 SetLastError(ERROR_INVALID_LEVEL);
6186 return FALSE;
6189 if (!pDriverInfo) {
6190 SetLastError(ERROR_INVALID_PARAMETER);
6191 return FALSE;
6194 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6197 /******************************************************************************
6198 * AddPrinterDriverExA (WINSPOOL.@)
6200 * See AddPrinterDriverExW.
6203 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6205 DRIVER_INFO_8A *diA;
6206 DRIVER_INFO_8W diW;
6207 LPWSTR nameW = NULL;
6208 DWORD lenA;
6209 DWORD len;
6210 DWORD res = FALSE;
6212 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6214 diA = (DRIVER_INFO_8A *) pDriverInfo;
6215 ZeroMemory(&diW, sizeof(diW));
6217 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6218 SetLastError(ERROR_INVALID_LEVEL);
6219 return FALSE;
6222 if (diA == NULL) {
6223 SetLastError(ERROR_INVALID_PARAMETER);
6224 return FALSE;
6227 /* convert servername to unicode */
6228 if (pName) {
6229 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6230 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6231 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6234 /* common fields */
6235 diW.cVersion = diA->cVersion;
6237 if (diA->pName) {
6238 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6239 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6240 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6243 if (diA->pEnvironment) {
6244 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6245 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6246 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6249 if (diA->pDriverPath) {
6250 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6251 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6252 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6255 if (diA->pDataFile) {
6256 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6257 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6258 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6261 if (diA->pConfigFile) {
6262 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6263 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6264 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6267 if ((Level > 2) && diA->pDependentFiles) {
6268 lenA = multi_sz_lenA(diA->pDependentFiles);
6269 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6270 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6271 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6274 if ((Level > 2) && diA->pMonitorName) {
6275 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6276 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6277 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6280 if ((Level > 3) && diA->pDefaultDataType) {
6281 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6282 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6283 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6286 if ((Level > 3) && diA->pszzPreviousNames) {
6287 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6288 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6289 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6290 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6293 if ((Level > 5) && diA->pszMfgName) {
6294 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6295 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6296 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6299 if ((Level > 5) && diA->pszOEMUrl) {
6300 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6301 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6302 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6305 if ((Level > 5) && diA->pszHardwareID) {
6306 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6307 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6308 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6311 if ((Level > 5) && diA->pszProvider) {
6312 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6313 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6314 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6317 if (Level > 7) {
6318 FIXME("level %u is incomplete\n", Level);
6321 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6322 TRACE("got %u with %u\n", res, GetLastError());
6323 HeapFree(GetProcessHeap(), 0, nameW);
6324 HeapFree(GetProcessHeap(), 0, diW.pName);
6325 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6326 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6327 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6328 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6329 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6330 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6331 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6332 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6333 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6334 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6335 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6336 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6338 TRACE("=> %u with %u\n", res, GetLastError());
6339 return res;
6342 /******************************************************************************
6343 * ConfigurePortA (WINSPOOL.@)
6345 * See ConfigurePortW.
6348 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6350 LPWSTR nameW = NULL;
6351 LPWSTR portW = NULL;
6352 INT len;
6353 DWORD res;
6355 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6357 /* convert servername to unicode */
6358 if (pName) {
6359 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6360 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6361 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6364 /* convert portname to unicode */
6365 if (pPortName) {
6366 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6367 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6368 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6371 res = ConfigurePortW(nameW, hWnd, portW);
6372 HeapFree(GetProcessHeap(), 0, nameW);
6373 HeapFree(GetProcessHeap(), 0, portW);
6374 return res;
6377 /******************************************************************************
6378 * ConfigurePortW (WINSPOOL.@)
6380 * Display the Configuration-Dialog for a specific Port
6382 * PARAMS
6383 * pName [I] Servername or NULL (local Computer)
6384 * hWnd [I] Handle to parent Window for the Dialog-Box
6385 * pPortName [I] Name of the Port, that should be configured
6387 * RETURNS
6388 * Success: TRUE
6389 * Failure: FALSE
6392 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6395 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6397 if ((backend == NULL) && !load_backend()) return FALSE;
6399 if (!pPortName) {
6400 SetLastError(RPC_X_NULL_REF_POINTER);
6401 return FALSE;
6404 return backend->fpConfigurePort(pName, hWnd, pPortName);
6407 /******************************************************************************
6408 * ConnectToPrinterDlg (WINSPOOL.@)
6410 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6412 FIXME("%p %x\n", hWnd, Flags);
6413 return NULL;
6416 /******************************************************************************
6417 * DeletePrinterConnectionA (WINSPOOL.@)
6419 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6421 FIXME("%s\n", debugstr_a(pName));
6422 return TRUE;
6425 /******************************************************************************
6426 * DeletePrinterConnectionW (WINSPOOL.@)
6428 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6430 FIXME("%s\n", debugstr_w(pName));
6431 return TRUE;
6434 /******************************************************************************
6435 * DeletePrinterDriverExW (WINSPOOL.@)
6437 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6438 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6440 HKEY hkey_drivers;
6441 BOOL ret = FALSE;
6443 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6444 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6446 if(pName && pName[0])
6448 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6449 SetLastError(ERROR_INVALID_PARAMETER);
6450 return FALSE;
6453 if(dwDeleteFlag)
6455 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6456 SetLastError(ERROR_INVALID_PARAMETER);
6457 return FALSE;
6460 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6462 if(!hkey_drivers)
6464 ERR("Can't open drivers key\n");
6465 return FALSE;
6468 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6469 ret = TRUE;
6471 RegCloseKey(hkey_drivers);
6473 return ret;
6476 /******************************************************************************
6477 * DeletePrinterDriverExA (WINSPOOL.@)
6479 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6480 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6482 UNICODE_STRING NameW, EnvW, DriverW;
6483 BOOL ret;
6485 asciitounicode(&NameW, pName);
6486 asciitounicode(&EnvW, pEnvironment);
6487 asciitounicode(&DriverW, pDriverName);
6489 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6491 RtlFreeUnicodeString(&DriverW);
6492 RtlFreeUnicodeString(&EnvW);
6493 RtlFreeUnicodeString(&NameW);
6495 return ret;
6498 /******************************************************************************
6499 * DeletePrinterDataExW (WINSPOOL.@)
6501 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6502 LPCWSTR pValueName)
6504 FIXME("%p %s %s\n", hPrinter,
6505 debugstr_w(pKeyName), debugstr_w(pValueName));
6506 return ERROR_INVALID_PARAMETER;
6509 /******************************************************************************
6510 * DeletePrinterDataExA (WINSPOOL.@)
6512 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6513 LPCSTR pValueName)
6515 FIXME("%p %s %s\n", hPrinter,
6516 debugstr_a(pKeyName), debugstr_a(pValueName));
6517 return ERROR_INVALID_PARAMETER;
6520 /******************************************************************************
6521 * DeletePrintProcessorA (WINSPOOL.@)
6523 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6525 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6526 debugstr_a(pPrintProcessorName));
6527 return TRUE;
6530 /******************************************************************************
6531 * DeletePrintProcessorW (WINSPOOL.@)
6533 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6535 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6536 debugstr_w(pPrintProcessorName));
6537 return TRUE;
6540 /******************************************************************************
6541 * DeletePrintProvidorA (WINSPOOL.@)
6543 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6545 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6546 debugstr_a(pPrintProviderName));
6547 return TRUE;
6550 /******************************************************************************
6551 * DeletePrintProvidorW (WINSPOOL.@)
6553 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6555 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6556 debugstr_w(pPrintProviderName));
6557 return TRUE;
6560 /******************************************************************************
6561 * EnumFormsA (WINSPOOL.@)
6563 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6564 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6566 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6567 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6568 return FALSE;
6571 /******************************************************************************
6572 * EnumFormsW (WINSPOOL.@)
6574 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6575 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6577 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6578 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6579 return FALSE;
6582 /*****************************************************************************
6583 * EnumMonitorsA [WINSPOOL.@]
6585 * See EnumMonitorsW.
6588 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6589 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6591 BOOL res;
6592 LPBYTE bufferW = NULL;
6593 LPWSTR nameW = NULL;
6594 DWORD needed = 0;
6595 DWORD numentries = 0;
6596 INT len;
6598 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6599 cbBuf, pcbNeeded, pcReturned);
6601 /* convert servername to unicode */
6602 if (pName) {
6603 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6604 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6605 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6607 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6608 needed = cbBuf * sizeof(WCHAR);
6609 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6610 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6612 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6613 if (pcbNeeded) needed = *pcbNeeded;
6614 /* HeapReAlloc return NULL, when bufferW was NULL */
6615 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6616 HeapAlloc(GetProcessHeap(), 0, needed);
6618 /* Try again with the large Buffer */
6619 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6621 numentries = pcReturned ? *pcReturned : 0;
6622 needed = 0;
6624 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6625 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6627 if (res) {
6628 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6629 DWORD entrysize = 0;
6630 DWORD index;
6631 LPSTR ptr;
6632 LPMONITOR_INFO_2W mi2w;
6633 LPMONITOR_INFO_2A mi2a;
6635 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6636 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6638 /* First pass: calculate the size for all Entries */
6639 mi2w = (LPMONITOR_INFO_2W) bufferW;
6640 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6641 index = 0;
6642 while (index < numentries) {
6643 index++;
6644 needed += entrysize; /* MONITOR_INFO_?A */
6645 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6647 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6648 NULL, 0, NULL, NULL);
6649 if (Level > 1) {
6650 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6651 NULL, 0, NULL, NULL);
6652 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6653 NULL, 0, NULL, NULL);
6655 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6656 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6657 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6660 /* check for errors and quit on failure */
6661 if (cbBuf < needed) {
6662 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6663 res = FALSE;
6664 goto emA_cleanup;
6666 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6667 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6668 cbBuf -= len ; /* free Bytes in the user-Buffer */
6669 mi2w = (LPMONITOR_INFO_2W) bufferW;
6670 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6671 index = 0;
6672 /* Second Pass: Fill the User Buffer (if we have one) */
6673 while ((index < numentries) && pMonitors) {
6674 index++;
6675 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6676 mi2a->pName = ptr;
6677 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6678 ptr, cbBuf , NULL, NULL);
6679 ptr += len;
6680 cbBuf -= len;
6681 if (Level > 1) {
6682 mi2a->pEnvironment = ptr;
6683 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6684 ptr, cbBuf, NULL, NULL);
6685 ptr += len;
6686 cbBuf -= len;
6688 mi2a->pDLLName = ptr;
6689 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6690 ptr, cbBuf, NULL, NULL);
6691 ptr += len;
6692 cbBuf -= len;
6694 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6695 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6696 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6699 emA_cleanup:
6700 if (pcbNeeded) *pcbNeeded = needed;
6701 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6703 HeapFree(GetProcessHeap(), 0, nameW);
6704 HeapFree(GetProcessHeap(), 0, bufferW);
6706 TRACE("returning %d with %d (%d byte for %d entries)\n",
6707 (res), GetLastError(), needed, numentries);
6709 return (res);
6713 /*****************************************************************************
6714 * EnumMonitorsW [WINSPOOL.@]
6716 * Enumerate available Port-Monitors
6718 * PARAMS
6719 * pName [I] Servername or NULL (local Computer)
6720 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6721 * pMonitors [O] PTR to Buffer that receives the Result
6722 * cbBuf [I] Size of Buffer at pMonitors
6723 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6724 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6726 * RETURNS
6727 * Success: TRUE
6728 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6731 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6732 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6735 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6736 cbBuf, pcbNeeded, pcReturned);
6738 if ((backend == NULL) && !load_backend()) return FALSE;
6740 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6741 SetLastError(RPC_X_NULL_REF_POINTER);
6742 return FALSE;
6745 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6748 /******************************************************************************
6749 * SpoolerInit (WINSPOOL.@)
6751 * Initialize the Spooler
6753 * RETURNS
6754 * Success: TRUE
6755 * Failure: FALSE
6757 * NOTES
6758 * The function fails on windows, when the spooler service is not running
6761 BOOL WINAPI SpoolerInit(void)
6764 if ((backend == NULL) && !load_backend()) return FALSE;
6765 return TRUE;
6768 /******************************************************************************
6769 * XcvDataW (WINSPOOL.@)
6771 * Execute commands in the Printmonitor DLL
6773 * PARAMS
6774 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6775 * pszDataName [i] Name of the command to execute
6776 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6777 * cbInputData [i] Size in Bytes of Buffer at pInputData
6778 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6779 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6780 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6781 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6783 * RETURNS
6784 * Success: TRUE
6785 * Failure: FALSE
6787 * NOTES
6788 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6789 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6791 * Minimal List of commands, that a Printmonitor DLL should support:
6793 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6794 *| "AddPort" : Add a Port
6795 *| "DeletePort": Delete a Port
6797 * Many Printmonitors support additional commands. Examples for localspl.dll:
6798 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6799 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6802 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6803 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6804 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6806 opened_printer_t *printer;
6808 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6809 pInputData, cbInputData, pOutputData,
6810 cbOutputData, pcbOutputNeeded, pdwStatus);
6812 if ((backend == NULL) && !load_backend()) return FALSE;
6814 printer = get_opened_printer(hXcv);
6815 if (!printer || (!printer->backend_printer)) {
6816 SetLastError(ERROR_INVALID_HANDLE);
6817 return FALSE;
6820 if (!pcbOutputNeeded) {
6821 SetLastError(ERROR_INVALID_PARAMETER);
6822 return FALSE;
6825 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6826 SetLastError(RPC_X_NULL_REF_POINTER);
6827 return FALSE;
6830 *pcbOutputNeeded = 0;
6832 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6833 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6837 /*****************************************************************************
6838 * EnumPrinterDataA [WINSPOOL.@]
6841 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6842 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6843 DWORD cbData, LPDWORD pcbData )
6845 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6846 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6847 return ERROR_NO_MORE_ITEMS;
6850 /*****************************************************************************
6851 * EnumPrinterDataW [WINSPOOL.@]
6854 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6855 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6856 DWORD cbData, LPDWORD pcbData )
6858 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6859 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6860 return ERROR_NO_MORE_ITEMS;
6863 /*****************************************************************************
6864 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6867 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6868 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6869 LPDWORD pcbNeeded, LPDWORD pcReturned)
6871 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6872 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6873 pcbNeeded, pcReturned);
6874 return FALSE;
6877 /*****************************************************************************
6878 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6881 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6882 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6883 LPDWORD pcbNeeded, LPDWORD pcReturned)
6885 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6886 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6887 pcbNeeded, pcReturned);
6888 return FALSE;
6891 /*****************************************************************************
6892 * EnumPrintProcessorsA [WINSPOOL.@]
6894 * See EnumPrintProcessorsW.
6897 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6898 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6900 BOOL res;
6901 LPBYTE bufferW = NULL;
6902 LPWSTR nameW = NULL;
6903 LPWSTR envW = NULL;
6904 DWORD needed = 0;
6905 DWORD numentries = 0;
6906 INT len;
6908 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6909 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6911 /* convert names to unicode */
6912 if (pName) {
6913 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6914 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6915 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6917 if (pEnvironment) {
6918 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6919 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6920 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6923 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6924 needed = cbBuf * sizeof(WCHAR);
6925 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6926 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6928 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6929 if (pcbNeeded) needed = *pcbNeeded;
6930 /* HeapReAlloc return NULL, when bufferW was NULL */
6931 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6932 HeapAlloc(GetProcessHeap(), 0, needed);
6934 /* Try again with the large Buffer */
6935 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6937 numentries = pcReturned ? *pcReturned : 0;
6938 needed = 0;
6940 if (res) {
6941 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6942 DWORD index;
6943 LPSTR ptr;
6944 PPRINTPROCESSOR_INFO_1W ppiw;
6945 PPRINTPROCESSOR_INFO_1A ppia;
6947 /* First pass: calculate the size for all Entries */
6948 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6949 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6950 index = 0;
6951 while (index < numentries) {
6952 index++;
6953 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6954 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6956 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6957 NULL, 0, NULL, NULL);
6959 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6960 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6963 /* check for errors and quit on failure */
6964 if (cbBuf < needed) {
6965 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6966 res = FALSE;
6967 goto epp_cleanup;
6970 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6971 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6972 cbBuf -= len ; /* free Bytes in the user-Buffer */
6973 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6974 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6975 index = 0;
6976 /* Second Pass: Fill the User Buffer (if we have one) */
6977 while ((index < numentries) && pPPInfo) {
6978 index++;
6979 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6980 ppia->pName = ptr;
6981 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6982 ptr, cbBuf , NULL, NULL);
6983 ptr += len;
6984 cbBuf -= len;
6986 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6987 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6991 epp_cleanup:
6992 if (pcbNeeded) *pcbNeeded = needed;
6993 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6995 HeapFree(GetProcessHeap(), 0, nameW);
6996 HeapFree(GetProcessHeap(), 0, envW);
6997 HeapFree(GetProcessHeap(), 0, bufferW);
6999 TRACE("returning %d with %d (%d byte for %d entries)\n",
7000 (res), GetLastError(), needed, numentries);
7002 return (res);
7005 /*****************************************************************************
7006 * EnumPrintProcessorsW [WINSPOOL.@]
7008 * Enumerate available Print Processors
7010 * PARAMS
7011 * pName [I] Servername or NULL (local Computer)
7012 * pEnvironment [I] Printing-Environment or NULL (Default)
7013 * Level [I] Structure-Level (Only 1 is allowed)
7014 * pPPInfo [O] PTR to Buffer that receives the Result
7015 * cbBuf [I] Size of Buffer at pPPInfo
7016 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7017 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7019 * RETURNS
7020 * Success: TRUE
7021 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7024 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7025 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7028 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7029 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7031 if ((backend == NULL) && !load_backend()) return FALSE;
7033 if (!pcbNeeded || !pcReturned) {
7034 SetLastError(RPC_X_NULL_REF_POINTER);
7035 return FALSE;
7038 if (!pPPInfo && (cbBuf > 0)) {
7039 SetLastError(ERROR_INVALID_USER_BUFFER);
7040 return FALSE;
7043 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7044 cbBuf, pcbNeeded, pcReturned);
7047 /*****************************************************************************
7048 * ExtDeviceMode [WINSPOOL.@]
7051 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7052 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7053 DWORD fMode)
7055 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7056 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7057 debugstr_a(pProfile), fMode);
7058 return -1;
7061 /*****************************************************************************
7062 * FindClosePrinterChangeNotification [WINSPOOL.@]
7065 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7067 FIXME("Stub: %p\n", hChange);
7068 return TRUE;
7071 /*****************************************************************************
7072 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7075 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7076 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7078 FIXME("Stub: %p %x %x %p\n",
7079 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7080 return INVALID_HANDLE_VALUE;
7083 /*****************************************************************************
7084 * FindNextPrinterChangeNotification [WINSPOOL.@]
7087 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7088 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7090 FIXME("Stub: %p %p %p %p\n",
7091 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7092 return FALSE;
7095 /*****************************************************************************
7096 * FreePrinterNotifyInfo [WINSPOOL.@]
7099 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7101 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7102 return TRUE;
7105 /*****************************************************************************
7106 * string_to_buf
7108 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7109 * ansi depending on the unicode parameter.
7111 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7113 if(!str)
7115 *size = 0;
7116 return TRUE;
7119 if(unicode)
7121 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7122 if(*size <= cb)
7124 memcpy(ptr, str, *size);
7125 return TRUE;
7127 return FALSE;
7129 else
7131 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7132 if(*size <= cb)
7134 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7135 return TRUE;
7137 return FALSE;
7141 /*****************************************************************************
7142 * get_job_info_1
7144 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7145 LPDWORD pcbNeeded, BOOL unicode)
7147 DWORD size, left = cbBuf;
7148 BOOL space = (cbBuf > 0);
7149 LPBYTE ptr = buf;
7151 *pcbNeeded = 0;
7153 if(space)
7155 ji1->JobId = job->job_id;
7158 string_to_buf(job->document_title, ptr, left, &size, unicode);
7159 if(space && size <= left)
7161 ji1->pDocument = (LPWSTR)ptr;
7162 ptr += size;
7163 left -= size;
7165 else
7166 space = FALSE;
7167 *pcbNeeded += size;
7169 if (job->printer_name)
7171 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7172 if(space && size <= left)
7174 ji1->pPrinterName = (LPWSTR)ptr;
7175 ptr += size;
7176 left -= size;
7178 else
7179 space = FALSE;
7180 *pcbNeeded += size;
7183 return space;
7186 /*****************************************************************************
7187 * get_job_info_2
7189 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7190 LPDWORD pcbNeeded, BOOL unicode)
7192 DWORD size, left = cbBuf;
7193 DWORD shift;
7194 BOOL space = (cbBuf > 0);
7195 LPBYTE ptr = buf;
7196 LPDEVMODEA dmA;
7197 LPDEVMODEW devmode;
7199 *pcbNeeded = 0;
7201 if(space)
7203 ji2->JobId = job->job_id;
7206 string_to_buf(job->document_title, ptr, left, &size, unicode);
7207 if(space && size <= left)
7209 ji2->pDocument = (LPWSTR)ptr;
7210 ptr += size;
7211 left -= size;
7213 else
7214 space = FALSE;
7215 *pcbNeeded += size;
7217 if (job->printer_name)
7219 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7220 if(space && size <= left)
7222 ji2->pPrinterName = (LPWSTR)ptr;
7223 ptr += size;
7224 left -= size;
7226 else
7227 space = FALSE;
7228 *pcbNeeded += size;
7231 if (job->devmode)
7233 if (!unicode)
7235 dmA = DEVMODEdupWtoA(job->devmode);
7236 devmode = (LPDEVMODEW) dmA;
7237 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7239 else
7241 devmode = job->devmode;
7242 size = devmode->dmSize + devmode->dmDriverExtra;
7245 if (!devmode)
7246 FIXME("Can't convert DEVMODE W to A\n");
7247 else
7249 /* align DEVMODE to a DWORD boundary */
7250 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7251 size += shift;
7253 if (size <= left)
7255 ptr += shift;
7256 memcpy(ptr, devmode, size-shift);
7257 ji2->pDevMode = (LPDEVMODEW)ptr;
7258 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7259 ptr += size;
7260 left -= size;
7262 else
7263 space = FALSE;
7264 *pcbNeeded +=size;
7268 return space;
7271 /*****************************************************************************
7272 * get_job_info
7274 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7275 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7277 BOOL ret = FALSE;
7278 DWORD needed = 0, size;
7279 job_t *job;
7280 LPBYTE ptr = pJob;
7282 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7284 EnterCriticalSection(&printer_handles_cs);
7285 job = get_job(hPrinter, JobId);
7286 if(!job)
7287 goto end;
7289 switch(Level)
7291 case 1:
7292 size = sizeof(JOB_INFO_1W);
7293 if(cbBuf >= size)
7295 cbBuf -= size;
7296 ptr += size;
7297 memset(pJob, 0, size);
7299 else
7300 cbBuf = 0;
7301 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7302 needed += size;
7303 break;
7305 case 2:
7306 size = sizeof(JOB_INFO_2W);
7307 if(cbBuf >= size)
7309 cbBuf -= size;
7310 ptr += size;
7311 memset(pJob, 0, size);
7313 else
7314 cbBuf = 0;
7315 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7316 needed += size;
7317 break;
7319 case 3:
7320 size = sizeof(JOB_INFO_3);
7321 if(cbBuf >= size)
7323 cbBuf -= size;
7324 memset(pJob, 0, size);
7325 ret = TRUE;
7327 else
7328 cbBuf = 0;
7329 needed = size;
7330 break;
7332 default:
7333 SetLastError(ERROR_INVALID_LEVEL);
7334 goto end;
7336 if(pcbNeeded)
7337 *pcbNeeded = needed;
7338 end:
7339 LeaveCriticalSection(&printer_handles_cs);
7340 return ret;
7343 /*****************************************************************************
7344 * GetJobA [WINSPOOL.@]
7347 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7348 DWORD cbBuf, LPDWORD pcbNeeded)
7350 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7353 /*****************************************************************************
7354 * GetJobW [WINSPOOL.@]
7357 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7358 DWORD cbBuf, LPDWORD pcbNeeded)
7360 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7363 /*****************************************************************************
7364 * schedule_lpr
7366 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7368 char *unixname, *queue, *cmd;
7369 char fmt[] = "lpr -P'%s' '%s'";
7370 DWORD len;
7371 int r;
7373 if(!(unixname = wine_get_unix_file_name(filename)))
7374 return FALSE;
7376 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7377 queue = HeapAlloc(GetProcessHeap(), 0, len);
7378 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7380 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7381 sprintf(cmd, fmt, queue, unixname);
7383 TRACE("printing with: %s\n", cmd);
7384 r = system(cmd);
7386 HeapFree(GetProcessHeap(), 0, cmd);
7387 HeapFree(GetProcessHeap(), 0, queue);
7388 HeapFree(GetProcessHeap(), 0, unixname);
7389 return (r == 0);
7392 /*****************************************************************************
7393 * schedule_cups
7395 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7397 #ifdef SONAME_LIBCUPS
7398 if(pcupsPrintFile)
7400 char *unixname, *queue, *unix_doc_title;
7401 DWORD len;
7402 BOOL ret;
7404 if(!(unixname = wine_get_unix_file_name(filename)))
7405 return FALSE;
7407 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7408 queue = HeapAlloc(GetProcessHeap(), 0, len);
7409 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7411 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7412 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7413 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7415 TRACE("printing via cups\n");
7416 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7417 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7418 HeapFree(GetProcessHeap(), 0, queue);
7419 HeapFree(GetProcessHeap(), 0, unixname);
7420 return ret;
7422 else
7423 #endif
7425 return schedule_lpr(printer_name, filename);
7429 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7431 LPWSTR filename;
7433 switch(msg)
7435 case WM_INITDIALOG:
7436 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7437 return TRUE;
7439 case WM_COMMAND:
7440 if(HIWORD(wparam) == BN_CLICKED)
7442 if(LOWORD(wparam) == IDOK)
7444 HANDLE hf;
7445 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7446 LPWSTR *output;
7448 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7449 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7451 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7453 WCHAR caption[200], message[200];
7454 int mb_ret;
7456 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7457 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7458 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7459 if(mb_ret == IDCANCEL)
7461 HeapFree(GetProcessHeap(), 0, filename);
7462 return TRUE;
7465 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7466 if(hf == INVALID_HANDLE_VALUE)
7468 WCHAR caption[200], message[200];
7470 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7471 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7472 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7473 HeapFree(GetProcessHeap(), 0, filename);
7474 return TRUE;
7476 CloseHandle(hf);
7477 DeleteFileW(filename);
7478 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7479 *output = filename;
7480 EndDialog(hwnd, IDOK);
7481 return TRUE;
7483 if(LOWORD(wparam) == IDCANCEL)
7485 EndDialog(hwnd, IDCANCEL);
7486 return TRUE;
7489 return FALSE;
7491 return FALSE;
7494 /*****************************************************************************
7495 * get_filename
7497 static BOOL get_filename(LPWSTR *filename)
7499 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7500 file_dlg_proc, (LPARAM)filename) == IDOK;
7503 /*****************************************************************************
7504 * schedule_file
7506 static BOOL schedule_file(LPCWSTR filename)
7508 LPWSTR output = NULL;
7510 if(get_filename(&output))
7512 BOOL r;
7513 TRACE("copy to %s\n", debugstr_w(output));
7514 r = CopyFileW(filename, output, FALSE);
7515 HeapFree(GetProcessHeap(), 0, output);
7516 return r;
7518 return FALSE;
7521 /*****************************************************************************
7522 * schedule_pipe
7524 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7526 #ifdef HAVE_FORK
7527 char *unixname, *cmdA;
7528 DWORD len;
7529 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7530 BOOL ret = FALSE;
7531 char buf[1024];
7533 if(!(unixname = wine_get_unix_file_name(filename)))
7534 return FALSE;
7536 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7537 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7538 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7540 TRACE("printing with: %s\n", cmdA);
7542 if((file_fd = open(unixname, O_RDONLY)) == -1)
7543 goto end;
7545 if (pipe(fds))
7547 ERR("pipe() failed!\n");
7548 goto end;
7551 if (fork() == 0)
7553 close(0);
7554 dup2(fds[0], 0);
7555 close(fds[1]);
7557 /* reset signals that we previously set to SIG_IGN */
7558 signal(SIGPIPE, SIG_DFL);
7559 signal(SIGCHLD, SIG_DFL);
7561 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7562 _exit(1);
7565 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7566 write(fds[1], buf, no_read);
7568 ret = TRUE;
7570 end:
7571 if(file_fd != -1) close(file_fd);
7572 if(fds[0] != -1) close(fds[0]);
7573 if(fds[1] != -1) close(fds[1]);
7575 HeapFree(GetProcessHeap(), 0, cmdA);
7576 HeapFree(GetProcessHeap(), 0, unixname);
7577 return ret;
7578 #else
7579 return FALSE;
7580 #endif
7583 /*****************************************************************************
7584 * schedule_unixfile
7586 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7588 int in_fd, out_fd, no_read;
7589 char buf[1024];
7590 BOOL ret = FALSE;
7591 char *unixname, *outputA;
7592 DWORD len;
7594 if(!(unixname = wine_get_unix_file_name(filename)))
7595 return FALSE;
7597 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7598 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7599 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7601 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7602 in_fd = open(unixname, O_RDONLY);
7603 if(out_fd == -1 || in_fd == -1)
7604 goto end;
7606 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7607 write(out_fd, buf, no_read);
7609 ret = TRUE;
7610 end:
7611 if(in_fd != -1) close(in_fd);
7612 if(out_fd != -1) close(out_fd);
7613 HeapFree(GetProcessHeap(), 0, outputA);
7614 HeapFree(GetProcessHeap(), 0, unixname);
7615 return ret;
7618 /*****************************************************************************
7619 * ScheduleJob [WINSPOOL.@]
7622 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7624 opened_printer_t *printer;
7625 BOOL ret = FALSE;
7626 struct list *cursor, *cursor2;
7628 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7629 EnterCriticalSection(&printer_handles_cs);
7630 printer = get_opened_printer(hPrinter);
7631 if(!printer)
7632 goto end;
7634 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7636 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7637 HANDLE hf;
7639 if(job->job_id != dwJobID) continue;
7641 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7642 if(hf != INVALID_HANDLE_VALUE)
7644 PRINTER_INFO_5W *pi5 = NULL;
7645 LPWSTR portname = job->portname;
7646 DWORD needed;
7647 HKEY hkey;
7648 WCHAR output[1024];
7649 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7650 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7652 if (!portname)
7654 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7655 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7656 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7657 portname = pi5->pPortName;
7659 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7660 debugstr_w(portname));
7662 output[0] = 0;
7664 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7665 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7667 DWORD type, count = sizeof(output);
7668 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7669 RegCloseKey(hkey);
7671 if(output[0] == '|')
7673 ret = schedule_pipe(output + 1, job->filename);
7675 else if(output[0])
7677 ret = schedule_unixfile(output, job->filename);
7679 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7681 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7683 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7685 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7687 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7689 ret = schedule_file(job->filename);
7691 else
7693 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7695 HeapFree(GetProcessHeap(), 0, pi5);
7696 CloseHandle(hf);
7697 DeleteFileW(job->filename);
7699 list_remove(cursor);
7700 HeapFree(GetProcessHeap(), 0, job->document_title);
7701 HeapFree(GetProcessHeap(), 0, job->printer_name);
7702 HeapFree(GetProcessHeap(), 0, job->portname);
7703 HeapFree(GetProcessHeap(), 0, job->filename);
7704 HeapFree(GetProcessHeap(), 0, job->devmode);
7705 HeapFree(GetProcessHeap(), 0, job);
7706 break;
7708 end:
7709 LeaveCriticalSection(&printer_handles_cs);
7710 return ret;
7713 /*****************************************************************************
7714 * StartDocDlgA [WINSPOOL.@]
7716 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7718 UNICODE_STRING usBuffer;
7719 DOCINFOW docW;
7720 LPWSTR retW;
7721 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7722 LPSTR ret = NULL;
7724 docW.cbSize = sizeof(docW);
7725 if (doc->lpszDocName)
7727 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7728 if (!(docW.lpszDocName = docnameW)) return NULL;
7730 if (doc->lpszOutput)
7732 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7733 if (!(docW.lpszOutput = outputW)) return NULL;
7735 if (doc->lpszDatatype)
7737 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7738 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7740 docW.fwType = doc->fwType;
7742 retW = StartDocDlgW(hPrinter, &docW);
7744 if(retW)
7746 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7747 ret = HeapAlloc(GetProcessHeap(), 0, len);
7748 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7749 HeapFree(GetProcessHeap(), 0, retW);
7752 HeapFree(GetProcessHeap(), 0, datatypeW);
7753 HeapFree(GetProcessHeap(), 0, outputW);
7754 HeapFree(GetProcessHeap(), 0, docnameW);
7756 return ret;
7759 /*****************************************************************************
7760 * StartDocDlgW [WINSPOOL.@]
7762 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7763 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7764 * port is "FILE:". Also returns the full path if passed a relative path.
7766 * The caller should free the returned string from the process heap.
7768 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7770 LPWSTR ret = NULL;
7771 DWORD len, attr;
7773 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7775 PRINTER_INFO_5W *pi5;
7776 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7777 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7778 return NULL;
7779 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7780 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7781 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7783 HeapFree(GetProcessHeap(), 0, pi5);
7784 return NULL;
7786 HeapFree(GetProcessHeap(), 0, pi5);
7789 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7791 LPWSTR name;
7793 if (get_filename(&name))
7795 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7797 HeapFree(GetProcessHeap(), 0, name);
7798 return NULL;
7800 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7801 GetFullPathNameW(name, len, ret, NULL);
7802 HeapFree(GetProcessHeap(), 0, name);
7804 return ret;
7807 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7808 return NULL;
7810 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7811 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7813 attr = GetFileAttributesW(ret);
7814 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7816 HeapFree(GetProcessHeap(), 0, ret);
7817 ret = NULL;
7819 return ret;