ntdll: Fix race in NtRead/WriteFile.
[wine/testsucceed.git] / dlls / winspool.drv / info.c
blob885b8df0b563b5c074cbfeeab68abf875801bfb2
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-2009 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
76 /* ############################### */
78 typedef struct {
79 DWORD job_id;
80 HANDLE hf;
81 } started_doc_t;
83 typedef struct {
84 struct list jobs;
85 LONG ref;
86 } jobqueue_t;
88 typedef struct {
89 LPWSTR name;
90 LPWSTR printername;
91 HANDLE backend_printer;
92 jobqueue_t *queue;
93 started_doc_t *doc;
94 } opened_printer_t;
96 typedef struct {
97 struct list entry;
98 DWORD job_id;
99 WCHAR *filename;
100 WCHAR *document_title;
101 } job_t;
104 typedef struct {
105 LPCWSTR envname;
106 LPCWSTR subdir;
107 DWORD driverversion;
108 LPCWSTR versionregpath;
109 LPCWSTR versionsubdir;
110 } printenv_t;
112 /* ############################### */
114 static opened_printer_t **printer_handles;
115 static UINT nb_printer_handles;
116 static LONG next_job_id = 1;
118 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
119 WORD fwCapability, LPSTR lpszOutput,
120 LPDEVMODEA lpdm );
121 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
122 LPSTR lpszDevice, LPSTR lpszPort,
123 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
124 DWORD fwMode );
126 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
127 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
128 'c','o','n','t','r','o','l','\\',
129 'P','r','i','n','t','\\',
130 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
131 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
133 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
134 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
135 'C','o','n','t','r','o','l','\\',
136 'P','r','i','n','t','\\',
137 'P','r','i','n','t','e','r','s',0};
139 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
141 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
142 'M','i','c','r','o','s','o','f','t','\\',
143 'W','i','n','d','o','w','s',' ','N','T','\\',
144 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
145 'W','i','n','d','o','w','s',0};
147 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
148 'M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s',' ','N','T','\\',
150 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
151 'D','e','v','i','c','e','s',0};
153 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
154 'M','i','c','r','o','s','o','f','t','\\',
155 'W','i','n','d','o','w','s',' ','N','T','\\',
156 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
157 'P','o','r','t','s',0};
159 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
160 'M','i','c','r','o','s','o','f','t','\\',
161 'W','i','n','d','o','w','s',' ','N','T','\\',
162 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
163 'P','r','i','n','t','e','r','P','o','r','t','s',0};
165 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
166 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
167 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
168 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
169 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
170 static const WCHAR subdir_x64W[] = {'x','6','4',0};
171 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
172 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
173 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
174 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
175 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
177 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
178 static const WCHAR backslashW[] = {'\\',0};
179 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
180 'i','o','n',' ','F','i','l','e',0};
181 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
182 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
183 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
184 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
185 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
186 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
187 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
188 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
189 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
190 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
191 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
192 static const WCHAR NameW[] = {'N','a','m','e',0};
193 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
194 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
195 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
196 static const WCHAR PortW[] = {'P','o','r','t',0};
197 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
198 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
199 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
200 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
201 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
202 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
203 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
204 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
205 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
206 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
207 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
208 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
209 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
210 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
211 static const WCHAR emptyStringW[] = {0};
213 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
215 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
216 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
217 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
219 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
220 'D','o','c','u','m','e','n','t',0};
222 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
223 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
224 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
225 0, sizeof(DRIVER_INFO_8W)};
228 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
229 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
230 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
231 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
232 sizeof(PRINTER_INFO_9W)};
234 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
235 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
236 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
238 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
240 /******************************************************************
241 * validate the user-supplied printing-environment [internal]
243 * PARAMS
244 * env [I] PTR to Environment-String or NULL
246 * RETURNS
247 * Failure: NULL
248 * Success: PTR to printenv_t
250 * NOTES
251 * An empty string is handled the same way as NULL.
252 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
256 static const printenv_t * validate_envW(LPCWSTR env)
258 const printenv_t *result = NULL;
259 unsigned int i;
261 TRACE("testing %s\n", debugstr_w(env));
262 if (env && env[0])
264 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
266 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
268 result = all_printenv[i];
269 break;
273 if (result == NULL) {
274 FIXME("unsupported Environment: %s\n", debugstr_w(env));
275 SetLastError(ERROR_INVALID_ENVIRONMENT);
277 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
279 else
281 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
283 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
285 return result;
289 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
290 if passed a NULL string. This returns NULLs to the result.
292 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
294 if ( (src) )
296 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
297 return usBufferPtr->Buffer;
299 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
300 return NULL;
303 static LPWSTR strdupW(LPCWSTR p)
305 LPWSTR ret;
306 DWORD len;
308 if(!p) return NULL;
309 len = (strlenW(p) + 1) * sizeof(WCHAR);
310 ret = HeapAlloc(GetProcessHeap(), 0, len);
311 memcpy(ret, p, len);
312 return ret;
315 static LPSTR strdupWtoA( LPCWSTR str )
317 LPSTR ret;
318 INT len;
320 if (!str) return NULL;
321 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
322 ret = HeapAlloc( GetProcessHeap(), 0, len );
323 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
324 return ret;
327 /******************************************************************
328 * Return the number of bytes for an multi_sz string.
329 * The result includes all \0s
330 * (specifically the extra \0, that is needed as multi_sz terminator).
332 #if 0
333 static int multi_sz_lenW(const WCHAR *str)
335 const WCHAR *ptr = str;
336 if(!str) return 0;
339 ptr += lstrlenW(ptr) + 1;
340 } while(*ptr);
342 return (ptr - str + 1) * sizeof(WCHAR);
344 #endif
345 /* ################################ */
347 static int multi_sz_lenA(const char *str)
349 const char *ptr = str;
350 if(!str) return 0;
353 ptr += lstrlenA(ptr) + 1;
354 } while(*ptr);
356 return ptr - str + 1;
359 static void
360 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
361 char qbuf[200];
363 /* If forcing, or no profile string entry for device yet, set the entry
365 * The always change entry if not WINEPS yet is discussable.
367 if (force ||
368 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
369 !strcmp(qbuf,"*") ||
370 !strstr(qbuf,"WINEPS.DRV")
372 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
373 HKEY hkey;
375 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
376 WriteProfileStringA("windows","device",buf);
377 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
378 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
379 RegCloseKey(hkey);
381 HeapFree(GetProcessHeap(),0,buf);
385 static BOOL add_printer_driver(const char *name)
387 DRIVER_INFO_3A di3a;
389 static char driver_9x[] = "wineps16.drv",
390 driver_nt[] = "wineps.drv",
391 env_9x[] = "Windows 4.0",
392 env_nt[] = "Windows NT x86",
393 data_file[] = "generic.ppd",
394 default_data_type[] = "RAW";
396 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
397 di3a.cVersion = 3;
398 di3a.pName = (char *)name;
399 di3a.pEnvironment = env_nt;
400 di3a.pDriverPath = driver_nt;
401 di3a.pDataFile = data_file;
402 di3a.pConfigFile = driver_nt;
403 di3a.pDefaultDataType = default_data_type;
405 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
406 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
408 di3a.cVersion = 0;
409 di3a.pEnvironment = env_9x;
410 di3a.pDriverPath = driver_9x;
411 di3a.pConfigFile = driver_9x;
412 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
413 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
415 return TRUE;
418 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
419 debugstr_a(di3a.pEnvironment), GetLastError());
420 return FALSE;
423 #ifdef SONAME_LIBCUPS
424 static typeof(cupsFreeDests) *pcupsFreeDests;
425 static typeof(cupsGetDests) *pcupsGetDests;
426 static typeof(cupsGetPPD) *pcupsGetPPD;
427 static typeof(cupsPrintFile) *pcupsPrintFile;
428 static void *cupshandle;
430 static BOOL CUPS_LoadPrinters(void)
432 int i, nrofdests;
433 BOOL hadprinter = FALSE, haddefault = FALSE;
434 cups_dest_t *dests;
435 PRINTER_INFO_2A pinfo2a;
436 char *port,*devline;
437 HKEY hkeyPrinter, hkeyPrinters, hkey;
438 char loaderror[256];
440 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
441 if (!cupshandle) {
442 TRACE("%s\n", loaderror);
443 return FALSE;
445 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
447 #define DYNCUPS(x) \
448 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
449 if (!p##x) return FALSE;
451 DYNCUPS(cupsFreeDests);
452 DYNCUPS(cupsGetPPD);
453 DYNCUPS(cupsGetDests);
454 DYNCUPS(cupsPrintFile);
455 #undef DYNCUPS
457 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
458 ERROR_SUCCESS) {
459 ERR("Can't create Printers key\n");
460 return FALSE;
463 nrofdests = pcupsGetDests(&dests);
464 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
465 for (i=0;i<nrofdests;i++) {
466 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
467 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
468 sprintf(port,"LPR:%s", dests[i].name);
469 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
470 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
471 sprintf(devline, "WINEPS.DRV,%s", port);
472 WriteProfileStringA("devices", dests[i].name, devline);
473 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
474 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
475 RegCloseKey(hkey);
478 lstrcatA(devline, ",15,45");
479 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
480 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
481 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
482 RegCloseKey(hkey);
485 HeapFree(GetProcessHeap(), 0, devline);
487 TRACE("Printer %d: %s\n", i, dests[i].name);
488 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
489 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
490 and continue */
491 TRACE("Printer already exists\n");
492 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
493 RegCloseKey(hkeyPrinter);
494 } else {
495 static CHAR data_type[] = "RAW",
496 print_proc[] = "WinPrint",
497 comment[] = "WINEPS Printer using CUPS",
498 location[] = "<physical location of printer>",
499 params[] = "<parameters?>",
500 share_name[] = "<share name?>",
501 sep_file[] = "<sep file?>";
503 add_printer_driver(dests[i].name);
505 memset(&pinfo2a,0,sizeof(pinfo2a));
506 pinfo2a.pPrinterName = dests[i].name;
507 pinfo2a.pDatatype = data_type;
508 pinfo2a.pPrintProcessor = print_proc;
509 pinfo2a.pDriverName = dests[i].name;
510 pinfo2a.pComment = comment;
511 pinfo2a.pLocation = location;
512 pinfo2a.pPortName = port;
513 pinfo2a.pParameters = params;
514 pinfo2a.pShareName = share_name;
515 pinfo2a.pSepFile = sep_file;
517 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
518 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
519 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
522 HeapFree(GetProcessHeap(),0,port);
524 hadprinter = TRUE;
525 if (dests[i].is_default) {
526 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
527 haddefault = TRUE;
530 if (hadprinter & !haddefault)
531 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
532 pcupsFreeDests(nrofdests, dests);
533 RegCloseKey(hkeyPrinters);
534 return hadprinter;
536 #endif
538 static BOOL
539 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
540 PRINTER_INFO_2A pinfo2a;
541 char *e,*s,*name,*prettyname,*devname;
542 BOOL ret = FALSE, set_default = FALSE;
543 char *port = NULL, *devline,*env_default;
544 HKEY hkeyPrinter, hkeyPrinters, hkey;
546 while (isspace(*pent)) pent++;
547 s = strchr(pent,':');
548 if(s) *s='\0';
549 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
550 strcpy(name,pent);
551 if(s) {
552 *s=':';
553 pent = s;
554 } else
555 pent = "";
557 TRACE("name=%s entry=%s\n",name, pent);
559 if(ispunct(*name)) { /* a tc entry, not a real printer */
560 TRACE("skipping tc entry\n");
561 goto end;
564 if(strstr(pent,":server")) { /* server only version so skip */
565 TRACE("skipping server entry\n");
566 goto end;
569 /* Determine whether this is a postscript printer. */
571 ret = TRUE;
572 env_default = getenv("PRINTER");
573 prettyname = name;
574 /* Get longest name, usually the one at the right for later display. */
575 while((s=strchr(prettyname,'|'))) {
576 *s = '\0';
577 e = s;
578 while(isspace(*--e)) *e = '\0';
579 TRACE("\t%s\n", debugstr_a(prettyname));
580 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
581 for(prettyname = s+1; isspace(*prettyname); prettyname++)
584 e = prettyname + strlen(prettyname);
585 while(isspace(*--e)) *e = '\0';
586 TRACE("\t%s\n", debugstr_a(prettyname));
587 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
589 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
590 * if it is too long, we use it as comment below. */
591 devname = prettyname;
592 if (strlen(devname)>=CCHDEVICENAME-1)
593 devname = name;
594 if (strlen(devname)>=CCHDEVICENAME-1) {
595 ret = FALSE;
596 goto end;
599 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
600 sprintf(port,"LPR:%s",name);
602 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
603 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
604 sprintf(devline, "WINEPS.DRV,%s", port);
605 WriteProfileStringA("devices", devname, devline);
606 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
607 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
608 RegCloseKey(hkey);
611 lstrcatA(devline, ",15,45");
612 WriteProfileStringA("PrinterPorts", devname, devline);
613 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
614 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
615 RegCloseKey(hkey);
618 HeapFree(GetProcessHeap(),0,devline);
620 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
621 ERROR_SUCCESS) {
622 ERR("Can't create Printers key\n");
623 ret = FALSE;
624 goto end;
626 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
627 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
628 and continue */
629 TRACE("Printer already exists\n");
630 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
631 RegCloseKey(hkeyPrinter);
632 } else {
633 static CHAR data_type[] = "RAW",
634 print_proc[] = "WinPrint",
635 comment[] = "WINEPS Printer using LPR",
636 params[] = "<parameters?>",
637 share_name[] = "<share name?>",
638 sep_file[] = "<sep file?>";
640 add_printer_driver(devname);
642 memset(&pinfo2a,0,sizeof(pinfo2a));
643 pinfo2a.pPrinterName = devname;
644 pinfo2a.pDatatype = data_type;
645 pinfo2a.pPrintProcessor = print_proc;
646 pinfo2a.pDriverName = devname;
647 pinfo2a.pComment = comment;
648 pinfo2a.pLocation = prettyname;
649 pinfo2a.pPortName = port;
650 pinfo2a.pParameters = params;
651 pinfo2a.pShareName = share_name;
652 pinfo2a.pSepFile = sep_file;
654 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
655 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
656 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
659 RegCloseKey(hkeyPrinters);
661 if (isfirst || set_default)
662 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
664 end:
665 HeapFree(GetProcessHeap(), 0, port);
666 HeapFree(GetProcessHeap(), 0, name);
667 return ret;
670 static BOOL
671 PRINTCAP_LoadPrinters(void) {
672 BOOL hadprinter = FALSE;
673 char buf[200];
674 FILE *f;
675 char *pent = NULL;
676 BOOL had_bash = FALSE;
678 f = fopen("/etc/printcap","r");
679 if (!f)
680 return FALSE;
682 while(fgets(buf,sizeof(buf),f)) {
683 char *start, *end;
685 end=strchr(buf,'\n');
686 if (end) *end='\0';
688 start = buf;
689 while(isspace(*start)) start++;
690 if(*start == '#' || *start == '\0')
691 continue;
693 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
694 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
695 HeapFree(GetProcessHeap(),0,pent);
696 pent = NULL;
699 if (end && *--end == '\\') {
700 *end = '\0';
701 had_bash = TRUE;
702 } else
703 had_bash = FALSE;
705 if (pent) {
706 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
707 strcat(pent,start);
708 } else {
709 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
710 strcpy(pent,start);
714 if(pent) {
715 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
716 HeapFree(GetProcessHeap(),0,pent);
718 fclose(f);
719 return hadprinter;
722 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
724 if (value)
725 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
726 (lstrlenW(value) + 1) * sizeof(WCHAR));
727 else
728 return ERROR_FILE_NOT_FOUND;
731 /******************************************************************
732 * get_servername_from_name (internal)
734 * for an external server, a copy of the serverpart from the full name is returned
737 static LPWSTR get_servername_from_name(LPCWSTR name)
739 LPWSTR server;
740 LPWSTR ptr;
741 WCHAR buffer[MAX_PATH];
742 DWORD len;
744 if (name == NULL) return NULL;
745 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
747 server = strdupW(&name[2]); /* skip over both backslash */
748 if (server == NULL) return NULL;
750 /* strip '\' and the printername */
751 ptr = strchrW(server, '\\');
752 if (ptr) ptr[0] = '\0';
754 TRACE("found %s\n", debugstr_w(server));
756 len = sizeof(buffer)/sizeof(buffer[0]);
757 if (GetComputerNameW(buffer, &len)) {
758 if (lstrcmpW(buffer, server) == 0) {
759 /* The requested Servername is our computername */
760 HeapFree(GetProcessHeap(), 0, server);
761 return NULL;
764 return server;
767 /******************************************************************
768 * get_basename_from_name (internal)
770 * skip over the serverpart from the full name
773 static LPCWSTR get_basename_from_name(LPCWSTR name)
775 if (name == NULL) return NULL;
776 if ((name[0] == '\\') && (name[1] == '\\')) {
777 /* skip over the servername and search for the following '\' */
778 name = strchrW(&name[2], '\\');
779 if ((name) && (name[1])) {
780 /* found a separator ('\') followed by a name:
781 skip over the separator and return the rest */
782 name++;
784 else
786 /* no basename present (we found only a servername) */
787 return NULL;
790 return name;
793 /******************************************************************
794 * get_opened_printer_entry
795 * Get the first place empty in the opened printer table
797 * ToDo:
798 * - pDefault is ignored
800 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
802 UINT_PTR handle = nb_printer_handles, i;
803 jobqueue_t *queue = NULL;
804 opened_printer_t *printer = NULL;
805 LPWSTR servername;
806 LPCWSTR printername;
808 if ((backend == NULL) && !load_backend()) return NULL;
810 servername = get_servername_from_name(name);
811 if (servername) {
812 FIXME("server %s not supported\n", debugstr_w(servername));
813 HeapFree(GetProcessHeap(), 0, servername);
814 SetLastError(ERROR_INVALID_PRINTER_NAME);
815 return NULL;
818 printername = get_basename_from_name(name);
819 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
821 /* an empty printername is invalid */
822 if (printername && (!printername[0])) {
823 SetLastError(ERROR_INVALID_PARAMETER);
824 return NULL;
827 EnterCriticalSection(&printer_handles_cs);
829 for (i = 0; i < nb_printer_handles; i++)
831 if (!printer_handles[i])
833 if(handle == nb_printer_handles)
834 handle = i;
836 else
838 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
839 queue = printer_handles[i]->queue;
843 if (handle >= nb_printer_handles)
845 opened_printer_t **new_array;
846 if (printer_handles)
847 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
848 (nb_printer_handles + 16) * sizeof(*new_array) );
849 else
850 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
851 (nb_printer_handles + 16) * sizeof(*new_array) );
853 if (!new_array)
855 handle = 0;
856 goto end;
858 printer_handles = new_array;
859 nb_printer_handles += 16;
862 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
864 handle = 0;
865 goto end;
868 /* get a printer handle from the backend */
869 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
870 handle = 0;
871 goto end;
874 /* clone the base name. This is NULL for the printserver */
875 printer->printername = strdupW(printername);
877 /* clone the full name */
878 printer->name = strdupW(name);
879 if (name && (!printer->name)) {
880 handle = 0;
881 goto end;
884 if(queue)
885 printer->queue = queue;
886 else
888 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
889 if (!printer->queue) {
890 handle = 0;
891 goto end;
893 list_init(&printer->queue->jobs);
894 printer->queue->ref = 0;
896 InterlockedIncrement(&printer->queue->ref);
898 printer_handles[handle] = printer;
899 handle++;
900 end:
901 LeaveCriticalSection(&printer_handles_cs);
902 if (!handle && printer) {
903 /* Something failed: Free all resources */
904 HeapFree(GetProcessHeap(), 0, printer->printername);
905 HeapFree(GetProcessHeap(), 0, printer->name);
906 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
907 HeapFree(GetProcessHeap(), 0, printer);
910 return (HANDLE)handle;
913 /******************************************************************
914 * get_opened_printer
915 * Get the pointer to the opened printer referred by the handle
917 static opened_printer_t *get_opened_printer(HANDLE hprn)
919 UINT_PTR idx = (UINT_PTR)hprn;
920 opened_printer_t *ret = NULL;
922 EnterCriticalSection(&printer_handles_cs);
924 if ((idx > 0) && (idx <= nb_printer_handles)) {
925 ret = printer_handles[idx - 1];
927 LeaveCriticalSection(&printer_handles_cs);
928 return ret;
931 /******************************************************************
932 * get_opened_printer_name
933 * Get the pointer to the opened printer name referred by the handle
935 static LPCWSTR get_opened_printer_name(HANDLE hprn)
937 opened_printer_t *printer = get_opened_printer(hprn);
938 if(!printer) return NULL;
939 return printer->name;
942 /******************************************************************
943 * WINSPOOL_GetOpenedPrinterRegKey
946 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
948 LPCWSTR name = get_opened_printer_name(hPrinter);
949 DWORD ret;
950 HKEY hkeyPrinters;
952 if(!name) return ERROR_INVALID_HANDLE;
954 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
955 ERROR_SUCCESS)
956 return ret;
958 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
960 ERR("Can't find opened printer %s in registry\n",
961 debugstr_w(name));
962 RegCloseKey(hkeyPrinters);
963 return ERROR_INVALID_PRINTER_NAME; /* ? */
965 RegCloseKey(hkeyPrinters);
966 return ERROR_SUCCESS;
969 void WINSPOOL_LoadSystemPrinters(void)
971 HKEY hkey, hkeyPrinters;
972 HANDLE hprn;
973 DWORD needed, num, i;
974 WCHAR PrinterName[256];
975 BOOL done = FALSE;
977 /* This ensures that all printer entries have a valid Name value. If causes
978 problems later if they don't. If one is found to be missed we create one
979 and set it equal to the name of the key */
980 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
981 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
982 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
983 for(i = 0; i < num; i++) {
984 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
985 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
986 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
987 set_reg_szW(hkey, NameW, PrinterName);
989 RegCloseKey(hkey);
994 RegCloseKey(hkeyPrinters);
997 /* We want to avoid calling AddPrinter on printers as much as
998 possible, because on cups printers this will (eventually) lead
999 to a call to cupsGetPPD which takes forever, even with non-cups
1000 printers AddPrinter takes a while. So we'll tag all printers that
1001 were automatically added last time around, if they still exist
1002 we'll leave them be otherwise we'll delete them. */
1003 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1004 if(needed) {
1005 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1006 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1007 for(i = 0; i < num; i++) {
1008 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1009 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1010 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1011 DWORD dw = 1;
1012 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1013 RegCloseKey(hkey);
1015 ClosePrinter(hprn);
1020 HeapFree(GetProcessHeap(), 0, pi);
1024 #ifdef SONAME_LIBCUPS
1025 done = CUPS_LoadPrinters();
1026 #endif
1028 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1029 PRINTCAP_LoadPrinters();
1031 /* Now enumerate the list again and delete any printers that are still tagged */
1032 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1033 if(needed) {
1034 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1035 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1036 for(i = 0; i < num; i++) {
1037 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1038 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1039 BOOL delete_driver = FALSE;
1040 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1041 DWORD dw, type, size = sizeof(dw);
1042 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1043 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1044 DeletePrinter(hprn);
1045 delete_driver = TRUE;
1047 RegCloseKey(hkey);
1049 ClosePrinter(hprn);
1050 if(delete_driver)
1051 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1056 HeapFree(GetProcessHeap(), 0, pi);
1059 return;
1063 /******************************************************************
1064 * get_job
1066 * Get the pointer to the specified job.
1067 * Should hold the printer_handles_cs before calling.
1069 static job_t *get_job(HANDLE hprn, DWORD JobId)
1071 opened_printer_t *printer = get_opened_printer(hprn);
1072 job_t *job;
1074 if(!printer) return NULL;
1075 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1077 if(job->job_id == JobId)
1078 return job;
1080 return NULL;
1083 /***********************************************************
1084 * DEVMODEcpyAtoW
1086 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1088 BOOL Formname;
1089 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1090 DWORD size;
1092 Formname = (dmA->dmSize > off_formname);
1093 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1094 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1095 dmW->dmDeviceName, CCHDEVICENAME);
1096 if(!Formname) {
1097 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1098 dmA->dmSize - CCHDEVICENAME);
1099 } else {
1100 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1101 off_formname - CCHDEVICENAME);
1102 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1103 dmW->dmFormName, CCHFORMNAME);
1104 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1105 (off_formname + CCHFORMNAME));
1107 dmW->dmSize = size;
1108 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1109 dmA->dmDriverExtra);
1110 return dmW;
1113 /***********************************************************
1114 * DEVMODEdupWtoA
1115 * Creates an ansi copy of supplied devmode
1117 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1119 LPDEVMODEA dmA;
1120 DWORD size;
1122 if (!dmW) return NULL;
1123 size = dmW->dmSize - CCHDEVICENAME -
1124 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1126 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1127 if (!dmA) return NULL;
1129 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1130 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1132 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1133 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1134 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1136 else
1138 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1139 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1140 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1141 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1143 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1146 dmA->dmSize = size;
1147 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1148 return dmA;
1151 /******************************************************************
1152 * convert_printerinfo_W_to_A [internal]
1155 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1156 DWORD level, DWORD outlen, DWORD numentries)
1158 DWORD id = 0;
1159 LPSTR ptr;
1160 INT len;
1162 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1164 len = pi_sizeof[level] * numentries;
1165 ptr = (LPSTR) out + len;
1166 outlen -= len;
1168 /* copy the numbers of all PRINTER_INFO_* first */
1169 memcpy(out, pPrintersW, len);
1171 while (id < numentries) {
1172 switch (level) {
1173 case 1:
1175 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1176 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1178 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1179 if (piW->pDescription) {
1180 piA->pDescription = ptr;
1181 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1182 ptr, outlen, NULL, NULL);
1183 ptr += len;
1184 outlen -= len;
1186 if (piW->pName) {
1187 piA->pName = ptr;
1188 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1189 ptr, outlen, NULL, NULL);
1190 ptr += len;
1191 outlen -= len;
1193 if (piW->pComment) {
1194 piA->pComment = ptr;
1195 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1196 ptr, outlen, NULL, NULL);
1197 ptr += len;
1198 outlen -= len;
1200 break;
1203 case 2:
1205 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1206 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1207 LPDEVMODEA dmA;
1209 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1210 if (piW->pServerName) {
1211 piA->pServerName = ptr;
1212 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1213 ptr, outlen, NULL, NULL);
1214 ptr += len;
1215 outlen -= len;
1217 if (piW->pPrinterName) {
1218 piA->pPrinterName = ptr;
1219 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1220 ptr, outlen, NULL, NULL);
1221 ptr += len;
1222 outlen -= len;
1224 if (piW->pShareName) {
1225 piA->pShareName = ptr;
1226 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1227 ptr, outlen, NULL, NULL);
1228 ptr += len;
1229 outlen -= len;
1231 if (piW->pPortName) {
1232 piA->pPortName = ptr;
1233 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1234 ptr, outlen, NULL, NULL);
1235 ptr += len;
1236 outlen -= len;
1238 if (piW->pDriverName) {
1239 piA->pDriverName = ptr;
1240 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1241 ptr, outlen, NULL, NULL);
1242 ptr += len;
1243 outlen -= len;
1245 if (piW->pComment) {
1246 piA->pComment = ptr;
1247 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1248 ptr, outlen, NULL, NULL);
1249 ptr += len;
1250 outlen -= len;
1252 if (piW->pLocation) {
1253 piA->pLocation = ptr;
1254 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1255 ptr, outlen, NULL, NULL);
1256 ptr += len;
1257 outlen -= len;
1260 dmA = DEVMODEdupWtoA(piW->pDevMode);
1261 if (dmA) {
1262 /* align DEVMODEA to a DWORD boundary */
1263 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1264 ptr += len;
1265 outlen -= len;
1267 piA->pDevMode = (LPDEVMODEA) ptr;
1268 len = dmA->dmSize + dmA->dmDriverExtra;
1269 memcpy(ptr, dmA, len);
1270 HeapFree(GetProcessHeap(), 0, dmA);
1272 ptr += len;
1273 outlen -= len;
1276 if (piW->pSepFile) {
1277 piA->pSepFile = ptr;
1278 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1279 ptr, outlen, NULL, NULL);
1280 ptr += len;
1281 outlen -= len;
1283 if (piW->pPrintProcessor) {
1284 piA->pPrintProcessor = ptr;
1285 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1286 ptr, outlen, NULL, NULL);
1287 ptr += len;
1288 outlen -= len;
1290 if (piW->pDatatype) {
1291 piA->pDatatype = ptr;
1292 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1293 ptr, outlen, NULL, NULL);
1294 ptr += len;
1295 outlen -= len;
1297 if (piW->pParameters) {
1298 piA->pParameters = ptr;
1299 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1300 ptr, outlen, NULL, NULL);
1301 ptr += len;
1302 outlen -= len;
1304 if (piW->pSecurityDescriptor) {
1305 piA->pSecurityDescriptor = NULL;
1306 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1308 break;
1311 case 4:
1313 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1314 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1316 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1318 if (piW->pPrinterName) {
1319 piA->pPrinterName = ptr;
1320 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1321 ptr, outlen, NULL, NULL);
1322 ptr += len;
1323 outlen -= len;
1325 if (piW->pServerName) {
1326 piA->pServerName = ptr;
1327 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1328 ptr, outlen, NULL, NULL);
1329 ptr += len;
1330 outlen -= len;
1332 break;
1335 case 5:
1337 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1338 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1340 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1342 if (piW->pPrinterName) {
1343 piA->pPrinterName = ptr;
1344 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1345 ptr, outlen, NULL, NULL);
1346 ptr += len;
1347 outlen -= len;
1349 if (piW->pPortName) {
1350 piA->pPortName = ptr;
1351 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1352 ptr, outlen, NULL, NULL);
1353 ptr += len;
1354 outlen -= len;
1356 break;
1359 case 6: /* 6A and 6W are the same structure */
1360 break;
1362 case 7:
1364 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1365 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1367 TRACE("(%u) #%u\n", level, id);
1368 if (piW->pszObjectGUID) {
1369 piA->pszObjectGUID = ptr;
1370 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1371 ptr, outlen, NULL, NULL);
1372 ptr += len;
1373 outlen -= len;
1375 break;
1378 case 9:
1380 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1381 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1382 LPDEVMODEA dmA;
1384 TRACE("(%u) #%u\n", level, id);
1385 dmA = DEVMODEdupWtoA(piW->pDevMode);
1386 if (dmA) {
1387 /* align DEVMODEA to a DWORD boundary */
1388 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1389 ptr += len;
1390 outlen -= len;
1392 piA->pDevMode = (LPDEVMODEA) ptr;
1393 len = dmA->dmSize + dmA->dmDriverExtra;
1394 memcpy(ptr, dmA, len);
1395 HeapFree(GetProcessHeap(), 0, dmA);
1397 ptr += len;
1398 outlen -= len;
1401 break;
1404 default:
1405 FIXME("for level %u\n", level);
1407 pPrintersW += pi_sizeof[level];
1408 out += pi_sizeof[level];
1409 id++;
1413 /******************************************************************
1414 * convert_driverinfo_W_to_A [internal]
1417 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1418 DWORD level, DWORD outlen, DWORD numentries)
1420 DWORD id = 0;
1421 LPSTR ptr;
1422 INT len;
1424 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1426 len = di_sizeof[level] * numentries;
1427 ptr = (LPSTR) out + len;
1428 outlen -= len;
1430 /* copy the numbers of all PRINTER_INFO_* first */
1431 memcpy(out, pDriversW, len);
1433 #define COPY_STRING(fld) \
1434 { if (diW->fld){ \
1435 diA->fld = ptr; \
1436 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1437 ptr += len; outlen -= len;\
1439 #define COPY_MULTIZ_STRING(fld) \
1440 { LPWSTR p = diW->fld; if (p){ \
1441 diA->fld = ptr; \
1442 do {\
1443 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1444 ptr += len; outlen -= len; p += len;\
1446 while(len > 1 && outlen > 0); \
1449 while (id < numentries)
1451 switch (level)
1453 case 1:
1455 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1456 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1458 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1460 COPY_STRING(pName);
1461 break;
1463 case 2:
1465 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1466 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1468 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1470 COPY_STRING(pName);
1471 COPY_STRING(pEnvironment);
1472 COPY_STRING(pDriverPath);
1473 COPY_STRING(pDataFile);
1474 COPY_STRING(pConfigFile);
1475 break;
1477 case 3:
1479 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1480 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1482 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1484 COPY_STRING(pName);
1485 COPY_STRING(pEnvironment);
1486 COPY_STRING(pDriverPath);
1487 COPY_STRING(pDataFile);
1488 COPY_STRING(pConfigFile);
1489 COPY_STRING(pHelpFile);
1490 COPY_MULTIZ_STRING(pDependentFiles);
1491 COPY_STRING(pMonitorName);
1492 COPY_STRING(pDefaultDataType);
1493 break;
1495 case 4:
1497 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1498 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1500 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1502 COPY_STRING(pName);
1503 COPY_STRING(pEnvironment);
1504 COPY_STRING(pDriverPath);
1505 COPY_STRING(pDataFile);
1506 COPY_STRING(pConfigFile);
1507 COPY_STRING(pHelpFile);
1508 COPY_MULTIZ_STRING(pDependentFiles);
1509 COPY_STRING(pMonitorName);
1510 COPY_STRING(pDefaultDataType);
1511 COPY_MULTIZ_STRING(pszzPreviousNames);
1512 break;
1514 case 5:
1516 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1517 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) 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 break;
1528 case 6:
1530 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1531 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1533 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1535 COPY_STRING(pName);
1536 COPY_STRING(pEnvironment);
1537 COPY_STRING(pDriverPath);
1538 COPY_STRING(pDataFile);
1539 COPY_STRING(pConfigFile);
1540 COPY_STRING(pHelpFile);
1541 COPY_MULTIZ_STRING(pDependentFiles);
1542 COPY_STRING(pMonitorName);
1543 COPY_STRING(pDefaultDataType);
1544 COPY_MULTIZ_STRING(pszzPreviousNames);
1545 COPY_STRING(pszMfgName);
1546 COPY_STRING(pszOEMUrl);
1547 COPY_STRING(pszHardwareID);
1548 COPY_STRING(pszProvider);
1549 break;
1551 case 8:
1553 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1554 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1556 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1558 COPY_STRING(pName);
1559 COPY_STRING(pEnvironment);
1560 COPY_STRING(pDriverPath);
1561 COPY_STRING(pDataFile);
1562 COPY_STRING(pConfigFile);
1563 COPY_STRING(pHelpFile);
1564 COPY_MULTIZ_STRING(pDependentFiles);
1565 COPY_STRING(pMonitorName);
1566 COPY_STRING(pDefaultDataType);
1567 COPY_MULTIZ_STRING(pszzPreviousNames);
1568 COPY_STRING(pszMfgName);
1569 COPY_STRING(pszOEMUrl);
1570 COPY_STRING(pszHardwareID);
1571 COPY_STRING(pszProvider);
1572 COPY_STRING(pszPrintProcessor);
1573 COPY_STRING(pszVendorSetup);
1574 COPY_MULTIZ_STRING(pszzColorProfiles);
1575 COPY_STRING(pszInfPath);
1576 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1577 break;
1581 default:
1582 FIXME("for level %u\n", level);
1585 pDriversW += di_sizeof[level];
1586 out += di_sizeof[level];
1587 id++;
1590 #undef COPY_STRING
1591 #undef COPY_MULTIZ_STRING
1595 /***********************************************************
1596 * PRINTER_INFO_2AtoW
1597 * Creates a unicode copy of PRINTER_INFO_2A on heap
1599 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1601 LPPRINTER_INFO_2W piW;
1602 UNICODE_STRING usBuffer;
1604 if(!piA) return NULL;
1605 piW = HeapAlloc(heap, 0, sizeof(*piW));
1606 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1608 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1609 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1610 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1611 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1612 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1613 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1614 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1615 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1616 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1617 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1618 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1619 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1620 return piW;
1623 /***********************************************************
1624 * FREE_PRINTER_INFO_2W
1625 * Free PRINTER_INFO_2W and all strings
1627 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1629 if(!piW) return;
1631 HeapFree(heap,0,piW->pServerName);
1632 HeapFree(heap,0,piW->pPrinterName);
1633 HeapFree(heap,0,piW->pShareName);
1634 HeapFree(heap,0,piW->pPortName);
1635 HeapFree(heap,0,piW->pDriverName);
1636 HeapFree(heap,0,piW->pComment);
1637 HeapFree(heap,0,piW->pLocation);
1638 HeapFree(heap,0,piW->pDevMode);
1639 HeapFree(heap,0,piW->pSepFile);
1640 HeapFree(heap,0,piW->pPrintProcessor);
1641 HeapFree(heap,0,piW->pDatatype);
1642 HeapFree(heap,0,piW->pParameters);
1643 HeapFree(heap,0,piW);
1644 return;
1647 /******************************************************************
1648 * DeviceCapabilities [WINSPOOL.@]
1649 * DeviceCapabilitiesA [WINSPOOL.@]
1652 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1653 LPSTR pOutput, LPDEVMODEA lpdm)
1655 INT ret;
1657 if (!GDI_CallDeviceCapabilities16)
1659 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1660 (LPCSTR)104 );
1661 if (!GDI_CallDeviceCapabilities16) return -1;
1663 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1665 /* If DC_PAPERSIZE map POINT16s to POINTs */
1666 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1667 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1668 POINT *pt = (POINT *)pOutput;
1669 INT i;
1670 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1671 for(i = 0; i < ret; i++, pt++)
1673 pt->x = tmp[i].x;
1674 pt->y = tmp[i].y;
1676 HeapFree( GetProcessHeap(), 0, tmp );
1678 return ret;
1682 /*****************************************************************************
1683 * DeviceCapabilitiesW [WINSPOOL.@]
1685 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1688 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1689 WORD fwCapability, LPWSTR pOutput,
1690 const DEVMODEW *pDevMode)
1692 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1693 LPSTR pDeviceA = strdupWtoA(pDevice);
1694 LPSTR pPortA = strdupWtoA(pPort);
1695 INT ret;
1697 if(pOutput && (fwCapability == DC_BINNAMES ||
1698 fwCapability == DC_FILEDEPENDENCIES ||
1699 fwCapability == DC_PAPERNAMES)) {
1700 /* These need A -> W translation */
1701 INT size = 0, i;
1702 LPSTR pOutputA;
1703 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1704 dmA);
1705 if(ret == -1)
1706 return ret;
1707 switch(fwCapability) {
1708 case DC_BINNAMES:
1709 size = 24;
1710 break;
1711 case DC_PAPERNAMES:
1712 case DC_FILEDEPENDENCIES:
1713 size = 64;
1714 break;
1716 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1717 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1718 dmA);
1719 for(i = 0; i < ret; i++)
1720 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1721 pOutput + (i * size), size);
1722 HeapFree(GetProcessHeap(), 0, pOutputA);
1723 } else {
1724 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1725 (LPSTR)pOutput, dmA);
1727 HeapFree(GetProcessHeap(),0,pPortA);
1728 HeapFree(GetProcessHeap(),0,pDeviceA);
1729 HeapFree(GetProcessHeap(),0,dmA);
1730 return ret;
1733 /******************************************************************
1734 * DocumentPropertiesA [WINSPOOL.@]
1736 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1738 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1739 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1740 LPDEVMODEA pDevModeInput,DWORD fMode )
1742 LPSTR lpName = pDeviceName;
1743 static CHAR port[] = "LPT1:";
1744 LONG ret;
1746 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1747 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1750 if(!pDeviceName) {
1751 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1752 if(!lpNameW) {
1753 ERR("no name from hPrinter?\n");
1754 SetLastError(ERROR_INVALID_HANDLE);
1755 return -1;
1757 lpName = strdupWtoA(lpNameW);
1760 if (!GDI_CallExtDeviceMode16)
1762 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1763 (LPCSTR)102 );
1764 if (!GDI_CallExtDeviceMode16) {
1765 ERR("No CallExtDeviceMode16?\n");
1766 return -1;
1769 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1770 pDevModeInput, NULL, fMode);
1772 if(!pDeviceName)
1773 HeapFree(GetProcessHeap(),0,lpName);
1774 return ret;
1778 /*****************************************************************************
1779 * DocumentPropertiesW (WINSPOOL.@)
1781 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1783 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1784 LPWSTR pDeviceName,
1785 LPDEVMODEW pDevModeOutput,
1786 LPDEVMODEW pDevModeInput, DWORD fMode)
1789 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1790 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1791 LPDEVMODEA pDevModeOutputA = NULL;
1792 LONG ret;
1794 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1795 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1796 fMode);
1797 if(pDevModeOutput) {
1798 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1799 if(ret < 0) return ret;
1800 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1802 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1803 pDevModeInputA, fMode);
1804 if(pDevModeOutput) {
1805 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1806 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1808 if(fMode == 0 && ret > 0)
1809 ret += (CCHDEVICENAME + CCHFORMNAME);
1810 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1811 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1812 return ret;
1815 /******************************************************************
1816 * OpenPrinterA [WINSPOOL.@]
1818 * See OpenPrinterW.
1821 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1822 LPPRINTER_DEFAULTSA pDefault)
1824 UNICODE_STRING lpPrinterNameW;
1825 UNICODE_STRING usBuffer;
1826 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1827 PWSTR pwstrPrinterNameW;
1828 BOOL ret;
1830 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1832 if(pDefault) {
1833 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1834 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1835 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1836 pDefaultW = &DefaultW;
1838 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1839 if(pDefault) {
1840 RtlFreeUnicodeString(&usBuffer);
1841 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1843 RtlFreeUnicodeString(&lpPrinterNameW);
1844 return ret;
1847 /******************************************************************
1848 * OpenPrinterW [WINSPOOL.@]
1850 * Open a Printer / Printserver or a Printer-Object
1852 * PARAMS
1853 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1854 * phPrinter [O] The resulting Handle is stored here
1855 * pDefault [I] PTR to Default Printer Settings or NULL
1857 * RETURNS
1858 * Success: TRUE
1859 * Failure: FALSE
1861 * NOTES
1862 * lpPrinterName is one of:
1863 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1864 *| Printer: "PrinterName"
1865 *| Printer-Object: "PrinterName,Job xxx"
1866 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1867 *| XcvPort: "Servername,XcvPort PortName"
1869 * BUGS
1870 *| Printer-Object not supported
1871 *| pDefaults is ignored
1874 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1877 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1878 if (pDefault) {
1879 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1880 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1883 if(!phPrinter) {
1884 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1885 SetLastError(ERROR_INVALID_PARAMETER);
1886 return FALSE;
1889 /* Get the unique handle of the printer or Printserver */
1890 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1891 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1892 return (*phPrinter != 0);
1895 /******************************************************************
1896 * AddMonitorA [WINSPOOL.@]
1898 * See AddMonitorW.
1901 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1903 LPWSTR nameW = NULL;
1904 INT len;
1905 BOOL res;
1906 LPMONITOR_INFO_2A mi2a;
1907 MONITOR_INFO_2W mi2w;
1909 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1910 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1911 debugstr_a(mi2a ? mi2a->pName : NULL),
1912 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1913 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1915 if (Level != 2) {
1916 SetLastError(ERROR_INVALID_LEVEL);
1917 return FALSE;
1920 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1921 if (mi2a == NULL) {
1922 return FALSE;
1925 if (pName) {
1926 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1927 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1928 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1931 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1932 if (mi2a->pName) {
1933 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1934 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1935 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1937 if (mi2a->pEnvironment) {
1938 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1939 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1940 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1942 if (mi2a->pDLLName) {
1943 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1944 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1945 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1948 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1950 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1951 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1952 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1954 HeapFree(GetProcessHeap(), 0, nameW);
1955 return (res);
1958 /******************************************************************************
1959 * AddMonitorW [WINSPOOL.@]
1961 * Install a Printmonitor
1963 * PARAMS
1964 * pName [I] Servername or NULL (local Computer)
1965 * Level [I] Structure-Level (Must be 2)
1966 * pMonitors [I] PTR to MONITOR_INFO_2
1968 * RETURNS
1969 * Success: TRUE
1970 * Failure: FALSE
1972 * NOTES
1973 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1976 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1978 LPMONITOR_INFO_2W mi2w;
1980 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1981 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1982 debugstr_w(mi2w ? mi2w->pName : NULL),
1983 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1984 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1986 if ((backend == NULL) && !load_backend()) return FALSE;
1988 if (Level != 2) {
1989 SetLastError(ERROR_INVALID_LEVEL);
1990 return FALSE;
1993 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1994 if (mi2w == NULL) {
1995 return FALSE;
1998 return backend->fpAddMonitor(pName, Level, pMonitors);
2001 /******************************************************************
2002 * DeletePrinterDriverA [WINSPOOL.@]
2005 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2007 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2010 /******************************************************************
2011 * DeletePrinterDriverW [WINSPOOL.@]
2014 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2016 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2019 /******************************************************************
2020 * DeleteMonitorA [WINSPOOL.@]
2022 * See DeleteMonitorW.
2025 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2027 LPWSTR nameW = NULL;
2028 LPWSTR EnvironmentW = NULL;
2029 LPWSTR MonitorNameW = NULL;
2030 BOOL res;
2031 INT len;
2033 if (pName) {
2034 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2035 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2036 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2039 if (pEnvironment) {
2040 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2041 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2044 if (pMonitorName) {
2045 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2046 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2047 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2050 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2052 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2053 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2054 HeapFree(GetProcessHeap(), 0, nameW);
2055 return (res);
2058 /******************************************************************
2059 * DeleteMonitorW [WINSPOOL.@]
2061 * Delete a specific Printmonitor from a Printing-Environment
2063 * PARAMS
2064 * pName [I] Servername or NULL (local Computer)
2065 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2066 * pMonitorName [I] Name of the Monitor, that should be deleted
2068 * RETURNS
2069 * Success: TRUE
2070 * Failure: FALSE
2072 * NOTES
2073 * pEnvironment is ignored in Windows for the local Computer.
2076 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2079 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2080 debugstr_w(pMonitorName));
2082 if ((backend == NULL) && !load_backend()) return FALSE;
2084 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2088 /******************************************************************
2089 * DeletePortA [WINSPOOL.@]
2091 * See DeletePortW.
2094 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2096 LPWSTR nameW = NULL;
2097 LPWSTR portW = NULL;
2098 INT len;
2099 DWORD res;
2101 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2103 /* convert servername to unicode */
2104 if (pName) {
2105 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2106 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2107 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2110 /* convert portname to unicode */
2111 if (pPortName) {
2112 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2113 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2114 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2117 res = DeletePortW(nameW, hWnd, portW);
2118 HeapFree(GetProcessHeap(), 0, nameW);
2119 HeapFree(GetProcessHeap(), 0, portW);
2120 return res;
2123 /******************************************************************
2124 * DeletePortW [WINSPOOL.@]
2126 * Delete a specific Port
2128 * PARAMS
2129 * pName [I] Servername or NULL (local Computer)
2130 * hWnd [I] Handle to parent Window for the Dialog-Box
2131 * pPortName [I] Name of the Port, that should be deleted
2133 * RETURNS
2134 * Success: TRUE
2135 * Failure: FALSE
2138 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2140 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2142 if ((backend == NULL) && !load_backend()) return FALSE;
2144 if (!pPortName) {
2145 SetLastError(RPC_X_NULL_REF_POINTER);
2146 return FALSE;
2149 return backend->fpDeletePort(pName, hWnd, pPortName);
2152 /******************************************************************************
2153 * SetPrinterW [WINSPOOL.@]
2155 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2157 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2158 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2159 return FALSE;
2162 /******************************************************************************
2163 * WritePrinter [WINSPOOL.@]
2165 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2167 opened_printer_t *printer;
2168 BOOL ret = FALSE;
2170 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2172 EnterCriticalSection(&printer_handles_cs);
2173 printer = get_opened_printer(hPrinter);
2174 if(!printer)
2176 SetLastError(ERROR_INVALID_HANDLE);
2177 goto end;
2180 if(!printer->doc)
2182 SetLastError(ERROR_SPL_NO_STARTDOC);
2183 goto end;
2186 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2187 end:
2188 LeaveCriticalSection(&printer_handles_cs);
2189 return ret;
2192 /*****************************************************************************
2193 * AddFormA [WINSPOOL.@]
2195 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2197 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2198 return 1;
2201 /*****************************************************************************
2202 * AddFormW [WINSPOOL.@]
2204 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2206 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2207 return 1;
2210 /*****************************************************************************
2211 * AddJobA [WINSPOOL.@]
2213 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2215 BOOL ret;
2216 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2217 DWORD needed;
2219 if(Level != 1) {
2220 SetLastError(ERROR_INVALID_LEVEL);
2221 return FALSE;
2224 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2226 if(ret) {
2227 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2228 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2229 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2230 if(*pcbNeeded > cbBuf) {
2231 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2232 ret = FALSE;
2233 } else {
2234 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2235 addjobA->JobId = addjobW->JobId;
2236 addjobA->Path = (char *)(addjobA + 1);
2237 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2240 return ret;
2243 /*****************************************************************************
2244 * AddJobW [WINSPOOL.@]
2246 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2248 opened_printer_t *printer;
2249 job_t *job;
2250 BOOL ret = FALSE;
2251 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2252 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2253 WCHAR path[MAX_PATH], filename[MAX_PATH];
2254 DWORD len;
2255 ADDJOB_INFO_1W *addjob;
2257 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2259 EnterCriticalSection(&printer_handles_cs);
2261 printer = get_opened_printer(hPrinter);
2263 if(!printer) {
2264 SetLastError(ERROR_INVALID_HANDLE);
2265 goto end;
2268 if(Level != 1) {
2269 SetLastError(ERROR_INVALID_LEVEL);
2270 goto end;
2273 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2274 if(!job)
2275 goto end;
2277 job->job_id = InterlockedIncrement(&next_job_id);
2279 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2280 if(path[len - 1] != '\\')
2281 path[len++] = '\\';
2282 memcpy(path + len, spool_path, sizeof(spool_path));
2283 sprintfW(filename, fmtW, path, job->job_id);
2285 len = strlenW(filename);
2286 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2287 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2288 job->document_title = strdupW(default_doc_title);
2289 list_add_tail(&printer->queue->jobs, &job->entry);
2291 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2292 if(*pcbNeeded <= cbBuf) {
2293 addjob = (ADDJOB_INFO_1W*)pData;
2294 addjob->JobId = job->job_id;
2295 addjob->Path = (WCHAR *)(addjob + 1);
2296 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2297 ret = TRUE;
2298 } else
2299 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2301 end:
2302 LeaveCriticalSection(&printer_handles_cs);
2303 return ret;
2306 /*****************************************************************************
2307 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2309 * Return the PATH for the Print-Processors
2311 * See GetPrintProcessorDirectoryW.
2315 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2316 DWORD level, LPBYTE Info,
2317 DWORD cbBuf, LPDWORD pcbNeeded)
2319 LPWSTR serverW = NULL;
2320 LPWSTR envW = NULL;
2321 BOOL ret;
2322 INT len;
2324 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2325 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2328 if (server) {
2329 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2330 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2331 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2334 if (env) {
2335 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2336 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2337 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2340 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2341 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2343 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2344 cbBuf, pcbNeeded);
2346 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2347 cbBuf, NULL, NULL) > 0;
2350 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2351 HeapFree(GetProcessHeap(), 0, envW);
2352 HeapFree(GetProcessHeap(), 0, serverW);
2353 return ret;
2356 /*****************************************************************************
2357 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2359 * Return the PATH for the Print-Processors
2361 * PARAMS
2362 * server [I] Servername (NT only) or NULL (local Computer)
2363 * env [I] Printing-Environment (see below) or NULL (Default)
2364 * level [I] Structure-Level (must be 1)
2365 * Info [O] PTR to Buffer that receives the Result
2366 * cbBuf [I] Size of Buffer at "Info"
2367 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2368 * required for the Buffer at "Info"
2370 * RETURNS
2371 * Success: TRUE and in pcbNeeded the Bytes used in Info
2372 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2373 * if cbBuf is too small
2375 * Native Values returned in Info on Success:
2376 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2377 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2378 *| win9x(Windows 4.0): "%winsysdir%"
2380 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2382 * BUGS
2383 * Only NULL or "" is supported for server
2386 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2387 DWORD level, LPBYTE Info,
2388 DWORD cbBuf, LPDWORD pcbNeeded)
2391 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2392 Info, cbBuf, pcbNeeded);
2394 if ((backend == NULL) && !load_backend()) return FALSE;
2396 if (level != 1) {
2397 /* (Level != 1) is ignored in win9x */
2398 SetLastError(ERROR_INVALID_LEVEL);
2399 return FALSE;
2402 if (pcbNeeded == NULL) {
2403 /* (pcbNeeded == NULL) is ignored in win9x */
2404 SetLastError(RPC_X_NULL_REF_POINTER);
2405 return FALSE;
2408 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2411 /*****************************************************************************
2412 * WINSPOOL_OpenDriverReg [internal]
2414 * opens the registry for the printer drivers depending on the given input
2415 * variable pEnvironment
2417 * RETURNS:
2418 * the opened hkey on success
2419 * NULL on error
2421 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2423 HKEY retval = NULL;
2424 LPWSTR buffer;
2425 const printenv_t * env;
2427 TRACE("(%s)\n", debugstr_w(pEnvironment));
2429 env = validate_envW(pEnvironment);
2430 if (!env) return NULL;
2432 buffer = HeapAlloc( GetProcessHeap(), 0,
2433 (strlenW(DriversW) + strlenW(env->envname) +
2434 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2435 if(buffer) {
2436 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2437 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2438 HeapFree(GetProcessHeap(), 0, buffer);
2440 return retval;
2443 /*****************************************************************************
2444 * AddPrinterW [WINSPOOL.@]
2446 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2448 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2449 LPDEVMODEA dmA;
2450 LPDEVMODEW dmW;
2451 HANDLE retval;
2452 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2453 LONG size;
2454 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2455 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2456 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2457 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2458 statusW[] = {'S','t','a','t','u','s',0},
2459 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2461 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2463 if(pName != NULL) {
2464 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2465 SetLastError(ERROR_INVALID_PARAMETER);
2466 return 0;
2468 if(Level != 2) {
2469 ERR("Level = %d, unsupported!\n", Level);
2470 SetLastError(ERROR_INVALID_LEVEL);
2471 return 0;
2473 if(!pPrinter) {
2474 SetLastError(ERROR_INVALID_PARAMETER);
2475 return 0;
2477 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2478 ERROR_SUCCESS) {
2479 ERR("Can't create Printers key\n");
2480 return 0;
2482 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2483 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2484 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2485 RegCloseKey(hkeyPrinter);
2486 RegCloseKey(hkeyPrinters);
2487 return 0;
2489 RegCloseKey(hkeyPrinter);
2491 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2492 if(!hkeyDrivers) {
2493 ERR("Can't create Drivers key\n");
2494 RegCloseKey(hkeyPrinters);
2495 return 0;
2497 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2498 ERROR_SUCCESS) {
2499 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2500 RegCloseKey(hkeyPrinters);
2501 RegCloseKey(hkeyDrivers);
2502 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2503 return 0;
2505 RegCloseKey(hkeyDriver);
2506 RegCloseKey(hkeyDrivers);
2508 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2509 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2510 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2511 RegCloseKey(hkeyPrinters);
2512 return 0;
2515 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2516 ERROR_SUCCESS) {
2517 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2518 SetLastError(ERROR_INVALID_PRINTER_NAME);
2519 RegCloseKey(hkeyPrinters);
2520 return 0;
2522 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2523 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2524 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2526 /* See if we can load the driver. We may need the devmode structure anyway
2528 * FIXME:
2529 * Note that DocumentPropertiesW will briefly try to open the printer we
2530 * just create to find a DEVMODEA struct (it will use the WINEPS default
2531 * one in case it is not there, so we are ok).
2533 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2535 if(size < 0) {
2536 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2537 size = sizeof(DEVMODEW);
2539 if(pi->pDevMode)
2540 dmW = pi->pDevMode;
2541 else
2543 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2544 dmW->dmSize = size;
2545 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2547 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2548 HeapFree(GetProcessHeap(),0,dmW);
2549 dmW=NULL;
2551 else
2553 /* set devmode to printer name */
2554 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2558 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2559 and we support these drivers. NT writes DEVMODEW so somehow
2560 we'll need to distinguish between these when we support NT
2561 drivers */
2562 if (dmW)
2564 dmA = DEVMODEdupWtoA(dmW);
2565 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2566 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2567 HeapFree(GetProcessHeap(), 0, dmA);
2568 if(!pi->pDevMode)
2569 HeapFree(GetProcessHeap(), 0, dmW);
2571 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2572 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2573 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2574 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2576 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2577 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2578 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2579 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2580 (LPBYTE)&pi->Priority, sizeof(DWORD));
2581 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2582 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2583 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2584 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2585 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2586 (LPBYTE)&pi->Status, sizeof(DWORD));
2587 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2588 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2590 RegCloseKey(hkeyPrinter);
2591 RegCloseKey(hkeyPrinters);
2592 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2593 ERR("OpenPrinter failing\n");
2594 return 0;
2596 return retval;
2599 /*****************************************************************************
2600 * AddPrinterA [WINSPOOL.@]
2602 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2604 UNICODE_STRING pNameW;
2605 PWSTR pwstrNameW;
2606 PRINTER_INFO_2W *piW;
2607 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2608 HANDLE ret;
2610 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2611 if(Level != 2) {
2612 ERR("Level = %d, unsupported!\n", Level);
2613 SetLastError(ERROR_INVALID_LEVEL);
2614 return 0;
2616 pwstrNameW = asciitounicode(&pNameW,pName);
2617 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2619 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2621 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2622 RtlFreeUnicodeString(&pNameW);
2623 return ret;
2627 /*****************************************************************************
2628 * ClosePrinter [WINSPOOL.@]
2630 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2632 UINT_PTR i = (UINT_PTR)hPrinter;
2633 opened_printer_t *printer = NULL;
2634 BOOL ret = FALSE;
2636 TRACE("(%p)\n", hPrinter);
2638 EnterCriticalSection(&printer_handles_cs);
2640 if ((i > 0) && (i <= nb_printer_handles))
2641 printer = printer_handles[i - 1];
2644 if(printer)
2646 struct list *cursor, *cursor2;
2648 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2650 if (printer->backend_printer) {
2651 backend->fpClosePrinter(printer->backend_printer);
2654 if(printer->doc)
2655 EndDocPrinter(hPrinter);
2657 if(InterlockedDecrement(&printer->queue->ref) == 0)
2659 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2661 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2662 ScheduleJob(hPrinter, job->job_id);
2664 HeapFree(GetProcessHeap(), 0, printer->queue);
2667 HeapFree(GetProcessHeap(), 0, printer->printername);
2668 HeapFree(GetProcessHeap(), 0, printer->name);
2669 HeapFree(GetProcessHeap(), 0, printer);
2670 printer_handles[i - 1] = NULL;
2671 ret = TRUE;
2673 LeaveCriticalSection(&printer_handles_cs);
2674 return ret;
2677 /*****************************************************************************
2678 * DeleteFormA [WINSPOOL.@]
2680 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2682 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2683 return 1;
2686 /*****************************************************************************
2687 * DeleteFormW [WINSPOOL.@]
2689 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2691 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2692 return 1;
2695 /*****************************************************************************
2696 * DeletePrinter [WINSPOOL.@]
2698 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2700 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2701 HKEY hkeyPrinters, hkey;
2703 if(!lpNameW) {
2704 SetLastError(ERROR_INVALID_HANDLE);
2705 return FALSE;
2707 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2708 RegDeleteTreeW(hkeyPrinters, lpNameW);
2709 RegCloseKey(hkeyPrinters);
2711 WriteProfileStringW(devicesW, lpNameW, NULL);
2712 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2714 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2715 RegDeleteValueW(hkey, lpNameW);
2716 RegCloseKey(hkey);
2719 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2720 RegDeleteValueW(hkey, lpNameW);
2721 RegCloseKey(hkey);
2723 return TRUE;
2726 /*****************************************************************************
2727 * SetPrinterA [WINSPOOL.@]
2729 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2730 DWORD Command)
2732 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2733 return FALSE;
2736 /*****************************************************************************
2737 * SetJobA [WINSPOOL.@]
2739 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2740 LPBYTE pJob, DWORD Command)
2742 BOOL ret;
2743 LPBYTE JobW;
2744 UNICODE_STRING usBuffer;
2746 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2748 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2749 are all ignored by SetJob, so we don't bother copying them */
2750 switch(Level)
2752 case 0:
2753 JobW = NULL;
2754 break;
2755 case 1:
2757 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2758 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2760 JobW = (LPBYTE)info1W;
2761 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2762 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2763 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2764 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2765 info1W->Status = info1A->Status;
2766 info1W->Priority = info1A->Priority;
2767 info1W->Position = info1A->Position;
2768 info1W->PagesPrinted = info1A->PagesPrinted;
2769 break;
2771 case 2:
2773 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2774 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2776 JobW = (LPBYTE)info2W;
2777 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2778 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2779 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2780 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2781 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2782 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2783 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2784 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2785 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2786 info2W->Status = info2A->Status;
2787 info2W->Priority = info2A->Priority;
2788 info2W->Position = info2A->Position;
2789 info2W->StartTime = info2A->StartTime;
2790 info2W->UntilTime = info2A->UntilTime;
2791 info2W->PagesPrinted = info2A->PagesPrinted;
2792 break;
2794 case 3:
2795 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2796 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2797 break;
2798 default:
2799 SetLastError(ERROR_INVALID_LEVEL);
2800 return FALSE;
2803 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2805 switch(Level)
2807 case 1:
2809 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2810 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2811 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2812 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2813 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2814 break;
2816 case 2:
2818 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2819 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2820 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2821 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2822 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2823 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2824 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2825 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2826 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2827 break;
2830 HeapFree(GetProcessHeap(), 0, JobW);
2832 return ret;
2835 /*****************************************************************************
2836 * SetJobW [WINSPOOL.@]
2838 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2839 LPBYTE pJob, DWORD Command)
2841 BOOL ret = FALSE;
2842 job_t *job;
2844 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2845 FIXME("Ignoring everything other than document title\n");
2847 EnterCriticalSection(&printer_handles_cs);
2848 job = get_job(hPrinter, JobId);
2849 if(!job)
2850 goto end;
2852 switch(Level)
2854 case 0:
2855 break;
2856 case 1:
2858 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2859 HeapFree(GetProcessHeap(), 0, job->document_title);
2860 job->document_title = strdupW(info1->pDocument);
2861 break;
2863 case 2:
2865 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2866 HeapFree(GetProcessHeap(), 0, job->document_title);
2867 job->document_title = strdupW(info2->pDocument);
2868 break;
2870 case 3:
2871 break;
2872 default:
2873 SetLastError(ERROR_INVALID_LEVEL);
2874 goto end;
2876 ret = TRUE;
2877 end:
2878 LeaveCriticalSection(&printer_handles_cs);
2879 return ret;
2882 /*****************************************************************************
2883 * EndDocPrinter [WINSPOOL.@]
2885 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2887 opened_printer_t *printer;
2888 BOOL ret = FALSE;
2889 TRACE("(%p)\n", hPrinter);
2891 EnterCriticalSection(&printer_handles_cs);
2893 printer = get_opened_printer(hPrinter);
2894 if(!printer)
2896 SetLastError(ERROR_INVALID_HANDLE);
2897 goto end;
2900 if(!printer->doc)
2902 SetLastError(ERROR_SPL_NO_STARTDOC);
2903 goto end;
2906 CloseHandle(printer->doc->hf);
2907 ScheduleJob(hPrinter, printer->doc->job_id);
2908 HeapFree(GetProcessHeap(), 0, printer->doc);
2909 printer->doc = NULL;
2910 ret = TRUE;
2911 end:
2912 LeaveCriticalSection(&printer_handles_cs);
2913 return ret;
2916 /*****************************************************************************
2917 * EndPagePrinter [WINSPOOL.@]
2919 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2921 FIXME("(%p): stub\n", hPrinter);
2922 return TRUE;
2925 /*****************************************************************************
2926 * StartDocPrinterA [WINSPOOL.@]
2928 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2930 UNICODE_STRING usBuffer;
2931 DOC_INFO_2W doc2W;
2932 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2933 DWORD ret;
2935 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2936 or one (DOC_INFO_3) extra DWORDs */
2938 switch(Level) {
2939 case 2:
2940 doc2W.JobId = doc2->JobId;
2941 /* fall through */
2942 case 3:
2943 doc2W.dwMode = doc2->dwMode;
2944 /* fall through */
2945 case 1:
2946 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2947 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2948 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2949 break;
2951 default:
2952 SetLastError(ERROR_INVALID_LEVEL);
2953 return FALSE;
2956 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2958 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2959 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2960 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2962 return ret;
2965 /*****************************************************************************
2966 * StartDocPrinterW [WINSPOOL.@]
2968 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2970 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2971 opened_printer_t *printer;
2972 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2973 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2974 JOB_INFO_1W job_info;
2975 DWORD needed, ret = 0;
2976 HANDLE hf;
2977 WCHAR *filename;
2979 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2980 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2981 debugstr_w(doc->pDatatype));
2983 if(Level < 1 || Level > 3)
2985 SetLastError(ERROR_INVALID_LEVEL);
2986 return 0;
2989 EnterCriticalSection(&printer_handles_cs);
2990 printer = get_opened_printer(hPrinter);
2991 if(!printer)
2993 SetLastError(ERROR_INVALID_HANDLE);
2994 goto end;
2997 if(printer->doc)
2999 SetLastError(ERROR_INVALID_PRINTER_STATE);
3000 goto end;
3003 /* Even if we're printing to a file we still add a print job, we'll
3004 just ignore the spool file name */
3006 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3008 ERR("AddJob failed gle %u\n", GetLastError());
3009 goto end;
3012 if(doc->pOutputFile)
3013 filename = doc->pOutputFile;
3014 else
3015 filename = addjob->Path;
3017 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3018 if(hf == INVALID_HANDLE_VALUE)
3019 goto end;
3021 memset(&job_info, 0, sizeof(job_info));
3022 job_info.pDocument = doc->pDocName;
3023 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3025 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3026 printer->doc->hf = hf;
3027 ret = printer->doc->job_id = addjob->JobId;
3028 end:
3029 LeaveCriticalSection(&printer_handles_cs);
3031 return ret;
3034 /*****************************************************************************
3035 * StartPagePrinter [WINSPOOL.@]
3037 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3039 FIXME("(%p): stub\n", hPrinter);
3040 return TRUE;
3043 /*****************************************************************************
3044 * GetFormA [WINSPOOL.@]
3046 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3047 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3049 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3050 Level,pForm,cbBuf,pcbNeeded);
3051 return FALSE;
3054 /*****************************************************************************
3055 * GetFormW [WINSPOOL.@]
3057 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3058 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3060 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3061 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3062 return FALSE;
3065 /*****************************************************************************
3066 * SetFormA [WINSPOOL.@]
3068 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3069 LPBYTE pForm)
3071 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3072 return FALSE;
3075 /*****************************************************************************
3076 * SetFormW [WINSPOOL.@]
3078 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3079 LPBYTE pForm)
3081 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3082 return FALSE;
3085 /*****************************************************************************
3086 * ReadPrinter [WINSPOOL.@]
3088 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3089 LPDWORD pNoBytesRead)
3091 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3092 return FALSE;
3095 /*****************************************************************************
3096 * ResetPrinterA [WINSPOOL.@]
3098 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3100 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3101 return FALSE;
3104 /*****************************************************************************
3105 * ResetPrinterW [WINSPOOL.@]
3107 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3109 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3110 return FALSE;
3113 /*****************************************************************************
3114 * WINSPOOL_GetDWORDFromReg
3116 * Return DWORD associated with ValueName from hkey.
3118 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3120 DWORD sz = sizeof(DWORD), type, value = 0;
3121 LONG ret;
3123 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3125 if(ret != ERROR_SUCCESS) {
3126 WARN("Got ret = %d on name %s\n", ret, ValueName);
3127 return 0;
3129 if(type != REG_DWORD) {
3130 ERR("Got type %d\n", type);
3131 return 0;
3133 return value;
3137 /*****************************************************************************
3138 * get_filename_from_reg [internal]
3140 * Get ValueName from hkey storing result in out
3141 * when the Value in the registry has only a filename, use driverdir as prefix
3142 * outlen is space left in out
3143 * String is stored either as unicode or ascii
3147 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3148 LPBYTE out, DWORD outlen, LPDWORD needed)
3150 WCHAR filename[MAX_PATH];
3151 DWORD size;
3152 DWORD type;
3153 LONG ret;
3154 LPWSTR buffer = filename;
3155 LPWSTR ptr;
3157 *needed = 0;
3158 size = sizeof(filename);
3159 buffer[0] = '\0';
3160 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3161 if (ret == ERROR_MORE_DATA) {
3162 TRACE("need dynamic buffer: %u\n", size);
3163 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3164 if (!buffer) {
3165 /* No Memory is bad */
3166 return FALSE;
3168 buffer[0] = '\0';
3169 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3172 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3173 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3174 return FALSE;
3177 ptr = buffer;
3178 while (ptr) {
3179 /* do we have a full path ? */
3180 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3181 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3183 if (!ret) {
3184 /* we must build the full Path */
3185 *needed += dirlen;
3186 if ((out) && (outlen > dirlen)) {
3187 lstrcpyW((LPWSTR)out, driverdir);
3188 out += dirlen;
3189 outlen -= dirlen;
3191 else
3192 out = NULL;
3195 /* write the filename */
3196 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3197 if ((out) && (outlen >= size)) {
3198 lstrcpyW((LPWSTR)out, ptr);
3199 out += size;
3200 outlen -= size;
3202 else
3203 out = NULL;
3204 *needed += size;
3205 ptr += lstrlenW(ptr)+1;
3206 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3209 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3211 /* write the multisz-termination */
3212 if (type == REG_MULTI_SZ) {
3213 size = sizeof(WCHAR);
3215 *needed += size;
3216 if (out && (outlen >= size)) {
3217 memset (out, 0, size);
3220 return TRUE;
3223 /*****************************************************************************
3224 * WINSPOOL_GetStringFromReg
3226 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3227 * String is stored as unicode.
3229 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3230 DWORD buflen, DWORD *needed)
3232 DWORD sz = buflen, type;
3233 LONG ret;
3235 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3236 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3237 WARN("Got ret = %d\n", ret);
3238 *needed = 0;
3239 return FALSE;
3241 /* add space for terminating '\0' */
3242 sz += sizeof(WCHAR);
3243 *needed = sz;
3245 if (ptr)
3246 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3248 return TRUE;
3251 /*****************************************************************************
3252 * WINSPOOL_GetDefaultDevMode
3254 * Get a default DevMode values for wineps.
3255 * FIXME - use ppd.
3258 static void WINSPOOL_GetDefaultDevMode(
3259 LPBYTE ptr,
3260 DWORD buflen, DWORD *needed)
3262 DEVMODEW dm;
3263 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3265 /* fill default DEVMODE - should be read from ppd... */
3266 ZeroMemory( &dm, sizeof(dm) );
3267 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3268 dm.dmSpecVersion = DM_SPECVERSION;
3269 dm.dmDriverVersion = 1;
3270 dm.dmSize = sizeof(DEVMODEW);
3271 dm.dmDriverExtra = 0;
3272 dm.dmFields =
3273 DM_ORIENTATION | DM_PAPERSIZE |
3274 DM_PAPERLENGTH | DM_PAPERWIDTH |
3275 DM_SCALE |
3276 DM_COPIES |
3277 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3278 DM_YRESOLUTION | DM_TTOPTION;
3280 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3281 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3282 dm.u1.s1.dmPaperLength = 2970;
3283 dm.u1.s1.dmPaperWidth = 2100;
3285 dm.u1.s1.dmScale = 100;
3286 dm.u1.s1.dmCopies = 1;
3287 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3288 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3289 /* dm.dmColor */
3290 /* dm.dmDuplex */
3291 dm.dmYResolution = 300; /* 300dpi */
3292 dm.dmTTOption = DMTT_BITMAP;
3293 /* dm.dmCollate */
3294 /* dm.dmFormName */
3295 /* dm.dmLogPixels */
3296 /* dm.dmBitsPerPel */
3297 /* dm.dmPelsWidth */
3298 /* dm.dmPelsHeight */
3299 /* dm.u2.dmDisplayFlags */
3300 /* dm.dmDisplayFrequency */
3301 /* dm.dmICMMethod */
3302 /* dm.dmICMIntent */
3303 /* dm.dmMediaType */
3304 /* dm.dmDitherType */
3305 /* dm.dmReserved1 */
3306 /* dm.dmReserved2 */
3307 /* dm.dmPanningWidth */
3308 /* dm.dmPanningHeight */
3310 if(buflen >= sizeof(DEVMODEW))
3311 memcpy(ptr, &dm, sizeof(DEVMODEW));
3312 *needed = sizeof(DEVMODEW);
3315 /*****************************************************************************
3316 * WINSPOOL_GetDevModeFromReg
3318 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3319 * DevMode is stored either as unicode or ascii.
3321 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3322 LPBYTE ptr,
3323 DWORD buflen, DWORD *needed)
3325 DWORD sz = buflen, type;
3326 LONG ret;
3328 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3329 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3330 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3331 if (sz < sizeof(DEVMODEA))
3333 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3334 return FALSE;
3336 /* ensures that dmSize is not erratically bogus if registry is invalid */
3337 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3338 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3339 sz += (CCHDEVICENAME + CCHFORMNAME);
3340 if (ptr && (buflen >= sz)) {
3341 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3342 memcpy(ptr, dmW, sz);
3343 HeapFree(GetProcessHeap(),0,dmW);
3345 *needed = sz;
3346 return TRUE;
3349 /*********************************************************************
3350 * WINSPOOL_GetPrinter_1
3352 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3354 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3355 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3357 DWORD size, left = cbBuf;
3358 BOOL space = (cbBuf > 0);
3359 LPBYTE ptr = buf;
3361 *pcbNeeded = 0;
3363 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3364 if(space && size <= left) {
3365 pi1->pName = (LPWSTR)ptr;
3366 ptr += size;
3367 left -= size;
3368 } else
3369 space = FALSE;
3370 *pcbNeeded += size;
3373 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3374 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3375 if(space && size <= left) {
3376 pi1->pDescription = (LPWSTR)ptr;
3377 ptr += size;
3378 left -= size;
3379 } else
3380 space = FALSE;
3381 *pcbNeeded += size;
3384 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3385 if(space && size <= left) {
3386 pi1->pComment = (LPWSTR)ptr;
3387 ptr += size;
3388 left -= size;
3389 } else
3390 space = FALSE;
3391 *pcbNeeded += size;
3394 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3396 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3397 memset(pi1, 0, sizeof(*pi1));
3399 return space;
3401 /*********************************************************************
3402 * WINSPOOL_GetPrinter_2
3404 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3406 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3407 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3409 DWORD size, left = cbBuf;
3410 BOOL space = (cbBuf > 0);
3411 LPBYTE ptr = buf;
3413 *pcbNeeded = 0;
3415 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3416 if(space && size <= left) {
3417 pi2->pPrinterName = (LPWSTR)ptr;
3418 ptr += size;
3419 left -= size;
3420 } else
3421 space = FALSE;
3422 *pcbNeeded += size;
3424 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3425 if(space && size <= left) {
3426 pi2->pShareName = (LPWSTR)ptr;
3427 ptr += size;
3428 left -= size;
3429 } else
3430 space = FALSE;
3431 *pcbNeeded += size;
3433 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3434 if(space && size <= left) {
3435 pi2->pPortName = (LPWSTR)ptr;
3436 ptr += size;
3437 left -= size;
3438 } else
3439 space = FALSE;
3440 *pcbNeeded += size;
3442 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3443 if(space && size <= left) {
3444 pi2->pDriverName = (LPWSTR)ptr;
3445 ptr += size;
3446 left -= size;
3447 } else
3448 space = FALSE;
3449 *pcbNeeded += size;
3451 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3452 if(space && size <= left) {
3453 pi2->pComment = (LPWSTR)ptr;
3454 ptr += size;
3455 left -= size;
3456 } else
3457 space = FALSE;
3458 *pcbNeeded += size;
3460 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3461 if(space && size <= left) {
3462 pi2->pLocation = (LPWSTR)ptr;
3463 ptr += size;
3464 left -= size;
3465 } else
3466 space = FALSE;
3467 *pcbNeeded += size;
3469 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3470 if(space && size <= left) {
3471 pi2->pDevMode = (LPDEVMODEW)ptr;
3472 ptr += size;
3473 left -= size;
3474 } else
3475 space = FALSE;
3476 *pcbNeeded += size;
3478 else
3480 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3481 if(space && size <= left) {
3482 pi2->pDevMode = (LPDEVMODEW)ptr;
3483 ptr += size;
3484 left -= size;
3485 } else
3486 space = FALSE;
3487 *pcbNeeded += size;
3489 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3490 if(space && size <= left) {
3491 pi2->pSepFile = (LPWSTR)ptr;
3492 ptr += size;
3493 left -= size;
3494 } else
3495 space = FALSE;
3496 *pcbNeeded += size;
3498 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3499 if(space && size <= left) {
3500 pi2->pPrintProcessor = (LPWSTR)ptr;
3501 ptr += size;
3502 left -= size;
3503 } else
3504 space = FALSE;
3505 *pcbNeeded += size;
3507 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3508 if(space && size <= left) {
3509 pi2->pDatatype = (LPWSTR)ptr;
3510 ptr += size;
3511 left -= size;
3512 } else
3513 space = FALSE;
3514 *pcbNeeded += size;
3516 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3517 if(space && size <= left) {
3518 pi2->pParameters = (LPWSTR)ptr;
3519 ptr += size;
3520 left -= size;
3521 } else
3522 space = FALSE;
3523 *pcbNeeded += size;
3525 if(pi2) {
3526 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3527 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3528 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3529 "Default Priority");
3530 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3531 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3534 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3535 memset(pi2, 0, sizeof(*pi2));
3537 return space;
3540 /*********************************************************************
3541 * WINSPOOL_GetPrinter_4
3543 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3545 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3546 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3548 DWORD size, left = cbBuf;
3549 BOOL space = (cbBuf > 0);
3550 LPBYTE ptr = buf;
3552 *pcbNeeded = 0;
3554 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3555 if(space && size <= left) {
3556 pi4->pPrinterName = (LPWSTR)ptr;
3557 ptr += size;
3558 left -= size;
3559 } else
3560 space = FALSE;
3561 *pcbNeeded += size;
3563 if(pi4) {
3564 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3567 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3568 memset(pi4, 0, sizeof(*pi4));
3570 return space;
3573 /*********************************************************************
3574 * WINSPOOL_GetPrinter_5
3576 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3578 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3579 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3581 DWORD size, left = cbBuf;
3582 BOOL space = (cbBuf > 0);
3583 LPBYTE ptr = buf;
3585 *pcbNeeded = 0;
3587 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3588 if(space && size <= left) {
3589 pi5->pPrinterName = (LPWSTR)ptr;
3590 ptr += size;
3591 left -= size;
3592 } else
3593 space = FALSE;
3594 *pcbNeeded += size;
3596 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3597 if(space && size <= left) {
3598 pi5->pPortName = (LPWSTR)ptr;
3599 ptr += size;
3600 left -= size;
3601 } else
3602 space = FALSE;
3603 *pcbNeeded += size;
3605 if(pi5) {
3606 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3607 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3608 "dnsTimeout");
3609 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3610 "txTimeout");
3613 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3614 memset(pi5, 0, sizeof(*pi5));
3616 return space;
3619 /*********************************************************************
3620 * WINSPOOL_GetPrinter_7
3622 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3624 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3625 DWORD cbBuf, LPDWORD pcbNeeded)
3627 DWORD size, left = cbBuf;
3628 BOOL space = (cbBuf > 0);
3629 LPBYTE ptr = buf;
3631 *pcbNeeded = 0;
3633 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3635 ptr = NULL;
3636 size = sizeof(pi7->pszObjectGUID);
3638 if (space && size <= left) {
3639 pi7->pszObjectGUID = (LPWSTR)ptr;
3640 ptr += size;
3641 left -= size;
3642 } else
3643 space = FALSE;
3644 *pcbNeeded += size;
3645 if (pi7) {
3646 /* We do not have a Directory Service */
3647 pi7->dwAction = DSPRINT_UNPUBLISH;
3650 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3651 memset(pi7, 0, sizeof(*pi7));
3653 return space;
3656 /*********************************************************************
3657 * WINSPOOL_GetPrinter_9
3659 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3661 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3662 DWORD cbBuf, LPDWORD pcbNeeded)
3664 DWORD size;
3665 BOOL space = (cbBuf > 0);
3667 *pcbNeeded = 0;
3669 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3670 if(space && size <= cbBuf) {
3671 pi9->pDevMode = (LPDEVMODEW)buf;
3672 } else
3673 space = FALSE;
3674 *pcbNeeded += size;
3676 else
3678 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3679 if(space && size <= cbBuf) {
3680 pi9->pDevMode = (LPDEVMODEW)buf;
3681 } else
3682 space = FALSE;
3683 *pcbNeeded += size;
3686 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3687 memset(pi9, 0, sizeof(*pi9));
3689 return space;
3692 /*****************************************************************************
3693 * GetPrinterW [WINSPOOL.@]
3695 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3696 DWORD cbBuf, LPDWORD pcbNeeded)
3698 LPCWSTR name;
3699 DWORD size, needed = 0;
3700 LPBYTE ptr = NULL;
3701 HKEY hkeyPrinter, hkeyPrinters;
3702 BOOL ret;
3704 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3706 if (!(name = get_opened_printer_name(hPrinter))) {
3707 SetLastError(ERROR_INVALID_HANDLE);
3708 return FALSE;
3711 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3712 ERROR_SUCCESS) {
3713 ERR("Can't create Printers key\n");
3714 return FALSE;
3716 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3718 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3719 RegCloseKey(hkeyPrinters);
3720 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3721 return FALSE;
3724 switch(Level) {
3725 case 2:
3727 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3729 size = sizeof(PRINTER_INFO_2W);
3730 if(size <= cbBuf) {
3731 ptr = pPrinter + size;
3732 cbBuf -= size;
3733 memset(pPrinter, 0, size);
3734 } else {
3735 pi2 = NULL;
3736 cbBuf = 0;
3738 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3739 needed += size;
3740 break;
3743 case 4:
3745 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3747 size = sizeof(PRINTER_INFO_4W);
3748 if(size <= cbBuf) {
3749 ptr = pPrinter + size;
3750 cbBuf -= size;
3751 memset(pPrinter, 0, size);
3752 } else {
3753 pi4 = NULL;
3754 cbBuf = 0;
3756 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3757 needed += size;
3758 break;
3762 case 5:
3764 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3766 size = sizeof(PRINTER_INFO_5W);
3767 if(size <= cbBuf) {
3768 ptr = pPrinter + size;
3769 cbBuf -= size;
3770 memset(pPrinter, 0, size);
3771 } else {
3772 pi5 = NULL;
3773 cbBuf = 0;
3776 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3777 needed += size;
3778 break;
3782 case 6:
3784 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3786 size = sizeof(PRINTER_INFO_6);
3787 if (size <= cbBuf) {
3788 /* FIXME: We do not update the status yet */
3789 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3790 ret = TRUE;
3791 } else {
3792 ret = FALSE;
3795 needed += size;
3796 break;
3799 case 7:
3801 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3803 size = sizeof(PRINTER_INFO_7W);
3804 if (size <= cbBuf) {
3805 ptr = pPrinter + size;
3806 cbBuf -= size;
3807 memset(pPrinter, 0, size);
3808 } else {
3809 pi7 = NULL;
3810 cbBuf = 0;
3813 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3814 needed += size;
3815 break;
3819 case 9:
3821 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3823 size = sizeof(PRINTER_INFO_9W);
3824 if(size <= cbBuf) {
3825 ptr = pPrinter + size;
3826 cbBuf -= size;
3827 memset(pPrinter, 0, size);
3828 } else {
3829 pi9 = NULL;
3830 cbBuf = 0;
3833 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3834 needed += size;
3835 break;
3839 default:
3840 FIXME("Unimplemented level %d\n", Level);
3841 SetLastError(ERROR_INVALID_LEVEL);
3842 RegCloseKey(hkeyPrinters);
3843 RegCloseKey(hkeyPrinter);
3844 return FALSE;
3847 RegCloseKey(hkeyPrinter);
3848 RegCloseKey(hkeyPrinters);
3850 TRACE("returning %d needed = %d\n", ret, needed);
3851 if(pcbNeeded) *pcbNeeded = needed;
3852 if(!ret)
3853 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3854 return ret;
3857 /*****************************************************************************
3858 * GetPrinterA [WINSPOOL.@]
3860 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3861 DWORD cbBuf, LPDWORD pcbNeeded)
3863 BOOL ret;
3864 LPBYTE buf = NULL;
3866 if (cbBuf)
3867 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3869 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3870 if (ret)
3871 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3872 HeapFree(GetProcessHeap(), 0, buf);
3874 return ret;
3877 /*****************************************************************************
3878 * WINSPOOL_EnumPrintersW
3880 * Implementation of EnumPrintersW
3882 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3883 DWORD dwLevel, LPBYTE lpbPrinters,
3884 DWORD cbBuf, LPDWORD lpdwNeeded,
3885 LPDWORD lpdwReturned)
3888 HKEY hkeyPrinters, hkeyPrinter;
3889 WCHAR PrinterName[255];
3890 DWORD needed = 0, number = 0;
3891 DWORD used, i, left;
3892 PBYTE pi, buf;
3894 if(lpbPrinters)
3895 memset(lpbPrinters, 0, cbBuf);
3896 if(lpdwReturned)
3897 *lpdwReturned = 0;
3898 if(lpdwNeeded)
3899 *lpdwNeeded = 0;
3901 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3902 if(dwType == PRINTER_ENUM_DEFAULT)
3903 return TRUE;
3905 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3906 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3907 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3908 if (!dwType) {
3909 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3910 return TRUE;
3915 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3916 FIXME("dwType = %08x\n", dwType);
3917 SetLastError(ERROR_INVALID_FLAGS);
3918 return FALSE;
3921 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3922 ERROR_SUCCESS) {
3923 ERR("Can't create Printers key\n");
3924 return FALSE;
3927 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3928 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3929 RegCloseKey(hkeyPrinters);
3930 ERR("Can't query Printers key\n");
3931 return FALSE;
3933 TRACE("Found %d printers\n", number);
3935 switch(dwLevel) {
3936 case 1:
3937 used = number * sizeof(PRINTER_INFO_1W);
3938 break;
3939 case 2:
3940 used = number * sizeof(PRINTER_INFO_2W);
3941 break;
3942 case 4:
3943 used = number * sizeof(PRINTER_INFO_4W);
3944 break;
3945 case 5:
3946 used = number * sizeof(PRINTER_INFO_5W);
3947 break;
3949 default:
3950 SetLastError(ERROR_INVALID_LEVEL);
3951 RegCloseKey(hkeyPrinters);
3952 return FALSE;
3954 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3956 for(i = 0; i < number; i++) {
3957 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3958 ERROR_SUCCESS) {
3959 ERR("Can't enum key number %d\n", i);
3960 RegCloseKey(hkeyPrinters);
3961 return FALSE;
3963 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3964 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3965 ERROR_SUCCESS) {
3966 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3967 RegCloseKey(hkeyPrinters);
3968 return FALSE;
3971 if(cbBuf > used) {
3972 buf = lpbPrinters + used;
3973 left = cbBuf - used;
3974 } else {
3975 buf = NULL;
3976 left = 0;
3979 switch(dwLevel) {
3980 case 1:
3981 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3982 left, &needed);
3983 used += needed;
3984 if(pi) pi += sizeof(PRINTER_INFO_1W);
3985 break;
3986 case 2:
3987 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3988 left, &needed);
3989 used += needed;
3990 if(pi) pi += sizeof(PRINTER_INFO_2W);
3991 break;
3992 case 4:
3993 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3994 left, &needed);
3995 used += needed;
3996 if(pi) pi += sizeof(PRINTER_INFO_4W);
3997 break;
3998 case 5:
3999 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4000 left, &needed);
4001 used += needed;
4002 if(pi) pi += sizeof(PRINTER_INFO_5W);
4003 break;
4004 default:
4005 ERR("Shouldn't be here!\n");
4006 RegCloseKey(hkeyPrinter);
4007 RegCloseKey(hkeyPrinters);
4008 return FALSE;
4010 RegCloseKey(hkeyPrinter);
4012 RegCloseKey(hkeyPrinters);
4014 if(lpdwNeeded)
4015 *lpdwNeeded = used;
4017 if(used > cbBuf) {
4018 if(lpbPrinters)
4019 memset(lpbPrinters, 0, cbBuf);
4020 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4021 return FALSE;
4023 if(lpdwReturned)
4024 *lpdwReturned = number;
4025 SetLastError(ERROR_SUCCESS);
4026 return TRUE;
4030 /******************************************************************
4031 * EnumPrintersW [WINSPOOL.@]
4033 * Enumerates the available printers, print servers and print
4034 * providers, depending on the specified flags, name and level.
4036 * RETURNS:
4038 * If level is set to 1:
4039 * Returns an array of PRINTER_INFO_1 data structures in the
4040 * lpbPrinters buffer.
4042 * If level is set to 2:
4043 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4044 * Returns an array of PRINTER_INFO_2 data structures in the
4045 * lpbPrinters buffer. Note that according to MSDN also an
4046 * OpenPrinter should be performed on every remote printer.
4048 * If level is set to 4 (officially WinNT only):
4049 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4050 * Fast: Only the registry is queried to retrieve printer names,
4051 * no connection to the driver is made.
4052 * Returns an array of PRINTER_INFO_4 data structures in the
4053 * lpbPrinters buffer.
4055 * If level is set to 5 (officially WinNT4/Win9x only):
4056 * Fast: Only the registry is queried to retrieve printer names,
4057 * no connection to the driver is made.
4058 * Returns an array of PRINTER_INFO_5 data structures in the
4059 * lpbPrinters buffer.
4061 * If level set to 3 or 6+:
4062 * returns zero (failure!)
4064 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4065 * for information.
4067 * BUGS:
4068 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4069 * - Only levels 2, 4 and 5 are implemented at the moment.
4070 * - 16-bit printer drivers are not enumerated.
4071 * - Returned amount of bytes used/needed does not match the real Windoze
4072 * implementation (as in this implementation, all strings are part
4073 * of the buffer, whereas Win32 keeps them somewhere else)
4074 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4076 * NOTE:
4077 * - In a regular Wine installation, no registry settings for printers
4078 * exist, which makes this function return an empty list.
4080 BOOL WINAPI EnumPrintersW(
4081 DWORD dwType, /* [in] Types of print objects to enumerate */
4082 LPWSTR lpszName, /* [in] name of objects to enumerate */
4083 DWORD dwLevel, /* [in] type of printer info structure */
4084 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4085 DWORD cbBuf, /* [in] max size of buffer in bytes */
4086 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4087 LPDWORD lpdwReturned /* [out] number of entries returned */
4090 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4091 lpdwNeeded, lpdwReturned);
4094 /******************************************************************
4095 * EnumPrintersA [WINSPOOL.@]
4097 * See EnumPrintersW
4100 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4101 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4103 BOOL ret;
4104 UNICODE_STRING pNameU;
4105 LPWSTR pNameW;
4106 LPBYTE pPrintersW;
4108 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4109 pPrinters, cbBuf, pcbNeeded, pcReturned);
4111 pNameW = asciitounicode(&pNameU, pName);
4113 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4114 MS Office need this */
4115 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4117 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4119 RtlFreeUnicodeString(&pNameU);
4120 if (ret) {
4121 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4123 HeapFree(GetProcessHeap(), 0, pPrintersW);
4124 return ret;
4127 /*****************************************************************************
4128 * WINSPOOL_GetDriverInfoFromReg [internal]
4130 * Enters the information from the registry into the DRIVER_INFO struct
4132 * RETURNS
4133 * zero if the printer driver does not exist in the registry
4134 * (only if Level > 1) otherwise nonzero
4136 static BOOL WINSPOOL_GetDriverInfoFromReg(
4137 HKEY hkeyDrivers,
4138 LPWSTR DriverName,
4139 const printenv_t * env,
4140 DWORD Level,
4141 LPBYTE ptr, /* DRIVER_INFO */
4142 LPBYTE pDriverStrings, /* strings buffer */
4143 DWORD cbBuf, /* size of string buffer */
4144 LPDWORD pcbNeeded) /* space needed for str. */
4146 DWORD size, tmp;
4147 HKEY hkeyDriver;
4148 WCHAR driverdir[MAX_PATH];
4149 DWORD dirlen;
4150 LPBYTE strPtr = pDriverStrings;
4151 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4153 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4154 debugstr_w(DriverName), env,
4155 Level, di, pDriverStrings, cbBuf);
4157 if (di) ZeroMemory(di, di_sizeof[Level]);
4159 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4160 if (*pcbNeeded <= cbBuf)
4161 strcpyW((LPWSTR)strPtr, DriverName);
4163 /* pName for level 1 has a different offset! */
4164 if (Level == 1) {
4165 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4166 return TRUE;
4169 /* .cVersion and .pName for level > 1 */
4170 if (di) {
4171 di->cVersion = env->driverversion;
4172 di->pName = (LPWSTR) strPtr;
4173 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4176 /* Reserve Space for the largest subdir and a Backslash*/
4177 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4178 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4179 /* Should never Fail */
4180 return FALSE;
4182 lstrcatW(driverdir, env->versionsubdir);
4183 lstrcatW(driverdir, backslashW);
4185 /* dirlen must not include the terminating zero */
4186 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4188 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4189 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4190 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4191 return FALSE;
4194 /* pEnvironment */
4195 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4197 *pcbNeeded += size;
4198 if (*pcbNeeded <= cbBuf) {
4199 lstrcpyW((LPWSTR)strPtr, env->envname);
4200 if (di) di->pEnvironment = (LPWSTR)strPtr;
4201 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4204 /* .pDriverPath is the Graphics rendering engine.
4205 The full Path is required to avoid a crash in some apps */
4206 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4207 *pcbNeeded += size;
4208 if (*pcbNeeded <= cbBuf)
4209 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4211 if (di) di->pDriverPath = (LPWSTR)strPtr;
4212 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4215 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4216 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4217 *pcbNeeded += size;
4218 if (*pcbNeeded <= cbBuf)
4219 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4221 if (di) di->pDataFile = (LPWSTR)strPtr;
4222 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4225 /* .pConfigFile is the Driver user Interface */
4226 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4227 *pcbNeeded += size;
4228 if (*pcbNeeded <= cbBuf)
4229 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4231 if (di) di->pConfigFile = (LPWSTR)strPtr;
4232 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4235 if (Level == 2 ) {
4236 RegCloseKey(hkeyDriver);
4237 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4238 return TRUE;
4241 if (Level == 5 ) {
4242 RegCloseKey(hkeyDriver);
4243 FIXME("level 5: incomplete\n");
4244 return TRUE;
4247 /* .pHelpFile */
4248 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4249 *pcbNeeded += size;
4250 if (*pcbNeeded <= cbBuf)
4251 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4253 if (di) di->pHelpFile = (LPWSTR)strPtr;
4254 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4257 /* .pDependentFiles */
4258 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4259 *pcbNeeded += size;
4260 if (*pcbNeeded <= cbBuf)
4261 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4263 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4264 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4266 else if (GetVersion() & 0x80000000) {
4267 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4268 size = 2 * sizeof(WCHAR);
4269 *pcbNeeded += size;
4270 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4272 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4273 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4276 /* .pMonitorName is the optional Language Monitor */
4277 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4278 *pcbNeeded += size;
4279 if (*pcbNeeded <= cbBuf)
4280 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4282 if (di) di->pMonitorName = (LPWSTR)strPtr;
4283 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4286 /* .pDefaultDataType */
4287 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4288 *pcbNeeded += size;
4289 if(*pcbNeeded <= cbBuf)
4290 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4292 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4293 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4296 if (Level == 3 ) {
4297 RegCloseKey(hkeyDriver);
4298 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4299 return TRUE;
4302 /* .pszzPreviousNames */
4303 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4304 *pcbNeeded += size;
4305 if(*pcbNeeded <= cbBuf)
4306 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4308 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4309 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4312 if (Level == 4 ) {
4313 RegCloseKey(hkeyDriver);
4314 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4315 return TRUE;
4318 /* support is missing, but not important enough for a FIXME */
4319 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4321 /* .pszMfgName */
4322 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4323 *pcbNeeded += size;
4324 if(*pcbNeeded <= cbBuf)
4325 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4327 if (di) di->pszMfgName = (LPWSTR)strPtr;
4328 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4331 /* .pszOEMUrl */
4332 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4333 *pcbNeeded += size;
4334 if(*pcbNeeded <= cbBuf)
4335 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4337 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4338 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4341 /* .pszHardwareID */
4342 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4343 *pcbNeeded += size;
4344 if(*pcbNeeded <= cbBuf)
4345 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4347 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4348 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4351 /* .pszProvider */
4352 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4353 *pcbNeeded += size;
4354 if(*pcbNeeded <= cbBuf)
4355 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4357 if (di) di->pszProvider = (LPWSTR)strPtr;
4358 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4361 if (Level == 6 ) {
4362 RegCloseKey(hkeyDriver);
4363 return TRUE;
4366 /* support is missing, but not important enough for a FIXME */
4367 TRACE("level 8: incomplete\n");
4369 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4370 RegCloseKey(hkeyDriver);
4371 return TRUE;
4374 /*****************************************************************************
4375 * GetPrinterDriverW [WINSPOOL.@]
4377 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4378 DWORD Level, LPBYTE pDriverInfo,
4379 DWORD cbBuf, LPDWORD pcbNeeded)
4381 LPCWSTR name;
4382 WCHAR DriverName[100];
4383 DWORD ret, type, size, needed = 0;
4384 LPBYTE ptr = NULL;
4385 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4386 const printenv_t * env;
4388 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4389 Level,pDriverInfo,cbBuf, pcbNeeded);
4391 if (cbBuf > 0)
4392 ZeroMemory(pDriverInfo, cbBuf);
4394 if (!(name = get_opened_printer_name(hPrinter))) {
4395 SetLastError(ERROR_INVALID_HANDLE);
4396 return FALSE;
4399 if (Level < 1 || Level == 7 || Level > 8) {
4400 SetLastError(ERROR_INVALID_LEVEL);
4401 return FALSE;
4404 env = validate_envW(pEnvironment);
4405 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4407 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4408 ERROR_SUCCESS) {
4409 ERR("Can't create Printers key\n");
4410 return FALSE;
4412 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4413 != ERROR_SUCCESS) {
4414 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4415 RegCloseKey(hkeyPrinters);
4416 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4417 return FALSE;
4419 size = sizeof(DriverName);
4420 DriverName[0] = 0;
4421 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4422 (LPBYTE)DriverName, &size);
4423 RegCloseKey(hkeyPrinter);
4424 RegCloseKey(hkeyPrinters);
4425 if(ret != ERROR_SUCCESS) {
4426 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4427 return FALSE;
4430 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4431 if(!hkeyDrivers) {
4432 ERR("Can't create Drivers key\n");
4433 return FALSE;
4436 size = di_sizeof[Level];
4437 if ((size <= cbBuf) && pDriverInfo)
4438 ptr = pDriverInfo + size;
4440 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4441 env, Level, pDriverInfo, ptr,
4442 (cbBuf < size) ? 0 : cbBuf - size,
4443 &needed)) {
4444 RegCloseKey(hkeyDrivers);
4445 return FALSE;
4448 RegCloseKey(hkeyDrivers);
4450 if(pcbNeeded) *pcbNeeded = size + needed;
4451 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4452 if(cbBuf >= size + needed) return TRUE;
4453 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4454 return FALSE;
4457 /*****************************************************************************
4458 * GetPrinterDriverA [WINSPOOL.@]
4460 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4461 DWORD Level, LPBYTE pDriverInfo,
4462 DWORD cbBuf, LPDWORD pcbNeeded)
4464 BOOL ret;
4465 UNICODE_STRING pEnvW;
4466 PWSTR pwstrEnvW;
4467 LPBYTE buf = NULL;
4469 if (cbBuf)
4471 ZeroMemory(pDriverInfo, cbBuf);
4472 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4475 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4476 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4477 cbBuf, pcbNeeded);
4478 if (ret)
4479 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4481 HeapFree(GetProcessHeap(), 0, buf);
4483 RtlFreeUnicodeString(&pEnvW);
4484 return ret;
4487 /*****************************************************************************
4488 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4490 * Return the PATH for the Printer-Drivers (UNICODE)
4492 * PARAMS
4493 * pName [I] Servername (NT only) or NULL (local Computer)
4494 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4495 * Level [I] Structure-Level (must be 1)
4496 * pDriverDirectory [O] PTR to Buffer that receives the Result
4497 * cbBuf [I] Size of Buffer at pDriverDirectory
4498 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4499 * required for pDriverDirectory
4501 * RETURNS
4502 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4503 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4504 * if cbBuf is too small
4506 * Native Values returned in pDriverDirectory on Success:
4507 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4508 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4509 *| win9x(Windows 4.0): "%winsysdir%"
4511 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4513 * FIXME
4514 *- Only NULL or "" is supported for pName
4517 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4518 DWORD Level, LPBYTE pDriverDirectory,
4519 DWORD cbBuf, LPDWORD pcbNeeded)
4521 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4522 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4524 if ((backend == NULL) && !load_backend()) return FALSE;
4526 if (Level != 1) {
4527 /* (Level != 1) is ignored in win9x */
4528 SetLastError(ERROR_INVALID_LEVEL);
4529 return FALSE;
4531 if (pcbNeeded == NULL) {
4532 /* (pcbNeeded == NULL) is ignored in win9x */
4533 SetLastError(RPC_X_NULL_REF_POINTER);
4534 return FALSE;
4537 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4538 pDriverDirectory, cbBuf, pcbNeeded);
4543 /*****************************************************************************
4544 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4546 * Return the PATH for the Printer-Drivers (ANSI)
4548 * See GetPrinterDriverDirectoryW.
4550 * NOTES
4551 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4554 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4555 DWORD Level, LPBYTE pDriverDirectory,
4556 DWORD cbBuf, LPDWORD pcbNeeded)
4558 UNICODE_STRING nameW, environmentW;
4559 BOOL ret;
4560 DWORD pcbNeededW;
4561 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4562 WCHAR *driverDirectoryW = NULL;
4564 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4565 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4567 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4569 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4570 else nameW.Buffer = NULL;
4571 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4572 else environmentW.Buffer = NULL;
4574 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4575 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4576 if (ret) {
4577 DWORD needed;
4578 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4579 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4580 if(pcbNeeded)
4581 *pcbNeeded = needed;
4582 ret = (needed <= cbBuf) ? TRUE : FALSE;
4583 } else
4584 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4586 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4588 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4589 RtlFreeUnicodeString(&environmentW);
4590 RtlFreeUnicodeString(&nameW);
4592 return ret;
4595 /*****************************************************************************
4596 * AddPrinterDriverA [WINSPOOL.@]
4598 * See AddPrinterDriverW.
4601 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4603 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4604 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4607 /******************************************************************************
4608 * AddPrinterDriverW (WINSPOOL.@)
4610 * Install a Printer Driver
4612 * PARAMS
4613 * pName [I] Servername or NULL (local Computer)
4614 * level [I] Level for the supplied DRIVER_INFO_*W struct
4615 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4617 * RESULTS
4618 * Success: TRUE
4619 * Failure: FALSE
4622 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4624 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4625 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4628 /*****************************************************************************
4629 * AddPrintProcessorA [WINSPOOL.@]
4631 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4632 LPSTR pPrintProcessorName)
4634 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4635 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4636 return FALSE;
4639 /*****************************************************************************
4640 * AddPrintProcessorW [WINSPOOL.@]
4642 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4643 LPWSTR pPrintProcessorName)
4645 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4646 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4647 return FALSE;
4650 /*****************************************************************************
4651 * AddPrintProvidorA [WINSPOOL.@]
4653 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4655 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4656 return FALSE;
4659 /*****************************************************************************
4660 * AddPrintProvidorW [WINSPOOL.@]
4662 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4664 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4665 return FALSE;
4668 /*****************************************************************************
4669 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4671 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4672 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4674 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4675 pDevModeOutput, pDevModeInput);
4676 return 0;
4679 /*****************************************************************************
4680 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4682 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4683 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4685 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4686 pDevModeOutput, pDevModeInput);
4687 return 0;
4690 /*****************************************************************************
4691 * PrinterProperties [WINSPOOL.@]
4693 * Displays a dialog to set the properties of the printer.
4695 * RETURNS
4696 * nonzero on success or zero on failure
4698 * BUGS
4699 * implemented as stub only
4701 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4702 HANDLE hPrinter /* [in] handle to printer object */
4704 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4705 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4706 return FALSE;
4709 /*****************************************************************************
4710 * EnumJobsA [WINSPOOL.@]
4713 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4714 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4715 LPDWORD pcReturned)
4717 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4718 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4720 if(pcbNeeded) *pcbNeeded = 0;
4721 if(pcReturned) *pcReturned = 0;
4722 return FALSE;
4726 /*****************************************************************************
4727 * EnumJobsW [WINSPOOL.@]
4730 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4731 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4732 LPDWORD pcReturned)
4734 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4735 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4737 if(pcbNeeded) *pcbNeeded = 0;
4738 if(pcReturned) *pcReturned = 0;
4739 return FALSE;
4742 /*****************************************************************************
4743 * WINSPOOL_EnumPrinterDrivers [internal]
4745 * Delivers information about all printer drivers installed on the
4746 * localhost or a given server
4748 * RETURNS
4749 * nonzero on success or zero on failure. If the buffer for the returned
4750 * information is too small the function will return an error
4752 * BUGS
4753 * - only implemented for localhost, foreign hosts will return an error
4755 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4756 DWORD Level, LPBYTE pDriverInfo,
4757 DWORD driver_index,
4758 DWORD cbBuf, LPDWORD pcbNeeded,
4759 LPDWORD pcFound, DWORD data_offset)
4761 { HKEY hkeyDrivers;
4762 DWORD i, size = 0;
4763 const printenv_t * env;
4765 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4766 debugstr_w(pName), debugstr_w(pEnvironment),
4767 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4769 env = validate_envW(pEnvironment);
4770 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4772 *pcFound = 0;
4774 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4775 if(!hkeyDrivers) {
4776 ERR("Can't open Drivers key\n");
4777 return FALSE;
4780 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4781 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4782 RegCloseKey(hkeyDrivers);
4783 ERR("Can't query Drivers key\n");
4784 return FALSE;
4786 TRACE("Found %d Drivers\n", *pcFound);
4788 /* get size of single struct
4789 * unicode and ascii structure have the same size
4791 size = di_sizeof[Level];
4793 if (data_offset == 0)
4794 data_offset = size * (*pcFound);
4795 *pcbNeeded = data_offset;
4797 for( i = 0; i < *pcFound; i++) {
4798 WCHAR DriverNameW[255];
4799 PBYTE table_ptr = NULL;
4800 PBYTE data_ptr = NULL;
4801 DWORD needed = 0;
4803 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4804 != ERROR_SUCCESS) {
4805 ERR("Can't enum key number %d\n", i);
4806 RegCloseKey(hkeyDrivers);
4807 return FALSE;
4810 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4811 table_ptr = pDriverInfo + (driver_index + i) * size;
4812 if (pDriverInfo && *pcbNeeded <= cbBuf)
4813 data_ptr = pDriverInfo + *pcbNeeded;
4815 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4816 env, Level, table_ptr, data_ptr,
4817 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4818 &needed)) {
4819 RegCloseKey(hkeyDrivers);
4820 return FALSE;
4823 *pcbNeeded += needed;
4826 RegCloseKey(hkeyDrivers);
4828 if(cbBuf < *pcbNeeded){
4829 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4830 return FALSE;
4833 return TRUE;
4836 /*****************************************************************************
4837 * EnumPrinterDriversW [WINSPOOL.@]
4839 * see function EnumPrinterDrivers for RETURNS, BUGS
4841 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4842 LPBYTE pDriverInfo, DWORD cbBuf,
4843 LPDWORD pcbNeeded, LPDWORD pcReturned)
4845 static const WCHAR allW[] = {'a','l','l',0};
4846 BOOL ret;
4847 DWORD found;
4849 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4851 SetLastError(RPC_X_NULL_REF_POINTER);
4852 return FALSE;
4855 /* check for local drivers */
4856 if((pName) && (pName[0])) {
4857 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4858 SetLastError(ERROR_ACCESS_DENIED);
4859 return FALSE;
4862 /* check input parameter */
4863 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4864 SetLastError(ERROR_INVALID_LEVEL);
4865 return FALSE;
4868 if(pDriverInfo && cbBuf > 0)
4869 memset( pDriverInfo, 0, cbBuf);
4871 /* Exception: pull all printers */
4872 if (pEnvironment && !strcmpW(pEnvironment, allW))
4874 DWORD i, needed, bufsize = cbBuf;
4875 DWORD total_needed = 0;
4876 DWORD total_found = 0;
4877 DWORD data_offset;
4879 /* Precompute the overall total; we need this to know
4880 where pointers end and data begins (i.e. data_offset) */
4881 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4883 needed = found = 0;
4884 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4885 NULL, 0, 0, &needed, &found, 0);
4886 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4887 total_needed += needed;
4888 total_found += found;
4891 data_offset = di_sizeof[Level] * total_found;
4893 *pcReturned = 0;
4894 *pcbNeeded = 0;
4895 total_found = 0;
4896 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4898 needed = found = 0;
4899 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4900 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4901 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4902 else if (ret)
4903 *pcReturned += found;
4904 *pcbNeeded = needed;
4905 data_offset = needed;
4906 total_found += found;
4908 return ret;
4911 /* Normal behavior */
4912 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4913 0, cbBuf, pcbNeeded, &found, 0);
4914 if (ret)
4915 *pcReturned = found;
4917 return ret;
4920 /*****************************************************************************
4921 * EnumPrinterDriversA [WINSPOOL.@]
4923 * see function EnumPrinterDrivers for RETURNS, BUGS
4925 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4926 LPBYTE pDriverInfo, DWORD cbBuf,
4927 LPDWORD pcbNeeded, LPDWORD pcReturned)
4929 BOOL ret;
4930 UNICODE_STRING pNameW, pEnvironmentW;
4931 PWSTR pwstrNameW, pwstrEnvironmentW;
4932 LPBYTE buf = NULL;
4934 if (cbBuf)
4935 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4937 pwstrNameW = asciitounicode(&pNameW, pName);
4938 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4940 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4941 buf, cbBuf, pcbNeeded, pcReturned);
4942 if (ret)
4943 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4945 HeapFree(GetProcessHeap(), 0, buf);
4947 RtlFreeUnicodeString(&pNameW);
4948 RtlFreeUnicodeString(&pEnvironmentW);
4950 return ret;
4953 /******************************************************************************
4954 * EnumPortsA (WINSPOOL.@)
4956 * See EnumPortsW.
4959 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4960 LPDWORD pcbNeeded, LPDWORD pcReturned)
4962 BOOL res;
4963 LPBYTE bufferW = NULL;
4964 LPWSTR nameW = NULL;
4965 DWORD needed = 0;
4966 DWORD numentries = 0;
4967 INT len;
4969 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4970 cbBuf, pcbNeeded, pcReturned);
4972 /* convert servername to unicode */
4973 if (pName) {
4974 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4975 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4976 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4978 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4979 needed = cbBuf * sizeof(WCHAR);
4980 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4981 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4983 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4984 if (pcbNeeded) needed = *pcbNeeded;
4985 /* HeapReAlloc return NULL, when bufferW was NULL */
4986 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4987 HeapAlloc(GetProcessHeap(), 0, needed);
4989 /* Try again with the large Buffer */
4990 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4992 needed = pcbNeeded ? *pcbNeeded : 0;
4993 numentries = pcReturned ? *pcReturned : 0;
4996 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4997 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4999 if (res) {
5000 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5001 DWORD entrysize = 0;
5002 DWORD index;
5003 LPSTR ptr;
5004 LPPORT_INFO_2W pi2w;
5005 LPPORT_INFO_2A pi2a;
5007 needed = 0;
5008 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5010 /* First pass: calculate the size for all Entries */
5011 pi2w = (LPPORT_INFO_2W) bufferW;
5012 pi2a = (LPPORT_INFO_2A) pPorts;
5013 index = 0;
5014 while (index < numentries) {
5015 index++;
5016 needed += entrysize; /* PORT_INFO_?A */
5017 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5019 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5020 NULL, 0, NULL, NULL);
5021 if (Level > 1) {
5022 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5023 NULL, 0, NULL, NULL);
5024 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5025 NULL, 0, NULL, NULL);
5027 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5028 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5029 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5032 /* check for errors and quit on failure */
5033 if (cbBuf < needed) {
5034 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5035 res = FALSE;
5036 goto cleanup;
5038 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5039 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5040 cbBuf -= len ; /* free Bytes in the user-Buffer */
5041 pi2w = (LPPORT_INFO_2W) bufferW;
5042 pi2a = (LPPORT_INFO_2A) pPorts;
5043 index = 0;
5044 /* Second Pass: Fill the User Buffer (if we have one) */
5045 while ((index < numentries) && pPorts) {
5046 index++;
5047 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5048 pi2a->pPortName = ptr;
5049 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5050 ptr, cbBuf , NULL, NULL);
5051 ptr += len;
5052 cbBuf -= len;
5053 if (Level > 1) {
5054 pi2a->pMonitorName = ptr;
5055 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5056 ptr, cbBuf, NULL, NULL);
5057 ptr += len;
5058 cbBuf -= len;
5060 pi2a->pDescription = ptr;
5061 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5062 ptr, cbBuf, NULL, NULL);
5063 ptr += len;
5064 cbBuf -= len;
5066 pi2a->fPortType = pi2w->fPortType;
5067 pi2a->Reserved = 0; /* documented: "must be zero" */
5070 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5071 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5072 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5076 cleanup:
5077 if (pcbNeeded) *pcbNeeded = needed;
5078 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5080 HeapFree(GetProcessHeap(), 0, nameW);
5081 HeapFree(GetProcessHeap(), 0, bufferW);
5083 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5084 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5086 return (res);
5090 /******************************************************************************
5091 * EnumPortsW (WINSPOOL.@)
5093 * Enumerate available Ports
5095 * PARAMS
5096 * pName [I] Servername or NULL (local Computer)
5097 * Level [I] Structure-Level (1 or 2)
5098 * pPorts [O] PTR to Buffer that receives the Result
5099 * cbBuf [I] Size of Buffer at pPorts
5100 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5101 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5103 * RETURNS
5104 * Success: TRUE
5105 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5108 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5111 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5112 cbBuf, pcbNeeded, pcReturned);
5114 if ((backend == NULL) && !load_backend()) return FALSE;
5116 /* Level is not checked in win9x */
5117 if (!Level || (Level > 2)) {
5118 WARN("level (%d) is ignored in win9x\n", Level);
5119 SetLastError(ERROR_INVALID_LEVEL);
5120 return FALSE;
5122 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5123 SetLastError(RPC_X_NULL_REF_POINTER);
5124 return FALSE;
5127 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5130 /******************************************************************************
5131 * GetDefaultPrinterW (WINSPOOL.@)
5133 * FIXME
5134 * This function must read the value from data 'device' of key
5135 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5137 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5139 BOOL retval = TRUE;
5140 DWORD insize, len;
5141 WCHAR *buffer, *ptr;
5143 if (!namesize)
5145 SetLastError(ERROR_INVALID_PARAMETER);
5146 return FALSE;
5149 /* make the buffer big enough for the stuff from the profile/registry,
5150 * the content must fit into the local buffer to compute the correct
5151 * size even if the extern buffer is too small or not given.
5152 * (20 for ,driver,port) */
5153 insize = *namesize;
5154 len = max(100, (insize + 20));
5155 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5157 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5159 SetLastError (ERROR_FILE_NOT_FOUND);
5160 retval = FALSE;
5161 goto end;
5163 TRACE("%s\n", debugstr_w(buffer));
5165 if ((ptr = strchrW(buffer, ',')) == NULL)
5167 SetLastError(ERROR_INVALID_NAME);
5168 retval = FALSE;
5169 goto end;
5172 *ptr = 0;
5173 *namesize = strlenW(buffer) + 1;
5174 if(!name || (*namesize > insize))
5176 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5177 retval = FALSE;
5178 goto end;
5180 strcpyW(name, buffer);
5182 end:
5183 HeapFree( GetProcessHeap(), 0, buffer);
5184 return retval;
5188 /******************************************************************************
5189 * GetDefaultPrinterA (WINSPOOL.@)
5191 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5193 BOOL retval = TRUE;
5194 DWORD insize = 0;
5195 WCHAR *bufferW = NULL;
5197 if (!namesize)
5199 SetLastError(ERROR_INVALID_PARAMETER);
5200 return FALSE;
5203 if(name && *namesize) {
5204 insize = *namesize;
5205 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5208 if(!GetDefaultPrinterW( bufferW, namesize)) {
5209 retval = FALSE;
5210 goto end;
5213 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5214 NULL, NULL);
5215 if (!*namesize)
5217 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5218 retval = FALSE;
5220 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5222 end:
5223 HeapFree( GetProcessHeap(), 0, bufferW);
5224 return retval;
5228 /******************************************************************************
5229 * SetDefaultPrinterW (WINSPOOL.204)
5231 * Set the Name of the Default Printer
5233 * PARAMS
5234 * pszPrinter [I] Name of the Printer or NULL
5236 * RETURNS
5237 * Success: True
5238 * Failure: FALSE
5240 * NOTES
5241 * When the Parameter is NULL or points to an Empty String and
5242 * a Default Printer was already present, then this Function changes nothing.
5243 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5244 * the First enumerated local Printer is used.
5247 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5250 TRACE("(%s)\n", debugstr_w(pszPrinter));
5252 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5253 return FALSE;
5256 /******************************************************************************
5257 * SetDefaultPrinterA (WINSPOOL.202)
5259 * See SetDefaultPrinterW.
5262 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5265 TRACE("(%s)\n", debugstr_a(pszPrinter));
5267 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5268 return FALSE;
5272 /******************************************************************************
5273 * SetPrinterDataExA (WINSPOOL.@)
5275 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5276 LPCSTR pValueName, DWORD Type,
5277 LPBYTE pData, DWORD cbData)
5279 HKEY hkeyPrinter, hkeySubkey;
5280 DWORD ret;
5282 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5283 debugstr_a(pValueName), Type, pData, cbData);
5285 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5286 != ERROR_SUCCESS)
5287 return ret;
5289 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5290 != ERROR_SUCCESS) {
5291 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5292 RegCloseKey(hkeyPrinter);
5293 return ret;
5295 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5296 RegCloseKey(hkeySubkey);
5297 RegCloseKey(hkeyPrinter);
5298 return ret;
5301 /******************************************************************************
5302 * SetPrinterDataExW (WINSPOOL.@)
5304 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5305 LPCWSTR pValueName, DWORD Type,
5306 LPBYTE pData, DWORD cbData)
5308 HKEY hkeyPrinter, hkeySubkey;
5309 DWORD ret;
5311 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5312 debugstr_w(pValueName), Type, pData, cbData);
5314 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5315 != ERROR_SUCCESS)
5316 return ret;
5318 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5319 != ERROR_SUCCESS) {
5320 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5321 RegCloseKey(hkeyPrinter);
5322 return ret;
5324 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5325 RegCloseKey(hkeySubkey);
5326 RegCloseKey(hkeyPrinter);
5327 return ret;
5330 /******************************************************************************
5331 * SetPrinterDataA (WINSPOOL.@)
5333 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5334 LPBYTE pData, DWORD cbData)
5336 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5337 pData, cbData);
5340 /******************************************************************************
5341 * SetPrinterDataW (WINSPOOL.@)
5343 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5344 LPBYTE pData, DWORD cbData)
5346 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5347 pData, cbData);
5350 /******************************************************************************
5351 * GetPrinterDataExA (WINSPOOL.@)
5353 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5354 LPCSTR pValueName, LPDWORD pType,
5355 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5357 opened_printer_t *printer;
5358 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5359 DWORD ret;
5361 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5362 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5364 printer = get_opened_printer(hPrinter);
5365 if(!printer) return ERROR_INVALID_HANDLE;
5367 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5368 if (ret) return ret;
5370 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5372 if (printer->name) {
5374 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5375 if (ret) {
5376 RegCloseKey(hkeyPrinters);
5377 return ret;
5379 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5380 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5381 RegCloseKey(hkeyPrinter);
5382 RegCloseKey(hkeyPrinters);
5383 return ret;
5386 *pcbNeeded = nSize;
5387 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5388 0, pType, pData, pcbNeeded);
5390 if (!ret && !pData) ret = ERROR_MORE_DATA;
5392 RegCloseKey(hkeySubkey);
5393 RegCloseKey(hkeyPrinter);
5394 RegCloseKey(hkeyPrinters);
5396 TRACE("--> %d\n", ret);
5397 return ret;
5400 /******************************************************************************
5401 * GetPrinterDataExW (WINSPOOL.@)
5403 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5404 LPCWSTR pValueName, LPDWORD pType,
5405 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5407 opened_printer_t *printer;
5408 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5409 DWORD ret;
5411 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5412 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5414 printer = get_opened_printer(hPrinter);
5415 if(!printer) return ERROR_INVALID_HANDLE;
5417 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5418 if (ret) return ret;
5420 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5422 if (printer->name) {
5424 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5425 if (ret) {
5426 RegCloseKey(hkeyPrinters);
5427 return ret;
5429 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5430 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5431 RegCloseKey(hkeyPrinter);
5432 RegCloseKey(hkeyPrinters);
5433 return ret;
5436 *pcbNeeded = nSize;
5437 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5438 0, pType, pData, pcbNeeded);
5440 if (!ret && !pData) ret = ERROR_MORE_DATA;
5442 RegCloseKey(hkeySubkey);
5443 RegCloseKey(hkeyPrinter);
5444 RegCloseKey(hkeyPrinters);
5446 TRACE("--> %d\n", ret);
5447 return ret;
5450 /******************************************************************************
5451 * GetPrinterDataA (WINSPOOL.@)
5453 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5454 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5456 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5457 pData, nSize, pcbNeeded);
5460 /******************************************************************************
5461 * GetPrinterDataW (WINSPOOL.@)
5463 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5464 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5466 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5467 pData, nSize, pcbNeeded);
5470 /*******************************************************************************
5471 * EnumPrinterDataExW [WINSPOOL.@]
5473 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5474 LPBYTE pEnumValues, DWORD cbEnumValues,
5475 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5477 HKEY hkPrinter, hkSubKey;
5478 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5479 cbValueNameLen, cbMaxValueLen, cbValueLen,
5480 cbBufSize, dwType;
5481 LPWSTR lpValueName;
5482 HANDLE hHeap;
5483 PBYTE lpValue;
5484 PPRINTER_ENUM_VALUESW ppev;
5486 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5488 if (pKeyName == NULL || *pKeyName == 0)
5489 return ERROR_INVALID_PARAMETER;
5491 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5492 if (ret != ERROR_SUCCESS)
5494 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5495 hPrinter, ret);
5496 return ret;
5499 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5500 if (ret != ERROR_SUCCESS)
5502 r = RegCloseKey (hkPrinter);
5503 if (r != ERROR_SUCCESS)
5504 WARN ("RegCloseKey returned %i\n", r);
5505 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5506 debugstr_w (pKeyName), ret);
5507 return ret;
5510 ret = RegCloseKey (hkPrinter);
5511 if (ret != ERROR_SUCCESS)
5513 ERR ("RegCloseKey returned %i\n", ret);
5514 r = RegCloseKey (hkSubKey);
5515 if (r != ERROR_SUCCESS)
5516 WARN ("RegCloseKey returned %i\n", r);
5517 return ret;
5520 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5521 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5522 if (ret != ERROR_SUCCESS)
5524 r = RegCloseKey (hkSubKey);
5525 if (r != ERROR_SUCCESS)
5526 WARN ("RegCloseKey returned %i\n", r);
5527 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5528 return ret;
5531 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5532 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5534 if (cValues == 0) /* empty key */
5536 r = RegCloseKey (hkSubKey);
5537 if (r != ERROR_SUCCESS)
5538 WARN ("RegCloseKey returned %i\n", r);
5539 *pcbEnumValues = *pnEnumValues = 0;
5540 return ERROR_SUCCESS;
5543 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5545 hHeap = GetProcessHeap ();
5546 if (hHeap == NULL)
5548 ERR ("GetProcessHeap failed\n");
5549 r = RegCloseKey (hkSubKey);
5550 if (r != ERROR_SUCCESS)
5551 WARN ("RegCloseKey returned %i\n", r);
5552 return ERROR_OUTOFMEMORY;
5555 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5556 if (lpValueName == NULL)
5558 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5559 r = RegCloseKey (hkSubKey);
5560 if (r != ERROR_SUCCESS)
5561 WARN ("RegCloseKey returned %i\n", r);
5562 return ERROR_OUTOFMEMORY;
5565 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5566 if (lpValue == NULL)
5568 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5569 if (HeapFree (hHeap, 0, lpValueName) == 0)
5570 WARN ("HeapFree failed with code %i\n", GetLastError ());
5571 r = RegCloseKey (hkSubKey);
5572 if (r != ERROR_SUCCESS)
5573 WARN ("RegCloseKey returned %i\n", r);
5574 return ERROR_OUTOFMEMORY;
5577 TRACE ("pass 1: calculating buffer required for all names and values\n");
5579 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5581 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5583 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5585 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5586 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5587 NULL, NULL, lpValue, &cbValueLen);
5588 if (ret != ERROR_SUCCESS)
5590 if (HeapFree (hHeap, 0, lpValue) == 0)
5591 WARN ("HeapFree failed with code %i\n", GetLastError ());
5592 if (HeapFree (hHeap, 0, lpValueName) == 0)
5593 WARN ("HeapFree failed with code %i\n", GetLastError ());
5594 r = RegCloseKey (hkSubKey);
5595 if (r != ERROR_SUCCESS)
5596 WARN ("RegCloseKey returned %i\n", r);
5597 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5598 return ret;
5601 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5602 debugstr_w (lpValueName), dwIndex,
5603 cbValueNameLen + 1, cbValueLen);
5605 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5606 cbBufSize += cbValueLen;
5609 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5611 *pcbEnumValues = cbBufSize;
5612 *pnEnumValues = cValues;
5614 if (cbEnumValues < cbBufSize) /* buffer too small */
5616 if (HeapFree (hHeap, 0, lpValue) == 0)
5617 WARN ("HeapFree failed with code %i\n", GetLastError ());
5618 if (HeapFree (hHeap, 0, lpValueName) == 0)
5619 WARN ("HeapFree failed with code %i\n", GetLastError ());
5620 r = RegCloseKey (hkSubKey);
5621 if (r != ERROR_SUCCESS)
5622 WARN ("RegCloseKey returned %i\n", r);
5623 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5624 return ERROR_MORE_DATA;
5627 TRACE ("pass 2: copying all names and values to buffer\n");
5629 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5630 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5632 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5634 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5635 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5636 NULL, &dwType, lpValue, &cbValueLen);
5637 if (ret != ERROR_SUCCESS)
5639 if (HeapFree (hHeap, 0, lpValue) == 0)
5640 WARN ("HeapFree failed with code %i\n", GetLastError ());
5641 if (HeapFree (hHeap, 0, lpValueName) == 0)
5642 WARN ("HeapFree failed with code %i\n", GetLastError ());
5643 r = RegCloseKey (hkSubKey);
5644 if (r != ERROR_SUCCESS)
5645 WARN ("RegCloseKey returned %i\n", r);
5646 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5647 return ret;
5650 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5651 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5652 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5653 pEnumValues += cbValueNameLen;
5655 /* return # of *bytes* (including trailing \0), not # of chars */
5656 ppev[dwIndex].cbValueName = cbValueNameLen;
5658 ppev[dwIndex].dwType = dwType;
5660 memcpy (pEnumValues, lpValue, cbValueLen);
5661 ppev[dwIndex].pData = pEnumValues;
5662 pEnumValues += cbValueLen;
5664 ppev[dwIndex].cbData = cbValueLen;
5666 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5667 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5670 if (HeapFree (hHeap, 0, lpValue) == 0)
5672 ret = GetLastError ();
5673 ERR ("HeapFree failed with code %i\n", ret);
5674 if (HeapFree (hHeap, 0, lpValueName) == 0)
5675 WARN ("HeapFree failed with code %i\n", GetLastError ());
5676 r = RegCloseKey (hkSubKey);
5677 if (r != ERROR_SUCCESS)
5678 WARN ("RegCloseKey returned %i\n", r);
5679 return ret;
5682 if (HeapFree (hHeap, 0, lpValueName) == 0)
5684 ret = GetLastError ();
5685 ERR ("HeapFree failed with code %i\n", ret);
5686 r = RegCloseKey (hkSubKey);
5687 if (r != ERROR_SUCCESS)
5688 WARN ("RegCloseKey returned %i\n", r);
5689 return ret;
5692 ret = RegCloseKey (hkSubKey);
5693 if (ret != ERROR_SUCCESS)
5695 ERR ("RegCloseKey returned %i\n", ret);
5696 return ret;
5699 return ERROR_SUCCESS;
5702 /*******************************************************************************
5703 * EnumPrinterDataExA [WINSPOOL.@]
5705 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5706 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5707 * what Windows 2000 SP1 does.
5710 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5711 LPBYTE pEnumValues, DWORD cbEnumValues,
5712 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5714 INT len;
5715 LPWSTR pKeyNameW;
5716 DWORD ret, dwIndex, dwBufSize;
5717 HANDLE hHeap;
5718 LPSTR pBuffer;
5720 TRACE ("%p %s\n", hPrinter, pKeyName);
5722 if (pKeyName == NULL || *pKeyName == 0)
5723 return ERROR_INVALID_PARAMETER;
5725 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5726 if (len == 0)
5728 ret = GetLastError ();
5729 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5730 return ret;
5733 hHeap = GetProcessHeap ();
5734 if (hHeap == NULL)
5736 ERR ("GetProcessHeap failed\n");
5737 return ERROR_OUTOFMEMORY;
5740 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5741 if (pKeyNameW == NULL)
5743 ERR ("Failed to allocate %i bytes from process heap\n",
5744 (LONG)(len * sizeof (WCHAR)));
5745 return ERROR_OUTOFMEMORY;
5748 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5750 ret = GetLastError ();
5751 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5752 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5753 WARN ("HeapFree failed with code %i\n", GetLastError ());
5754 return ret;
5757 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5758 pcbEnumValues, pnEnumValues);
5759 if (ret != ERROR_SUCCESS)
5761 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5762 WARN ("HeapFree failed with code %i\n", GetLastError ());
5763 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5764 return ret;
5767 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5769 ret = GetLastError ();
5770 ERR ("HeapFree failed with code %i\n", ret);
5771 return ret;
5774 if (*pnEnumValues == 0) /* empty key */
5775 return ERROR_SUCCESS;
5777 dwBufSize = 0;
5778 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5780 PPRINTER_ENUM_VALUESW ppev =
5781 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5783 if (dwBufSize < ppev->cbValueName)
5784 dwBufSize = ppev->cbValueName;
5786 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5787 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5788 dwBufSize = ppev->cbData;
5791 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5793 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5794 if (pBuffer == NULL)
5796 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5797 return ERROR_OUTOFMEMORY;
5800 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5802 PPRINTER_ENUM_VALUESW ppev =
5803 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5805 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5806 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5807 NULL);
5808 if (len == 0)
5810 ret = GetLastError ();
5811 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5812 if (HeapFree (hHeap, 0, pBuffer) == 0)
5813 WARN ("HeapFree failed with code %i\n", GetLastError ());
5814 return ret;
5817 memcpy (ppev->pValueName, pBuffer, len);
5819 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5821 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5822 ppev->dwType != REG_MULTI_SZ)
5823 continue;
5825 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5826 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5827 if (len == 0)
5829 ret = GetLastError ();
5830 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5831 if (HeapFree (hHeap, 0, pBuffer) == 0)
5832 WARN ("HeapFree failed with code %i\n", GetLastError ());
5833 return ret;
5836 memcpy (ppev->pData, pBuffer, len);
5838 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5839 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5842 if (HeapFree (hHeap, 0, pBuffer) == 0)
5844 ret = GetLastError ();
5845 ERR ("HeapFree failed with code %i\n", ret);
5846 return ret;
5849 return ERROR_SUCCESS;
5852 /******************************************************************************
5853 * AbortPrinter (WINSPOOL.@)
5855 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5857 FIXME("(%p), stub!\n", hPrinter);
5858 return TRUE;
5861 /******************************************************************************
5862 * AddPortA (WINSPOOL.@)
5864 * See AddPortW.
5867 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5869 LPWSTR nameW = NULL;
5870 LPWSTR monitorW = NULL;
5871 DWORD len;
5872 BOOL res;
5874 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5876 if (pName) {
5877 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5878 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5879 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5882 if (pMonitorName) {
5883 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5884 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5885 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5887 res = AddPortW(nameW, hWnd, monitorW);
5888 HeapFree(GetProcessHeap(), 0, nameW);
5889 HeapFree(GetProcessHeap(), 0, monitorW);
5890 return res;
5893 /******************************************************************************
5894 * AddPortW (WINSPOOL.@)
5896 * Add a Port for a specific Monitor
5898 * PARAMS
5899 * pName [I] Servername or NULL (local Computer)
5900 * hWnd [I] Handle to parent Window for the Dialog-Box
5901 * pMonitorName [I] Name of the Monitor that manage the Port
5903 * RETURNS
5904 * Success: TRUE
5905 * Failure: FALSE
5908 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5910 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5912 if ((backend == NULL) && !load_backend()) return FALSE;
5914 if (!pMonitorName) {
5915 SetLastError(RPC_X_NULL_REF_POINTER);
5916 return FALSE;
5919 return backend->fpAddPort(pName, hWnd, pMonitorName);
5922 /******************************************************************************
5923 * AddPortExA (WINSPOOL.@)
5925 * See AddPortExW.
5928 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5930 PORT_INFO_2W pi2W;
5931 PORT_INFO_2A * pi2A;
5932 LPWSTR nameW = NULL;
5933 LPWSTR monitorW = NULL;
5934 DWORD len;
5935 BOOL res;
5937 pi2A = (PORT_INFO_2A *) pBuffer;
5939 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5940 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5942 if ((level < 1) || (level > 2)) {
5943 SetLastError(ERROR_INVALID_LEVEL);
5944 return FALSE;
5947 if (!pi2A) {
5948 SetLastError(ERROR_INVALID_PARAMETER);
5949 return FALSE;
5952 if (pName) {
5953 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5954 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5955 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5958 if (pMonitorName) {
5959 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5960 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5961 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5964 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5966 if (pi2A->pPortName) {
5967 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5968 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5969 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5972 if (level > 1) {
5973 if (pi2A->pMonitorName) {
5974 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5975 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5976 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5979 if (pi2A->pDescription) {
5980 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5981 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5982 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5984 pi2W.fPortType = pi2A->fPortType;
5985 pi2W.Reserved = pi2A->Reserved;
5988 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
5990 HeapFree(GetProcessHeap(), 0, nameW);
5991 HeapFree(GetProcessHeap(), 0, monitorW);
5992 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
5993 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
5994 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
5995 return res;
5999 /******************************************************************************
6000 * AddPortExW (WINSPOOL.@)
6002 * Add a Port for a specific Monitor, without presenting a user interface
6004 * PARAMS
6005 * pName [I] Servername or NULL (local Computer)
6006 * level [I] Structure-Level (1 or 2) for pBuffer
6007 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6008 * pMonitorName [I] Name of the Monitor that manage the Port
6010 * RETURNS
6011 * Success: TRUE
6012 * Failure: FALSE
6015 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6017 PORT_INFO_2W * pi2;
6019 pi2 = (PORT_INFO_2W *) pBuffer;
6021 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6022 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6023 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6024 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6026 if ((backend == NULL) && !load_backend()) return FALSE;
6028 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6029 SetLastError(ERROR_INVALID_PARAMETER);
6030 return FALSE;
6033 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6036 /******************************************************************************
6037 * AddPrinterConnectionA (WINSPOOL.@)
6039 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6041 FIXME("%s\n", debugstr_a(pName));
6042 return FALSE;
6045 /******************************************************************************
6046 * AddPrinterConnectionW (WINSPOOL.@)
6048 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6050 FIXME("%s\n", debugstr_w(pName));
6051 return FALSE;
6054 /******************************************************************************
6055 * AddPrinterDriverExW (WINSPOOL.@)
6057 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6059 * PARAMS
6060 * pName [I] Servername or NULL (local Computer)
6061 * level [I] Level for the supplied DRIVER_INFO_*W struct
6062 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6063 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6065 * RESULTS
6066 * Success: TRUE
6067 * Failure: FALSE
6070 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6072 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6074 if ((backend == NULL) && !load_backend()) return FALSE;
6076 if (level < 2 || level == 5 || level == 7 || level > 8) {
6077 SetLastError(ERROR_INVALID_LEVEL);
6078 return FALSE;
6081 if (!pDriverInfo) {
6082 SetLastError(ERROR_INVALID_PARAMETER);
6083 return FALSE;
6086 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6089 /******************************************************************************
6090 * AddPrinterDriverExA (WINSPOOL.@)
6092 * See AddPrinterDriverExW.
6095 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6097 DRIVER_INFO_8A *diA;
6098 DRIVER_INFO_8W diW;
6099 LPWSTR nameW = NULL;
6100 DWORD lenA;
6101 DWORD len;
6102 DWORD res = FALSE;
6104 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6106 diA = (DRIVER_INFO_8A *) pDriverInfo;
6107 ZeroMemory(&diW, sizeof(diW));
6109 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6110 SetLastError(ERROR_INVALID_LEVEL);
6111 return FALSE;
6114 if (diA == NULL) {
6115 SetLastError(ERROR_INVALID_PARAMETER);
6116 return FALSE;
6119 /* convert servername to unicode */
6120 if (pName) {
6121 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6122 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6123 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6126 /* common fields */
6127 diW.cVersion = diA->cVersion;
6129 if (diA->pName) {
6130 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6131 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6132 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6135 if (diA->pEnvironment) {
6136 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6137 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6138 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6141 if (diA->pDriverPath) {
6142 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6143 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6144 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6147 if (diA->pDataFile) {
6148 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6149 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6150 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6153 if (diA->pConfigFile) {
6154 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6155 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6156 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6159 if ((Level > 2) && diA->pDependentFiles) {
6160 lenA = multi_sz_lenA(diA->pDependentFiles);
6161 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6162 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6163 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6166 if ((Level > 2) && diA->pMonitorName) {
6167 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6168 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6169 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6172 if ((Level > 3) && diA->pDefaultDataType) {
6173 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6174 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6175 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6178 if ((Level > 3) && diA->pszzPreviousNames) {
6179 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6180 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6181 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6182 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6185 if ((Level > 5) && diA->pszMfgName) {
6186 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6187 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6188 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6191 if ((Level > 5) && diA->pszOEMUrl) {
6192 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6193 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6194 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6197 if ((Level > 5) && diA->pszHardwareID) {
6198 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6199 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6200 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6203 if ((Level > 5) && diA->pszProvider) {
6204 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6205 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6206 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6209 if (Level > 7) {
6210 FIXME("level %u is incomplete\n", Level);
6213 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6214 TRACE("got %u with %u\n", res, GetLastError());
6215 HeapFree(GetProcessHeap(), 0, nameW);
6216 HeapFree(GetProcessHeap(), 0, diW.pName);
6217 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6218 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6219 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6220 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6221 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6222 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6223 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6224 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6225 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6226 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6227 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6228 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6230 TRACE("=> %u with %u\n", res, GetLastError());
6231 return res;
6234 /******************************************************************************
6235 * ConfigurePortA (WINSPOOL.@)
6237 * See ConfigurePortW.
6240 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6242 LPWSTR nameW = NULL;
6243 LPWSTR portW = NULL;
6244 INT len;
6245 DWORD res;
6247 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6249 /* convert servername to unicode */
6250 if (pName) {
6251 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6252 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6253 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6256 /* convert portname to unicode */
6257 if (pPortName) {
6258 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6259 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6260 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6263 res = ConfigurePortW(nameW, hWnd, portW);
6264 HeapFree(GetProcessHeap(), 0, nameW);
6265 HeapFree(GetProcessHeap(), 0, portW);
6266 return res;
6269 /******************************************************************************
6270 * ConfigurePortW (WINSPOOL.@)
6272 * Display the Configuration-Dialog for a specific Port
6274 * PARAMS
6275 * pName [I] Servername or NULL (local Computer)
6276 * hWnd [I] Handle to parent Window for the Dialog-Box
6277 * pPortName [I] Name of the Port, that should be configured
6279 * RETURNS
6280 * Success: TRUE
6281 * Failure: FALSE
6284 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6287 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6289 if ((backend == NULL) && !load_backend()) return FALSE;
6291 if (!pPortName) {
6292 SetLastError(RPC_X_NULL_REF_POINTER);
6293 return FALSE;
6296 return backend->fpConfigurePort(pName, hWnd, pPortName);
6299 /******************************************************************************
6300 * ConnectToPrinterDlg (WINSPOOL.@)
6302 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6304 FIXME("%p %x\n", hWnd, Flags);
6305 return NULL;
6308 /******************************************************************************
6309 * DeletePrinterConnectionA (WINSPOOL.@)
6311 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6313 FIXME("%s\n", debugstr_a(pName));
6314 return TRUE;
6317 /******************************************************************************
6318 * DeletePrinterConnectionW (WINSPOOL.@)
6320 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6322 FIXME("%s\n", debugstr_w(pName));
6323 return TRUE;
6326 /******************************************************************************
6327 * DeletePrinterDriverExW (WINSPOOL.@)
6329 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6330 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6332 HKEY hkey_drivers;
6333 BOOL ret = FALSE;
6335 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6336 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6338 if(pName && pName[0])
6340 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6341 SetLastError(ERROR_INVALID_PARAMETER);
6342 return FALSE;
6345 if(dwDeleteFlag)
6347 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6348 SetLastError(ERROR_INVALID_PARAMETER);
6349 return FALSE;
6352 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6354 if(!hkey_drivers)
6356 ERR("Can't open drivers key\n");
6357 return FALSE;
6360 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6361 ret = TRUE;
6363 RegCloseKey(hkey_drivers);
6365 return ret;
6368 /******************************************************************************
6369 * DeletePrinterDriverExA (WINSPOOL.@)
6371 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6372 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6374 UNICODE_STRING NameW, EnvW, DriverW;
6375 BOOL ret;
6377 asciitounicode(&NameW, pName);
6378 asciitounicode(&EnvW, pEnvironment);
6379 asciitounicode(&DriverW, pDriverName);
6381 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6383 RtlFreeUnicodeString(&DriverW);
6384 RtlFreeUnicodeString(&EnvW);
6385 RtlFreeUnicodeString(&NameW);
6387 return ret;
6390 /******************************************************************************
6391 * DeletePrinterDataExW (WINSPOOL.@)
6393 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6394 LPCWSTR pValueName)
6396 FIXME("%p %s %s\n", hPrinter,
6397 debugstr_w(pKeyName), debugstr_w(pValueName));
6398 return ERROR_INVALID_PARAMETER;
6401 /******************************************************************************
6402 * DeletePrinterDataExA (WINSPOOL.@)
6404 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6405 LPCSTR pValueName)
6407 FIXME("%p %s %s\n", hPrinter,
6408 debugstr_a(pKeyName), debugstr_a(pValueName));
6409 return ERROR_INVALID_PARAMETER;
6412 /******************************************************************************
6413 * DeletePrintProcessorA (WINSPOOL.@)
6415 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6417 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6418 debugstr_a(pPrintProcessorName));
6419 return TRUE;
6422 /******************************************************************************
6423 * DeletePrintProcessorW (WINSPOOL.@)
6425 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6427 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6428 debugstr_w(pPrintProcessorName));
6429 return TRUE;
6432 /******************************************************************************
6433 * DeletePrintProvidorA (WINSPOOL.@)
6435 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6437 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6438 debugstr_a(pPrintProviderName));
6439 return TRUE;
6442 /******************************************************************************
6443 * DeletePrintProvidorW (WINSPOOL.@)
6445 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6447 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6448 debugstr_w(pPrintProviderName));
6449 return TRUE;
6452 /******************************************************************************
6453 * EnumFormsA (WINSPOOL.@)
6455 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6456 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6458 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6459 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6460 return FALSE;
6463 /******************************************************************************
6464 * EnumFormsW (WINSPOOL.@)
6466 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6467 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6469 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6470 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6471 return FALSE;
6474 /*****************************************************************************
6475 * EnumMonitorsA [WINSPOOL.@]
6477 * See EnumMonitorsW.
6480 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6481 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6483 BOOL res;
6484 LPBYTE bufferW = NULL;
6485 LPWSTR nameW = NULL;
6486 DWORD needed = 0;
6487 DWORD numentries = 0;
6488 INT len;
6490 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6491 cbBuf, pcbNeeded, pcReturned);
6493 /* convert servername to unicode */
6494 if (pName) {
6495 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6496 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6497 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6499 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6500 needed = cbBuf * sizeof(WCHAR);
6501 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6502 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6504 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6505 if (pcbNeeded) needed = *pcbNeeded;
6506 /* HeapReAlloc return NULL, when bufferW was NULL */
6507 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6508 HeapAlloc(GetProcessHeap(), 0, needed);
6510 /* Try again with the large Buffer */
6511 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6513 numentries = pcReturned ? *pcReturned : 0;
6514 needed = 0;
6516 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6517 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6519 if (res) {
6520 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6521 DWORD entrysize = 0;
6522 DWORD index;
6523 LPSTR ptr;
6524 LPMONITOR_INFO_2W mi2w;
6525 LPMONITOR_INFO_2A mi2a;
6527 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6528 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6530 /* First pass: calculate the size for all Entries */
6531 mi2w = (LPMONITOR_INFO_2W) bufferW;
6532 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6533 index = 0;
6534 while (index < numentries) {
6535 index++;
6536 needed += entrysize; /* MONITOR_INFO_?A */
6537 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6539 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6540 NULL, 0, NULL, NULL);
6541 if (Level > 1) {
6542 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6543 NULL, 0, NULL, NULL);
6544 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6545 NULL, 0, NULL, NULL);
6547 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6548 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6549 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6552 /* check for errors and quit on failure */
6553 if (cbBuf < needed) {
6554 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6555 res = FALSE;
6556 goto emA_cleanup;
6558 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6559 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6560 cbBuf -= len ; /* free Bytes in the user-Buffer */
6561 mi2w = (LPMONITOR_INFO_2W) bufferW;
6562 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6563 index = 0;
6564 /* Second Pass: Fill the User Buffer (if we have one) */
6565 while ((index < numentries) && pMonitors) {
6566 index++;
6567 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6568 mi2a->pName = ptr;
6569 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6570 ptr, cbBuf , NULL, NULL);
6571 ptr += len;
6572 cbBuf -= len;
6573 if (Level > 1) {
6574 mi2a->pEnvironment = ptr;
6575 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6576 ptr, cbBuf, NULL, NULL);
6577 ptr += len;
6578 cbBuf -= len;
6580 mi2a->pDLLName = ptr;
6581 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6582 ptr, cbBuf, NULL, NULL);
6583 ptr += len;
6584 cbBuf -= len;
6586 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6587 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6588 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6591 emA_cleanup:
6592 if (pcbNeeded) *pcbNeeded = needed;
6593 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6595 HeapFree(GetProcessHeap(), 0, nameW);
6596 HeapFree(GetProcessHeap(), 0, bufferW);
6598 TRACE("returning %d with %d (%d byte for %d entries)\n",
6599 (res), GetLastError(), needed, numentries);
6601 return (res);
6605 /*****************************************************************************
6606 * EnumMonitorsW [WINSPOOL.@]
6608 * Enumerate available Port-Monitors
6610 * PARAMS
6611 * pName [I] Servername or NULL (local Computer)
6612 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6613 * pMonitors [O] PTR to Buffer that receives the Result
6614 * cbBuf [I] Size of Buffer at pMonitors
6615 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6616 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6618 * RETURNS
6619 * Success: TRUE
6620 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6623 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6624 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6627 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6628 cbBuf, pcbNeeded, pcReturned);
6630 if ((backend == NULL) && !load_backend()) return FALSE;
6632 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6633 SetLastError(RPC_X_NULL_REF_POINTER);
6634 return FALSE;
6637 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6640 /******************************************************************************
6641 * SpoolerInit (WINSPOOL.@)
6643 * Initialize the Spooler
6645 * RETURNS
6646 * Success: TRUE
6647 * Failure: FALSE
6649 * NOTES
6650 * The function fails on windows, when the spooler service is not running
6653 BOOL WINAPI SpoolerInit(void)
6656 if ((backend == NULL) && !load_backend()) return FALSE;
6657 return TRUE;
6660 /******************************************************************************
6661 * XcvDataW (WINSPOOL.@)
6663 * Execute commands in the Printmonitor DLL
6665 * PARAMS
6666 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6667 * pszDataName [i] Name of the command to execute
6668 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6669 * cbInputData [i] Size in Bytes of Buffer at pInputData
6670 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6671 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6672 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6673 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6675 * RETURNS
6676 * Success: TRUE
6677 * Failure: FALSE
6679 * NOTES
6680 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6681 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6683 * Minimal List of commands, that a Printmonitor DLL should support:
6685 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6686 *| "AddPort" : Add a Port
6687 *| "DeletePort": Delete a Port
6689 * Many Printmonitors support additional commands. Examples for localspl.dll:
6690 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6691 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6694 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6695 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6696 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6698 opened_printer_t *printer;
6700 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6701 pInputData, cbInputData, pOutputData,
6702 cbOutputData, pcbOutputNeeded, pdwStatus);
6704 if ((backend == NULL) && !load_backend()) return FALSE;
6706 printer = get_opened_printer(hXcv);
6707 if (!printer || (!printer->backend_printer)) {
6708 SetLastError(ERROR_INVALID_HANDLE);
6709 return FALSE;
6712 if (!pcbOutputNeeded) {
6713 SetLastError(ERROR_INVALID_PARAMETER);
6714 return FALSE;
6717 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6718 SetLastError(RPC_X_NULL_REF_POINTER);
6719 return FALSE;
6722 *pcbOutputNeeded = 0;
6724 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6725 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6729 /*****************************************************************************
6730 * EnumPrinterDataA [WINSPOOL.@]
6733 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6734 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6735 DWORD cbData, LPDWORD pcbData )
6737 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6738 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6739 return ERROR_NO_MORE_ITEMS;
6742 /*****************************************************************************
6743 * EnumPrinterDataW [WINSPOOL.@]
6746 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6747 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6748 DWORD cbData, LPDWORD pcbData )
6750 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6751 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6752 return ERROR_NO_MORE_ITEMS;
6755 /*****************************************************************************
6756 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6759 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6760 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6761 LPDWORD pcbNeeded, LPDWORD pcReturned)
6763 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6764 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6765 pcbNeeded, pcReturned);
6766 return FALSE;
6769 /*****************************************************************************
6770 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6773 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6774 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6775 LPDWORD pcbNeeded, LPDWORD pcReturned)
6777 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6778 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6779 pcbNeeded, pcReturned);
6780 return FALSE;
6783 /*****************************************************************************
6784 * EnumPrintProcessorsA [WINSPOOL.@]
6786 * See EnumPrintProcessorsW.
6789 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6790 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6792 BOOL res;
6793 LPBYTE bufferW = NULL;
6794 LPWSTR nameW = NULL;
6795 LPWSTR envW = NULL;
6796 DWORD needed = 0;
6797 DWORD numentries = 0;
6798 INT len;
6800 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6801 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6803 /* convert names to unicode */
6804 if (pName) {
6805 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6806 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6807 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6809 if (pEnvironment) {
6810 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6811 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6812 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6815 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6816 needed = cbBuf * sizeof(WCHAR);
6817 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6818 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6820 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6821 if (pcbNeeded) needed = *pcbNeeded;
6822 /* HeapReAlloc return NULL, when bufferW was NULL */
6823 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6824 HeapAlloc(GetProcessHeap(), 0, needed);
6826 /* Try again with the large Buffer */
6827 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6829 numentries = pcReturned ? *pcReturned : 0;
6830 needed = 0;
6832 if (res) {
6833 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6834 DWORD index;
6835 LPSTR ptr;
6836 PPRINTPROCESSOR_INFO_1W ppiw;
6837 PPRINTPROCESSOR_INFO_1A ppia;
6839 /* First pass: calculate the size for all Entries */
6840 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6841 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6842 index = 0;
6843 while (index < numentries) {
6844 index++;
6845 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6846 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6848 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6849 NULL, 0, NULL, NULL);
6851 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6852 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6855 /* check for errors and quit on failure */
6856 if (cbBuf < needed) {
6857 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6858 res = FALSE;
6859 goto epp_cleanup;
6862 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6863 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6864 cbBuf -= len ; /* free Bytes in the user-Buffer */
6865 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6866 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6867 index = 0;
6868 /* Second Pass: Fill the User Buffer (if we have one) */
6869 while ((index < numentries) && pPPInfo) {
6870 index++;
6871 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6872 ppia->pName = ptr;
6873 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6874 ptr, cbBuf , NULL, NULL);
6875 ptr += len;
6876 cbBuf -= len;
6878 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6879 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6883 epp_cleanup:
6884 if (pcbNeeded) *pcbNeeded = needed;
6885 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6887 HeapFree(GetProcessHeap(), 0, nameW);
6888 HeapFree(GetProcessHeap(), 0, envW);
6889 HeapFree(GetProcessHeap(), 0, bufferW);
6891 TRACE("returning %d with %d (%d byte for %d entries)\n",
6892 (res), GetLastError(), needed, numentries);
6894 return (res);
6897 /*****************************************************************************
6898 * EnumPrintProcessorsW [WINSPOOL.@]
6900 * Enumerate available Print Processors
6902 * PARAMS
6903 * pName [I] Servername or NULL (local Computer)
6904 * pEnvironment [I] Printing-Environment or NULL (Default)
6905 * Level [I] Structure-Level (Only 1 is allowed)
6906 * pPPInfo [O] PTR to Buffer that receives the Result
6907 * cbBuf [I] Size of Buffer at pPPInfo
6908 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6909 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6911 * RETURNS
6912 * Success: TRUE
6913 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6916 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6917 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6920 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6921 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6923 if ((backend == NULL) && !load_backend()) return FALSE;
6925 if (!pcbNeeded || !pcReturned) {
6926 SetLastError(RPC_X_NULL_REF_POINTER);
6927 return FALSE;
6930 if (!pPPInfo && (cbBuf > 0)) {
6931 SetLastError(ERROR_INVALID_USER_BUFFER);
6932 return FALSE;
6935 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6936 cbBuf, pcbNeeded, pcReturned);
6939 /*****************************************************************************
6940 * ExtDeviceMode [WINSPOOL.@]
6943 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6944 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6945 DWORD fMode)
6947 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6948 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6949 debugstr_a(pProfile), fMode);
6950 return -1;
6953 /*****************************************************************************
6954 * FindClosePrinterChangeNotification [WINSPOOL.@]
6957 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6959 FIXME("Stub: %p\n", hChange);
6960 return TRUE;
6963 /*****************************************************************************
6964 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6967 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6968 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6970 FIXME("Stub: %p %x %x %p\n",
6971 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6972 return INVALID_HANDLE_VALUE;
6975 /*****************************************************************************
6976 * FindNextPrinterChangeNotification [WINSPOOL.@]
6979 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6980 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6982 FIXME("Stub: %p %p %p %p\n",
6983 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6984 return FALSE;
6987 /*****************************************************************************
6988 * FreePrinterNotifyInfo [WINSPOOL.@]
6991 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6993 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6994 return TRUE;
6997 /*****************************************************************************
6998 * string_to_buf
7000 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7001 * ansi depending on the unicode parameter.
7003 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7005 if(!str)
7007 *size = 0;
7008 return TRUE;
7011 if(unicode)
7013 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7014 if(*size <= cb)
7016 memcpy(ptr, str, *size);
7017 return TRUE;
7019 return FALSE;
7021 else
7023 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7024 if(*size <= cb)
7026 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7027 return TRUE;
7029 return FALSE;
7033 /*****************************************************************************
7034 * get_job_info_1
7036 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7037 LPDWORD pcbNeeded, BOOL unicode)
7039 DWORD size, left = cbBuf;
7040 BOOL space = (cbBuf > 0);
7041 LPBYTE ptr = buf;
7043 *pcbNeeded = 0;
7045 if(space)
7047 ji1->JobId = job->job_id;
7050 string_to_buf(job->document_title, ptr, left, &size, unicode);
7051 if(space && size <= left)
7053 ji1->pDocument = (LPWSTR)ptr;
7054 ptr += size;
7055 left -= size;
7057 else
7058 space = FALSE;
7059 *pcbNeeded += size;
7061 return space;
7064 /*****************************************************************************
7065 * get_job_info_2
7067 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7068 LPDWORD pcbNeeded, BOOL unicode)
7070 DWORD size, left = cbBuf;
7071 BOOL space = (cbBuf > 0);
7072 LPBYTE ptr = buf;
7074 *pcbNeeded = 0;
7076 if(space)
7078 ji2->JobId = job->job_id;
7081 string_to_buf(job->document_title, ptr, left, &size, unicode);
7082 if(space && size <= left)
7084 ji2->pDocument = (LPWSTR)ptr;
7085 ptr += size;
7086 left -= size;
7088 else
7089 space = FALSE;
7090 *pcbNeeded += size;
7092 return space;
7095 /*****************************************************************************
7096 * get_job_info
7098 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7099 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7101 BOOL ret = FALSE;
7102 DWORD needed = 0, size;
7103 job_t *job;
7104 LPBYTE ptr = pJob;
7106 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7108 EnterCriticalSection(&printer_handles_cs);
7109 job = get_job(hPrinter, JobId);
7110 if(!job)
7111 goto end;
7113 switch(Level)
7115 case 1:
7116 size = sizeof(JOB_INFO_1W);
7117 if(cbBuf >= size)
7119 cbBuf -= size;
7120 ptr += size;
7121 memset(pJob, 0, size);
7123 else
7124 cbBuf = 0;
7125 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7126 needed += size;
7127 break;
7129 case 2:
7130 size = sizeof(JOB_INFO_2W);
7131 if(cbBuf >= size)
7133 cbBuf -= size;
7134 ptr += size;
7135 memset(pJob, 0, size);
7137 else
7138 cbBuf = 0;
7139 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7140 needed += size;
7141 break;
7143 case 3:
7144 size = sizeof(JOB_INFO_3);
7145 if(cbBuf >= size)
7147 cbBuf -= size;
7148 memset(pJob, 0, size);
7149 ret = TRUE;
7151 else
7152 cbBuf = 0;
7153 needed = size;
7154 break;
7156 default:
7157 SetLastError(ERROR_INVALID_LEVEL);
7158 goto end;
7160 if(pcbNeeded)
7161 *pcbNeeded = needed;
7162 end:
7163 LeaveCriticalSection(&printer_handles_cs);
7164 return ret;
7167 /*****************************************************************************
7168 * GetJobA [WINSPOOL.@]
7171 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7172 DWORD cbBuf, LPDWORD pcbNeeded)
7174 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7177 /*****************************************************************************
7178 * GetJobW [WINSPOOL.@]
7181 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7182 DWORD cbBuf, LPDWORD pcbNeeded)
7184 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7187 /*****************************************************************************
7188 * schedule_lpr
7190 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7192 char *unixname, *queue, *cmd;
7193 char fmt[] = "lpr -P%s %s";
7194 DWORD len;
7195 int r;
7197 if(!(unixname = wine_get_unix_file_name(filename)))
7198 return FALSE;
7200 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7201 queue = HeapAlloc(GetProcessHeap(), 0, len);
7202 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7204 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7205 sprintf(cmd, fmt, queue, unixname);
7207 TRACE("printing with: %s\n", cmd);
7208 r = system(cmd);
7210 HeapFree(GetProcessHeap(), 0, cmd);
7211 HeapFree(GetProcessHeap(), 0, queue);
7212 HeapFree(GetProcessHeap(), 0, unixname);
7213 return (r == 0);
7216 /*****************************************************************************
7217 * schedule_cups
7219 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7221 #ifdef SONAME_LIBCUPS
7222 if(pcupsPrintFile)
7224 char *unixname, *queue, *unix_doc_title;
7225 DWORD len;
7226 BOOL ret;
7228 if(!(unixname = wine_get_unix_file_name(filename)))
7229 return FALSE;
7231 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7232 queue = HeapAlloc(GetProcessHeap(), 0, len);
7233 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7235 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7236 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7237 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7239 TRACE("printing via cups\n");
7240 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7241 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7242 HeapFree(GetProcessHeap(), 0, queue);
7243 HeapFree(GetProcessHeap(), 0, unixname);
7244 return ret;
7246 else
7247 #endif
7249 return schedule_lpr(printer_name, filename);
7253 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7255 LPWSTR filename;
7257 switch(msg)
7259 case WM_INITDIALOG:
7260 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7261 return TRUE;
7263 case WM_COMMAND:
7264 if(HIWORD(wparam) == BN_CLICKED)
7266 if(LOWORD(wparam) == IDOK)
7268 HANDLE hf;
7269 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7270 LPWSTR *output;
7272 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7273 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7275 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7277 WCHAR caption[200], message[200];
7278 int mb_ret;
7280 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7281 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7282 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7283 if(mb_ret == IDCANCEL)
7285 HeapFree(GetProcessHeap(), 0, filename);
7286 return TRUE;
7289 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7290 if(hf == INVALID_HANDLE_VALUE)
7292 WCHAR caption[200], message[200];
7294 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7295 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7296 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7297 HeapFree(GetProcessHeap(), 0, filename);
7298 return TRUE;
7300 CloseHandle(hf);
7301 DeleteFileW(filename);
7302 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7303 *output = filename;
7304 EndDialog(hwnd, IDOK);
7305 return TRUE;
7307 if(LOWORD(wparam) == IDCANCEL)
7309 EndDialog(hwnd, IDCANCEL);
7310 return TRUE;
7313 return FALSE;
7315 return FALSE;
7318 /*****************************************************************************
7319 * get_filename
7321 static BOOL get_filename(LPWSTR *filename)
7323 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7324 file_dlg_proc, (LPARAM)filename) == IDOK;
7327 /*****************************************************************************
7328 * schedule_file
7330 static BOOL schedule_file(LPCWSTR filename)
7332 LPWSTR output = NULL;
7334 if(get_filename(&output))
7336 BOOL r;
7337 TRACE("copy to %s\n", debugstr_w(output));
7338 r = CopyFileW(filename, output, FALSE);
7339 HeapFree(GetProcessHeap(), 0, output);
7340 return r;
7342 return FALSE;
7345 /*****************************************************************************
7346 * schedule_pipe
7348 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7350 #ifdef HAVE_FORK
7351 char *unixname, *cmdA;
7352 DWORD len;
7353 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7354 BOOL ret = FALSE;
7355 char buf[1024];
7357 if(!(unixname = wine_get_unix_file_name(filename)))
7358 return FALSE;
7360 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7361 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7362 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7364 TRACE("printing with: %s\n", cmdA);
7366 if((file_fd = open(unixname, O_RDONLY)) == -1)
7367 goto end;
7369 if (pipe(fds))
7371 ERR("pipe() failed!\n");
7372 goto end;
7375 if (fork() == 0)
7377 close(0);
7378 dup2(fds[0], 0);
7379 close(fds[1]);
7381 /* reset signals that we previously set to SIG_IGN */
7382 signal(SIGPIPE, SIG_DFL);
7383 signal(SIGCHLD, SIG_DFL);
7385 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7386 _exit(1);
7389 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7390 write(fds[1], buf, no_read);
7392 ret = TRUE;
7394 end:
7395 if(file_fd != -1) close(file_fd);
7396 if(fds[0] != -1) close(fds[0]);
7397 if(fds[1] != -1) close(fds[1]);
7399 HeapFree(GetProcessHeap(), 0, cmdA);
7400 HeapFree(GetProcessHeap(), 0, unixname);
7401 return ret;
7402 #else
7403 return FALSE;
7404 #endif
7407 /*****************************************************************************
7408 * schedule_unixfile
7410 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7412 int in_fd, out_fd, no_read;
7413 char buf[1024];
7414 BOOL ret = FALSE;
7415 char *unixname, *outputA;
7416 DWORD len;
7418 if(!(unixname = wine_get_unix_file_name(filename)))
7419 return FALSE;
7421 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7422 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7423 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7425 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7426 in_fd = open(unixname, O_RDONLY);
7427 if(out_fd == -1 || in_fd == -1)
7428 goto end;
7430 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7431 write(out_fd, buf, no_read);
7433 ret = TRUE;
7434 end:
7435 if(in_fd != -1) close(in_fd);
7436 if(out_fd != -1) close(out_fd);
7437 HeapFree(GetProcessHeap(), 0, outputA);
7438 HeapFree(GetProcessHeap(), 0, unixname);
7439 return ret;
7442 /*****************************************************************************
7443 * ScheduleJob [WINSPOOL.@]
7446 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7448 opened_printer_t *printer;
7449 BOOL ret = FALSE;
7450 struct list *cursor, *cursor2;
7452 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7453 EnterCriticalSection(&printer_handles_cs);
7454 printer = get_opened_printer(hPrinter);
7455 if(!printer)
7456 goto end;
7458 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7460 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7461 HANDLE hf;
7463 if(job->job_id != dwJobID) continue;
7465 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7466 if(hf != INVALID_HANDLE_VALUE)
7468 PRINTER_INFO_5W *pi5;
7469 DWORD needed;
7470 HKEY hkey;
7471 WCHAR output[1024];
7472 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7473 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7475 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7476 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7477 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7478 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7479 debugstr_w(pi5->pPortName));
7481 output[0] = 0;
7483 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7484 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7486 DWORD type, count = sizeof(output);
7487 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7488 RegCloseKey(hkey);
7490 if(output[0] == '|')
7492 ret = schedule_pipe(output + 1, job->filename);
7494 else if(output[0])
7496 ret = schedule_unixfile(output, job->filename);
7498 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7500 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7502 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7504 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7506 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7508 ret = schedule_file(job->filename);
7510 else
7512 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7514 HeapFree(GetProcessHeap(), 0, pi5);
7515 CloseHandle(hf);
7516 DeleteFileW(job->filename);
7518 list_remove(cursor);
7519 HeapFree(GetProcessHeap(), 0, job->document_title);
7520 HeapFree(GetProcessHeap(), 0, job->filename);
7521 HeapFree(GetProcessHeap(), 0, job);
7522 break;
7524 end:
7525 LeaveCriticalSection(&printer_handles_cs);
7526 return ret;
7529 /*****************************************************************************
7530 * StartDocDlgA [WINSPOOL.@]
7532 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7534 UNICODE_STRING usBuffer;
7535 DOCINFOW docW;
7536 LPWSTR retW;
7537 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7538 LPSTR ret = NULL;
7540 docW.cbSize = sizeof(docW);
7541 if (doc->lpszDocName)
7543 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7544 if (!(docW.lpszDocName = docnameW)) return NULL;
7546 if (doc->lpszOutput)
7548 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7549 if (!(docW.lpszOutput = outputW)) return NULL;
7551 if (doc->lpszDatatype)
7553 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7554 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7556 docW.fwType = doc->fwType;
7558 retW = StartDocDlgW(hPrinter, &docW);
7560 if(retW)
7562 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7563 ret = HeapAlloc(GetProcessHeap(), 0, len);
7564 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7565 HeapFree(GetProcessHeap(), 0, retW);
7568 HeapFree(GetProcessHeap(), 0, datatypeW);
7569 HeapFree(GetProcessHeap(), 0, outputW);
7570 HeapFree(GetProcessHeap(), 0, docnameW);
7572 return ret;
7575 /*****************************************************************************
7576 * StartDocDlgW [WINSPOOL.@]
7578 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7579 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7580 * port is "FILE:". Also returns the full path if passed a relative path.
7582 * The caller should free the returned string from the process heap.
7584 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7586 LPWSTR ret = NULL;
7587 DWORD len, attr;
7589 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7591 PRINTER_INFO_5W *pi5;
7592 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7593 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7594 return NULL;
7595 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7596 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7597 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7599 HeapFree(GetProcessHeap(), 0, pi5);
7600 return NULL;
7602 HeapFree(GetProcessHeap(), 0, pi5);
7605 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7607 LPWSTR name;
7609 if (get_filename(&name))
7611 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7613 HeapFree(GetProcessHeap(), 0, name);
7614 return NULL;
7616 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7617 GetFullPathNameW(name, len, ret, NULL);
7618 HeapFree(GetProcessHeap(), 0, name);
7620 return ret;
7623 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7624 return NULL;
7626 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7627 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7629 attr = GetFileAttributesW(ret);
7630 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7632 HeapFree(GetProcessHeap(), 0, ret);
7633 ret = NULL;
7635 return ret;