jscript: Update the Polish translation.
[wine.git] / dlls / winspool.drv / info.c
blob7f6d12c724a5cbdbacbd5f1c0d5731eb522887f4
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
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 *portname;
101 WCHAR *document_title;
102 WCHAR *printer_name;
103 } job_t;
106 typedef struct {
107 LPCWSTR envname;
108 LPCWSTR subdir;
109 DWORD driverversion;
110 LPCWSTR versionregpath;
111 LPCWSTR versionsubdir;
112 } printenv_t;
114 /* ############################### */
116 static opened_printer_t **printer_handles;
117 static UINT nb_printer_handles;
118 static LONG next_job_id = 1;
120 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
121 WORD fwCapability, LPSTR lpszOutput,
122 LPDEVMODEA lpdm );
123 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
124 LPSTR lpszDevice, LPSTR lpszPort,
125 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
126 DWORD fwMode );
128 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
129 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
130 'c','o','n','t','r','o','l','\\',
131 'P','r','i','n','t','\\',
132 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
133 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
135 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'C','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'P','r','i','n','t','e','r','s',0};
141 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
143 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'W','i','n','d','o','w','s',0};
149 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
150 'M','i','c','r','o','s','o','f','t','\\',
151 'W','i','n','d','o','w','s',' ','N','T','\\',
152 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
153 'D','e','v','i','c','e','s',0};
155 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
156 'M','i','c','r','o','s','o','f','t','\\',
157 'W','i','n','d','o','w','s',' ','N','T','\\',
158 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
159 'P','o','r','t','s',0};
161 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
162 'M','i','c','r','o','s','o','f','t','\\',
163 'W','i','n','d','o','w','s',' ','N','T','\\',
164 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
165 'P','r','i','n','t','e','r','P','o','r','t','s',0};
167 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
168 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
169 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
170 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
171 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
172 static const WCHAR subdir_x64W[] = {'x','6','4',0};
173 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
174 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
175 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
176 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
177 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
179 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
180 static const WCHAR backslashW[] = {'\\',0};
181 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
182 'i','o','n',' ','F','i','l','e',0};
183 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
184 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
185 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
186 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
187 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
188 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
189 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
190 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
191 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
192 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
193 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
194 static const WCHAR NameW[] = {'N','a','m','e',0};
195 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
196 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
197 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
198 static const WCHAR PortW[] = {'P','o','r','t',0};
199 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
200 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
201 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
202 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
203 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
204 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
205 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
206 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
207 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
208 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
209 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
210 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
211 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
212 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
213 static const WCHAR emptyStringW[] = {0};
215 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
217 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
218 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
219 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
221 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
222 'D','o','c','u','m','e','n','t',0};
224 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
225 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
226 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
227 0, sizeof(DRIVER_INFO_8W)};
230 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
231 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
232 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
233 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
234 sizeof(PRINTER_INFO_9W)};
236 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
237 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
238 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
240 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
242 /******************************************************************
243 * validate the user-supplied printing-environment [internal]
245 * PARAMS
246 * env [I] PTR to Environment-String or NULL
248 * RETURNS
249 * Failure: NULL
250 * Success: PTR to printenv_t
252 * NOTES
253 * An empty string is handled the same way as NULL.
254 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
258 static const printenv_t * validate_envW(LPCWSTR env)
260 const printenv_t *result = NULL;
261 unsigned int i;
263 TRACE("testing %s\n", debugstr_w(env));
264 if (env && env[0])
266 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
268 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
270 result = all_printenv[i];
271 break;
275 if (result == NULL) {
276 FIXME("unsupported Environment: %s\n", debugstr_w(env));
277 SetLastError(ERROR_INVALID_ENVIRONMENT);
279 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
281 else
283 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
285 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
287 return result;
291 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
292 if passed a NULL string. This returns NULLs to the result.
294 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
296 if ( (src) )
298 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
299 return usBufferPtr->Buffer;
301 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
302 return NULL;
305 static LPWSTR strdupW(LPCWSTR p)
307 LPWSTR ret;
308 DWORD len;
310 if(!p) return NULL;
311 len = (strlenW(p) + 1) * sizeof(WCHAR);
312 ret = HeapAlloc(GetProcessHeap(), 0, len);
313 memcpy(ret, p, len);
314 return ret;
317 static LPSTR strdupWtoA( LPCWSTR str )
319 LPSTR ret;
320 INT len;
322 if (!str) return NULL;
323 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
324 ret = HeapAlloc( GetProcessHeap(), 0, len );
325 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
326 return ret;
329 /******************************************************************
330 * verify, that the filename is a local file
333 static inline BOOL is_local_file(LPWSTR name)
335 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
338 /******************************************************************
339 * Return the number of bytes for an multi_sz string.
340 * The result includes all \0s
341 * (specifically the extra \0, that is needed as multi_sz terminator).
343 #if 0
344 static int multi_sz_lenW(const WCHAR *str)
346 const WCHAR *ptr = str;
347 if(!str) return 0;
350 ptr += lstrlenW(ptr) + 1;
351 } while(*ptr);
353 return (ptr - str + 1) * sizeof(WCHAR);
355 #endif
356 /* ################################ */
358 static int multi_sz_lenA(const char *str)
360 const char *ptr = str;
361 if(!str) return 0;
364 ptr += lstrlenA(ptr) + 1;
365 } while(*ptr);
367 return ptr - str + 1;
370 static void
371 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
372 char qbuf[200];
374 /* If forcing, or no profile string entry for device yet, set the entry
376 * The always change entry if not WINEPS yet is discussable.
378 if (force ||
379 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
380 !strcmp(qbuf,"*") ||
381 !strstr(qbuf,"WINEPS.DRV")
383 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
384 HKEY hkey;
386 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
387 WriteProfileStringA("windows","device",buf);
388 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
389 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
390 RegCloseKey(hkey);
392 HeapFree(GetProcessHeap(),0,buf);
396 static BOOL add_printer_driver(const char *name)
398 DRIVER_INFO_3A di3a;
400 static char driver_9x[] = "wineps16.drv",
401 driver_nt[] = "wineps.drv",
402 env_9x[] = "Windows 4.0",
403 env_nt[] = "Windows NT x86",
404 data_file[] = "generic.ppd",
405 default_data_type[] = "RAW";
407 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
408 di3a.cVersion = 3;
409 di3a.pName = (char *)name;
410 di3a.pEnvironment = env_nt;
411 di3a.pDriverPath = driver_nt;
412 di3a.pDataFile = data_file;
413 di3a.pConfigFile = driver_nt;
414 di3a.pDefaultDataType = default_data_type;
416 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
417 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
419 di3a.cVersion = 0;
420 di3a.pEnvironment = env_9x;
421 di3a.pDriverPath = driver_9x;
422 di3a.pConfigFile = driver_9x;
423 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
424 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
426 return TRUE;
429 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
430 debugstr_a(di3a.pEnvironment), GetLastError());
431 return FALSE;
434 #ifdef SONAME_LIBCUPS
435 static typeof(cupsFreeDests) *pcupsFreeDests;
436 static typeof(cupsGetDests) *pcupsGetDests;
437 static typeof(cupsGetPPD) *pcupsGetPPD;
438 static typeof(cupsPrintFile) *pcupsPrintFile;
439 static void *cupshandle;
441 static BOOL CUPS_LoadPrinters(void)
443 int i, nrofdests;
444 BOOL hadprinter = FALSE, haddefault = FALSE;
445 cups_dest_t *dests;
446 PRINTER_INFO_2A pinfo2a;
447 char *port,*devline;
448 HKEY hkeyPrinter, hkeyPrinters, hkey;
449 char loaderror[256];
451 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
452 if (!cupshandle) {
453 TRACE("%s\n", loaderror);
454 return FALSE;
456 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
458 #define DYNCUPS(x) \
459 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
460 if (!p##x) return FALSE;
462 DYNCUPS(cupsFreeDests);
463 DYNCUPS(cupsGetPPD);
464 DYNCUPS(cupsGetDests);
465 DYNCUPS(cupsPrintFile);
466 #undef DYNCUPS
468 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
469 ERROR_SUCCESS) {
470 ERR("Can't create Printers key\n");
471 return FALSE;
474 nrofdests = pcupsGetDests(&dests);
475 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
476 for (i=0;i<nrofdests;i++) {
477 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
478 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
479 sprintf(port,"LPR:%s", dests[i].name);
480 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
481 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
482 sprintf(devline, "WINEPS.DRV,%s", port);
483 WriteProfileStringA("devices", dests[i].name, devline);
484 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
485 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
486 RegCloseKey(hkey);
489 lstrcatA(devline, ",15,45");
490 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
491 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
492 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
493 RegCloseKey(hkey);
496 HeapFree(GetProcessHeap(), 0, devline);
498 TRACE("Printer %d: %s\n", i, dests[i].name);
499 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
500 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
501 and continue */
502 TRACE("Printer already exists\n");
503 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
504 RegCloseKey(hkeyPrinter);
505 } else {
506 static CHAR data_type[] = "RAW",
507 print_proc[] = "WinPrint",
508 comment[] = "WINEPS Printer using CUPS",
509 location[] = "<physical location of printer>",
510 params[] = "<parameters?>",
511 share_name[] = "<share name?>",
512 sep_file[] = "<sep file?>";
514 add_printer_driver(dests[i].name);
516 memset(&pinfo2a,0,sizeof(pinfo2a));
517 pinfo2a.pPrinterName = dests[i].name;
518 pinfo2a.pDatatype = data_type;
519 pinfo2a.pPrintProcessor = print_proc;
520 pinfo2a.pDriverName = dests[i].name;
521 pinfo2a.pComment = comment;
522 pinfo2a.pLocation = location;
523 pinfo2a.pPortName = port;
524 pinfo2a.pParameters = params;
525 pinfo2a.pShareName = share_name;
526 pinfo2a.pSepFile = sep_file;
528 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
529 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
530 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
533 HeapFree(GetProcessHeap(),0,port);
535 hadprinter = TRUE;
536 if (dests[i].is_default) {
537 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
538 haddefault = TRUE;
541 if (hadprinter & !haddefault)
542 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
543 pcupsFreeDests(nrofdests, dests);
544 RegCloseKey(hkeyPrinters);
545 return hadprinter;
547 #endif
549 static BOOL
550 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
551 PRINTER_INFO_2A pinfo2a;
552 char *e,*s,*name,*prettyname,*devname;
553 BOOL ret = FALSE, set_default = FALSE;
554 char *port = NULL, *devline,*env_default;
555 HKEY hkeyPrinter, hkeyPrinters, hkey;
557 while (isspace(*pent)) pent++;
558 s = strchr(pent,':');
559 if(s) *s='\0';
560 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
561 strcpy(name,pent);
562 if(s) {
563 *s=':';
564 pent = s;
565 } else
566 pent = "";
568 TRACE("name=%s entry=%s\n",name, pent);
570 if(ispunct(*name)) { /* a tc entry, not a real printer */
571 TRACE("skipping tc entry\n");
572 goto end;
575 if(strstr(pent,":server")) { /* server only version so skip */
576 TRACE("skipping server entry\n");
577 goto end;
580 /* Determine whether this is a postscript printer. */
582 ret = TRUE;
583 env_default = getenv("PRINTER");
584 prettyname = name;
585 /* Get longest name, usually the one at the right for later display. */
586 while((s=strchr(prettyname,'|'))) {
587 *s = '\0';
588 e = s;
589 while(isspace(*--e)) *e = '\0';
590 TRACE("\t%s\n", debugstr_a(prettyname));
591 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
592 for(prettyname = s+1; isspace(*prettyname); prettyname++)
595 e = prettyname + strlen(prettyname);
596 while(isspace(*--e)) *e = '\0';
597 TRACE("\t%s\n", debugstr_a(prettyname));
598 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
600 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
601 * if it is too long, we use it as comment below. */
602 devname = prettyname;
603 if (strlen(devname)>=CCHDEVICENAME-1)
604 devname = name;
605 if (strlen(devname)>=CCHDEVICENAME-1) {
606 ret = FALSE;
607 goto end;
610 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
611 sprintf(port,"LPR:%s",name);
613 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
614 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
615 sprintf(devline, "WINEPS.DRV,%s", port);
616 WriteProfileStringA("devices", devname, devline);
617 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
618 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
619 RegCloseKey(hkey);
622 lstrcatA(devline, ",15,45");
623 WriteProfileStringA("PrinterPorts", devname, devline);
624 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
625 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
626 RegCloseKey(hkey);
629 HeapFree(GetProcessHeap(),0,devline);
631 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
632 ERROR_SUCCESS) {
633 ERR("Can't create Printers key\n");
634 ret = FALSE;
635 goto end;
637 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
638 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
639 and continue */
640 TRACE("Printer already exists\n");
641 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
642 RegCloseKey(hkeyPrinter);
643 } else {
644 static CHAR data_type[] = "RAW",
645 print_proc[] = "WinPrint",
646 comment[] = "WINEPS Printer using LPR",
647 params[] = "<parameters?>",
648 share_name[] = "<share name?>",
649 sep_file[] = "<sep file?>";
651 add_printer_driver(devname);
653 memset(&pinfo2a,0,sizeof(pinfo2a));
654 pinfo2a.pPrinterName = devname;
655 pinfo2a.pDatatype = data_type;
656 pinfo2a.pPrintProcessor = print_proc;
657 pinfo2a.pDriverName = devname;
658 pinfo2a.pComment = comment;
659 pinfo2a.pLocation = prettyname;
660 pinfo2a.pPortName = port;
661 pinfo2a.pParameters = params;
662 pinfo2a.pShareName = share_name;
663 pinfo2a.pSepFile = sep_file;
665 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
666 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
667 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
670 RegCloseKey(hkeyPrinters);
672 if (isfirst || set_default)
673 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
675 end:
676 HeapFree(GetProcessHeap(), 0, port);
677 HeapFree(GetProcessHeap(), 0, name);
678 return ret;
681 static BOOL
682 PRINTCAP_LoadPrinters(void) {
683 BOOL hadprinter = FALSE;
684 char buf[200];
685 FILE *f;
686 char *pent = NULL;
687 BOOL had_bash = FALSE;
689 f = fopen("/etc/printcap","r");
690 if (!f)
691 return FALSE;
693 while(fgets(buf,sizeof(buf),f)) {
694 char *start, *end;
696 end=strchr(buf,'\n');
697 if (end) *end='\0';
699 start = buf;
700 while(isspace(*start)) start++;
701 if(*start == '#' || *start == '\0')
702 continue;
704 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
705 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
706 HeapFree(GetProcessHeap(),0,pent);
707 pent = NULL;
710 if (end && *--end == '\\') {
711 *end = '\0';
712 had_bash = TRUE;
713 } else
714 had_bash = FALSE;
716 if (pent) {
717 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
718 strcat(pent,start);
719 } else {
720 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
721 strcpy(pent,start);
725 if(pent) {
726 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
727 HeapFree(GetProcessHeap(),0,pent);
729 fclose(f);
730 return hadprinter;
733 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
735 if (value)
736 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
737 (lstrlenW(value) + 1) * sizeof(WCHAR));
738 else
739 return ERROR_FILE_NOT_FOUND;
742 /******************************************************************
743 * get_servername_from_name (internal)
745 * for an external server, a copy of the serverpart from the full name is returned
748 static LPWSTR get_servername_from_name(LPCWSTR name)
750 LPWSTR server;
751 LPWSTR ptr;
752 WCHAR buffer[MAX_PATH];
753 DWORD len;
755 if (name == NULL) return NULL;
756 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
758 server = strdupW(&name[2]); /* skip over both backslash */
759 if (server == NULL) return NULL;
761 /* strip '\' and the printername */
762 ptr = strchrW(server, '\\');
763 if (ptr) ptr[0] = '\0';
765 TRACE("found %s\n", debugstr_w(server));
767 len = sizeof(buffer)/sizeof(buffer[0]);
768 if (GetComputerNameW(buffer, &len)) {
769 if (lstrcmpW(buffer, server) == 0) {
770 /* The requested Servername is our computername */
771 HeapFree(GetProcessHeap(), 0, server);
772 return NULL;
775 return server;
778 /******************************************************************
779 * get_basename_from_name (internal)
781 * skip over the serverpart from the full name
784 static LPCWSTR get_basename_from_name(LPCWSTR name)
786 if (name == NULL) return NULL;
787 if ((name[0] == '\\') && (name[1] == '\\')) {
788 /* skip over the servername and search for the following '\' */
789 name = strchrW(&name[2], '\\');
790 if ((name) && (name[1])) {
791 /* found a separator ('\') followed by a name:
792 skip over the separator and return the rest */
793 name++;
795 else
797 /* no basename present (we found only a servername) */
798 return NULL;
801 return name;
804 /******************************************************************
805 * get_opened_printer_entry
806 * Get the first place empty in the opened printer table
808 * ToDo:
809 * - pDefault is ignored
811 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
813 UINT_PTR handle = nb_printer_handles, i;
814 jobqueue_t *queue = NULL;
815 opened_printer_t *printer = NULL;
816 LPWSTR servername;
817 LPCWSTR printername;
819 if ((backend == NULL) && !load_backend()) return NULL;
821 servername = get_servername_from_name(name);
822 if (servername) {
823 FIXME("server %s not supported\n", debugstr_w(servername));
824 HeapFree(GetProcessHeap(), 0, servername);
825 SetLastError(ERROR_INVALID_PRINTER_NAME);
826 return NULL;
829 printername = get_basename_from_name(name);
830 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
832 /* an empty printername is invalid */
833 if (printername && (!printername[0])) {
834 SetLastError(ERROR_INVALID_PARAMETER);
835 return NULL;
838 EnterCriticalSection(&printer_handles_cs);
840 for (i = 0; i < nb_printer_handles; i++)
842 if (!printer_handles[i])
844 if(handle == nb_printer_handles)
845 handle = i;
847 else
849 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
850 queue = printer_handles[i]->queue;
854 if (handle >= nb_printer_handles)
856 opened_printer_t **new_array;
857 if (printer_handles)
858 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
859 (nb_printer_handles + 16) * sizeof(*new_array) );
860 else
861 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
862 (nb_printer_handles + 16) * sizeof(*new_array) );
864 if (!new_array)
866 handle = 0;
867 goto end;
869 printer_handles = new_array;
870 nb_printer_handles += 16;
873 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
875 handle = 0;
876 goto end;
879 /* get a printer handle from the backend */
880 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
881 handle = 0;
882 goto end;
885 /* clone the base name. This is NULL for the printserver */
886 printer->printername = strdupW(printername);
888 /* clone the full name */
889 printer->name = strdupW(name);
890 if (name && (!printer->name)) {
891 handle = 0;
892 goto end;
895 if(queue)
896 printer->queue = queue;
897 else
899 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
900 if (!printer->queue) {
901 handle = 0;
902 goto end;
904 list_init(&printer->queue->jobs);
905 printer->queue->ref = 0;
907 InterlockedIncrement(&printer->queue->ref);
909 printer_handles[handle] = printer;
910 handle++;
911 end:
912 LeaveCriticalSection(&printer_handles_cs);
913 if (!handle && printer) {
914 /* Something failed: Free all resources */
915 HeapFree(GetProcessHeap(), 0, printer->printername);
916 HeapFree(GetProcessHeap(), 0, printer->name);
917 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
918 HeapFree(GetProcessHeap(), 0, printer);
921 return (HANDLE)handle;
924 /******************************************************************
925 * get_opened_printer
926 * Get the pointer to the opened printer referred by the handle
928 static opened_printer_t *get_opened_printer(HANDLE hprn)
930 UINT_PTR idx = (UINT_PTR)hprn;
931 opened_printer_t *ret = NULL;
933 EnterCriticalSection(&printer_handles_cs);
935 if ((idx > 0) && (idx <= nb_printer_handles)) {
936 ret = printer_handles[idx - 1];
938 LeaveCriticalSection(&printer_handles_cs);
939 return ret;
942 /******************************************************************
943 * get_opened_printer_name
944 * Get the pointer to the opened printer name referred by the handle
946 static LPCWSTR get_opened_printer_name(HANDLE hprn)
948 opened_printer_t *printer = get_opened_printer(hprn);
949 if(!printer) return NULL;
950 return printer->name;
953 /******************************************************************
954 * WINSPOOL_GetOpenedPrinterRegKey
957 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
959 LPCWSTR name = get_opened_printer_name(hPrinter);
960 DWORD ret;
961 HKEY hkeyPrinters;
963 if(!name) return ERROR_INVALID_HANDLE;
965 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
966 ERROR_SUCCESS)
967 return ret;
969 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
971 ERR("Can't find opened printer %s in registry\n",
972 debugstr_w(name));
973 RegCloseKey(hkeyPrinters);
974 return ERROR_INVALID_PRINTER_NAME; /* ? */
976 RegCloseKey(hkeyPrinters);
977 return ERROR_SUCCESS;
980 void WINSPOOL_LoadSystemPrinters(void)
982 HKEY hkey, hkeyPrinters;
983 HANDLE hprn;
984 DWORD needed, num, i;
985 WCHAR PrinterName[256];
986 BOOL done = FALSE;
988 /* This ensures that all printer entries have a valid Name value. If causes
989 problems later if they don't. If one is found to be missed we create one
990 and set it equal to the name of the key */
991 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
992 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
993 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
994 for(i = 0; i < num; i++) {
995 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
996 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
997 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
998 set_reg_szW(hkey, NameW, PrinterName);
1000 RegCloseKey(hkey);
1005 RegCloseKey(hkeyPrinters);
1008 /* We want to avoid calling AddPrinter on printers as much as
1009 possible, because on cups printers this will (eventually) lead
1010 to a call to cupsGetPPD which takes forever, even with non-cups
1011 printers AddPrinter takes a while. So we'll tag all printers that
1012 were automatically added last time around, if they still exist
1013 we'll leave them be otherwise we'll delete them. */
1014 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1015 if(needed) {
1016 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1017 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1018 for(i = 0; i < num; i++) {
1019 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1020 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1021 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1022 DWORD dw = 1;
1023 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1024 RegCloseKey(hkey);
1026 ClosePrinter(hprn);
1031 HeapFree(GetProcessHeap(), 0, pi);
1035 #ifdef SONAME_LIBCUPS
1036 done = CUPS_LoadPrinters();
1037 #endif
1039 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1040 PRINTCAP_LoadPrinters();
1042 /* Now enumerate the list again and delete any printers that are still tagged */
1043 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1044 if(needed) {
1045 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1046 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1047 for(i = 0; i < num; i++) {
1048 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1049 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1050 BOOL delete_driver = FALSE;
1051 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1052 DWORD dw, type, size = sizeof(dw);
1053 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1054 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1055 DeletePrinter(hprn);
1056 delete_driver = TRUE;
1058 RegCloseKey(hkey);
1060 ClosePrinter(hprn);
1061 if(delete_driver)
1062 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1067 HeapFree(GetProcessHeap(), 0, pi);
1070 return;
1074 /******************************************************************
1075 * get_job
1077 * Get the pointer to the specified job.
1078 * Should hold the printer_handles_cs before calling.
1080 static job_t *get_job(HANDLE hprn, DWORD JobId)
1082 opened_printer_t *printer = get_opened_printer(hprn);
1083 job_t *job;
1085 if(!printer) return NULL;
1086 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1088 if(job->job_id == JobId)
1089 return job;
1091 return NULL;
1094 /***********************************************************
1095 * DEVMODEcpyAtoW
1097 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1099 BOOL Formname;
1100 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1101 DWORD size;
1103 Formname = (dmA->dmSize > off_formname);
1104 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1105 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1106 dmW->dmDeviceName, CCHDEVICENAME);
1107 if(!Formname) {
1108 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1109 dmA->dmSize - CCHDEVICENAME);
1110 } else {
1111 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1112 off_formname - CCHDEVICENAME);
1113 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1114 dmW->dmFormName, CCHFORMNAME);
1115 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1116 (off_formname + CCHFORMNAME));
1118 dmW->dmSize = size;
1119 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1120 dmA->dmDriverExtra);
1121 return dmW;
1124 /***********************************************************
1125 * DEVMODEdupWtoA
1126 * Creates an ansi copy of supplied devmode
1128 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1130 LPDEVMODEA dmA;
1131 DWORD size;
1133 if (!dmW) return NULL;
1134 size = dmW->dmSize - CCHDEVICENAME -
1135 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1137 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1138 if (!dmA) return NULL;
1140 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1141 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1143 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1144 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1145 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1147 else
1149 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1150 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1151 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1152 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1154 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1157 dmA->dmSize = size;
1158 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1159 return dmA;
1162 /******************************************************************
1163 * convert_printerinfo_W_to_A [internal]
1166 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1167 DWORD level, DWORD outlen, DWORD numentries)
1169 DWORD id = 0;
1170 LPSTR ptr;
1171 INT len;
1173 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1175 len = pi_sizeof[level] * numentries;
1176 ptr = (LPSTR) out + len;
1177 outlen -= len;
1179 /* copy the numbers of all PRINTER_INFO_* first */
1180 memcpy(out, pPrintersW, len);
1182 while (id < numentries) {
1183 switch (level) {
1184 case 1:
1186 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1187 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1189 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1190 if (piW->pDescription) {
1191 piA->pDescription = ptr;
1192 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1193 ptr, outlen, NULL, NULL);
1194 ptr += len;
1195 outlen -= len;
1197 if (piW->pName) {
1198 piA->pName = ptr;
1199 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1200 ptr, outlen, NULL, NULL);
1201 ptr += len;
1202 outlen -= len;
1204 if (piW->pComment) {
1205 piA->pComment = ptr;
1206 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1207 ptr, outlen, NULL, NULL);
1208 ptr += len;
1209 outlen -= len;
1211 break;
1214 case 2:
1216 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1217 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1218 LPDEVMODEA dmA;
1220 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1221 if (piW->pServerName) {
1222 piA->pServerName = ptr;
1223 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1224 ptr, outlen, NULL, NULL);
1225 ptr += len;
1226 outlen -= len;
1228 if (piW->pPrinterName) {
1229 piA->pPrinterName = ptr;
1230 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1231 ptr, outlen, NULL, NULL);
1232 ptr += len;
1233 outlen -= len;
1235 if (piW->pShareName) {
1236 piA->pShareName = ptr;
1237 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1238 ptr, outlen, NULL, NULL);
1239 ptr += len;
1240 outlen -= len;
1242 if (piW->pPortName) {
1243 piA->pPortName = ptr;
1244 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1245 ptr, outlen, NULL, NULL);
1246 ptr += len;
1247 outlen -= len;
1249 if (piW->pDriverName) {
1250 piA->pDriverName = ptr;
1251 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1252 ptr, outlen, NULL, NULL);
1253 ptr += len;
1254 outlen -= len;
1256 if (piW->pComment) {
1257 piA->pComment = ptr;
1258 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1259 ptr, outlen, NULL, NULL);
1260 ptr += len;
1261 outlen -= len;
1263 if (piW->pLocation) {
1264 piA->pLocation = ptr;
1265 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1266 ptr, outlen, NULL, NULL);
1267 ptr += len;
1268 outlen -= len;
1271 dmA = DEVMODEdupWtoA(piW->pDevMode);
1272 if (dmA) {
1273 /* align DEVMODEA to a DWORD boundary */
1274 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1275 ptr += len;
1276 outlen -= len;
1278 piA->pDevMode = (LPDEVMODEA) ptr;
1279 len = dmA->dmSize + dmA->dmDriverExtra;
1280 memcpy(ptr, dmA, len);
1281 HeapFree(GetProcessHeap(), 0, dmA);
1283 ptr += len;
1284 outlen -= len;
1287 if (piW->pSepFile) {
1288 piA->pSepFile = ptr;
1289 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1290 ptr, outlen, NULL, NULL);
1291 ptr += len;
1292 outlen -= len;
1294 if (piW->pPrintProcessor) {
1295 piA->pPrintProcessor = ptr;
1296 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1297 ptr, outlen, NULL, NULL);
1298 ptr += len;
1299 outlen -= len;
1301 if (piW->pDatatype) {
1302 piA->pDatatype = ptr;
1303 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1304 ptr, outlen, NULL, NULL);
1305 ptr += len;
1306 outlen -= len;
1308 if (piW->pParameters) {
1309 piA->pParameters = ptr;
1310 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1311 ptr, outlen, NULL, NULL);
1312 ptr += len;
1313 outlen -= len;
1315 if (piW->pSecurityDescriptor) {
1316 piA->pSecurityDescriptor = NULL;
1317 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1319 break;
1322 case 4:
1324 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1325 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1327 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1329 if (piW->pPrinterName) {
1330 piA->pPrinterName = ptr;
1331 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1332 ptr, outlen, NULL, NULL);
1333 ptr += len;
1334 outlen -= len;
1336 if (piW->pServerName) {
1337 piA->pServerName = ptr;
1338 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1339 ptr, outlen, NULL, NULL);
1340 ptr += len;
1341 outlen -= len;
1343 break;
1346 case 5:
1348 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1349 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1351 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1353 if (piW->pPrinterName) {
1354 piA->pPrinterName = ptr;
1355 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1356 ptr, outlen, NULL, NULL);
1357 ptr += len;
1358 outlen -= len;
1360 if (piW->pPortName) {
1361 piA->pPortName = ptr;
1362 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1363 ptr, outlen, NULL, NULL);
1364 ptr += len;
1365 outlen -= len;
1367 break;
1370 case 6: /* 6A and 6W are the same structure */
1371 break;
1373 case 7:
1375 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1376 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1378 TRACE("(%u) #%u\n", level, id);
1379 if (piW->pszObjectGUID) {
1380 piA->pszObjectGUID = ptr;
1381 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1382 ptr, outlen, NULL, NULL);
1383 ptr += len;
1384 outlen -= len;
1386 break;
1389 case 9:
1391 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1392 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1393 LPDEVMODEA dmA;
1395 TRACE("(%u) #%u\n", level, id);
1396 dmA = DEVMODEdupWtoA(piW->pDevMode);
1397 if (dmA) {
1398 /* align DEVMODEA to a DWORD boundary */
1399 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1400 ptr += len;
1401 outlen -= len;
1403 piA->pDevMode = (LPDEVMODEA) ptr;
1404 len = dmA->dmSize + dmA->dmDriverExtra;
1405 memcpy(ptr, dmA, len);
1406 HeapFree(GetProcessHeap(), 0, dmA);
1408 ptr += len;
1409 outlen -= len;
1412 break;
1415 default:
1416 FIXME("for level %u\n", level);
1418 pPrintersW += pi_sizeof[level];
1419 out += pi_sizeof[level];
1420 id++;
1424 /******************************************************************
1425 * convert_driverinfo_W_to_A [internal]
1428 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1429 DWORD level, DWORD outlen, DWORD numentries)
1431 DWORD id = 0;
1432 LPSTR ptr;
1433 INT len;
1435 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1437 len = di_sizeof[level] * numentries;
1438 ptr = (LPSTR) out + len;
1439 outlen -= len;
1441 /* copy the numbers of all PRINTER_INFO_* first */
1442 memcpy(out, pDriversW, len);
1444 #define COPY_STRING(fld) \
1445 { if (diW->fld){ \
1446 diA->fld = ptr; \
1447 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1448 ptr += len; outlen -= len;\
1450 #define COPY_MULTIZ_STRING(fld) \
1451 { LPWSTR p = diW->fld; if (p){ \
1452 diA->fld = ptr; \
1453 do {\
1454 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1455 ptr += len; outlen -= len; p += len;\
1457 while(len > 1 && outlen > 0); \
1460 while (id < numentries)
1462 switch (level)
1464 case 1:
1466 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1467 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1469 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1471 COPY_STRING(pName);
1472 break;
1474 case 2:
1476 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1477 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1479 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1481 COPY_STRING(pName);
1482 COPY_STRING(pEnvironment);
1483 COPY_STRING(pDriverPath);
1484 COPY_STRING(pDataFile);
1485 COPY_STRING(pConfigFile);
1486 break;
1488 case 3:
1490 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1491 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1493 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1495 COPY_STRING(pName);
1496 COPY_STRING(pEnvironment);
1497 COPY_STRING(pDriverPath);
1498 COPY_STRING(pDataFile);
1499 COPY_STRING(pConfigFile);
1500 COPY_STRING(pHelpFile);
1501 COPY_MULTIZ_STRING(pDependentFiles);
1502 COPY_STRING(pMonitorName);
1503 COPY_STRING(pDefaultDataType);
1504 break;
1506 case 4:
1508 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1509 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1511 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1513 COPY_STRING(pName);
1514 COPY_STRING(pEnvironment);
1515 COPY_STRING(pDriverPath);
1516 COPY_STRING(pDataFile);
1517 COPY_STRING(pConfigFile);
1518 COPY_STRING(pHelpFile);
1519 COPY_MULTIZ_STRING(pDependentFiles);
1520 COPY_STRING(pMonitorName);
1521 COPY_STRING(pDefaultDataType);
1522 COPY_MULTIZ_STRING(pszzPreviousNames);
1523 break;
1525 case 5:
1527 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1528 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1530 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1532 COPY_STRING(pName);
1533 COPY_STRING(pEnvironment);
1534 COPY_STRING(pDriverPath);
1535 COPY_STRING(pDataFile);
1536 COPY_STRING(pConfigFile);
1537 break;
1539 case 6:
1541 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1542 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1544 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1546 COPY_STRING(pName);
1547 COPY_STRING(pEnvironment);
1548 COPY_STRING(pDriverPath);
1549 COPY_STRING(pDataFile);
1550 COPY_STRING(pConfigFile);
1551 COPY_STRING(pHelpFile);
1552 COPY_MULTIZ_STRING(pDependentFiles);
1553 COPY_STRING(pMonitorName);
1554 COPY_STRING(pDefaultDataType);
1555 COPY_MULTIZ_STRING(pszzPreviousNames);
1556 COPY_STRING(pszMfgName);
1557 COPY_STRING(pszOEMUrl);
1558 COPY_STRING(pszHardwareID);
1559 COPY_STRING(pszProvider);
1560 break;
1562 case 8:
1564 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1565 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1567 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1569 COPY_STRING(pName);
1570 COPY_STRING(pEnvironment);
1571 COPY_STRING(pDriverPath);
1572 COPY_STRING(pDataFile);
1573 COPY_STRING(pConfigFile);
1574 COPY_STRING(pHelpFile);
1575 COPY_MULTIZ_STRING(pDependentFiles);
1576 COPY_STRING(pMonitorName);
1577 COPY_STRING(pDefaultDataType);
1578 COPY_MULTIZ_STRING(pszzPreviousNames);
1579 COPY_STRING(pszMfgName);
1580 COPY_STRING(pszOEMUrl);
1581 COPY_STRING(pszHardwareID);
1582 COPY_STRING(pszProvider);
1583 COPY_STRING(pszPrintProcessor);
1584 COPY_STRING(pszVendorSetup);
1585 COPY_MULTIZ_STRING(pszzColorProfiles);
1586 COPY_STRING(pszInfPath);
1587 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1588 break;
1592 default:
1593 FIXME("for level %u\n", level);
1596 pDriversW += di_sizeof[level];
1597 out += di_sizeof[level];
1598 id++;
1601 #undef COPY_STRING
1602 #undef COPY_MULTIZ_STRING
1606 /***********************************************************
1607 * PRINTER_INFO_2AtoW
1608 * Creates a unicode copy of PRINTER_INFO_2A on heap
1610 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1612 LPPRINTER_INFO_2W piW;
1613 UNICODE_STRING usBuffer;
1615 if(!piA) return NULL;
1616 piW = HeapAlloc(heap, 0, sizeof(*piW));
1617 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1619 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1620 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1621 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1622 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1623 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1624 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1625 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1626 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1627 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1628 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1629 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1630 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1631 return piW;
1634 /***********************************************************
1635 * FREE_PRINTER_INFO_2W
1636 * Free PRINTER_INFO_2W and all strings
1638 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1640 if(!piW) return;
1642 HeapFree(heap,0,piW->pServerName);
1643 HeapFree(heap,0,piW->pPrinterName);
1644 HeapFree(heap,0,piW->pShareName);
1645 HeapFree(heap,0,piW->pPortName);
1646 HeapFree(heap,0,piW->pDriverName);
1647 HeapFree(heap,0,piW->pComment);
1648 HeapFree(heap,0,piW->pLocation);
1649 HeapFree(heap,0,piW->pDevMode);
1650 HeapFree(heap,0,piW->pSepFile);
1651 HeapFree(heap,0,piW->pPrintProcessor);
1652 HeapFree(heap,0,piW->pDatatype);
1653 HeapFree(heap,0,piW->pParameters);
1654 HeapFree(heap,0,piW);
1655 return;
1658 /******************************************************************
1659 * DeviceCapabilities [WINSPOOL.@]
1660 * DeviceCapabilitiesA [WINSPOOL.@]
1663 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1664 LPSTR pOutput, LPDEVMODEA lpdm)
1666 INT ret;
1668 if (!GDI_CallDeviceCapabilities16)
1670 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1671 (LPCSTR)104 );
1672 if (!GDI_CallDeviceCapabilities16) return -1;
1674 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1676 /* If DC_PAPERSIZE map POINT16s to POINTs */
1677 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1678 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1679 POINT *pt = (POINT *)pOutput;
1680 INT i;
1681 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1682 for(i = 0; i < ret; i++, pt++)
1684 pt->x = tmp[i].x;
1685 pt->y = tmp[i].y;
1687 HeapFree( GetProcessHeap(), 0, tmp );
1689 return ret;
1693 /*****************************************************************************
1694 * DeviceCapabilitiesW [WINSPOOL.@]
1696 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1699 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1700 WORD fwCapability, LPWSTR pOutput,
1701 const DEVMODEW *pDevMode)
1703 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1704 LPSTR pDeviceA = strdupWtoA(pDevice);
1705 LPSTR pPortA = strdupWtoA(pPort);
1706 INT ret;
1708 if(pOutput && (fwCapability == DC_BINNAMES ||
1709 fwCapability == DC_FILEDEPENDENCIES ||
1710 fwCapability == DC_PAPERNAMES)) {
1711 /* These need A -> W translation */
1712 INT size = 0, i;
1713 LPSTR pOutputA;
1714 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1715 dmA);
1716 if(ret == -1)
1717 return ret;
1718 switch(fwCapability) {
1719 case DC_BINNAMES:
1720 size = 24;
1721 break;
1722 case DC_PAPERNAMES:
1723 case DC_FILEDEPENDENCIES:
1724 size = 64;
1725 break;
1727 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1728 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1729 dmA);
1730 for(i = 0; i < ret; i++)
1731 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1732 pOutput + (i * size), size);
1733 HeapFree(GetProcessHeap(), 0, pOutputA);
1734 } else {
1735 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1736 (LPSTR)pOutput, dmA);
1738 HeapFree(GetProcessHeap(),0,pPortA);
1739 HeapFree(GetProcessHeap(),0,pDeviceA);
1740 HeapFree(GetProcessHeap(),0,dmA);
1741 return ret;
1744 /******************************************************************
1745 * DocumentPropertiesA [WINSPOOL.@]
1747 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1749 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1750 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1751 LPDEVMODEA pDevModeInput,DWORD fMode )
1753 LPSTR lpName = pDeviceName;
1754 static CHAR port[] = "LPT1:";
1755 LONG ret;
1757 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1758 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1761 if(!pDeviceName) {
1762 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1763 if(!lpNameW) {
1764 ERR("no name from hPrinter?\n");
1765 SetLastError(ERROR_INVALID_HANDLE);
1766 return -1;
1768 lpName = strdupWtoA(lpNameW);
1771 if (!GDI_CallExtDeviceMode16)
1773 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1774 (LPCSTR)102 );
1775 if (!GDI_CallExtDeviceMode16) {
1776 ERR("No CallExtDeviceMode16?\n");
1777 return -1;
1780 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1781 pDevModeInput, NULL, fMode);
1783 if(!pDeviceName)
1784 HeapFree(GetProcessHeap(),0,lpName);
1785 return ret;
1789 /*****************************************************************************
1790 * DocumentPropertiesW (WINSPOOL.@)
1792 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1794 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1795 LPWSTR pDeviceName,
1796 LPDEVMODEW pDevModeOutput,
1797 LPDEVMODEW pDevModeInput, DWORD fMode)
1800 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1801 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1802 LPDEVMODEA pDevModeOutputA = NULL;
1803 LONG ret;
1805 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1806 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1807 fMode);
1808 if(pDevModeOutput) {
1809 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1810 if(ret < 0) return ret;
1811 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1813 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1814 pDevModeInputA, fMode);
1815 if(pDevModeOutput) {
1816 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1817 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1819 if(fMode == 0 && ret > 0)
1820 ret += (CCHDEVICENAME + CCHFORMNAME);
1821 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1822 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1823 return ret;
1826 /******************************************************************
1827 * OpenPrinterA [WINSPOOL.@]
1829 * See OpenPrinterW.
1832 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1833 LPPRINTER_DEFAULTSA pDefault)
1835 UNICODE_STRING lpPrinterNameW;
1836 UNICODE_STRING usBuffer;
1837 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1838 PWSTR pwstrPrinterNameW;
1839 BOOL ret;
1841 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1843 if(pDefault) {
1844 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1845 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1846 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1847 pDefaultW = &DefaultW;
1849 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1850 if(pDefault) {
1851 RtlFreeUnicodeString(&usBuffer);
1852 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1854 RtlFreeUnicodeString(&lpPrinterNameW);
1855 return ret;
1858 /******************************************************************
1859 * OpenPrinterW [WINSPOOL.@]
1861 * Open a Printer / Printserver or a Printer-Object
1863 * PARAMS
1864 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1865 * phPrinter [O] The resulting Handle is stored here
1866 * pDefault [I] PTR to Default Printer Settings or NULL
1868 * RETURNS
1869 * Success: TRUE
1870 * Failure: FALSE
1872 * NOTES
1873 * lpPrinterName is one of:
1874 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1875 *| Printer: "PrinterName"
1876 *| Printer-Object: "PrinterName,Job xxx"
1877 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1878 *| XcvPort: "Servername,XcvPort PortName"
1880 * BUGS
1881 *| Printer-Object not supported
1882 *| pDefaults is ignored
1885 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1888 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1889 if (pDefault) {
1890 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1891 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1894 if(!phPrinter) {
1895 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1896 SetLastError(ERROR_INVALID_PARAMETER);
1897 return FALSE;
1900 /* Get the unique handle of the printer or Printserver */
1901 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1902 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1903 return (*phPrinter != 0);
1906 /******************************************************************
1907 * AddMonitorA [WINSPOOL.@]
1909 * See AddMonitorW.
1912 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1914 LPWSTR nameW = NULL;
1915 INT len;
1916 BOOL res;
1917 LPMONITOR_INFO_2A mi2a;
1918 MONITOR_INFO_2W mi2w;
1920 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1921 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1922 debugstr_a(mi2a ? mi2a->pName : NULL),
1923 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1924 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1926 if (Level != 2) {
1927 SetLastError(ERROR_INVALID_LEVEL);
1928 return FALSE;
1931 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1932 if (mi2a == NULL) {
1933 return FALSE;
1936 if (pName) {
1937 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1938 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1939 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1942 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1943 if (mi2a->pName) {
1944 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1945 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1946 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1948 if (mi2a->pEnvironment) {
1949 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1950 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1951 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1953 if (mi2a->pDLLName) {
1954 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1955 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1956 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1959 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1961 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1962 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1963 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1965 HeapFree(GetProcessHeap(), 0, nameW);
1966 return (res);
1969 /******************************************************************************
1970 * AddMonitorW [WINSPOOL.@]
1972 * Install a Printmonitor
1974 * PARAMS
1975 * pName [I] Servername or NULL (local Computer)
1976 * Level [I] Structure-Level (Must be 2)
1977 * pMonitors [I] PTR to MONITOR_INFO_2
1979 * RETURNS
1980 * Success: TRUE
1981 * Failure: FALSE
1983 * NOTES
1984 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1987 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1989 LPMONITOR_INFO_2W mi2w;
1991 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1992 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1993 debugstr_w(mi2w ? mi2w->pName : NULL),
1994 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1995 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1997 if ((backend == NULL) && !load_backend()) return FALSE;
1999 if (Level != 2) {
2000 SetLastError(ERROR_INVALID_LEVEL);
2001 return FALSE;
2004 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2005 if (mi2w == NULL) {
2006 return FALSE;
2009 return backend->fpAddMonitor(pName, Level, pMonitors);
2012 /******************************************************************
2013 * DeletePrinterDriverA [WINSPOOL.@]
2016 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2018 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2021 /******************************************************************
2022 * DeletePrinterDriverW [WINSPOOL.@]
2025 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2027 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2030 /******************************************************************
2031 * DeleteMonitorA [WINSPOOL.@]
2033 * See DeleteMonitorW.
2036 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2038 LPWSTR nameW = NULL;
2039 LPWSTR EnvironmentW = NULL;
2040 LPWSTR MonitorNameW = NULL;
2041 BOOL res;
2042 INT len;
2044 if (pName) {
2045 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2046 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2047 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2050 if (pEnvironment) {
2051 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2052 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2053 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2055 if (pMonitorName) {
2056 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2057 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2058 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2061 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2063 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2064 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2065 HeapFree(GetProcessHeap(), 0, nameW);
2066 return (res);
2069 /******************************************************************
2070 * DeleteMonitorW [WINSPOOL.@]
2072 * Delete a specific Printmonitor from a Printing-Environment
2074 * PARAMS
2075 * pName [I] Servername or NULL (local Computer)
2076 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2077 * pMonitorName [I] Name of the Monitor, that should be deleted
2079 * RETURNS
2080 * Success: TRUE
2081 * Failure: FALSE
2083 * NOTES
2084 * pEnvironment is ignored in Windows for the local Computer.
2087 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2090 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2091 debugstr_w(pMonitorName));
2093 if ((backend == NULL) && !load_backend()) return FALSE;
2095 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2099 /******************************************************************
2100 * DeletePortA [WINSPOOL.@]
2102 * See DeletePortW.
2105 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2107 LPWSTR nameW = NULL;
2108 LPWSTR portW = NULL;
2109 INT len;
2110 DWORD res;
2112 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2114 /* convert servername to unicode */
2115 if (pName) {
2116 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2117 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2118 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2121 /* convert portname to unicode */
2122 if (pPortName) {
2123 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2124 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2125 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2128 res = DeletePortW(nameW, hWnd, portW);
2129 HeapFree(GetProcessHeap(), 0, nameW);
2130 HeapFree(GetProcessHeap(), 0, portW);
2131 return res;
2134 /******************************************************************
2135 * DeletePortW [WINSPOOL.@]
2137 * Delete a specific Port
2139 * PARAMS
2140 * pName [I] Servername or NULL (local Computer)
2141 * hWnd [I] Handle to parent Window for the Dialog-Box
2142 * pPortName [I] Name of the Port, that should be deleted
2144 * RETURNS
2145 * Success: TRUE
2146 * Failure: FALSE
2149 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2151 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2153 if ((backend == NULL) && !load_backend()) return FALSE;
2155 if (!pPortName) {
2156 SetLastError(RPC_X_NULL_REF_POINTER);
2157 return FALSE;
2160 return backend->fpDeletePort(pName, hWnd, pPortName);
2163 /******************************************************************************
2164 * SetPrinterW [WINSPOOL.@]
2166 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2168 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2169 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2170 return FALSE;
2173 /******************************************************************************
2174 * WritePrinter [WINSPOOL.@]
2176 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2178 opened_printer_t *printer;
2179 BOOL ret = FALSE;
2181 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2183 EnterCriticalSection(&printer_handles_cs);
2184 printer = get_opened_printer(hPrinter);
2185 if(!printer)
2187 SetLastError(ERROR_INVALID_HANDLE);
2188 goto end;
2191 if(!printer->doc)
2193 SetLastError(ERROR_SPL_NO_STARTDOC);
2194 goto end;
2197 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2198 end:
2199 LeaveCriticalSection(&printer_handles_cs);
2200 return ret;
2203 /*****************************************************************************
2204 * AddFormA [WINSPOOL.@]
2206 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2208 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2209 return 1;
2212 /*****************************************************************************
2213 * AddFormW [WINSPOOL.@]
2215 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2217 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2218 return 1;
2221 /*****************************************************************************
2222 * AddJobA [WINSPOOL.@]
2224 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2226 BOOL ret;
2227 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2228 DWORD needed;
2230 if(Level != 1) {
2231 SetLastError(ERROR_INVALID_LEVEL);
2232 return FALSE;
2235 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2237 if(ret) {
2238 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2239 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2240 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2241 if(*pcbNeeded > cbBuf) {
2242 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2243 ret = FALSE;
2244 } else {
2245 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2246 addjobA->JobId = addjobW->JobId;
2247 addjobA->Path = (char *)(addjobA + 1);
2248 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2251 return ret;
2254 /*****************************************************************************
2255 * AddJobW [WINSPOOL.@]
2257 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2259 opened_printer_t *printer;
2260 job_t *job;
2261 BOOL ret = FALSE;
2262 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2263 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2264 WCHAR path[MAX_PATH], filename[MAX_PATH];
2265 DWORD len;
2266 ADDJOB_INFO_1W *addjob;
2268 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2270 EnterCriticalSection(&printer_handles_cs);
2272 printer = get_opened_printer(hPrinter);
2274 if(!printer) {
2275 SetLastError(ERROR_INVALID_HANDLE);
2276 goto end;
2279 if(Level != 1) {
2280 SetLastError(ERROR_INVALID_LEVEL);
2281 goto end;
2284 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2285 if(!job)
2286 goto end;
2288 job->job_id = InterlockedIncrement(&next_job_id);
2290 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2291 if(path[len - 1] != '\\')
2292 path[len++] = '\\';
2293 memcpy(path + len, spool_path, sizeof(spool_path));
2294 sprintfW(filename, fmtW, path, job->job_id);
2296 len = strlenW(filename);
2297 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2298 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2299 job->document_title = strdupW(default_doc_title);
2300 job->printer_name = strdupW(printer->name);
2301 list_add_tail(&printer->queue->jobs, &job->entry);
2303 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2304 if(*pcbNeeded <= cbBuf) {
2305 addjob = (ADDJOB_INFO_1W*)pData;
2306 addjob->JobId = job->job_id;
2307 addjob->Path = (WCHAR *)(addjob + 1);
2308 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2309 ret = TRUE;
2310 } else
2311 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2313 end:
2314 LeaveCriticalSection(&printer_handles_cs);
2315 return ret;
2318 /*****************************************************************************
2319 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2321 * Return the PATH for the Print-Processors
2323 * See GetPrintProcessorDirectoryW.
2327 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2328 DWORD level, LPBYTE Info,
2329 DWORD cbBuf, LPDWORD pcbNeeded)
2331 LPWSTR serverW = NULL;
2332 LPWSTR envW = NULL;
2333 BOOL ret;
2334 INT len;
2336 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2337 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2340 if (server) {
2341 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2342 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2343 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2346 if (env) {
2347 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2348 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2349 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2352 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2353 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2355 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2356 cbBuf, pcbNeeded);
2358 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2359 cbBuf, NULL, NULL) > 0;
2362 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2363 HeapFree(GetProcessHeap(), 0, envW);
2364 HeapFree(GetProcessHeap(), 0, serverW);
2365 return ret;
2368 /*****************************************************************************
2369 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2371 * Return the PATH for the Print-Processors
2373 * PARAMS
2374 * server [I] Servername (NT only) or NULL (local Computer)
2375 * env [I] Printing-Environment (see below) or NULL (Default)
2376 * level [I] Structure-Level (must be 1)
2377 * Info [O] PTR to Buffer that receives the Result
2378 * cbBuf [I] Size of Buffer at "Info"
2379 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2380 * required for the Buffer at "Info"
2382 * RETURNS
2383 * Success: TRUE and in pcbNeeded the Bytes used in Info
2384 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2385 * if cbBuf is too small
2387 * Native Values returned in Info on Success:
2388 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2389 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2390 *| win9x(Windows 4.0): "%winsysdir%"
2392 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2394 * BUGS
2395 * Only NULL or "" is supported for server
2398 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2399 DWORD level, LPBYTE Info,
2400 DWORD cbBuf, LPDWORD pcbNeeded)
2403 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2404 Info, cbBuf, pcbNeeded);
2406 if ((backend == NULL) && !load_backend()) return FALSE;
2408 if (level != 1) {
2409 /* (Level != 1) is ignored in win9x */
2410 SetLastError(ERROR_INVALID_LEVEL);
2411 return FALSE;
2414 if (pcbNeeded == NULL) {
2415 /* (pcbNeeded == NULL) is ignored in win9x */
2416 SetLastError(RPC_X_NULL_REF_POINTER);
2417 return FALSE;
2420 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2423 /*****************************************************************************
2424 * WINSPOOL_OpenDriverReg [internal]
2426 * opens the registry for the printer drivers depending on the given input
2427 * variable pEnvironment
2429 * RETURNS:
2430 * the opened hkey on success
2431 * NULL on error
2433 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2435 HKEY retval = NULL;
2436 LPWSTR buffer;
2437 const printenv_t * env;
2439 TRACE("(%s)\n", debugstr_w(pEnvironment));
2441 env = validate_envW(pEnvironment);
2442 if (!env) return NULL;
2444 buffer = HeapAlloc( GetProcessHeap(), 0,
2445 (strlenW(DriversW) + strlenW(env->envname) +
2446 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2447 if(buffer) {
2448 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2449 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2450 HeapFree(GetProcessHeap(), 0, buffer);
2452 return retval;
2455 /*****************************************************************************
2456 * AddPrinterW [WINSPOOL.@]
2458 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2460 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2461 LPDEVMODEA dmA;
2462 LPDEVMODEW dmW;
2463 HANDLE retval;
2464 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2465 LONG size;
2466 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2467 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2468 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2469 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2470 statusW[] = {'S','t','a','t','u','s',0},
2471 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2473 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2475 if(pName != NULL) {
2476 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2477 SetLastError(ERROR_INVALID_PARAMETER);
2478 return 0;
2480 if(Level != 2) {
2481 ERR("Level = %d, unsupported!\n", Level);
2482 SetLastError(ERROR_INVALID_LEVEL);
2483 return 0;
2485 if(!pPrinter) {
2486 SetLastError(ERROR_INVALID_PARAMETER);
2487 return 0;
2489 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2490 ERROR_SUCCESS) {
2491 ERR("Can't create Printers key\n");
2492 return 0;
2494 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2495 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2496 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2497 RegCloseKey(hkeyPrinter);
2498 RegCloseKey(hkeyPrinters);
2499 return 0;
2501 RegCloseKey(hkeyPrinter);
2503 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2504 if(!hkeyDrivers) {
2505 ERR("Can't create Drivers key\n");
2506 RegCloseKey(hkeyPrinters);
2507 return 0;
2509 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2510 ERROR_SUCCESS) {
2511 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2512 RegCloseKey(hkeyPrinters);
2513 RegCloseKey(hkeyDrivers);
2514 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2515 return 0;
2517 RegCloseKey(hkeyDriver);
2518 RegCloseKey(hkeyDrivers);
2520 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2521 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2522 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2523 RegCloseKey(hkeyPrinters);
2524 return 0;
2527 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2528 ERROR_SUCCESS) {
2529 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2530 SetLastError(ERROR_INVALID_PRINTER_NAME);
2531 RegCloseKey(hkeyPrinters);
2532 return 0;
2534 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2535 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2536 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2538 /* See if we can load the driver. We may need the devmode structure anyway
2540 * FIXME:
2541 * Note that DocumentPropertiesW will briefly try to open the printer we
2542 * just create to find a DEVMODEA struct (it will use the WINEPS default
2543 * one in case it is not there, so we are ok).
2545 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2547 if(size < 0) {
2548 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2549 size = sizeof(DEVMODEW);
2551 if(pi->pDevMode)
2552 dmW = pi->pDevMode;
2553 else
2555 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2556 dmW->dmSize = size;
2557 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2559 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2560 HeapFree(GetProcessHeap(),0,dmW);
2561 dmW=NULL;
2563 else
2565 /* set devmode to printer name */
2566 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2570 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2571 and we support these drivers. NT writes DEVMODEW so somehow
2572 we'll need to distinguish between these when we support NT
2573 drivers */
2574 if (dmW)
2576 dmA = DEVMODEdupWtoA(dmW);
2577 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2578 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2579 HeapFree(GetProcessHeap(), 0, dmA);
2580 if(!pi->pDevMode)
2581 HeapFree(GetProcessHeap(), 0, dmW);
2583 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2584 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2585 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2586 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2588 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2589 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2590 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2591 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2592 (LPBYTE)&pi->Priority, sizeof(DWORD));
2593 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2594 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2595 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2596 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2597 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2598 (LPBYTE)&pi->Status, sizeof(DWORD));
2599 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2600 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2602 RegCloseKey(hkeyPrinter);
2603 RegCloseKey(hkeyPrinters);
2604 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2605 ERR("OpenPrinter failing\n");
2606 return 0;
2608 return retval;
2611 /*****************************************************************************
2612 * AddPrinterA [WINSPOOL.@]
2614 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2616 UNICODE_STRING pNameW;
2617 PWSTR pwstrNameW;
2618 PRINTER_INFO_2W *piW;
2619 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2620 HANDLE ret;
2622 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2623 if(Level != 2) {
2624 ERR("Level = %d, unsupported!\n", Level);
2625 SetLastError(ERROR_INVALID_LEVEL);
2626 return 0;
2628 pwstrNameW = asciitounicode(&pNameW,pName);
2629 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2631 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2633 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2634 RtlFreeUnicodeString(&pNameW);
2635 return ret;
2639 /*****************************************************************************
2640 * ClosePrinter [WINSPOOL.@]
2642 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2644 UINT_PTR i = (UINT_PTR)hPrinter;
2645 opened_printer_t *printer = NULL;
2646 BOOL ret = FALSE;
2648 TRACE("(%p)\n", hPrinter);
2650 EnterCriticalSection(&printer_handles_cs);
2652 if ((i > 0) && (i <= nb_printer_handles))
2653 printer = printer_handles[i - 1];
2656 if(printer)
2658 struct list *cursor, *cursor2;
2660 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2662 if (printer->backend_printer) {
2663 backend->fpClosePrinter(printer->backend_printer);
2666 if(printer->doc)
2667 EndDocPrinter(hPrinter);
2669 if(InterlockedDecrement(&printer->queue->ref) == 0)
2671 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2673 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2674 ScheduleJob(hPrinter, job->job_id);
2676 HeapFree(GetProcessHeap(), 0, printer->queue);
2679 HeapFree(GetProcessHeap(), 0, printer->printername);
2680 HeapFree(GetProcessHeap(), 0, printer->name);
2681 HeapFree(GetProcessHeap(), 0, printer);
2682 printer_handles[i - 1] = NULL;
2683 ret = TRUE;
2685 LeaveCriticalSection(&printer_handles_cs);
2686 return ret;
2689 /*****************************************************************************
2690 * DeleteFormA [WINSPOOL.@]
2692 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2694 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2695 return 1;
2698 /*****************************************************************************
2699 * DeleteFormW [WINSPOOL.@]
2701 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2703 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2704 return 1;
2707 /*****************************************************************************
2708 * DeletePrinter [WINSPOOL.@]
2710 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2712 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2713 HKEY hkeyPrinters, hkey;
2715 if(!lpNameW) {
2716 SetLastError(ERROR_INVALID_HANDLE);
2717 return FALSE;
2719 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2720 RegDeleteTreeW(hkeyPrinters, lpNameW);
2721 RegCloseKey(hkeyPrinters);
2723 WriteProfileStringW(devicesW, lpNameW, NULL);
2724 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2726 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2727 RegDeleteValueW(hkey, lpNameW);
2728 RegCloseKey(hkey);
2731 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2732 RegDeleteValueW(hkey, lpNameW);
2733 RegCloseKey(hkey);
2735 return TRUE;
2738 /*****************************************************************************
2739 * SetPrinterA [WINSPOOL.@]
2741 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2742 DWORD Command)
2744 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2745 return FALSE;
2748 /*****************************************************************************
2749 * SetJobA [WINSPOOL.@]
2751 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2752 LPBYTE pJob, DWORD Command)
2754 BOOL ret;
2755 LPBYTE JobW;
2756 UNICODE_STRING usBuffer;
2758 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2760 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2761 are all ignored by SetJob, so we don't bother copying them */
2762 switch(Level)
2764 case 0:
2765 JobW = NULL;
2766 break;
2767 case 1:
2769 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2770 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2772 JobW = (LPBYTE)info1W;
2773 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2774 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2775 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2776 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2777 info1W->Status = info1A->Status;
2778 info1W->Priority = info1A->Priority;
2779 info1W->Position = info1A->Position;
2780 info1W->PagesPrinted = info1A->PagesPrinted;
2781 break;
2783 case 2:
2785 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2786 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2788 JobW = (LPBYTE)info2W;
2789 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2790 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2791 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2792 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2793 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2794 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2795 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2796 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2797 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2798 info2W->Status = info2A->Status;
2799 info2W->Priority = info2A->Priority;
2800 info2W->Position = info2A->Position;
2801 info2W->StartTime = info2A->StartTime;
2802 info2W->UntilTime = info2A->UntilTime;
2803 info2W->PagesPrinted = info2A->PagesPrinted;
2804 break;
2806 case 3:
2807 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2808 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2809 break;
2810 default:
2811 SetLastError(ERROR_INVALID_LEVEL);
2812 return FALSE;
2815 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2817 switch(Level)
2819 case 1:
2821 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2822 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2823 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2824 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2825 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2826 break;
2828 case 2:
2830 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2831 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2832 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2833 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2834 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2835 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2836 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2837 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2838 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2839 break;
2842 HeapFree(GetProcessHeap(), 0, JobW);
2844 return ret;
2847 /*****************************************************************************
2848 * SetJobW [WINSPOOL.@]
2850 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2851 LPBYTE pJob, DWORD Command)
2853 BOOL ret = FALSE;
2854 job_t *job;
2856 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2857 FIXME("Ignoring everything other than document title\n");
2859 EnterCriticalSection(&printer_handles_cs);
2860 job = get_job(hPrinter, JobId);
2861 if(!job)
2862 goto end;
2864 switch(Level)
2866 case 0:
2867 break;
2868 case 1:
2870 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2871 HeapFree(GetProcessHeap(), 0, job->document_title);
2872 job->document_title = strdupW(info1->pDocument);
2873 break;
2875 case 2:
2877 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2878 HeapFree(GetProcessHeap(), 0, job->document_title);
2879 job->document_title = strdupW(info2->pDocument);
2880 break;
2882 case 3:
2883 break;
2884 default:
2885 SetLastError(ERROR_INVALID_LEVEL);
2886 goto end;
2888 ret = TRUE;
2889 end:
2890 LeaveCriticalSection(&printer_handles_cs);
2891 return ret;
2894 /*****************************************************************************
2895 * EndDocPrinter [WINSPOOL.@]
2897 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2899 opened_printer_t *printer;
2900 BOOL ret = FALSE;
2901 TRACE("(%p)\n", hPrinter);
2903 EnterCriticalSection(&printer_handles_cs);
2905 printer = get_opened_printer(hPrinter);
2906 if(!printer)
2908 SetLastError(ERROR_INVALID_HANDLE);
2909 goto end;
2912 if(!printer->doc)
2914 SetLastError(ERROR_SPL_NO_STARTDOC);
2915 goto end;
2918 CloseHandle(printer->doc->hf);
2919 ScheduleJob(hPrinter, printer->doc->job_id);
2920 HeapFree(GetProcessHeap(), 0, printer->doc);
2921 printer->doc = NULL;
2922 ret = TRUE;
2923 end:
2924 LeaveCriticalSection(&printer_handles_cs);
2925 return ret;
2928 /*****************************************************************************
2929 * EndPagePrinter [WINSPOOL.@]
2931 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2933 FIXME("(%p): stub\n", hPrinter);
2934 return TRUE;
2937 /*****************************************************************************
2938 * StartDocPrinterA [WINSPOOL.@]
2940 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2942 UNICODE_STRING usBuffer;
2943 DOC_INFO_2W doc2W;
2944 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2945 DWORD ret;
2947 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2948 or one (DOC_INFO_3) extra DWORDs */
2950 switch(Level) {
2951 case 2:
2952 doc2W.JobId = doc2->JobId;
2953 /* fall through */
2954 case 3:
2955 doc2W.dwMode = doc2->dwMode;
2956 /* fall through */
2957 case 1:
2958 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2959 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2960 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2961 break;
2963 default:
2964 SetLastError(ERROR_INVALID_LEVEL);
2965 return FALSE;
2968 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2970 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2971 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2972 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2974 return ret;
2977 /*****************************************************************************
2978 * StartDocPrinterW [WINSPOOL.@]
2980 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2982 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2983 opened_printer_t *printer;
2984 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2985 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2986 JOB_INFO_1W job_info;
2987 DWORD needed, ret = 0;
2988 HANDLE hf;
2989 WCHAR *filename;
2990 job_t *job;
2992 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2993 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2994 debugstr_w(doc->pDatatype));
2996 if(Level < 1 || Level > 3)
2998 SetLastError(ERROR_INVALID_LEVEL);
2999 return 0;
3002 EnterCriticalSection(&printer_handles_cs);
3003 printer = get_opened_printer(hPrinter);
3004 if(!printer)
3006 SetLastError(ERROR_INVALID_HANDLE);
3007 goto end;
3010 if(printer->doc)
3012 SetLastError(ERROR_INVALID_PRINTER_STATE);
3013 goto end;
3016 /* Even if we're printing to a file we still add a print job, we'll
3017 just ignore the spool file name */
3019 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3021 ERR("AddJob failed gle %u\n", GetLastError());
3022 goto end;
3025 /* use pOutputFile only, when it is a real filename */
3026 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3027 filename = doc->pOutputFile;
3028 else
3029 filename = addjob->Path;
3031 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3032 if(hf == INVALID_HANDLE_VALUE)
3033 goto end;
3035 memset(&job_info, 0, sizeof(job_info));
3036 job_info.pDocument = doc->pDocName;
3037 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3039 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3040 printer->doc->hf = hf;
3041 ret = printer->doc->job_id = addjob->JobId;
3042 job = get_job(hPrinter, ret);
3043 job->portname = strdupW(doc->pOutputFile);
3045 end:
3046 LeaveCriticalSection(&printer_handles_cs);
3048 return ret;
3051 /*****************************************************************************
3052 * StartPagePrinter [WINSPOOL.@]
3054 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3056 FIXME("(%p): stub\n", hPrinter);
3057 return TRUE;
3060 /*****************************************************************************
3061 * GetFormA [WINSPOOL.@]
3063 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3064 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3066 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3067 Level,pForm,cbBuf,pcbNeeded);
3068 return FALSE;
3071 /*****************************************************************************
3072 * GetFormW [WINSPOOL.@]
3074 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3075 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3077 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3078 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3079 return FALSE;
3082 /*****************************************************************************
3083 * SetFormA [WINSPOOL.@]
3085 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3086 LPBYTE pForm)
3088 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3089 return FALSE;
3092 /*****************************************************************************
3093 * SetFormW [WINSPOOL.@]
3095 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3096 LPBYTE pForm)
3098 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3099 return FALSE;
3102 /*****************************************************************************
3103 * ReadPrinter [WINSPOOL.@]
3105 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3106 LPDWORD pNoBytesRead)
3108 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3109 return FALSE;
3112 /*****************************************************************************
3113 * ResetPrinterA [WINSPOOL.@]
3115 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3117 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3118 return FALSE;
3121 /*****************************************************************************
3122 * ResetPrinterW [WINSPOOL.@]
3124 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3126 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3127 return FALSE;
3130 /*****************************************************************************
3131 * WINSPOOL_GetDWORDFromReg
3133 * Return DWORD associated with ValueName from hkey.
3135 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3137 DWORD sz = sizeof(DWORD), type, value = 0;
3138 LONG ret;
3140 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3142 if(ret != ERROR_SUCCESS) {
3143 WARN("Got ret = %d on name %s\n", ret, ValueName);
3144 return 0;
3146 if(type != REG_DWORD) {
3147 ERR("Got type %d\n", type);
3148 return 0;
3150 return value;
3154 /*****************************************************************************
3155 * get_filename_from_reg [internal]
3157 * Get ValueName from hkey storing result in out
3158 * when the Value in the registry has only a filename, use driverdir as prefix
3159 * outlen is space left in out
3160 * String is stored either as unicode or ascii
3164 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3165 LPBYTE out, DWORD outlen, LPDWORD needed)
3167 WCHAR filename[MAX_PATH];
3168 DWORD size;
3169 DWORD type;
3170 LONG ret;
3171 LPWSTR buffer = filename;
3172 LPWSTR ptr;
3174 *needed = 0;
3175 size = sizeof(filename);
3176 buffer[0] = '\0';
3177 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3178 if (ret == ERROR_MORE_DATA) {
3179 TRACE("need dynamic buffer: %u\n", size);
3180 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3181 if (!buffer) {
3182 /* No Memory is bad */
3183 return FALSE;
3185 buffer[0] = '\0';
3186 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3189 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3190 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3191 return FALSE;
3194 ptr = buffer;
3195 while (ptr) {
3196 /* do we have a full path ? */
3197 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3198 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3200 if (!ret) {
3201 /* we must build the full Path */
3202 *needed += dirlen;
3203 if ((out) && (outlen > dirlen)) {
3204 lstrcpyW((LPWSTR)out, driverdir);
3205 out += dirlen;
3206 outlen -= dirlen;
3208 else
3209 out = NULL;
3212 /* write the filename */
3213 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3214 if ((out) && (outlen >= size)) {
3215 lstrcpyW((LPWSTR)out, ptr);
3216 out += size;
3217 outlen -= size;
3219 else
3220 out = NULL;
3221 *needed += size;
3222 ptr += lstrlenW(ptr)+1;
3223 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3226 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3228 /* write the multisz-termination */
3229 if (type == REG_MULTI_SZ) {
3230 size = sizeof(WCHAR);
3232 *needed += size;
3233 if (out && (outlen >= size)) {
3234 memset (out, 0, size);
3237 return TRUE;
3240 /*****************************************************************************
3241 * WINSPOOL_GetStringFromReg
3243 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3244 * String is stored as unicode.
3246 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3247 DWORD buflen, DWORD *needed)
3249 DWORD sz = buflen, type;
3250 LONG ret;
3252 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3253 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3254 WARN("Got ret = %d\n", ret);
3255 *needed = 0;
3256 return FALSE;
3258 /* add space for terminating '\0' */
3259 sz += sizeof(WCHAR);
3260 *needed = sz;
3262 if (ptr)
3263 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3265 return TRUE;
3268 /*****************************************************************************
3269 * WINSPOOL_GetDefaultDevMode
3271 * Get a default DevMode values for wineps.
3272 * FIXME - use ppd.
3275 static void WINSPOOL_GetDefaultDevMode(
3276 LPBYTE ptr,
3277 DWORD buflen, DWORD *needed)
3279 DEVMODEW dm;
3280 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3282 /* fill default DEVMODE - should be read from ppd... */
3283 ZeroMemory( &dm, sizeof(dm) );
3284 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3285 dm.dmSpecVersion = DM_SPECVERSION;
3286 dm.dmDriverVersion = 1;
3287 dm.dmSize = sizeof(DEVMODEW);
3288 dm.dmDriverExtra = 0;
3289 dm.dmFields =
3290 DM_ORIENTATION | DM_PAPERSIZE |
3291 DM_PAPERLENGTH | DM_PAPERWIDTH |
3292 DM_SCALE |
3293 DM_COPIES |
3294 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3295 DM_YRESOLUTION | DM_TTOPTION;
3297 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3298 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3299 dm.u1.s1.dmPaperLength = 2970;
3300 dm.u1.s1.dmPaperWidth = 2100;
3302 dm.u1.s1.dmScale = 100;
3303 dm.u1.s1.dmCopies = 1;
3304 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3305 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3306 /* dm.dmColor */
3307 /* dm.dmDuplex */
3308 dm.dmYResolution = 300; /* 300dpi */
3309 dm.dmTTOption = DMTT_BITMAP;
3310 /* dm.dmCollate */
3311 /* dm.dmFormName */
3312 /* dm.dmLogPixels */
3313 /* dm.dmBitsPerPel */
3314 /* dm.dmPelsWidth */
3315 /* dm.dmPelsHeight */
3316 /* dm.u2.dmDisplayFlags */
3317 /* dm.dmDisplayFrequency */
3318 /* dm.dmICMMethod */
3319 /* dm.dmICMIntent */
3320 /* dm.dmMediaType */
3321 /* dm.dmDitherType */
3322 /* dm.dmReserved1 */
3323 /* dm.dmReserved2 */
3324 /* dm.dmPanningWidth */
3325 /* dm.dmPanningHeight */
3327 if(buflen >= sizeof(DEVMODEW))
3328 memcpy(ptr, &dm, sizeof(DEVMODEW));
3329 *needed = sizeof(DEVMODEW);
3332 /*****************************************************************************
3333 * WINSPOOL_GetDevModeFromReg
3335 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3336 * DevMode is stored either as unicode or ascii.
3338 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3339 LPBYTE ptr,
3340 DWORD buflen, DWORD *needed)
3342 DWORD sz = buflen, type;
3343 LONG ret;
3345 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3346 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3347 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3348 if (sz < sizeof(DEVMODEA))
3350 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3351 return FALSE;
3353 /* ensures that dmSize is not erratically bogus if registry is invalid */
3354 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3355 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3356 sz += (CCHDEVICENAME + CCHFORMNAME);
3357 if (ptr && (buflen >= sz)) {
3358 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3359 memcpy(ptr, dmW, sz);
3360 HeapFree(GetProcessHeap(),0,dmW);
3362 *needed = sz;
3363 return TRUE;
3366 /*********************************************************************
3367 * WINSPOOL_GetPrinter_1
3369 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3371 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3372 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3374 DWORD size, left = cbBuf;
3375 BOOL space = (cbBuf > 0);
3376 LPBYTE ptr = buf;
3378 *pcbNeeded = 0;
3380 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3381 if(space && size <= left) {
3382 pi1->pName = (LPWSTR)ptr;
3383 ptr += size;
3384 left -= size;
3385 } else
3386 space = FALSE;
3387 *pcbNeeded += size;
3390 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3391 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3392 if(space && size <= left) {
3393 pi1->pDescription = (LPWSTR)ptr;
3394 ptr += size;
3395 left -= size;
3396 } else
3397 space = FALSE;
3398 *pcbNeeded += size;
3401 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3402 if(space && size <= left) {
3403 pi1->pComment = (LPWSTR)ptr;
3404 ptr += size;
3405 left -= size;
3406 } else
3407 space = FALSE;
3408 *pcbNeeded += size;
3411 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3413 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3414 memset(pi1, 0, sizeof(*pi1));
3416 return space;
3418 /*********************************************************************
3419 * WINSPOOL_GetPrinter_2
3421 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3423 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3424 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3426 DWORD size, left = cbBuf;
3427 BOOL space = (cbBuf > 0);
3428 LPBYTE ptr = buf;
3430 *pcbNeeded = 0;
3432 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3433 if(space && size <= left) {
3434 pi2->pPrinterName = (LPWSTR)ptr;
3435 ptr += size;
3436 left -= size;
3437 } else
3438 space = FALSE;
3439 *pcbNeeded += size;
3441 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3442 if(space && size <= left) {
3443 pi2->pShareName = (LPWSTR)ptr;
3444 ptr += size;
3445 left -= size;
3446 } else
3447 space = FALSE;
3448 *pcbNeeded += size;
3450 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3451 if(space && size <= left) {
3452 pi2->pPortName = (LPWSTR)ptr;
3453 ptr += size;
3454 left -= size;
3455 } else
3456 space = FALSE;
3457 *pcbNeeded += size;
3459 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3460 if(space && size <= left) {
3461 pi2->pDriverName = (LPWSTR)ptr;
3462 ptr += size;
3463 left -= size;
3464 } else
3465 space = FALSE;
3466 *pcbNeeded += size;
3468 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3469 if(space && size <= left) {
3470 pi2->pComment = (LPWSTR)ptr;
3471 ptr += size;
3472 left -= size;
3473 } else
3474 space = FALSE;
3475 *pcbNeeded += size;
3477 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3478 if(space && size <= left) {
3479 pi2->pLocation = (LPWSTR)ptr;
3480 ptr += size;
3481 left -= size;
3482 } else
3483 space = FALSE;
3484 *pcbNeeded += size;
3486 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3487 if(space && size <= left) {
3488 pi2->pDevMode = (LPDEVMODEW)ptr;
3489 ptr += size;
3490 left -= size;
3491 } else
3492 space = FALSE;
3493 *pcbNeeded += size;
3495 else
3497 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3498 if(space && size <= left) {
3499 pi2->pDevMode = (LPDEVMODEW)ptr;
3500 ptr += size;
3501 left -= size;
3502 } else
3503 space = FALSE;
3504 *pcbNeeded += size;
3506 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3507 if(space && size <= left) {
3508 pi2->pSepFile = (LPWSTR)ptr;
3509 ptr += size;
3510 left -= size;
3511 } else
3512 space = FALSE;
3513 *pcbNeeded += size;
3515 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3516 if(space && size <= left) {
3517 pi2->pPrintProcessor = (LPWSTR)ptr;
3518 ptr += size;
3519 left -= size;
3520 } else
3521 space = FALSE;
3522 *pcbNeeded += size;
3524 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3525 if(space && size <= left) {
3526 pi2->pDatatype = (LPWSTR)ptr;
3527 ptr += size;
3528 left -= size;
3529 } else
3530 space = FALSE;
3531 *pcbNeeded += size;
3533 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3534 if(space && size <= left) {
3535 pi2->pParameters = (LPWSTR)ptr;
3536 ptr += size;
3537 left -= size;
3538 } else
3539 space = FALSE;
3540 *pcbNeeded += size;
3542 if(pi2) {
3543 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3544 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3545 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3546 "Default Priority");
3547 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3548 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3551 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3552 memset(pi2, 0, sizeof(*pi2));
3554 return space;
3557 /*********************************************************************
3558 * WINSPOOL_GetPrinter_4
3560 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3562 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3563 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3565 DWORD size, left = cbBuf;
3566 BOOL space = (cbBuf > 0);
3567 LPBYTE ptr = buf;
3569 *pcbNeeded = 0;
3571 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3572 if(space && size <= left) {
3573 pi4->pPrinterName = (LPWSTR)ptr;
3574 ptr += size;
3575 left -= size;
3576 } else
3577 space = FALSE;
3578 *pcbNeeded += size;
3580 if(pi4) {
3581 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3584 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3585 memset(pi4, 0, sizeof(*pi4));
3587 return space;
3590 /*********************************************************************
3591 * WINSPOOL_GetPrinter_5
3593 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3595 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3596 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3598 DWORD size, left = cbBuf;
3599 BOOL space = (cbBuf > 0);
3600 LPBYTE ptr = buf;
3602 *pcbNeeded = 0;
3604 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3605 if(space && size <= left) {
3606 pi5->pPrinterName = (LPWSTR)ptr;
3607 ptr += size;
3608 left -= size;
3609 } else
3610 space = FALSE;
3611 *pcbNeeded += size;
3613 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3614 if(space && size <= left) {
3615 pi5->pPortName = (LPWSTR)ptr;
3616 ptr += size;
3617 left -= size;
3618 } else
3619 space = FALSE;
3620 *pcbNeeded += size;
3622 if(pi5) {
3623 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3624 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3625 "dnsTimeout");
3626 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3627 "txTimeout");
3630 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3631 memset(pi5, 0, sizeof(*pi5));
3633 return space;
3636 /*********************************************************************
3637 * WINSPOOL_GetPrinter_7
3639 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3641 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3642 DWORD cbBuf, LPDWORD pcbNeeded)
3644 DWORD size, left = cbBuf;
3645 BOOL space = (cbBuf > 0);
3646 LPBYTE ptr = buf;
3648 *pcbNeeded = 0;
3650 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3652 ptr = NULL;
3653 size = sizeof(pi7->pszObjectGUID);
3655 if (space && size <= left) {
3656 pi7->pszObjectGUID = (LPWSTR)ptr;
3657 ptr += size;
3658 left -= size;
3659 } else
3660 space = FALSE;
3661 *pcbNeeded += size;
3662 if (pi7) {
3663 /* We do not have a Directory Service */
3664 pi7->dwAction = DSPRINT_UNPUBLISH;
3667 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3668 memset(pi7, 0, sizeof(*pi7));
3670 return space;
3673 /*********************************************************************
3674 * WINSPOOL_GetPrinter_9
3676 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3678 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3679 DWORD cbBuf, LPDWORD pcbNeeded)
3681 DWORD size;
3682 BOOL space = (cbBuf > 0);
3684 *pcbNeeded = 0;
3686 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3687 if(space && size <= cbBuf) {
3688 pi9->pDevMode = (LPDEVMODEW)buf;
3689 } else
3690 space = FALSE;
3691 *pcbNeeded += size;
3693 else
3695 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3696 if(space && size <= cbBuf) {
3697 pi9->pDevMode = (LPDEVMODEW)buf;
3698 } else
3699 space = FALSE;
3700 *pcbNeeded += size;
3703 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3704 memset(pi9, 0, sizeof(*pi9));
3706 return space;
3709 /*****************************************************************************
3710 * GetPrinterW [WINSPOOL.@]
3712 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3713 DWORD cbBuf, LPDWORD pcbNeeded)
3715 LPCWSTR name;
3716 DWORD size, needed = 0;
3717 LPBYTE ptr = NULL;
3718 HKEY hkeyPrinter, hkeyPrinters;
3719 BOOL ret;
3721 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3723 if (!(name = get_opened_printer_name(hPrinter))) {
3724 SetLastError(ERROR_INVALID_HANDLE);
3725 return FALSE;
3728 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3729 ERROR_SUCCESS) {
3730 ERR("Can't create Printers key\n");
3731 return FALSE;
3733 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3735 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3736 RegCloseKey(hkeyPrinters);
3737 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3738 return FALSE;
3741 switch(Level) {
3742 case 2:
3744 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3746 size = sizeof(PRINTER_INFO_2W);
3747 if(size <= cbBuf) {
3748 ptr = pPrinter + size;
3749 cbBuf -= size;
3750 memset(pPrinter, 0, size);
3751 } else {
3752 pi2 = NULL;
3753 cbBuf = 0;
3755 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3756 needed += size;
3757 break;
3760 case 4:
3762 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3764 size = sizeof(PRINTER_INFO_4W);
3765 if(size <= cbBuf) {
3766 ptr = pPrinter + size;
3767 cbBuf -= size;
3768 memset(pPrinter, 0, size);
3769 } else {
3770 pi4 = NULL;
3771 cbBuf = 0;
3773 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3774 needed += size;
3775 break;
3779 case 5:
3781 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3783 size = sizeof(PRINTER_INFO_5W);
3784 if(size <= cbBuf) {
3785 ptr = pPrinter + size;
3786 cbBuf -= size;
3787 memset(pPrinter, 0, size);
3788 } else {
3789 pi5 = NULL;
3790 cbBuf = 0;
3793 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3794 needed += size;
3795 break;
3799 case 6:
3801 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3803 size = sizeof(PRINTER_INFO_6);
3804 if (size <= cbBuf) {
3805 /* FIXME: We do not update the status yet */
3806 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3807 ret = TRUE;
3808 } else {
3809 ret = FALSE;
3812 needed += size;
3813 break;
3816 case 7:
3818 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3820 size = sizeof(PRINTER_INFO_7W);
3821 if (size <= cbBuf) {
3822 ptr = pPrinter + size;
3823 cbBuf -= size;
3824 memset(pPrinter, 0, size);
3825 } else {
3826 pi7 = NULL;
3827 cbBuf = 0;
3830 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3831 needed += size;
3832 break;
3836 case 9:
3838 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3840 size = sizeof(PRINTER_INFO_9W);
3841 if(size <= cbBuf) {
3842 ptr = pPrinter + size;
3843 cbBuf -= size;
3844 memset(pPrinter, 0, size);
3845 } else {
3846 pi9 = NULL;
3847 cbBuf = 0;
3850 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3851 needed += size;
3852 break;
3856 default:
3857 FIXME("Unimplemented level %d\n", Level);
3858 SetLastError(ERROR_INVALID_LEVEL);
3859 RegCloseKey(hkeyPrinters);
3860 RegCloseKey(hkeyPrinter);
3861 return FALSE;
3864 RegCloseKey(hkeyPrinter);
3865 RegCloseKey(hkeyPrinters);
3867 TRACE("returning %d needed = %d\n", ret, needed);
3868 if(pcbNeeded) *pcbNeeded = needed;
3869 if(!ret)
3870 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3871 return ret;
3874 /*****************************************************************************
3875 * GetPrinterA [WINSPOOL.@]
3877 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3878 DWORD cbBuf, LPDWORD pcbNeeded)
3880 BOOL ret;
3881 LPBYTE buf = NULL;
3883 if (cbBuf)
3884 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3886 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3887 if (ret)
3888 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3889 HeapFree(GetProcessHeap(), 0, buf);
3891 return ret;
3894 /*****************************************************************************
3895 * WINSPOOL_EnumPrintersW
3897 * Implementation of EnumPrintersW
3899 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3900 DWORD dwLevel, LPBYTE lpbPrinters,
3901 DWORD cbBuf, LPDWORD lpdwNeeded,
3902 LPDWORD lpdwReturned)
3905 HKEY hkeyPrinters, hkeyPrinter;
3906 WCHAR PrinterName[255];
3907 DWORD needed = 0, number = 0;
3908 DWORD used, i, left;
3909 PBYTE pi, buf;
3911 if(lpbPrinters)
3912 memset(lpbPrinters, 0, cbBuf);
3913 if(lpdwReturned)
3914 *lpdwReturned = 0;
3915 if(lpdwNeeded)
3916 *lpdwNeeded = 0;
3918 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3919 if(dwType == PRINTER_ENUM_DEFAULT)
3920 return TRUE;
3922 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3923 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3924 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3925 if (!dwType) {
3926 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3927 return TRUE;
3932 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3933 FIXME("dwType = %08x\n", dwType);
3934 SetLastError(ERROR_INVALID_FLAGS);
3935 return FALSE;
3938 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3939 ERROR_SUCCESS) {
3940 ERR("Can't create Printers key\n");
3941 return FALSE;
3944 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3945 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3946 RegCloseKey(hkeyPrinters);
3947 ERR("Can't query Printers key\n");
3948 return FALSE;
3950 TRACE("Found %d printers\n", number);
3952 switch(dwLevel) {
3953 case 1:
3954 used = number * sizeof(PRINTER_INFO_1W);
3955 break;
3956 case 2:
3957 used = number * sizeof(PRINTER_INFO_2W);
3958 break;
3959 case 4:
3960 used = number * sizeof(PRINTER_INFO_4W);
3961 break;
3962 case 5:
3963 used = number * sizeof(PRINTER_INFO_5W);
3964 break;
3966 default:
3967 SetLastError(ERROR_INVALID_LEVEL);
3968 RegCloseKey(hkeyPrinters);
3969 return FALSE;
3971 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3973 for(i = 0; i < number; i++) {
3974 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3975 ERROR_SUCCESS) {
3976 ERR("Can't enum key number %d\n", i);
3977 RegCloseKey(hkeyPrinters);
3978 return FALSE;
3980 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3981 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3982 ERROR_SUCCESS) {
3983 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3984 RegCloseKey(hkeyPrinters);
3985 return FALSE;
3988 if(cbBuf > used) {
3989 buf = lpbPrinters + used;
3990 left = cbBuf - used;
3991 } else {
3992 buf = NULL;
3993 left = 0;
3996 switch(dwLevel) {
3997 case 1:
3998 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3999 left, &needed);
4000 used += needed;
4001 if(pi) pi += sizeof(PRINTER_INFO_1W);
4002 break;
4003 case 2:
4004 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4005 left, &needed);
4006 used += needed;
4007 if(pi) pi += sizeof(PRINTER_INFO_2W);
4008 break;
4009 case 4:
4010 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4011 left, &needed);
4012 used += needed;
4013 if(pi) pi += sizeof(PRINTER_INFO_4W);
4014 break;
4015 case 5:
4016 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4017 left, &needed);
4018 used += needed;
4019 if(pi) pi += sizeof(PRINTER_INFO_5W);
4020 break;
4021 default:
4022 ERR("Shouldn't be here!\n");
4023 RegCloseKey(hkeyPrinter);
4024 RegCloseKey(hkeyPrinters);
4025 return FALSE;
4027 RegCloseKey(hkeyPrinter);
4029 RegCloseKey(hkeyPrinters);
4031 if(lpdwNeeded)
4032 *lpdwNeeded = used;
4034 if(used > cbBuf) {
4035 if(lpbPrinters)
4036 memset(lpbPrinters, 0, cbBuf);
4037 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4038 return FALSE;
4040 if(lpdwReturned)
4041 *lpdwReturned = number;
4042 SetLastError(ERROR_SUCCESS);
4043 return TRUE;
4047 /******************************************************************
4048 * EnumPrintersW [WINSPOOL.@]
4050 * Enumerates the available printers, print servers and print
4051 * providers, depending on the specified flags, name and level.
4053 * RETURNS:
4055 * If level is set to 1:
4056 * Returns an array of PRINTER_INFO_1 data structures in the
4057 * lpbPrinters buffer.
4059 * If level is set to 2:
4060 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4061 * Returns an array of PRINTER_INFO_2 data structures in the
4062 * lpbPrinters buffer. Note that according to MSDN also an
4063 * OpenPrinter should be performed on every remote printer.
4065 * If level is set to 4 (officially WinNT only):
4066 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4067 * Fast: Only the registry is queried to retrieve printer names,
4068 * no connection to the driver is made.
4069 * Returns an array of PRINTER_INFO_4 data structures in the
4070 * lpbPrinters buffer.
4072 * If level is set to 5 (officially WinNT4/Win9x only):
4073 * Fast: Only the registry is queried to retrieve printer names,
4074 * no connection to the driver is made.
4075 * Returns an array of PRINTER_INFO_5 data structures in the
4076 * lpbPrinters buffer.
4078 * If level set to 3 or 6+:
4079 * returns zero (failure!)
4081 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4082 * for information.
4084 * BUGS:
4085 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4086 * - Only levels 2, 4 and 5 are implemented at the moment.
4087 * - 16-bit printer drivers are not enumerated.
4088 * - Returned amount of bytes used/needed does not match the real Windoze
4089 * implementation (as in this implementation, all strings are part
4090 * of the buffer, whereas Win32 keeps them somewhere else)
4091 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4093 * NOTE:
4094 * - In a regular Wine installation, no registry settings for printers
4095 * exist, which makes this function return an empty list.
4097 BOOL WINAPI EnumPrintersW(
4098 DWORD dwType, /* [in] Types of print objects to enumerate */
4099 LPWSTR lpszName, /* [in] name of objects to enumerate */
4100 DWORD dwLevel, /* [in] type of printer info structure */
4101 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4102 DWORD cbBuf, /* [in] max size of buffer in bytes */
4103 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4104 LPDWORD lpdwReturned /* [out] number of entries returned */
4107 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4108 lpdwNeeded, lpdwReturned);
4111 /******************************************************************
4112 * EnumPrintersA [WINSPOOL.@]
4114 * See EnumPrintersW
4117 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4118 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4120 BOOL ret;
4121 UNICODE_STRING pNameU;
4122 LPWSTR pNameW;
4123 LPBYTE pPrintersW;
4125 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4126 pPrinters, cbBuf, pcbNeeded, pcReturned);
4128 pNameW = asciitounicode(&pNameU, pName);
4130 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4131 MS Office need this */
4132 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4134 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4136 RtlFreeUnicodeString(&pNameU);
4137 if (ret) {
4138 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4140 HeapFree(GetProcessHeap(), 0, pPrintersW);
4141 return ret;
4144 /*****************************************************************************
4145 * WINSPOOL_GetDriverInfoFromReg [internal]
4147 * Enters the information from the registry into the DRIVER_INFO struct
4149 * RETURNS
4150 * zero if the printer driver does not exist in the registry
4151 * (only if Level > 1) otherwise nonzero
4153 static BOOL WINSPOOL_GetDriverInfoFromReg(
4154 HKEY hkeyDrivers,
4155 LPWSTR DriverName,
4156 const printenv_t * env,
4157 DWORD Level,
4158 LPBYTE ptr, /* DRIVER_INFO */
4159 LPBYTE pDriverStrings, /* strings buffer */
4160 DWORD cbBuf, /* size of string buffer */
4161 LPDWORD pcbNeeded) /* space needed for str. */
4163 DWORD size, tmp;
4164 HKEY hkeyDriver;
4165 WCHAR driverdir[MAX_PATH];
4166 DWORD dirlen;
4167 LPBYTE strPtr = pDriverStrings;
4168 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4170 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4171 debugstr_w(DriverName), env,
4172 Level, di, pDriverStrings, cbBuf);
4174 if (di) ZeroMemory(di, di_sizeof[Level]);
4176 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4177 if (*pcbNeeded <= cbBuf)
4178 strcpyW((LPWSTR)strPtr, DriverName);
4180 /* pName for level 1 has a different offset! */
4181 if (Level == 1) {
4182 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4183 return TRUE;
4186 /* .cVersion and .pName for level > 1 */
4187 if (di) {
4188 di->cVersion = env->driverversion;
4189 di->pName = (LPWSTR) strPtr;
4190 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4193 /* Reserve Space for the largest subdir and a Backslash*/
4194 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4195 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4196 /* Should never Fail */
4197 return FALSE;
4199 lstrcatW(driverdir, env->versionsubdir);
4200 lstrcatW(driverdir, backslashW);
4202 /* dirlen must not include the terminating zero */
4203 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4205 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4206 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4207 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4208 return FALSE;
4211 /* pEnvironment */
4212 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4214 *pcbNeeded += size;
4215 if (*pcbNeeded <= cbBuf) {
4216 lstrcpyW((LPWSTR)strPtr, env->envname);
4217 if (di) di->pEnvironment = (LPWSTR)strPtr;
4218 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4221 /* .pDriverPath is the Graphics rendering engine.
4222 The full Path is required to avoid a crash in some apps */
4223 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4224 *pcbNeeded += size;
4225 if (*pcbNeeded <= cbBuf)
4226 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4228 if (di) di->pDriverPath = (LPWSTR)strPtr;
4229 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4232 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4233 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4234 *pcbNeeded += size;
4235 if (*pcbNeeded <= cbBuf)
4236 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4238 if (di) di->pDataFile = (LPWSTR)strPtr;
4239 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4242 /* .pConfigFile is the Driver user Interface */
4243 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4244 *pcbNeeded += size;
4245 if (*pcbNeeded <= cbBuf)
4246 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4248 if (di) di->pConfigFile = (LPWSTR)strPtr;
4249 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4252 if (Level == 2 ) {
4253 RegCloseKey(hkeyDriver);
4254 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4255 return TRUE;
4258 if (Level == 5 ) {
4259 RegCloseKey(hkeyDriver);
4260 FIXME("level 5: incomplete\n");
4261 return TRUE;
4264 /* .pHelpFile */
4265 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4266 *pcbNeeded += size;
4267 if (*pcbNeeded <= cbBuf)
4268 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4270 if (di) di->pHelpFile = (LPWSTR)strPtr;
4271 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4274 /* .pDependentFiles */
4275 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4276 *pcbNeeded += size;
4277 if (*pcbNeeded <= cbBuf)
4278 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4280 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4281 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4283 else if (GetVersion() & 0x80000000) {
4284 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4285 size = 2 * sizeof(WCHAR);
4286 *pcbNeeded += size;
4287 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4289 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4290 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4293 /* .pMonitorName is the optional Language Monitor */
4294 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4295 *pcbNeeded += size;
4296 if (*pcbNeeded <= cbBuf)
4297 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4299 if (di) di->pMonitorName = (LPWSTR)strPtr;
4300 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4303 /* .pDefaultDataType */
4304 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4305 *pcbNeeded += size;
4306 if(*pcbNeeded <= cbBuf)
4307 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4309 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4310 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4313 if (Level == 3 ) {
4314 RegCloseKey(hkeyDriver);
4315 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4316 return TRUE;
4319 /* .pszzPreviousNames */
4320 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4321 *pcbNeeded += size;
4322 if(*pcbNeeded <= cbBuf)
4323 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4325 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4326 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4329 if (Level == 4 ) {
4330 RegCloseKey(hkeyDriver);
4331 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4332 return TRUE;
4335 /* support is missing, but not important enough for a FIXME */
4336 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4338 /* .pszMfgName */
4339 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4340 *pcbNeeded += size;
4341 if(*pcbNeeded <= cbBuf)
4342 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4344 if (di) di->pszMfgName = (LPWSTR)strPtr;
4345 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4348 /* .pszOEMUrl */
4349 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4350 *pcbNeeded += size;
4351 if(*pcbNeeded <= cbBuf)
4352 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4354 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4355 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4358 /* .pszHardwareID */
4359 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4360 *pcbNeeded += size;
4361 if(*pcbNeeded <= cbBuf)
4362 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4364 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4365 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4368 /* .pszProvider */
4369 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4370 *pcbNeeded += size;
4371 if(*pcbNeeded <= cbBuf)
4372 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4374 if (di) di->pszProvider = (LPWSTR)strPtr;
4375 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4378 if (Level == 6 ) {
4379 RegCloseKey(hkeyDriver);
4380 return TRUE;
4383 /* support is missing, but not important enough for a FIXME */
4384 TRACE("level 8: incomplete\n");
4386 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4387 RegCloseKey(hkeyDriver);
4388 return TRUE;
4391 /*****************************************************************************
4392 * GetPrinterDriverW [WINSPOOL.@]
4394 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4395 DWORD Level, LPBYTE pDriverInfo,
4396 DWORD cbBuf, LPDWORD pcbNeeded)
4398 LPCWSTR name;
4399 WCHAR DriverName[100];
4400 DWORD ret, type, size, needed = 0;
4401 LPBYTE ptr = NULL;
4402 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4403 const printenv_t * env;
4405 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4406 Level,pDriverInfo,cbBuf, pcbNeeded);
4408 if (cbBuf > 0)
4409 ZeroMemory(pDriverInfo, cbBuf);
4411 if (!(name = get_opened_printer_name(hPrinter))) {
4412 SetLastError(ERROR_INVALID_HANDLE);
4413 return FALSE;
4416 if (Level < 1 || Level == 7 || Level > 8) {
4417 SetLastError(ERROR_INVALID_LEVEL);
4418 return FALSE;
4421 env = validate_envW(pEnvironment);
4422 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4424 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4425 ERROR_SUCCESS) {
4426 ERR("Can't create Printers key\n");
4427 return FALSE;
4429 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4430 != ERROR_SUCCESS) {
4431 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4432 RegCloseKey(hkeyPrinters);
4433 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4434 return FALSE;
4436 size = sizeof(DriverName);
4437 DriverName[0] = 0;
4438 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4439 (LPBYTE)DriverName, &size);
4440 RegCloseKey(hkeyPrinter);
4441 RegCloseKey(hkeyPrinters);
4442 if(ret != ERROR_SUCCESS) {
4443 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4444 return FALSE;
4447 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4448 if(!hkeyDrivers) {
4449 ERR("Can't create Drivers key\n");
4450 return FALSE;
4453 size = di_sizeof[Level];
4454 if ((size <= cbBuf) && pDriverInfo)
4455 ptr = pDriverInfo + size;
4457 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4458 env, Level, pDriverInfo, ptr,
4459 (cbBuf < size) ? 0 : cbBuf - size,
4460 &needed)) {
4461 RegCloseKey(hkeyDrivers);
4462 return FALSE;
4465 RegCloseKey(hkeyDrivers);
4467 if(pcbNeeded) *pcbNeeded = size + needed;
4468 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4469 if(cbBuf >= size + needed) return TRUE;
4470 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4471 return FALSE;
4474 /*****************************************************************************
4475 * GetPrinterDriverA [WINSPOOL.@]
4477 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4478 DWORD Level, LPBYTE pDriverInfo,
4479 DWORD cbBuf, LPDWORD pcbNeeded)
4481 BOOL ret;
4482 UNICODE_STRING pEnvW;
4483 PWSTR pwstrEnvW;
4484 LPBYTE buf = NULL;
4486 if (cbBuf)
4488 ZeroMemory(pDriverInfo, cbBuf);
4489 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4492 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4493 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4494 cbBuf, pcbNeeded);
4495 if (ret)
4496 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4498 HeapFree(GetProcessHeap(), 0, buf);
4500 RtlFreeUnicodeString(&pEnvW);
4501 return ret;
4504 /*****************************************************************************
4505 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4507 * Return the PATH for the Printer-Drivers (UNICODE)
4509 * PARAMS
4510 * pName [I] Servername (NT only) or NULL (local Computer)
4511 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4512 * Level [I] Structure-Level (must be 1)
4513 * pDriverDirectory [O] PTR to Buffer that receives the Result
4514 * cbBuf [I] Size of Buffer at pDriverDirectory
4515 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4516 * required for pDriverDirectory
4518 * RETURNS
4519 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4520 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4521 * if cbBuf is too small
4523 * Native Values returned in pDriverDirectory on Success:
4524 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4525 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4526 *| win9x(Windows 4.0): "%winsysdir%"
4528 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4530 * FIXME
4531 *- Only NULL or "" is supported for pName
4534 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4535 DWORD Level, LPBYTE pDriverDirectory,
4536 DWORD cbBuf, LPDWORD pcbNeeded)
4538 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4539 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4541 if ((backend == NULL) && !load_backend()) return FALSE;
4543 if (Level != 1) {
4544 /* (Level != 1) is ignored in win9x */
4545 SetLastError(ERROR_INVALID_LEVEL);
4546 return FALSE;
4548 if (pcbNeeded == NULL) {
4549 /* (pcbNeeded == NULL) is ignored in win9x */
4550 SetLastError(RPC_X_NULL_REF_POINTER);
4551 return FALSE;
4554 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4555 pDriverDirectory, cbBuf, pcbNeeded);
4560 /*****************************************************************************
4561 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4563 * Return the PATH for the Printer-Drivers (ANSI)
4565 * See GetPrinterDriverDirectoryW.
4567 * NOTES
4568 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4571 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4572 DWORD Level, LPBYTE pDriverDirectory,
4573 DWORD cbBuf, LPDWORD pcbNeeded)
4575 UNICODE_STRING nameW, environmentW;
4576 BOOL ret;
4577 DWORD pcbNeededW;
4578 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4579 WCHAR *driverDirectoryW = NULL;
4581 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4582 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4584 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4586 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4587 else nameW.Buffer = NULL;
4588 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4589 else environmentW.Buffer = NULL;
4591 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4592 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4593 if (ret) {
4594 DWORD needed;
4595 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4596 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4597 if(pcbNeeded)
4598 *pcbNeeded = needed;
4599 ret = (needed <= cbBuf) ? TRUE : FALSE;
4600 } else
4601 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4603 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4605 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4606 RtlFreeUnicodeString(&environmentW);
4607 RtlFreeUnicodeString(&nameW);
4609 return ret;
4612 /*****************************************************************************
4613 * AddPrinterDriverA [WINSPOOL.@]
4615 * See AddPrinterDriverW.
4618 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4620 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4621 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4624 /******************************************************************************
4625 * AddPrinterDriverW (WINSPOOL.@)
4627 * Install a Printer Driver
4629 * PARAMS
4630 * pName [I] Servername or NULL (local Computer)
4631 * level [I] Level for the supplied DRIVER_INFO_*W struct
4632 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4634 * RESULTS
4635 * Success: TRUE
4636 * Failure: FALSE
4639 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4641 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4642 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4645 /*****************************************************************************
4646 * AddPrintProcessorA [WINSPOOL.@]
4648 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4649 LPSTR pPrintProcessorName)
4651 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4652 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4653 return FALSE;
4656 /*****************************************************************************
4657 * AddPrintProcessorW [WINSPOOL.@]
4659 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4660 LPWSTR pPrintProcessorName)
4662 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4663 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4664 return FALSE;
4667 /*****************************************************************************
4668 * AddPrintProvidorA [WINSPOOL.@]
4670 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4672 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4673 return FALSE;
4676 /*****************************************************************************
4677 * AddPrintProvidorW [WINSPOOL.@]
4679 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4681 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4682 return FALSE;
4685 /*****************************************************************************
4686 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4688 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4689 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4691 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4692 pDevModeOutput, pDevModeInput);
4693 return 0;
4696 /*****************************************************************************
4697 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4699 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4700 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4702 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4703 pDevModeOutput, pDevModeInput);
4704 return 0;
4707 /*****************************************************************************
4708 * PrinterProperties [WINSPOOL.@]
4710 * Displays a dialog to set the properties of the printer.
4712 * RETURNS
4713 * nonzero on success or zero on failure
4715 * BUGS
4716 * implemented as stub only
4718 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4719 HANDLE hPrinter /* [in] handle to printer object */
4721 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4722 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4723 return FALSE;
4726 /*****************************************************************************
4727 * EnumJobsA [WINSPOOL.@]
4730 BOOL WINAPI EnumJobsA(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;
4743 /*****************************************************************************
4744 * EnumJobsW [WINSPOOL.@]
4747 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4748 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4749 LPDWORD pcReturned)
4751 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4752 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4754 if(pcbNeeded) *pcbNeeded = 0;
4755 if(pcReturned) *pcReturned = 0;
4756 return FALSE;
4759 /*****************************************************************************
4760 * WINSPOOL_EnumPrinterDrivers [internal]
4762 * Delivers information about all printer drivers installed on the
4763 * localhost or a given server
4765 * RETURNS
4766 * nonzero on success or zero on failure. If the buffer for the returned
4767 * information is too small the function will return an error
4769 * BUGS
4770 * - only implemented for localhost, foreign hosts will return an error
4772 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4773 DWORD Level, LPBYTE pDriverInfo,
4774 DWORD driver_index,
4775 DWORD cbBuf, LPDWORD pcbNeeded,
4776 LPDWORD pcFound, DWORD data_offset)
4778 { HKEY hkeyDrivers;
4779 DWORD i, size = 0;
4780 const printenv_t * env;
4782 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4783 debugstr_w(pName), debugstr_w(pEnvironment),
4784 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4786 env = validate_envW(pEnvironment);
4787 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4789 *pcFound = 0;
4791 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4792 if(!hkeyDrivers) {
4793 ERR("Can't open Drivers key\n");
4794 return FALSE;
4797 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4798 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4799 RegCloseKey(hkeyDrivers);
4800 ERR("Can't query Drivers key\n");
4801 return FALSE;
4803 TRACE("Found %d Drivers\n", *pcFound);
4805 /* get size of single struct
4806 * unicode and ascii structure have the same size
4808 size = di_sizeof[Level];
4810 if (data_offset == 0)
4811 data_offset = size * (*pcFound);
4812 *pcbNeeded = data_offset;
4814 for( i = 0; i < *pcFound; i++) {
4815 WCHAR DriverNameW[255];
4816 PBYTE table_ptr = NULL;
4817 PBYTE data_ptr = NULL;
4818 DWORD needed = 0;
4820 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4821 != ERROR_SUCCESS) {
4822 ERR("Can't enum key number %d\n", i);
4823 RegCloseKey(hkeyDrivers);
4824 return FALSE;
4827 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4828 table_ptr = pDriverInfo + (driver_index + i) * size;
4829 if (pDriverInfo && *pcbNeeded <= cbBuf)
4830 data_ptr = pDriverInfo + *pcbNeeded;
4832 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4833 env, Level, table_ptr, data_ptr,
4834 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4835 &needed)) {
4836 RegCloseKey(hkeyDrivers);
4837 return FALSE;
4840 *pcbNeeded += needed;
4843 RegCloseKey(hkeyDrivers);
4845 if(cbBuf < *pcbNeeded){
4846 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4847 return FALSE;
4850 return TRUE;
4853 /*****************************************************************************
4854 * EnumPrinterDriversW [WINSPOOL.@]
4856 * see function EnumPrinterDrivers for RETURNS, BUGS
4858 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4859 LPBYTE pDriverInfo, DWORD cbBuf,
4860 LPDWORD pcbNeeded, LPDWORD pcReturned)
4862 static const WCHAR allW[] = {'a','l','l',0};
4863 BOOL ret;
4864 DWORD found;
4866 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4868 SetLastError(RPC_X_NULL_REF_POINTER);
4869 return FALSE;
4872 /* check for local drivers */
4873 if((pName) && (pName[0])) {
4874 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4875 SetLastError(ERROR_ACCESS_DENIED);
4876 return FALSE;
4879 /* check input parameter */
4880 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4881 SetLastError(ERROR_INVALID_LEVEL);
4882 return FALSE;
4885 if(pDriverInfo && cbBuf > 0)
4886 memset( pDriverInfo, 0, cbBuf);
4888 /* Exception: pull all printers */
4889 if (pEnvironment && !strcmpW(pEnvironment, allW))
4891 DWORD i, needed, bufsize = cbBuf;
4892 DWORD total_needed = 0;
4893 DWORD total_found = 0;
4894 DWORD data_offset;
4896 /* Precompute the overall total; we need this to know
4897 where pointers end and data begins (i.e. data_offset) */
4898 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4900 needed = found = 0;
4901 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4902 NULL, 0, 0, &needed, &found, 0);
4903 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4904 total_needed += needed;
4905 total_found += found;
4908 data_offset = di_sizeof[Level] * total_found;
4910 *pcReturned = 0;
4911 *pcbNeeded = 0;
4912 total_found = 0;
4913 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4915 needed = found = 0;
4916 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4917 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4918 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4919 else if (ret)
4920 *pcReturned += found;
4921 *pcbNeeded = needed;
4922 data_offset = needed;
4923 total_found += found;
4925 return ret;
4928 /* Normal behavior */
4929 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4930 0, cbBuf, pcbNeeded, &found, 0);
4931 if (ret)
4932 *pcReturned = found;
4934 return ret;
4937 /*****************************************************************************
4938 * EnumPrinterDriversA [WINSPOOL.@]
4940 * see function EnumPrinterDrivers for RETURNS, BUGS
4942 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4943 LPBYTE pDriverInfo, DWORD cbBuf,
4944 LPDWORD pcbNeeded, LPDWORD pcReturned)
4946 BOOL ret;
4947 UNICODE_STRING pNameW, pEnvironmentW;
4948 PWSTR pwstrNameW, pwstrEnvironmentW;
4949 LPBYTE buf = NULL;
4951 if (cbBuf)
4952 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4954 pwstrNameW = asciitounicode(&pNameW, pName);
4955 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4957 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4958 buf, cbBuf, pcbNeeded, pcReturned);
4959 if (ret)
4960 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4962 HeapFree(GetProcessHeap(), 0, buf);
4964 RtlFreeUnicodeString(&pNameW);
4965 RtlFreeUnicodeString(&pEnvironmentW);
4967 return ret;
4970 /******************************************************************************
4971 * EnumPortsA (WINSPOOL.@)
4973 * See EnumPortsW.
4976 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4977 LPDWORD pcbNeeded, LPDWORD pcReturned)
4979 BOOL res;
4980 LPBYTE bufferW = NULL;
4981 LPWSTR nameW = NULL;
4982 DWORD needed = 0;
4983 DWORD numentries = 0;
4984 INT len;
4986 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4987 cbBuf, pcbNeeded, pcReturned);
4989 /* convert servername to unicode */
4990 if (pName) {
4991 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4992 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4993 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4995 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4996 needed = cbBuf * sizeof(WCHAR);
4997 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4998 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5000 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5001 if (pcbNeeded) needed = *pcbNeeded;
5002 /* HeapReAlloc return NULL, when bufferW was NULL */
5003 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5004 HeapAlloc(GetProcessHeap(), 0, needed);
5006 /* Try again with the large Buffer */
5007 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5009 needed = pcbNeeded ? *pcbNeeded : 0;
5010 numentries = pcReturned ? *pcReturned : 0;
5013 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5014 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5016 if (res) {
5017 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5018 DWORD entrysize = 0;
5019 DWORD index;
5020 LPSTR ptr;
5021 LPPORT_INFO_2W pi2w;
5022 LPPORT_INFO_2A pi2a;
5024 needed = 0;
5025 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5027 /* First pass: calculate the size for all Entries */
5028 pi2w = (LPPORT_INFO_2W) bufferW;
5029 pi2a = (LPPORT_INFO_2A) pPorts;
5030 index = 0;
5031 while (index < numentries) {
5032 index++;
5033 needed += entrysize; /* PORT_INFO_?A */
5034 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5036 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5037 NULL, 0, NULL, NULL);
5038 if (Level > 1) {
5039 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5040 NULL, 0, NULL, NULL);
5041 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5042 NULL, 0, NULL, NULL);
5044 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5045 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5046 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5049 /* check for errors and quit on failure */
5050 if (cbBuf < needed) {
5051 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5052 res = FALSE;
5053 goto cleanup;
5055 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5056 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5057 cbBuf -= len ; /* free Bytes in the user-Buffer */
5058 pi2w = (LPPORT_INFO_2W) bufferW;
5059 pi2a = (LPPORT_INFO_2A) pPorts;
5060 index = 0;
5061 /* Second Pass: Fill the User Buffer (if we have one) */
5062 while ((index < numentries) && pPorts) {
5063 index++;
5064 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5065 pi2a->pPortName = ptr;
5066 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5067 ptr, cbBuf , NULL, NULL);
5068 ptr += len;
5069 cbBuf -= len;
5070 if (Level > 1) {
5071 pi2a->pMonitorName = ptr;
5072 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5073 ptr, cbBuf, NULL, NULL);
5074 ptr += len;
5075 cbBuf -= len;
5077 pi2a->pDescription = ptr;
5078 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5079 ptr, cbBuf, NULL, NULL);
5080 ptr += len;
5081 cbBuf -= len;
5083 pi2a->fPortType = pi2w->fPortType;
5084 pi2a->Reserved = 0; /* documented: "must be zero" */
5087 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5088 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5089 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5093 cleanup:
5094 if (pcbNeeded) *pcbNeeded = needed;
5095 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5097 HeapFree(GetProcessHeap(), 0, nameW);
5098 HeapFree(GetProcessHeap(), 0, bufferW);
5100 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5101 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5103 return (res);
5107 /******************************************************************************
5108 * EnumPortsW (WINSPOOL.@)
5110 * Enumerate available Ports
5112 * PARAMS
5113 * pName [I] Servername or NULL (local Computer)
5114 * Level [I] Structure-Level (1 or 2)
5115 * pPorts [O] PTR to Buffer that receives the Result
5116 * cbBuf [I] Size of Buffer at pPorts
5117 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5118 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5120 * RETURNS
5121 * Success: TRUE
5122 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5125 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5128 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5129 cbBuf, pcbNeeded, pcReturned);
5131 if ((backend == NULL) && !load_backend()) return FALSE;
5133 /* Level is not checked in win9x */
5134 if (!Level || (Level > 2)) {
5135 WARN("level (%d) is ignored in win9x\n", Level);
5136 SetLastError(ERROR_INVALID_LEVEL);
5137 return FALSE;
5139 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5140 SetLastError(RPC_X_NULL_REF_POINTER);
5141 return FALSE;
5144 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5147 /******************************************************************************
5148 * GetDefaultPrinterW (WINSPOOL.@)
5150 * FIXME
5151 * This function must read the value from data 'device' of key
5152 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5154 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5156 BOOL retval = TRUE;
5157 DWORD insize, len;
5158 WCHAR *buffer, *ptr;
5160 if (!namesize)
5162 SetLastError(ERROR_INVALID_PARAMETER);
5163 return FALSE;
5166 /* make the buffer big enough for the stuff from the profile/registry,
5167 * the content must fit into the local buffer to compute the correct
5168 * size even if the extern buffer is too small or not given.
5169 * (20 for ,driver,port) */
5170 insize = *namesize;
5171 len = max(100, (insize + 20));
5172 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5174 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5176 SetLastError (ERROR_FILE_NOT_FOUND);
5177 retval = FALSE;
5178 goto end;
5180 TRACE("%s\n", debugstr_w(buffer));
5182 if ((ptr = strchrW(buffer, ',')) == NULL)
5184 SetLastError(ERROR_INVALID_NAME);
5185 retval = FALSE;
5186 goto end;
5189 *ptr = 0;
5190 *namesize = strlenW(buffer) + 1;
5191 if(!name || (*namesize > insize))
5193 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5194 retval = FALSE;
5195 goto end;
5197 strcpyW(name, buffer);
5199 end:
5200 HeapFree( GetProcessHeap(), 0, buffer);
5201 return retval;
5205 /******************************************************************************
5206 * GetDefaultPrinterA (WINSPOOL.@)
5208 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5210 BOOL retval = TRUE;
5211 DWORD insize = 0;
5212 WCHAR *bufferW = NULL;
5214 if (!namesize)
5216 SetLastError(ERROR_INVALID_PARAMETER);
5217 return FALSE;
5220 if(name && *namesize) {
5221 insize = *namesize;
5222 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5225 if(!GetDefaultPrinterW( bufferW, namesize)) {
5226 retval = FALSE;
5227 goto end;
5230 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5231 NULL, NULL);
5232 if (!*namesize)
5234 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5235 retval = FALSE;
5237 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5239 end:
5240 HeapFree( GetProcessHeap(), 0, bufferW);
5241 return retval;
5245 /******************************************************************************
5246 * SetDefaultPrinterW (WINSPOOL.204)
5248 * Set the Name of the Default Printer
5250 * PARAMS
5251 * pszPrinter [I] Name of the Printer or NULL
5253 * RETURNS
5254 * Success: True
5255 * Failure: FALSE
5257 * NOTES
5258 * When the Parameter is NULL or points to an Empty String and
5259 * a Default Printer was already present, then this Function changes nothing.
5260 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5261 * the First enumerated local Printer is used.
5264 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5267 TRACE("(%s)\n", debugstr_w(pszPrinter));
5269 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5270 return FALSE;
5273 /******************************************************************************
5274 * SetDefaultPrinterA (WINSPOOL.202)
5276 * See SetDefaultPrinterW.
5279 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5282 TRACE("(%s)\n", debugstr_a(pszPrinter));
5284 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5285 return FALSE;
5289 /******************************************************************************
5290 * SetPrinterDataExA (WINSPOOL.@)
5292 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5293 LPCSTR pValueName, DWORD Type,
5294 LPBYTE pData, DWORD cbData)
5296 HKEY hkeyPrinter, hkeySubkey;
5297 DWORD ret;
5299 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5300 debugstr_a(pValueName), Type, pData, cbData);
5302 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5303 != ERROR_SUCCESS)
5304 return ret;
5306 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5307 != ERROR_SUCCESS) {
5308 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5309 RegCloseKey(hkeyPrinter);
5310 return ret;
5312 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5313 RegCloseKey(hkeySubkey);
5314 RegCloseKey(hkeyPrinter);
5315 return ret;
5318 /******************************************************************************
5319 * SetPrinterDataExW (WINSPOOL.@)
5321 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5322 LPCWSTR pValueName, DWORD Type,
5323 LPBYTE pData, DWORD cbData)
5325 HKEY hkeyPrinter, hkeySubkey;
5326 DWORD ret;
5328 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5329 debugstr_w(pValueName), Type, pData, cbData);
5331 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5332 != ERROR_SUCCESS)
5333 return ret;
5335 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5336 != ERROR_SUCCESS) {
5337 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5338 RegCloseKey(hkeyPrinter);
5339 return ret;
5341 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5342 RegCloseKey(hkeySubkey);
5343 RegCloseKey(hkeyPrinter);
5344 return ret;
5347 /******************************************************************************
5348 * SetPrinterDataA (WINSPOOL.@)
5350 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5351 LPBYTE pData, DWORD cbData)
5353 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5354 pData, cbData);
5357 /******************************************************************************
5358 * SetPrinterDataW (WINSPOOL.@)
5360 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5361 LPBYTE pData, DWORD cbData)
5363 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5364 pData, cbData);
5367 /******************************************************************************
5368 * GetPrinterDataExA (WINSPOOL.@)
5370 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5371 LPCSTR pValueName, LPDWORD pType,
5372 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5374 opened_printer_t *printer;
5375 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5376 DWORD ret;
5378 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5379 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5381 printer = get_opened_printer(hPrinter);
5382 if(!printer) return ERROR_INVALID_HANDLE;
5384 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5385 if (ret) return ret;
5387 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5389 if (printer->name) {
5391 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5392 if (ret) {
5393 RegCloseKey(hkeyPrinters);
5394 return ret;
5396 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5397 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5398 RegCloseKey(hkeyPrinter);
5399 RegCloseKey(hkeyPrinters);
5400 return ret;
5403 *pcbNeeded = nSize;
5404 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5405 0, pType, pData, pcbNeeded);
5407 if (!ret && !pData) ret = ERROR_MORE_DATA;
5409 RegCloseKey(hkeySubkey);
5410 RegCloseKey(hkeyPrinter);
5411 RegCloseKey(hkeyPrinters);
5413 TRACE("--> %d\n", ret);
5414 return ret;
5417 /******************************************************************************
5418 * GetPrinterDataExW (WINSPOOL.@)
5420 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5421 LPCWSTR pValueName, LPDWORD pType,
5422 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5424 opened_printer_t *printer;
5425 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5426 DWORD ret;
5428 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5429 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5431 printer = get_opened_printer(hPrinter);
5432 if(!printer) return ERROR_INVALID_HANDLE;
5434 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5435 if (ret) return ret;
5437 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5439 if (printer->name) {
5441 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5442 if (ret) {
5443 RegCloseKey(hkeyPrinters);
5444 return ret;
5446 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5447 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5448 RegCloseKey(hkeyPrinter);
5449 RegCloseKey(hkeyPrinters);
5450 return ret;
5453 *pcbNeeded = nSize;
5454 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5455 0, pType, pData, pcbNeeded);
5457 if (!ret && !pData) ret = ERROR_MORE_DATA;
5459 RegCloseKey(hkeySubkey);
5460 RegCloseKey(hkeyPrinter);
5461 RegCloseKey(hkeyPrinters);
5463 TRACE("--> %d\n", ret);
5464 return ret;
5467 /******************************************************************************
5468 * GetPrinterDataA (WINSPOOL.@)
5470 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5471 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5473 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5474 pData, nSize, pcbNeeded);
5477 /******************************************************************************
5478 * GetPrinterDataW (WINSPOOL.@)
5480 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5481 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5483 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5484 pData, nSize, pcbNeeded);
5487 /*******************************************************************************
5488 * EnumPrinterDataExW [WINSPOOL.@]
5490 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5491 LPBYTE pEnumValues, DWORD cbEnumValues,
5492 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5494 HKEY hkPrinter, hkSubKey;
5495 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5496 cbValueNameLen, cbMaxValueLen, cbValueLen,
5497 cbBufSize, dwType;
5498 LPWSTR lpValueName;
5499 HANDLE hHeap;
5500 PBYTE lpValue;
5501 PPRINTER_ENUM_VALUESW ppev;
5503 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5505 if (pKeyName == NULL || *pKeyName == 0)
5506 return ERROR_INVALID_PARAMETER;
5508 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5509 if (ret != ERROR_SUCCESS)
5511 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5512 hPrinter, ret);
5513 return ret;
5516 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5517 if (ret != ERROR_SUCCESS)
5519 r = RegCloseKey (hkPrinter);
5520 if (r != ERROR_SUCCESS)
5521 WARN ("RegCloseKey returned %i\n", r);
5522 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5523 debugstr_w (pKeyName), ret);
5524 return ret;
5527 ret = RegCloseKey (hkPrinter);
5528 if (ret != ERROR_SUCCESS)
5530 ERR ("RegCloseKey returned %i\n", ret);
5531 r = RegCloseKey (hkSubKey);
5532 if (r != ERROR_SUCCESS)
5533 WARN ("RegCloseKey returned %i\n", r);
5534 return ret;
5537 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5538 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5539 if (ret != ERROR_SUCCESS)
5541 r = RegCloseKey (hkSubKey);
5542 if (r != ERROR_SUCCESS)
5543 WARN ("RegCloseKey returned %i\n", r);
5544 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5545 return ret;
5548 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5549 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5551 if (cValues == 0) /* empty key */
5553 r = RegCloseKey (hkSubKey);
5554 if (r != ERROR_SUCCESS)
5555 WARN ("RegCloseKey returned %i\n", r);
5556 *pcbEnumValues = *pnEnumValues = 0;
5557 return ERROR_SUCCESS;
5560 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5562 hHeap = GetProcessHeap ();
5563 if (hHeap == NULL)
5565 ERR ("GetProcessHeap failed\n");
5566 r = RegCloseKey (hkSubKey);
5567 if (r != ERROR_SUCCESS)
5568 WARN ("RegCloseKey returned %i\n", r);
5569 return ERROR_OUTOFMEMORY;
5572 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5573 if (lpValueName == NULL)
5575 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5576 r = RegCloseKey (hkSubKey);
5577 if (r != ERROR_SUCCESS)
5578 WARN ("RegCloseKey returned %i\n", r);
5579 return ERROR_OUTOFMEMORY;
5582 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5583 if (lpValue == NULL)
5585 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5586 if (HeapFree (hHeap, 0, lpValueName) == 0)
5587 WARN ("HeapFree failed with code %i\n", GetLastError ());
5588 r = RegCloseKey (hkSubKey);
5589 if (r != ERROR_SUCCESS)
5590 WARN ("RegCloseKey returned %i\n", r);
5591 return ERROR_OUTOFMEMORY;
5594 TRACE ("pass 1: calculating buffer required for all names and values\n");
5596 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5598 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5600 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5602 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5603 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5604 NULL, NULL, lpValue, &cbValueLen);
5605 if (ret != ERROR_SUCCESS)
5607 if (HeapFree (hHeap, 0, lpValue) == 0)
5608 WARN ("HeapFree failed with code %i\n", GetLastError ());
5609 if (HeapFree (hHeap, 0, lpValueName) == 0)
5610 WARN ("HeapFree failed with code %i\n", GetLastError ());
5611 r = RegCloseKey (hkSubKey);
5612 if (r != ERROR_SUCCESS)
5613 WARN ("RegCloseKey returned %i\n", r);
5614 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5615 return ret;
5618 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5619 debugstr_w (lpValueName), dwIndex,
5620 cbValueNameLen + 1, cbValueLen);
5622 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5623 cbBufSize += cbValueLen;
5626 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5628 *pcbEnumValues = cbBufSize;
5629 *pnEnumValues = cValues;
5631 if (cbEnumValues < cbBufSize) /* buffer too small */
5633 if (HeapFree (hHeap, 0, lpValue) == 0)
5634 WARN ("HeapFree failed with code %i\n", GetLastError ());
5635 if (HeapFree (hHeap, 0, lpValueName) == 0)
5636 WARN ("HeapFree failed with code %i\n", GetLastError ());
5637 r = RegCloseKey (hkSubKey);
5638 if (r != ERROR_SUCCESS)
5639 WARN ("RegCloseKey returned %i\n", r);
5640 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5641 return ERROR_MORE_DATA;
5644 TRACE ("pass 2: copying all names and values to buffer\n");
5646 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5647 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5649 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5651 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5652 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5653 NULL, &dwType, lpValue, &cbValueLen);
5654 if (ret != ERROR_SUCCESS)
5656 if (HeapFree (hHeap, 0, lpValue) == 0)
5657 WARN ("HeapFree failed with code %i\n", GetLastError ());
5658 if (HeapFree (hHeap, 0, lpValueName) == 0)
5659 WARN ("HeapFree failed with code %i\n", GetLastError ());
5660 r = RegCloseKey (hkSubKey);
5661 if (r != ERROR_SUCCESS)
5662 WARN ("RegCloseKey returned %i\n", r);
5663 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5664 return ret;
5667 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5668 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5669 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5670 pEnumValues += cbValueNameLen;
5672 /* return # of *bytes* (including trailing \0), not # of chars */
5673 ppev[dwIndex].cbValueName = cbValueNameLen;
5675 ppev[dwIndex].dwType = dwType;
5677 memcpy (pEnumValues, lpValue, cbValueLen);
5678 ppev[dwIndex].pData = pEnumValues;
5679 pEnumValues += cbValueLen;
5681 ppev[dwIndex].cbData = cbValueLen;
5683 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5684 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5687 if (HeapFree (hHeap, 0, lpValue) == 0)
5689 ret = GetLastError ();
5690 ERR ("HeapFree failed with code %i\n", ret);
5691 if (HeapFree (hHeap, 0, lpValueName) == 0)
5692 WARN ("HeapFree failed with code %i\n", GetLastError ());
5693 r = RegCloseKey (hkSubKey);
5694 if (r != ERROR_SUCCESS)
5695 WARN ("RegCloseKey returned %i\n", r);
5696 return ret;
5699 if (HeapFree (hHeap, 0, lpValueName) == 0)
5701 ret = GetLastError ();
5702 ERR ("HeapFree failed with code %i\n", ret);
5703 r = RegCloseKey (hkSubKey);
5704 if (r != ERROR_SUCCESS)
5705 WARN ("RegCloseKey returned %i\n", r);
5706 return ret;
5709 ret = RegCloseKey (hkSubKey);
5710 if (ret != ERROR_SUCCESS)
5712 ERR ("RegCloseKey returned %i\n", ret);
5713 return ret;
5716 return ERROR_SUCCESS;
5719 /*******************************************************************************
5720 * EnumPrinterDataExA [WINSPOOL.@]
5722 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5723 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5724 * what Windows 2000 SP1 does.
5727 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5728 LPBYTE pEnumValues, DWORD cbEnumValues,
5729 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5731 INT len;
5732 LPWSTR pKeyNameW;
5733 DWORD ret, dwIndex, dwBufSize;
5734 HANDLE hHeap;
5735 LPSTR pBuffer;
5737 TRACE ("%p %s\n", hPrinter, pKeyName);
5739 if (pKeyName == NULL || *pKeyName == 0)
5740 return ERROR_INVALID_PARAMETER;
5742 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5743 if (len == 0)
5745 ret = GetLastError ();
5746 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5747 return ret;
5750 hHeap = GetProcessHeap ();
5751 if (hHeap == NULL)
5753 ERR ("GetProcessHeap failed\n");
5754 return ERROR_OUTOFMEMORY;
5757 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5758 if (pKeyNameW == NULL)
5760 ERR ("Failed to allocate %i bytes from process heap\n",
5761 (LONG)(len * sizeof (WCHAR)));
5762 return ERROR_OUTOFMEMORY;
5765 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5767 ret = GetLastError ();
5768 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5769 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5770 WARN ("HeapFree failed with code %i\n", GetLastError ());
5771 return ret;
5774 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5775 pcbEnumValues, pnEnumValues);
5776 if (ret != ERROR_SUCCESS)
5778 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5779 WARN ("HeapFree failed with code %i\n", GetLastError ());
5780 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5781 return ret;
5784 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5786 ret = GetLastError ();
5787 ERR ("HeapFree failed with code %i\n", ret);
5788 return ret;
5791 if (*pnEnumValues == 0) /* empty key */
5792 return ERROR_SUCCESS;
5794 dwBufSize = 0;
5795 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5797 PPRINTER_ENUM_VALUESW ppev =
5798 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5800 if (dwBufSize < ppev->cbValueName)
5801 dwBufSize = ppev->cbValueName;
5803 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5804 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5805 dwBufSize = ppev->cbData;
5808 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5810 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5811 if (pBuffer == NULL)
5813 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5814 return ERROR_OUTOFMEMORY;
5817 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5819 PPRINTER_ENUM_VALUESW ppev =
5820 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5822 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5823 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5824 NULL);
5825 if (len == 0)
5827 ret = GetLastError ();
5828 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5829 if (HeapFree (hHeap, 0, pBuffer) == 0)
5830 WARN ("HeapFree failed with code %i\n", GetLastError ());
5831 return ret;
5834 memcpy (ppev->pValueName, pBuffer, len);
5836 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5838 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5839 ppev->dwType != REG_MULTI_SZ)
5840 continue;
5842 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5843 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5844 if (len == 0)
5846 ret = GetLastError ();
5847 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5848 if (HeapFree (hHeap, 0, pBuffer) == 0)
5849 WARN ("HeapFree failed with code %i\n", GetLastError ());
5850 return ret;
5853 memcpy (ppev->pData, pBuffer, len);
5855 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5856 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5859 if (HeapFree (hHeap, 0, pBuffer) == 0)
5861 ret = GetLastError ();
5862 ERR ("HeapFree failed with code %i\n", ret);
5863 return ret;
5866 return ERROR_SUCCESS;
5869 /******************************************************************************
5870 * AbortPrinter (WINSPOOL.@)
5872 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5874 FIXME("(%p), stub!\n", hPrinter);
5875 return TRUE;
5878 /******************************************************************************
5879 * AddPortA (WINSPOOL.@)
5881 * See AddPortW.
5884 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5886 LPWSTR nameW = NULL;
5887 LPWSTR monitorW = NULL;
5888 DWORD len;
5889 BOOL res;
5891 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5893 if (pName) {
5894 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5895 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5896 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5899 if (pMonitorName) {
5900 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5901 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5902 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5904 res = AddPortW(nameW, hWnd, monitorW);
5905 HeapFree(GetProcessHeap(), 0, nameW);
5906 HeapFree(GetProcessHeap(), 0, monitorW);
5907 return res;
5910 /******************************************************************************
5911 * AddPortW (WINSPOOL.@)
5913 * Add a Port for a specific Monitor
5915 * PARAMS
5916 * pName [I] Servername or NULL (local Computer)
5917 * hWnd [I] Handle to parent Window for the Dialog-Box
5918 * pMonitorName [I] Name of the Monitor that manage the Port
5920 * RETURNS
5921 * Success: TRUE
5922 * Failure: FALSE
5925 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5927 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5929 if ((backend == NULL) && !load_backend()) return FALSE;
5931 if (!pMonitorName) {
5932 SetLastError(RPC_X_NULL_REF_POINTER);
5933 return FALSE;
5936 return backend->fpAddPort(pName, hWnd, pMonitorName);
5939 /******************************************************************************
5940 * AddPortExA (WINSPOOL.@)
5942 * See AddPortExW.
5945 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5947 PORT_INFO_2W pi2W;
5948 PORT_INFO_2A * pi2A;
5949 LPWSTR nameW = NULL;
5950 LPWSTR monitorW = NULL;
5951 DWORD len;
5952 BOOL res;
5954 pi2A = (PORT_INFO_2A *) pBuffer;
5956 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5957 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5959 if ((level < 1) || (level > 2)) {
5960 SetLastError(ERROR_INVALID_LEVEL);
5961 return FALSE;
5964 if (!pi2A) {
5965 SetLastError(ERROR_INVALID_PARAMETER);
5966 return FALSE;
5969 if (pName) {
5970 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5971 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5972 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5975 if (pMonitorName) {
5976 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5977 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5978 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5981 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5983 if (pi2A->pPortName) {
5984 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5985 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5986 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5989 if (level > 1) {
5990 if (pi2A->pMonitorName) {
5991 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5992 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5993 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5996 if (pi2A->pDescription) {
5997 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5998 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5999 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6001 pi2W.fPortType = pi2A->fPortType;
6002 pi2W.Reserved = pi2A->Reserved;
6005 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6007 HeapFree(GetProcessHeap(), 0, nameW);
6008 HeapFree(GetProcessHeap(), 0, monitorW);
6009 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6010 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6011 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6012 return res;
6016 /******************************************************************************
6017 * AddPortExW (WINSPOOL.@)
6019 * Add a Port for a specific Monitor, without presenting a user interface
6021 * PARAMS
6022 * pName [I] Servername or NULL (local Computer)
6023 * level [I] Structure-Level (1 or 2) for pBuffer
6024 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6025 * pMonitorName [I] Name of the Monitor that manage the Port
6027 * RETURNS
6028 * Success: TRUE
6029 * Failure: FALSE
6032 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6034 PORT_INFO_2W * pi2;
6036 pi2 = (PORT_INFO_2W *) pBuffer;
6038 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6039 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6040 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6041 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6043 if ((backend == NULL) && !load_backend()) return FALSE;
6045 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6046 SetLastError(ERROR_INVALID_PARAMETER);
6047 return FALSE;
6050 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6053 /******************************************************************************
6054 * AddPrinterConnectionA (WINSPOOL.@)
6056 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6058 FIXME("%s\n", debugstr_a(pName));
6059 return FALSE;
6062 /******************************************************************************
6063 * AddPrinterConnectionW (WINSPOOL.@)
6065 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6067 FIXME("%s\n", debugstr_w(pName));
6068 return FALSE;
6071 /******************************************************************************
6072 * AddPrinterDriverExW (WINSPOOL.@)
6074 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6076 * PARAMS
6077 * pName [I] Servername or NULL (local Computer)
6078 * level [I] Level for the supplied DRIVER_INFO_*W struct
6079 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6080 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6082 * RESULTS
6083 * Success: TRUE
6084 * Failure: FALSE
6087 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6089 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6091 if ((backend == NULL) && !load_backend()) return FALSE;
6093 if (level < 2 || level == 5 || level == 7 || level > 8) {
6094 SetLastError(ERROR_INVALID_LEVEL);
6095 return FALSE;
6098 if (!pDriverInfo) {
6099 SetLastError(ERROR_INVALID_PARAMETER);
6100 return FALSE;
6103 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6106 /******************************************************************************
6107 * AddPrinterDriverExA (WINSPOOL.@)
6109 * See AddPrinterDriverExW.
6112 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6114 DRIVER_INFO_8A *diA;
6115 DRIVER_INFO_8W diW;
6116 LPWSTR nameW = NULL;
6117 DWORD lenA;
6118 DWORD len;
6119 DWORD res = FALSE;
6121 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6123 diA = (DRIVER_INFO_8A *) pDriverInfo;
6124 ZeroMemory(&diW, sizeof(diW));
6126 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6127 SetLastError(ERROR_INVALID_LEVEL);
6128 return FALSE;
6131 if (diA == NULL) {
6132 SetLastError(ERROR_INVALID_PARAMETER);
6133 return FALSE;
6136 /* convert servername to unicode */
6137 if (pName) {
6138 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6139 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6140 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6143 /* common fields */
6144 diW.cVersion = diA->cVersion;
6146 if (diA->pName) {
6147 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6148 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6149 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6152 if (diA->pEnvironment) {
6153 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6154 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6155 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6158 if (diA->pDriverPath) {
6159 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6160 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6161 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6164 if (diA->pDataFile) {
6165 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6166 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6167 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6170 if (diA->pConfigFile) {
6171 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6172 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6173 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6176 if ((Level > 2) && diA->pDependentFiles) {
6177 lenA = multi_sz_lenA(diA->pDependentFiles);
6178 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6179 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6180 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6183 if ((Level > 2) && diA->pMonitorName) {
6184 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6185 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6186 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6189 if ((Level > 3) && diA->pDefaultDataType) {
6190 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6191 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6192 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6195 if ((Level > 3) && diA->pszzPreviousNames) {
6196 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6197 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6198 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6199 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6202 if ((Level > 5) && diA->pszMfgName) {
6203 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6204 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6205 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6208 if ((Level > 5) && diA->pszOEMUrl) {
6209 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6210 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6211 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6214 if ((Level > 5) && diA->pszHardwareID) {
6215 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6216 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6217 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6220 if ((Level > 5) && diA->pszProvider) {
6221 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6222 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6223 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6226 if (Level > 7) {
6227 FIXME("level %u is incomplete\n", Level);
6230 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6231 TRACE("got %u with %u\n", res, GetLastError());
6232 HeapFree(GetProcessHeap(), 0, nameW);
6233 HeapFree(GetProcessHeap(), 0, diW.pName);
6234 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6235 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6236 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6237 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6238 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6239 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6240 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6241 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6242 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6243 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6244 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6245 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6247 TRACE("=> %u with %u\n", res, GetLastError());
6248 return res;
6251 /******************************************************************************
6252 * ConfigurePortA (WINSPOOL.@)
6254 * See ConfigurePortW.
6257 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6259 LPWSTR nameW = NULL;
6260 LPWSTR portW = NULL;
6261 INT len;
6262 DWORD res;
6264 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6266 /* convert servername to unicode */
6267 if (pName) {
6268 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6269 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6270 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6273 /* convert portname to unicode */
6274 if (pPortName) {
6275 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6276 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6277 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6280 res = ConfigurePortW(nameW, hWnd, portW);
6281 HeapFree(GetProcessHeap(), 0, nameW);
6282 HeapFree(GetProcessHeap(), 0, portW);
6283 return res;
6286 /******************************************************************************
6287 * ConfigurePortW (WINSPOOL.@)
6289 * Display the Configuration-Dialog for a specific Port
6291 * PARAMS
6292 * pName [I] Servername or NULL (local Computer)
6293 * hWnd [I] Handle to parent Window for the Dialog-Box
6294 * pPortName [I] Name of the Port, that should be configured
6296 * RETURNS
6297 * Success: TRUE
6298 * Failure: FALSE
6301 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6304 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6306 if ((backend == NULL) && !load_backend()) return FALSE;
6308 if (!pPortName) {
6309 SetLastError(RPC_X_NULL_REF_POINTER);
6310 return FALSE;
6313 return backend->fpConfigurePort(pName, hWnd, pPortName);
6316 /******************************************************************************
6317 * ConnectToPrinterDlg (WINSPOOL.@)
6319 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6321 FIXME("%p %x\n", hWnd, Flags);
6322 return NULL;
6325 /******************************************************************************
6326 * DeletePrinterConnectionA (WINSPOOL.@)
6328 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6330 FIXME("%s\n", debugstr_a(pName));
6331 return TRUE;
6334 /******************************************************************************
6335 * DeletePrinterConnectionW (WINSPOOL.@)
6337 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6339 FIXME("%s\n", debugstr_w(pName));
6340 return TRUE;
6343 /******************************************************************************
6344 * DeletePrinterDriverExW (WINSPOOL.@)
6346 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6347 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6349 HKEY hkey_drivers;
6350 BOOL ret = FALSE;
6352 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6353 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6355 if(pName && pName[0])
6357 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6358 SetLastError(ERROR_INVALID_PARAMETER);
6359 return FALSE;
6362 if(dwDeleteFlag)
6364 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6365 SetLastError(ERROR_INVALID_PARAMETER);
6366 return FALSE;
6369 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6371 if(!hkey_drivers)
6373 ERR("Can't open drivers key\n");
6374 return FALSE;
6377 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6378 ret = TRUE;
6380 RegCloseKey(hkey_drivers);
6382 return ret;
6385 /******************************************************************************
6386 * DeletePrinterDriverExA (WINSPOOL.@)
6388 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6389 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6391 UNICODE_STRING NameW, EnvW, DriverW;
6392 BOOL ret;
6394 asciitounicode(&NameW, pName);
6395 asciitounicode(&EnvW, pEnvironment);
6396 asciitounicode(&DriverW, pDriverName);
6398 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6400 RtlFreeUnicodeString(&DriverW);
6401 RtlFreeUnicodeString(&EnvW);
6402 RtlFreeUnicodeString(&NameW);
6404 return ret;
6407 /******************************************************************************
6408 * DeletePrinterDataExW (WINSPOOL.@)
6410 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6411 LPCWSTR pValueName)
6413 FIXME("%p %s %s\n", hPrinter,
6414 debugstr_w(pKeyName), debugstr_w(pValueName));
6415 return ERROR_INVALID_PARAMETER;
6418 /******************************************************************************
6419 * DeletePrinterDataExA (WINSPOOL.@)
6421 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6422 LPCSTR pValueName)
6424 FIXME("%p %s %s\n", hPrinter,
6425 debugstr_a(pKeyName), debugstr_a(pValueName));
6426 return ERROR_INVALID_PARAMETER;
6429 /******************************************************************************
6430 * DeletePrintProcessorA (WINSPOOL.@)
6432 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6434 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6435 debugstr_a(pPrintProcessorName));
6436 return TRUE;
6439 /******************************************************************************
6440 * DeletePrintProcessorW (WINSPOOL.@)
6442 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6444 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6445 debugstr_w(pPrintProcessorName));
6446 return TRUE;
6449 /******************************************************************************
6450 * DeletePrintProvidorA (WINSPOOL.@)
6452 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6454 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6455 debugstr_a(pPrintProviderName));
6456 return TRUE;
6459 /******************************************************************************
6460 * DeletePrintProvidorW (WINSPOOL.@)
6462 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6464 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6465 debugstr_w(pPrintProviderName));
6466 return TRUE;
6469 /******************************************************************************
6470 * EnumFormsA (WINSPOOL.@)
6472 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6473 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6475 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6476 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6477 return FALSE;
6480 /******************************************************************************
6481 * EnumFormsW (WINSPOOL.@)
6483 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6484 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6486 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6487 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6488 return FALSE;
6491 /*****************************************************************************
6492 * EnumMonitorsA [WINSPOOL.@]
6494 * See EnumMonitorsW.
6497 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6498 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6500 BOOL res;
6501 LPBYTE bufferW = NULL;
6502 LPWSTR nameW = NULL;
6503 DWORD needed = 0;
6504 DWORD numentries = 0;
6505 INT len;
6507 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6508 cbBuf, pcbNeeded, pcReturned);
6510 /* convert servername to unicode */
6511 if (pName) {
6512 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6513 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6514 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6516 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6517 needed = cbBuf * sizeof(WCHAR);
6518 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6519 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6521 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6522 if (pcbNeeded) needed = *pcbNeeded;
6523 /* HeapReAlloc return NULL, when bufferW was NULL */
6524 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6525 HeapAlloc(GetProcessHeap(), 0, needed);
6527 /* Try again with the large Buffer */
6528 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6530 numentries = pcReturned ? *pcReturned : 0;
6531 needed = 0;
6533 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6534 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6536 if (res) {
6537 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6538 DWORD entrysize = 0;
6539 DWORD index;
6540 LPSTR ptr;
6541 LPMONITOR_INFO_2W mi2w;
6542 LPMONITOR_INFO_2A mi2a;
6544 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6545 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6547 /* First pass: calculate the size for all Entries */
6548 mi2w = (LPMONITOR_INFO_2W) bufferW;
6549 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6550 index = 0;
6551 while (index < numentries) {
6552 index++;
6553 needed += entrysize; /* MONITOR_INFO_?A */
6554 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6556 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6557 NULL, 0, NULL, NULL);
6558 if (Level > 1) {
6559 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6560 NULL, 0, NULL, NULL);
6561 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6562 NULL, 0, NULL, NULL);
6564 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6565 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6566 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6569 /* check for errors and quit on failure */
6570 if (cbBuf < needed) {
6571 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6572 res = FALSE;
6573 goto emA_cleanup;
6575 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6576 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6577 cbBuf -= len ; /* free Bytes in the user-Buffer */
6578 mi2w = (LPMONITOR_INFO_2W) bufferW;
6579 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6580 index = 0;
6581 /* Second Pass: Fill the User Buffer (if we have one) */
6582 while ((index < numentries) && pMonitors) {
6583 index++;
6584 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6585 mi2a->pName = ptr;
6586 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6587 ptr, cbBuf , NULL, NULL);
6588 ptr += len;
6589 cbBuf -= len;
6590 if (Level > 1) {
6591 mi2a->pEnvironment = ptr;
6592 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6593 ptr, cbBuf, NULL, NULL);
6594 ptr += len;
6595 cbBuf -= len;
6597 mi2a->pDLLName = ptr;
6598 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6599 ptr, cbBuf, NULL, NULL);
6600 ptr += len;
6601 cbBuf -= len;
6603 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6604 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6605 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6608 emA_cleanup:
6609 if (pcbNeeded) *pcbNeeded = needed;
6610 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6612 HeapFree(GetProcessHeap(), 0, nameW);
6613 HeapFree(GetProcessHeap(), 0, bufferW);
6615 TRACE("returning %d with %d (%d byte for %d entries)\n",
6616 (res), GetLastError(), needed, numentries);
6618 return (res);
6622 /*****************************************************************************
6623 * EnumMonitorsW [WINSPOOL.@]
6625 * Enumerate available Port-Monitors
6627 * PARAMS
6628 * pName [I] Servername or NULL (local Computer)
6629 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6630 * pMonitors [O] PTR to Buffer that receives the Result
6631 * cbBuf [I] Size of Buffer at pMonitors
6632 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6633 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6635 * RETURNS
6636 * Success: TRUE
6637 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6640 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6641 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6644 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6645 cbBuf, pcbNeeded, pcReturned);
6647 if ((backend == NULL) && !load_backend()) return FALSE;
6649 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6650 SetLastError(RPC_X_NULL_REF_POINTER);
6651 return FALSE;
6654 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6657 /******************************************************************************
6658 * SpoolerInit (WINSPOOL.@)
6660 * Initialize the Spooler
6662 * RETURNS
6663 * Success: TRUE
6664 * Failure: FALSE
6666 * NOTES
6667 * The function fails on windows, when the spooler service is not running
6670 BOOL WINAPI SpoolerInit(void)
6673 if ((backend == NULL) && !load_backend()) return FALSE;
6674 return TRUE;
6677 /******************************************************************************
6678 * XcvDataW (WINSPOOL.@)
6680 * Execute commands in the Printmonitor DLL
6682 * PARAMS
6683 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6684 * pszDataName [i] Name of the command to execute
6685 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6686 * cbInputData [i] Size in Bytes of Buffer at pInputData
6687 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6688 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6689 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6690 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6692 * RETURNS
6693 * Success: TRUE
6694 * Failure: FALSE
6696 * NOTES
6697 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6698 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6700 * Minimal List of commands, that a Printmonitor DLL should support:
6702 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6703 *| "AddPort" : Add a Port
6704 *| "DeletePort": Delete a Port
6706 * Many Printmonitors support additional commands. Examples for localspl.dll:
6707 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6708 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6711 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6712 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6713 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6715 opened_printer_t *printer;
6717 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6718 pInputData, cbInputData, pOutputData,
6719 cbOutputData, pcbOutputNeeded, pdwStatus);
6721 if ((backend == NULL) && !load_backend()) return FALSE;
6723 printer = get_opened_printer(hXcv);
6724 if (!printer || (!printer->backend_printer)) {
6725 SetLastError(ERROR_INVALID_HANDLE);
6726 return FALSE;
6729 if (!pcbOutputNeeded) {
6730 SetLastError(ERROR_INVALID_PARAMETER);
6731 return FALSE;
6734 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6735 SetLastError(RPC_X_NULL_REF_POINTER);
6736 return FALSE;
6739 *pcbOutputNeeded = 0;
6741 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6742 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6746 /*****************************************************************************
6747 * EnumPrinterDataA [WINSPOOL.@]
6750 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6751 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6752 DWORD cbData, LPDWORD pcbData )
6754 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6755 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6756 return ERROR_NO_MORE_ITEMS;
6759 /*****************************************************************************
6760 * EnumPrinterDataW [WINSPOOL.@]
6763 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6764 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6765 DWORD cbData, LPDWORD pcbData )
6767 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6768 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6769 return ERROR_NO_MORE_ITEMS;
6772 /*****************************************************************************
6773 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6776 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6777 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6778 LPDWORD pcbNeeded, LPDWORD pcReturned)
6780 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6781 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6782 pcbNeeded, pcReturned);
6783 return FALSE;
6786 /*****************************************************************************
6787 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6790 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6791 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6792 LPDWORD pcbNeeded, LPDWORD pcReturned)
6794 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6795 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6796 pcbNeeded, pcReturned);
6797 return FALSE;
6800 /*****************************************************************************
6801 * EnumPrintProcessorsA [WINSPOOL.@]
6803 * See EnumPrintProcessorsW.
6806 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6807 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6809 BOOL res;
6810 LPBYTE bufferW = NULL;
6811 LPWSTR nameW = NULL;
6812 LPWSTR envW = NULL;
6813 DWORD needed = 0;
6814 DWORD numentries = 0;
6815 INT len;
6817 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6818 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6820 /* convert names to unicode */
6821 if (pName) {
6822 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6823 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6824 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6826 if (pEnvironment) {
6827 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6828 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6829 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6832 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6833 needed = cbBuf * sizeof(WCHAR);
6834 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6835 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6837 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6838 if (pcbNeeded) needed = *pcbNeeded;
6839 /* HeapReAlloc return NULL, when bufferW was NULL */
6840 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6841 HeapAlloc(GetProcessHeap(), 0, needed);
6843 /* Try again with the large Buffer */
6844 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6846 numentries = pcReturned ? *pcReturned : 0;
6847 needed = 0;
6849 if (res) {
6850 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6851 DWORD index;
6852 LPSTR ptr;
6853 PPRINTPROCESSOR_INFO_1W ppiw;
6854 PPRINTPROCESSOR_INFO_1A ppia;
6856 /* First pass: calculate the size for all Entries */
6857 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6858 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6859 index = 0;
6860 while (index < numentries) {
6861 index++;
6862 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6863 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6865 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6866 NULL, 0, NULL, NULL);
6868 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6869 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6872 /* check for errors and quit on failure */
6873 if (cbBuf < needed) {
6874 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6875 res = FALSE;
6876 goto epp_cleanup;
6879 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6880 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6881 cbBuf -= len ; /* free Bytes in the user-Buffer */
6882 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6883 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6884 index = 0;
6885 /* Second Pass: Fill the User Buffer (if we have one) */
6886 while ((index < numentries) && pPPInfo) {
6887 index++;
6888 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6889 ppia->pName = ptr;
6890 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6891 ptr, cbBuf , NULL, NULL);
6892 ptr += len;
6893 cbBuf -= len;
6895 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6896 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6900 epp_cleanup:
6901 if (pcbNeeded) *pcbNeeded = needed;
6902 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6904 HeapFree(GetProcessHeap(), 0, nameW);
6905 HeapFree(GetProcessHeap(), 0, envW);
6906 HeapFree(GetProcessHeap(), 0, bufferW);
6908 TRACE("returning %d with %d (%d byte for %d entries)\n",
6909 (res), GetLastError(), needed, numentries);
6911 return (res);
6914 /*****************************************************************************
6915 * EnumPrintProcessorsW [WINSPOOL.@]
6917 * Enumerate available Print Processors
6919 * PARAMS
6920 * pName [I] Servername or NULL (local Computer)
6921 * pEnvironment [I] Printing-Environment or NULL (Default)
6922 * Level [I] Structure-Level (Only 1 is allowed)
6923 * pPPInfo [O] PTR to Buffer that receives the Result
6924 * cbBuf [I] Size of Buffer at pPPInfo
6925 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6926 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6928 * RETURNS
6929 * Success: TRUE
6930 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6933 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6934 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6937 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6938 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6940 if ((backend == NULL) && !load_backend()) return FALSE;
6942 if (!pcbNeeded || !pcReturned) {
6943 SetLastError(RPC_X_NULL_REF_POINTER);
6944 return FALSE;
6947 if (!pPPInfo && (cbBuf > 0)) {
6948 SetLastError(ERROR_INVALID_USER_BUFFER);
6949 return FALSE;
6952 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6953 cbBuf, pcbNeeded, pcReturned);
6956 /*****************************************************************************
6957 * ExtDeviceMode [WINSPOOL.@]
6960 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6961 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6962 DWORD fMode)
6964 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6965 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6966 debugstr_a(pProfile), fMode);
6967 return -1;
6970 /*****************************************************************************
6971 * FindClosePrinterChangeNotification [WINSPOOL.@]
6974 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6976 FIXME("Stub: %p\n", hChange);
6977 return TRUE;
6980 /*****************************************************************************
6981 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6984 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6985 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6987 FIXME("Stub: %p %x %x %p\n",
6988 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6989 return INVALID_HANDLE_VALUE;
6992 /*****************************************************************************
6993 * FindNextPrinterChangeNotification [WINSPOOL.@]
6996 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6997 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6999 FIXME("Stub: %p %p %p %p\n",
7000 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7001 return FALSE;
7004 /*****************************************************************************
7005 * FreePrinterNotifyInfo [WINSPOOL.@]
7008 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7010 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7011 return TRUE;
7014 /*****************************************************************************
7015 * string_to_buf
7017 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7018 * ansi depending on the unicode parameter.
7020 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7022 if(!str)
7024 *size = 0;
7025 return TRUE;
7028 if(unicode)
7030 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7031 if(*size <= cb)
7033 memcpy(ptr, str, *size);
7034 return TRUE;
7036 return FALSE;
7038 else
7040 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7041 if(*size <= cb)
7043 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7044 return TRUE;
7046 return FALSE;
7050 /*****************************************************************************
7051 * get_job_info_1
7053 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7054 LPDWORD pcbNeeded, BOOL unicode)
7056 DWORD size, left = cbBuf;
7057 BOOL space = (cbBuf > 0);
7058 LPBYTE ptr = buf;
7060 *pcbNeeded = 0;
7062 if(space)
7064 ji1->JobId = job->job_id;
7067 string_to_buf(job->document_title, ptr, left, &size, unicode);
7068 if(space && size <= left)
7070 ji1->pDocument = (LPWSTR)ptr;
7071 ptr += size;
7072 left -= size;
7074 else
7075 space = FALSE;
7076 *pcbNeeded += size;
7078 if (job->printer_name)
7080 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7081 if(space && size <= left)
7083 ji1->pPrinterName = (LPWSTR)ptr;
7084 ptr += size;
7085 left -= size;
7087 else
7088 space = FALSE;
7089 *pcbNeeded += size;
7092 return space;
7095 /*****************************************************************************
7096 * get_job_info_2
7098 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7099 LPDWORD pcbNeeded, BOOL unicode)
7101 DWORD size, left = cbBuf;
7102 BOOL space = (cbBuf > 0);
7103 LPBYTE ptr = buf;
7105 *pcbNeeded = 0;
7107 if(space)
7109 ji2->JobId = job->job_id;
7112 string_to_buf(job->document_title, ptr, left, &size, unicode);
7113 if(space && size <= left)
7115 ji2->pDocument = (LPWSTR)ptr;
7116 ptr += size;
7117 left -= size;
7119 else
7120 space = FALSE;
7121 *pcbNeeded += size;
7123 if (job->printer_name)
7125 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7126 if(space && size <= left)
7128 ji2->pPrinterName = (LPWSTR)ptr;
7129 ptr += size;
7130 left -= size;
7132 else
7133 space = FALSE;
7134 *pcbNeeded += size;
7137 return space;
7140 /*****************************************************************************
7141 * get_job_info
7143 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7144 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7146 BOOL ret = FALSE;
7147 DWORD needed = 0, size;
7148 job_t *job;
7149 LPBYTE ptr = pJob;
7151 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7153 EnterCriticalSection(&printer_handles_cs);
7154 job = get_job(hPrinter, JobId);
7155 if(!job)
7156 goto end;
7158 switch(Level)
7160 case 1:
7161 size = sizeof(JOB_INFO_1W);
7162 if(cbBuf >= size)
7164 cbBuf -= size;
7165 ptr += size;
7166 memset(pJob, 0, size);
7168 else
7169 cbBuf = 0;
7170 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7171 needed += size;
7172 break;
7174 case 2:
7175 size = sizeof(JOB_INFO_2W);
7176 if(cbBuf >= size)
7178 cbBuf -= size;
7179 ptr += size;
7180 memset(pJob, 0, size);
7182 else
7183 cbBuf = 0;
7184 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7185 needed += size;
7186 break;
7188 case 3:
7189 size = sizeof(JOB_INFO_3);
7190 if(cbBuf >= size)
7192 cbBuf -= size;
7193 memset(pJob, 0, size);
7194 ret = TRUE;
7196 else
7197 cbBuf = 0;
7198 needed = size;
7199 break;
7201 default:
7202 SetLastError(ERROR_INVALID_LEVEL);
7203 goto end;
7205 if(pcbNeeded)
7206 *pcbNeeded = needed;
7207 end:
7208 LeaveCriticalSection(&printer_handles_cs);
7209 return ret;
7212 /*****************************************************************************
7213 * GetJobA [WINSPOOL.@]
7216 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7217 DWORD cbBuf, LPDWORD pcbNeeded)
7219 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7222 /*****************************************************************************
7223 * GetJobW [WINSPOOL.@]
7226 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7227 DWORD cbBuf, LPDWORD pcbNeeded)
7229 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7232 /*****************************************************************************
7233 * schedule_lpr
7235 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7237 char *unixname, *queue, *cmd;
7238 char fmt[] = "lpr -P'%s' '%s'";
7239 DWORD len;
7240 int r;
7242 if(!(unixname = wine_get_unix_file_name(filename)))
7243 return FALSE;
7245 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7246 queue = HeapAlloc(GetProcessHeap(), 0, len);
7247 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7249 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7250 sprintf(cmd, fmt, queue, unixname);
7252 TRACE("printing with: %s\n", cmd);
7253 r = system(cmd);
7255 HeapFree(GetProcessHeap(), 0, cmd);
7256 HeapFree(GetProcessHeap(), 0, queue);
7257 HeapFree(GetProcessHeap(), 0, unixname);
7258 return (r == 0);
7261 /*****************************************************************************
7262 * schedule_cups
7264 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7266 #ifdef SONAME_LIBCUPS
7267 if(pcupsPrintFile)
7269 char *unixname, *queue, *unix_doc_title;
7270 DWORD len;
7271 BOOL ret;
7273 if(!(unixname = wine_get_unix_file_name(filename)))
7274 return FALSE;
7276 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7277 queue = HeapAlloc(GetProcessHeap(), 0, len);
7278 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7280 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7281 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7282 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7284 TRACE("printing via cups\n");
7285 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7286 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7287 HeapFree(GetProcessHeap(), 0, queue);
7288 HeapFree(GetProcessHeap(), 0, unixname);
7289 return ret;
7291 else
7292 #endif
7294 return schedule_lpr(printer_name, filename);
7298 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7300 LPWSTR filename;
7302 switch(msg)
7304 case WM_INITDIALOG:
7305 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7306 return TRUE;
7308 case WM_COMMAND:
7309 if(HIWORD(wparam) == BN_CLICKED)
7311 if(LOWORD(wparam) == IDOK)
7313 HANDLE hf;
7314 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7315 LPWSTR *output;
7317 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7318 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7320 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7322 WCHAR caption[200], message[200];
7323 int mb_ret;
7325 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7326 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7327 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7328 if(mb_ret == IDCANCEL)
7330 HeapFree(GetProcessHeap(), 0, filename);
7331 return TRUE;
7334 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7335 if(hf == INVALID_HANDLE_VALUE)
7337 WCHAR caption[200], message[200];
7339 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7340 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7341 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7342 HeapFree(GetProcessHeap(), 0, filename);
7343 return TRUE;
7345 CloseHandle(hf);
7346 DeleteFileW(filename);
7347 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7348 *output = filename;
7349 EndDialog(hwnd, IDOK);
7350 return TRUE;
7352 if(LOWORD(wparam) == IDCANCEL)
7354 EndDialog(hwnd, IDCANCEL);
7355 return TRUE;
7358 return FALSE;
7360 return FALSE;
7363 /*****************************************************************************
7364 * get_filename
7366 static BOOL get_filename(LPWSTR *filename)
7368 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7369 file_dlg_proc, (LPARAM)filename) == IDOK;
7372 /*****************************************************************************
7373 * schedule_file
7375 static BOOL schedule_file(LPCWSTR filename)
7377 LPWSTR output = NULL;
7379 if(get_filename(&output))
7381 BOOL r;
7382 TRACE("copy to %s\n", debugstr_w(output));
7383 r = CopyFileW(filename, output, FALSE);
7384 HeapFree(GetProcessHeap(), 0, output);
7385 return r;
7387 return FALSE;
7390 /*****************************************************************************
7391 * schedule_pipe
7393 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7395 #ifdef HAVE_FORK
7396 char *unixname, *cmdA;
7397 DWORD len;
7398 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7399 BOOL ret = FALSE;
7400 char buf[1024];
7402 if(!(unixname = wine_get_unix_file_name(filename)))
7403 return FALSE;
7405 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7406 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7407 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7409 TRACE("printing with: %s\n", cmdA);
7411 if((file_fd = open(unixname, O_RDONLY)) == -1)
7412 goto end;
7414 if (pipe(fds))
7416 ERR("pipe() failed!\n");
7417 goto end;
7420 if (fork() == 0)
7422 close(0);
7423 dup2(fds[0], 0);
7424 close(fds[1]);
7426 /* reset signals that we previously set to SIG_IGN */
7427 signal(SIGPIPE, SIG_DFL);
7428 signal(SIGCHLD, SIG_DFL);
7430 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7431 _exit(1);
7434 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7435 write(fds[1], buf, no_read);
7437 ret = TRUE;
7439 end:
7440 if(file_fd != -1) close(file_fd);
7441 if(fds[0] != -1) close(fds[0]);
7442 if(fds[1] != -1) close(fds[1]);
7444 HeapFree(GetProcessHeap(), 0, cmdA);
7445 HeapFree(GetProcessHeap(), 0, unixname);
7446 return ret;
7447 #else
7448 return FALSE;
7449 #endif
7452 /*****************************************************************************
7453 * schedule_unixfile
7455 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7457 int in_fd, out_fd, no_read;
7458 char buf[1024];
7459 BOOL ret = FALSE;
7460 char *unixname, *outputA;
7461 DWORD len;
7463 if(!(unixname = wine_get_unix_file_name(filename)))
7464 return FALSE;
7466 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7467 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7468 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7470 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7471 in_fd = open(unixname, O_RDONLY);
7472 if(out_fd == -1 || in_fd == -1)
7473 goto end;
7475 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7476 write(out_fd, buf, no_read);
7478 ret = TRUE;
7479 end:
7480 if(in_fd != -1) close(in_fd);
7481 if(out_fd != -1) close(out_fd);
7482 HeapFree(GetProcessHeap(), 0, outputA);
7483 HeapFree(GetProcessHeap(), 0, unixname);
7484 return ret;
7487 /*****************************************************************************
7488 * ScheduleJob [WINSPOOL.@]
7491 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7493 opened_printer_t *printer;
7494 BOOL ret = FALSE;
7495 struct list *cursor, *cursor2;
7497 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7498 EnterCriticalSection(&printer_handles_cs);
7499 printer = get_opened_printer(hPrinter);
7500 if(!printer)
7501 goto end;
7503 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7505 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7506 HANDLE hf;
7508 if(job->job_id != dwJobID) continue;
7510 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7511 if(hf != INVALID_HANDLE_VALUE)
7513 PRINTER_INFO_5W *pi5 = NULL;
7514 LPWSTR portname = job->portname;
7515 DWORD needed;
7516 HKEY hkey;
7517 WCHAR output[1024];
7518 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7519 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7521 if (!portname)
7523 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7524 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7525 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7526 portname = pi5->pPortName;
7528 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7529 debugstr_w(portname));
7531 output[0] = 0;
7533 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7534 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7536 DWORD type, count = sizeof(output);
7537 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7538 RegCloseKey(hkey);
7540 if(output[0] == '|')
7542 ret = schedule_pipe(output + 1, job->filename);
7544 else if(output[0])
7546 ret = schedule_unixfile(output, job->filename);
7548 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7550 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7552 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7554 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7556 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7558 ret = schedule_file(job->filename);
7560 else
7562 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7564 HeapFree(GetProcessHeap(), 0, pi5);
7565 CloseHandle(hf);
7566 DeleteFileW(job->filename);
7568 list_remove(cursor);
7569 HeapFree(GetProcessHeap(), 0, job->document_title);
7570 HeapFree(GetProcessHeap(), 0, job->printer_name);
7571 HeapFree(GetProcessHeap(), 0, job->portname);
7572 HeapFree(GetProcessHeap(), 0, job->filename);
7573 HeapFree(GetProcessHeap(), 0, job);
7574 break;
7576 end:
7577 LeaveCriticalSection(&printer_handles_cs);
7578 return ret;
7581 /*****************************************************************************
7582 * StartDocDlgA [WINSPOOL.@]
7584 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7586 UNICODE_STRING usBuffer;
7587 DOCINFOW docW;
7588 LPWSTR retW;
7589 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7590 LPSTR ret = NULL;
7592 docW.cbSize = sizeof(docW);
7593 if (doc->lpszDocName)
7595 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7596 if (!(docW.lpszDocName = docnameW)) return NULL;
7598 if (doc->lpszOutput)
7600 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7601 if (!(docW.lpszOutput = outputW)) return NULL;
7603 if (doc->lpszDatatype)
7605 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7606 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7608 docW.fwType = doc->fwType;
7610 retW = StartDocDlgW(hPrinter, &docW);
7612 if(retW)
7614 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7615 ret = HeapAlloc(GetProcessHeap(), 0, len);
7616 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7617 HeapFree(GetProcessHeap(), 0, retW);
7620 HeapFree(GetProcessHeap(), 0, datatypeW);
7621 HeapFree(GetProcessHeap(), 0, outputW);
7622 HeapFree(GetProcessHeap(), 0, docnameW);
7624 return ret;
7627 /*****************************************************************************
7628 * StartDocDlgW [WINSPOOL.@]
7630 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7631 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7632 * port is "FILE:". Also returns the full path if passed a relative path.
7634 * The caller should free the returned string from the process heap.
7636 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7638 LPWSTR ret = NULL;
7639 DWORD len, attr;
7641 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7643 PRINTER_INFO_5W *pi5;
7644 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7645 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7646 return NULL;
7647 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7648 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7649 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7651 HeapFree(GetProcessHeap(), 0, pi5);
7652 return NULL;
7654 HeapFree(GetProcessHeap(), 0, pi5);
7657 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7659 LPWSTR name;
7661 if (get_filename(&name))
7663 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7665 HeapFree(GetProcessHeap(), 0, name);
7666 return NULL;
7668 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7669 GetFullPathNameW(name, len, ret, NULL);
7670 HeapFree(GetProcessHeap(), 0, name);
7672 return ret;
7675 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7676 return NULL;
7678 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7679 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7681 attr = GetFileAttributesW(ret);
7682 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7684 HeapFree(GetProcessHeap(), 0, ret);
7685 ret = NULL;
7687 return ret;