wpp: Add I/O callbacks.
[wine/hacks.git] / dlls / winspool.drv / info.c
blob4bd88a262b97277d85f3248fc3b2952aea1dd8fd
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2009 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
76 /* ############################### */
78 typedef struct {
79 DWORD job_id;
80 HANDLE hf;
81 } started_doc_t;
83 typedef struct {
84 struct list jobs;
85 LONG ref;
86 } jobqueue_t;
88 typedef struct {
89 LPWSTR name;
90 LPWSTR printername;
91 HANDLE backend_printer;
92 jobqueue_t *queue;
93 started_doc_t *doc;
94 } opened_printer_t;
96 typedef struct {
97 struct list entry;
98 DWORD job_id;
99 WCHAR *filename;
100 WCHAR *document_title;
101 } job_t;
104 typedef struct {
105 LPCWSTR envname;
106 LPCWSTR subdir;
107 DWORD driverversion;
108 LPCWSTR versionregpath;
109 LPCWSTR versionsubdir;
110 } printenv_t;
112 /* ############################### */
114 static opened_printer_t **printer_handles;
115 static UINT nb_printer_handles;
116 static LONG next_job_id = 1;
118 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
119 WORD fwCapability, LPSTR lpszOutput,
120 LPDEVMODEA lpdm );
121 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
122 LPSTR lpszDevice, LPSTR lpszPort,
123 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
124 DWORD fwMode );
126 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
127 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
128 'c','o','n','t','r','o','l','\\',
129 'P','r','i','n','t','\\',
130 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
131 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
133 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
134 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
135 'C','o','n','t','r','o','l','\\',
136 'P','r','i','n','t','\\',
137 'P','r','i','n','t','e','r','s',0};
139 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
141 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
142 'M','i','c','r','o','s','o','f','t','\\',
143 'W','i','n','d','o','w','s',' ','N','T','\\',
144 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
145 'W','i','n','d','o','w','s',0};
147 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
148 'M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s',' ','N','T','\\',
150 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
151 'D','e','v','i','c','e','s',0};
153 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
154 'M','i','c','r','o','s','o','f','t','\\',
155 'W','i','n','d','o','w','s',' ','N','T','\\',
156 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
157 'P','o','r','t','s',0};
159 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
160 'M','i','c','r','o','s','o','f','t','\\',
161 'W','i','n','d','o','w','s',' ','N','T','\\',
162 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
163 'P','r','i','n','t','e','r','P','o','r','t','s',0};
165 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
166 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
167 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
168 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
169 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
170 static const WCHAR subdir_x64W[] = {'x','6','4',0};
171 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
172 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
173 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
174 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
175 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
177 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
178 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','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 * Return the number of bytes for an multi_sz string.
331 * The result includes all \0s
332 * (specifically the extra \0, that is needed as multi_sz terminator).
334 #if 0
335 static int multi_sz_lenW(const WCHAR *str)
337 const WCHAR *ptr = str;
338 if(!str) return 0;
341 ptr += lstrlenW(ptr) + 1;
342 } while(*ptr);
344 return (ptr - str + 1) * sizeof(WCHAR);
346 #endif
347 /* ################################ */
349 static int multi_sz_lenA(const char *str)
351 const char *ptr = str;
352 if(!str) return 0;
355 ptr += lstrlenA(ptr) + 1;
356 } while(*ptr);
358 return ptr - str + 1;
361 static void
362 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
363 char qbuf[200];
365 /* If forcing, or no profile string entry for device yet, set the entry
367 * The always change entry if not WINEPS yet is discussable.
369 if (force ||
370 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
371 !strcmp(qbuf,"*") ||
372 !strstr(qbuf,"WINEPS.DRV")
374 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
375 HKEY hkey;
377 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
378 WriteProfileStringA("windows","device",buf);
379 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
380 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
381 RegCloseKey(hkey);
383 HeapFree(GetProcessHeap(),0,buf);
387 static BOOL add_printer_driver(const char *name)
389 DRIVER_INFO_3A di3a;
391 static char driver_9x[] = "wineps16.drv",
392 driver_nt[] = "wineps.drv",
393 env_9x[] = "Windows 4.0",
394 env_nt[] = "Windows NT x86",
395 data_file[] = "generic.ppd",
396 default_data_type[] = "RAW";
398 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
399 di3a.cVersion = 3;
400 di3a.pName = (char *)name;
401 di3a.pEnvironment = env_nt;
402 di3a.pDriverPath = driver_nt;
403 di3a.pDataFile = data_file;
404 di3a.pConfigFile = driver_nt;
405 di3a.pDefaultDataType = default_data_type;
407 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
408 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
410 di3a.cVersion = 0;
411 di3a.pEnvironment = env_9x;
412 di3a.pDriverPath = driver_9x;
413 di3a.pConfigFile = driver_9x;
414 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
415 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
417 return TRUE;
420 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
421 debugstr_a(di3a.pEnvironment), GetLastError());
422 return FALSE;
425 #ifdef SONAME_LIBCUPS
426 static typeof(cupsFreeDests) *pcupsFreeDests;
427 static typeof(cupsGetDests) *pcupsGetDests;
428 static typeof(cupsGetPPD) *pcupsGetPPD;
429 static typeof(cupsPrintFile) *pcupsPrintFile;
430 static void *cupshandle;
432 static BOOL CUPS_LoadPrinters(void)
434 int i, nrofdests;
435 BOOL hadprinter = FALSE, haddefault = FALSE;
436 cups_dest_t *dests;
437 PRINTER_INFO_2A pinfo2a;
438 char *port,*devline;
439 HKEY hkeyPrinter, hkeyPrinters, hkey;
440 char loaderror[256];
442 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
443 if (!cupshandle) {
444 TRACE("%s\n", loaderror);
445 return FALSE;
447 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
449 #define DYNCUPS(x) \
450 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
451 if (!p##x) return FALSE;
453 DYNCUPS(cupsFreeDests);
454 DYNCUPS(cupsGetPPD);
455 DYNCUPS(cupsGetDests);
456 DYNCUPS(cupsPrintFile);
457 #undef DYNCUPS
459 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
460 ERROR_SUCCESS) {
461 ERR("Can't create Printers key\n");
462 return FALSE;
465 nrofdests = pcupsGetDests(&dests);
466 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
467 for (i=0;i<nrofdests;i++) {
468 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
469 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
470 sprintf(port,"LPR:%s", dests[i].name);
471 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
472 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
473 sprintf(devline, "WINEPS.DRV,%s", port);
474 WriteProfileStringA("devices", dests[i].name, devline);
475 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
476 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
477 RegCloseKey(hkey);
480 lstrcatA(devline, ",15,45");
481 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
482 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
483 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
484 RegCloseKey(hkey);
487 HeapFree(GetProcessHeap(), 0, devline);
489 TRACE("Printer %d: %s\n", i, dests[i].name);
490 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
491 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
492 and continue */
493 TRACE("Printer already exists\n");
494 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
495 RegCloseKey(hkeyPrinter);
496 } else {
497 static CHAR data_type[] = "RAW",
498 print_proc[] = "WinPrint",
499 comment[] = "WINEPS Printer using CUPS",
500 location[] = "<physical location of printer>",
501 params[] = "<parameters?>",
502 share_name[] = "<share name?>",
503 sep_file[] = "<sep file?>";
505 add_printer_driver(dests[i].name);
507 memset(&pinfo2a,0,sizeof(pinfo2a));
508 pinfo2a.pPrinterName = dests[i].name;
509 pinfo2a.pDatatype = data_type;
510 pinfo2a.pPrintProcessor = print_proc;
511 pinfo2a.pDriverName = dests[i].name;
512 pinfo2a.pComment = comment;
513 pinfo2a.pLocation = location;
514 pinfo2a.pPortName = port;
515 pinfo2a.pParameters = params;
516 pinfo2a.pShareName = share_name;
517 pinfo2a.pSepFile = sep_file;
519 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
520 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
521 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
524 HeapFree(GetProcessHeap(),0,port);
526 hadprinter = TRUE;
527 if (dests[i].is_default) {
528 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
529 haddefault = TRUE;
532 if (hadprinter & !haddefault)
533 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
534 pcupsFreeDests(nrofdests, dests);
535 RegCloseKey(hkeyPrinters);
536 return hadprinter;
538 #endif
540 static BOOL
541 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
542 PRINTER_INFO_2A pinfo2a;
543 char *e,*s,*name,*prettyname,*devname;
544 BOOL ret = FALSE, set_default = FALSE;
545 char *port = NULL, *devline,*env_default;
546 HKEY hkeyPrinter, hkeyPrinters, hkey;
548 while (isspace(*pent)) pent++;
549 s = strchr(pent,':');
550 if(s) *s='\0';
551 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
552 strcpy(name,pent);
553 if(s) {
554 *s=':';
555 pent = s;
556 } else
557 pent = "";
559 TRACE("name=%s entry=%s\n",name, pent);
561 if(ispunct(*name)) { /* a tc entry, not a real printer */
562 TRACE("skipping tc entry\n");
563 goto end;
566 if(strstr(pent,":server")) { /* server only version so skip */
567 TRACE("skipping server entry\n");
568 goto end;
571 /* Determine whether this is a postscript printer. */
573 ret = TRUE;
574 env_default = getenv("PRINTER");
575 prettyname = name;
576 /* Get longest name, usually the one at the right for later display. */
577 while((s=strchr(prettyname,'|'))) {
578 *s = '\0';
579 e = s;
580 while(isspace(*--e)) *e = '\0';
581 TRACE("\t%s\n", debugstr_a(prettyname));
582 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
583 for(prettyname = s+1; isspace(*prettyname); prettyname++)
586 e = prettyname + strlen(prettyname);
587 while(isspace(*--e)) *e = '\0';
588 TRACE("\t%s\n", debugstr_a(prettyname));
589 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
591 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
592 * if it is too long, we use it as comment below. */
593 devname = prettyname;
594 if (strlen(devname)>=CCHDEVICENAME-1)
595 devname = name;
596 if (strlen(devname)>=CCHDEVICENAME-1) {
597 ret = FALSE;
598 goto end;
601 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
602 sprintf(port,"LPR:%s",name);
604 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
605 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
606 sprintf(devline, "WINEPS.DRV,%s", port);
607 WriteProfileStringA("devices", devname, devline);
608 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
609 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
610 RegCloseKey(hkey);
613 lstrcatA(devline, ",15,45");
614 WriteProfileStringA("PrinterPorts", devname, devline);
615 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
616 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
617 RegCloseKey(hkey);
620 HeapFree(GetProcessHeap(),0,devline);
622 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
623 ERROR_SUCCESS) {
624 ERR("Can't create Printers key\n");
625 ret = FALSE;
626 goto end;
628 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
629 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
630 and continue */
631 TRACE("Printer already exists\n");
632 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
633 RegCloseKey(hkeyPrinter);
634 } else {
635 static CHAR data_type[] = "RAW",
636 print_proc[] = "WinPrint",
637 comment[] = "WINEPS Printer using LPR",
638 params[] = "<parameters?>",
639 share_name[] = "<share name?>",
640 sep_file[] = "<sep file?>";
642 add_printer_driver(devname);
644 memset(&pinfo2a,0,sizeof(pinfo2a));
645 pinfo2a.pPrinterName = devname;
646 pinfo2a.pDatatype = data_type;
647 pinfo2a.pPrintProcessor = print_proc;
648 pinfo2a.pDriverName = devname;
649 pinfo2a.pComment = comment;
650 pinfo2a.pLocation = prettyname;
651 pinfo2a.pPortName = port;
652 pinfo2a.pParameters = params;
653 pinfo2a.pShareName = share_name;
654 pinfo2a.pSepFile = sep_file;
656 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
657 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
658 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
661 RegCloseKey(hkeyPrinters);
663 if (isfirst || set_default)
664 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
666 end:
667 HeapFree(GetProcessHeap(), 0, port);
668 HeapFree(GetProcessHeap(), 0, name);
669 return ret;
672 static BOOL
673 PRINTCAP_LoadPrinters(void) {
674 BOOL hadprinter = FALSE;
675 char buf[200];
676 FILE *f;
677 char *pent = NULL;
678 BOOL had_bash = FALSE;
680 f = fopen("/etc/printcap","r");
681 if (!f)
682 return FALSE;
684 while(fgets(buf,sizeof(buf),f)) {
685 char *start, *end;
687 end=strchr(buf,'\n');
688 if (end) *end='\0';
690 start = buf;
691 while(isspace(*start)) start++;
692 if(*start == '#' || *start == '\0')
693 continue;
695 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
696 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
697 HeapFree(GetProcessHeap(),0,pent);
698 pent = NULL;
701 if (end && *--end == '\\') {
702 *end = '\0';
703 had_bash = TRUE;
704 } else
705 had_bash = FALSE;
707 if (pent) {
708 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
709 strcat(pent,start);
710 } else {
711 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
712 strcpy(pent,start);
716 if(pent) {
717 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
718 HeapFree(GetProcessHeap(),0,pent);
720 fclose(f);
721 return hadprinter;
724 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
726 if (value)
727 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
728 (lstrlenW(value) + 1) * sizeof(WCHAR));
729 else
730 return ERROR_FILE_NOT_FOUND;
733 /******************************************************************
734 * get_servername_from_name (internal)
736 * for an external server, a copy of the serverpart from the full name is returned
739 static LPWSTR get_servername_from_name(LPCWSTR name)
741 LPWSTR server;
742 LPWSTR ptr;
743 WCHAR buffer[MAX_PATH];
744 DWORD len;
746 if (name == NULL) return NULL;
747 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
749 server = strdupW(&name[2]); /* skip over both backslash */
750 if (server == NULL) return NULL;
752 /* strip '\' and the printername */
753 ptr = strchrW(server, '\\');
754 if (ptr) ptr[0] = '\0';
756 TRACE("found %s\n", debugstr_w(server));
758 len = sizeof(buffer)/sizeof(buffer[0]);
759 if (GetComputerNameW(buffer, &len)) {
760 if (lstrcmpW(buffer, server) == 0) {
761 /* The requested Servername is our computername */
762 HeapFree(GetProcessHeap(), 0, server);
763 return NULL;
766 return server;
769 /******************************************************************
770 * get_basename_from_name (internal)
772 * skip over the serverpart from the full name
775 static LPCWSTR get_basename_from_name(LPCWSTR name)
777 if (name == NULL) return NULL;
778 if ((name[0] == '\\') && (name[1] == '\\')) {
779 /* skip over the servername and search for the following '\' */
780 name = strchrW(&name[2], '\\');
781 if ((name) && (name[1])) {
782 /* found a separator ('\') followed by a name:
783 skip over the separator and return the rest */
784 name++;
786 else
788 /* no basename present (we found only a servername) */
789 return NULL;
792 return name;
795 /******************************************************************
796 * get_opened_printer_entry
797 * Get the first place empty in the opened printer table
799 * ToDo:
800 * - pDefault is ignored
802 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
804 UINT_PTR handle = nb_printer_handles, i;
805 jobqueue_t *queue = NULL;
806 opened_printer_t *printer = NULL;
807 LPWSTR servername;
808 LPCWSTR printername;
810 if ((backend == NULL) && !load_backend()) return NULL;
812 servername = get_servername_from_name(name);
813 if (servername) {
814 FIXME("server %s not supported\n", debugstr_w(servername));
815 HeapFree(GetProcessHeap(), 0, servername);
816 SetLastError(ERROR_INVALID_PRINTER_NAME);
817 return NULL;
820 printername = get_basename_from_name(name);
821 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
823 /* an empty printername is invalid */
824 if (printername && (!printername[0])) {
825 SetLastError(ERROR_INVALID_PARAMETER);
826 return NULL;
829 EnterCriticalSection(&printer_handles_cs);
831 for (i = 0; i < nb_printer_handles; i++)
833 if (!printer_handles[i])
835 if(handle == nb_printer_handles)
836 handle = i;
838 else
840 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
841 queue = printer_handles[i]->queue;
845 if (handle >= nb_printer_handles)
847 opened_printer_t **new_array;
848 if (printer_handles)
849 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
850 (nb_printer_handles + 16) * sizeof(*new_array) );
851 else
852 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
853 (nb_printer_handles + 16) * sizeof(*new_array) );
855 if (!new_array)
857 handle = 0;
858 goto end;
860 printer_handles = new_array;
861 nb_printer_handles += 16;
864 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
866 handle = 0;
867 goto end;
870 /* get a printer handle from the backend */
871 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
872 handle = 0;
873 goto end;
876 /* clone the base name. This is NULL for the printserver */
877 printer->printername = strdupW(printername);
879 /* clone the full name */
880 printer->name = strdupW(name);
881 if (name && (!printer->name)) {
882 handle = 0;
883 goto end;
886 if(queue)
887 printer->queue = queue;
888 else
890 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
891 if (!printer->queue) {
892 handle = 0;
893 goto end;
895 list_init(&printer->queue->jobs);
896 printer->queue->ref = 0;
898 InterlockedIncrement(&printer->queue->ref);
900 printer_handles[handle] = printer;
901 handle++;
902 end:
903 LeaveCriticalSection(&printer_handles_cs);
904 if (!handle && printer) {
905 /* Something failed: Free all resources */
906 HeapFree(GetProcessHeap(), 0, printer->printername);
907 HeapFree(GetProcessHeap(), 0, printer->name);
908 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
909 HeapFree(GetProcessHeap(), 0, printer);
912 return (HANDLE)handle;
915 /******************************************************************
916 * get_opened_printer
917 * Get the pointer to the opened printer referred by the handle
919 static opened_printer_t *get_opened_printer(HANDLE hprn)
921 UINT_PTR idx = (UINT_PTR)hprn;
922 opened_printer_t *ret = NULL;
924 EnterCriticalSection(&printer_handles_cs);
926 if ((idx > 0) && (idx <= nb_printer_handles)) {
927 ret = printer_handles[idx - 1];
929 LeaveCriticalSection(&printer_handles_cs);
930 return ret;
933 /******************************************************************
934 * get_opened_printer_name
935 * Get the pointer to the opened printer name referred by the handle
937 static LPCWSTR get_opened_printer_name(HANDLE hprn)
939 opened_printer_t *printer = get_opened_printer(hprn);
940 if(!printer) return NULL;
941 return printer->name;
944 /******************************************************************
945 * WINSPOOL_GetOpenedPrinterRegKey
948 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
950 LPCWSTR name = get_opened_printer_name(hPrinter);
951 DWORD ret;
952 HKEY hkeyPrinters;
954 if(!name) return ERROR_INVALID_HANDLE;
956 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
957 ERROR_SUCCESS)
958 return ret;
960 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
962 ERR("Can't find opened printer %s in registry\n",
963 debugstr_w(name));
964 RegCloseKey(hkeyPrinters);
965 return ERROR_INVALID_PRINTER_NAME; /* ? */
967 RegCloseKey(hkeyPrinters);
968 return ERROR_SUCCESS;
971 void WINSPOOL_LoadSystemPrinters(void)
973 HKEY hkey, hkeyPrinters;
974 HANDLE hprn;
975 DWORD needed, num, i;
976 WCHAR PrinterName[256];
977 BOOL done = FALSE;
979 /* This ensures that all printer entries have a valid Name value. If causes
980 problems later if they don't. If one is found to be missed we create one
981 and set it equal to the name of the key */
982 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
983 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
984 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
985 for(i = 0; i < num; i++) {
986 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
987 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
988 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
989 set_reg_szW(hkey, NameW, PrinterName);
991 RegCloseKey(hkey);
996 RegCloseKey(hkeyPrinters);
999 /* We want to avoid calling AddPrinter on printers as much as
1000 possible, because on cups printers this will (eventually) lead
1001 to a call to cupsGetPPD which takes forever, even with non-cups
1002 printers AddPrinter takes a while. So we'll tag all printers that
1003 were automatically added last time around, if they still exist
1004 we'll leave them be otherwise we'll delete them. */
1005 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1006 if(needed) {
1007 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1008 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1009 for(i = 0; i < num; i++) {
1010 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1011 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1012 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1013 DWORD dw = 1;
1014 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1015 RegCloseKey(hkey);
1017 ClosePrinter(hprn);
1022 HeapFree(GetProcessHeap(), 0, pi);
1026 #ifdef SONAME_LIBCUPS
1027 done = CUPS_LoadPrinters();
1028 #endif
1030 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1031 PRINTCAP_LoadPrinters();
1033 /* Now enumerate the list again and delete any printers that are still tagged */
1034 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1035 if(needed) {
1036 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1037 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1038 for(i = 0; i < num; i++) {
1039 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1040 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1041 BOOL delete_driver = FALSE;
1042 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1043 DWORD dw, type, size = sizeof(dw);
1044 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1045 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1046 DeletePrinter(hprn);
1047 delete_driver = TRUE;
1049 RegCloseKey(hkey);
1051 ClosePrinter(hprn);
1052 if(delete_driver)
1053 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1058 HeapFree(GetProcessHeap(), 0, pi);
1061 return;
1065 /******************************************************************
1066 * get_job
1068 * Get the pointer to the specified job.
1069 * Should hold the printer_handles_cs before calling.
1071 static job_t *get_job(HANDLE hprn, DWORD JobId)
1073 opened_printer_t *printer = get_opened_printer(hprn);
1074 job_t *job;
1076 if(!printer) return NULL;
1077 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1079 if(job->job_id == JobId)
1080 return job;
1082 return NULL;
1085 /***********************************************************
1086 * DEVMODEcpyAtoW
1088 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1090 BOOL Formname;
1091 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1092 DWORD size;
1094 Formname = (dmA->dmSize > off_formname);
1095 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1096 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1097 dmW->dmDeviceName, CCHDEVICENAME);
1098 if(!Formname) {
1099 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1100 dmA->dmSize - CCHDEVICENAME);
1101 } else {
1102 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1103 off_formname - CCHDEVICENAME);
1104 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1105 dmW->dmFormName, CCHFORMNAME);
1106 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1107 (off_formname + CCHFORMNAME));
1109 dmW->dmSize = size;
1110 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1111 dmA->dmDriverExtra);
1112 return dmW;
1115 /***********************************************************
1116 * DEVMODEdupWtoA
1117 * Creates an ansi copy of supplied devmode
1119 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1121 LPDEVMODEA dmA;
1122 DWORD size;
1124 if (!dmW) return NULL;
1125 size = dmW->dmSize - CCHDEVICENAME -
1126 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1128 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1129 if (!dmA) return NULL;
1131 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1132 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1134 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1135 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1136 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1138 else
1140 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1141 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1142 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1143 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1145 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1148 dmA->dmSize = size;
1149 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1150 return dmA;
1153 /******************************************************************
1154 * convert_printerinfo_W_to_A [internal]
1157 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1158 DWORD level, DWORD outlen, DWORD numentries)
1160 DWORD id = 0;
1161 LPSTR ptr;
1162 INT len;
1164 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1166 len = pi_sizeof[level] * numentries;
1167 ptr = (LPSTR) out + len;
1168 outlen -= len;
1170 /* copy the numbers of all PRINTER_INFO_* first */
1171 memcpy(out, pPrintersW, len);
1173 while (id < numentries) {
1174 switch (level) {
1175 case 1:
1177 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1178 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1180 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1181 if (piW->pDescription) {
1182 piA->pDescription = ptr;
1183 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1184 ptr, outlen, NULL, NULL);
1185 ptr += len;
1186 outlen -= len;
1188 if (piW->pName) {
1189 piA->pName = ptr;
1190 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1191 ptr, outlen, NULL, NULL);
1192 ptr += len;
1193 outlen -= len;
1195 if (piW->pComment) {
1196 piA->pComment = ptr;
1197 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1198 ptr, outlen, NULL, NULL);
1199 ptr += len;
1200 outlen -= len;
1202 break;
1205 case 2:
1207 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1208 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1209 LPDEVMODEA dmA;
1211 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1212 if (piW->pServerName) {
1213 piA->pServerName = ptr;
1214 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1215 ptr, outlen, NULL, NULL);
1216 ptr += len;
1217 outlen -= len;
1219 if (piW->pPrinterName) {
1220 piA->pPrinterName = ptr;
1221 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1222 ptr, outlen, NULL, NULL);
1223 ptr += len;
1224 outlen -= len;
1226 if (piW->pShareName) {
1227 piA->pShareName = ptr;
1228 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1229 ptr, outlen, NULL, NULL);
1230 ptr += len;
1231 outlen -= len;
1233 if (piW->pPortName) {
1234 piA->pPortName = ptr;
1235 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1236 ptr, outlen, NULL, NULL);
1237 ptr += len;
1238 outlen -= len;
1240 if (piW->pDriverName) {
1241 piA->pDriverName = ptr;
1242 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1243 ptr, outlen, NULL, NULL);
1244 ptr += len;
1245 outlen -= len;
1247 if (piW->pComment) {
1248 piA->pComment = ptr;
1249 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1250 ptr, outlen, NULL, NULL);
1251 ptr += len;
1252 outlen -= len;
1254 if (piW->pLocation) {
1255 piA->pLocation = ptr;
1256 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1257 ptr, outlen, NULL, NULL);
1258 ptr += len;
1259 outlen -= len;
1262 dmA = DEVMODEdupWtoA(piW->pDevMode);
1263 if (dmA) {
1264 /* align DEVMODEA to a DWORD boundary */
1265 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1266 ptr += len;
1267 outlen -= len;
1269 piA->pDevMode = (LPDEVMODEA) ptr;
1270 len = dmA->dmSize + dmA->dmDriverExtra;
1271 memcpy(ptr, dmA, len);
1272 HeapFree(GetProcessHeap(), 0, dmA);
1274 ptr += len;
1275 outlen -= len;
1278 if (piW->pSepFile) {
1279 piA->pSepFile = ptr;
1280 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1281 ptr, outlen, NULL, NULL);
1282 ptr += len;
1283 outlen -= len;
1285 if (piW->pPrintProcessor) {
1286 piA->pPrintProcessor = ptr;
1287 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1288 ptr, outlen, NULL, NULL);
1289 ptr += len;
1290 outlen -= len;
1292 if (piW->pDatatype) {
1293 piA->pDatatype = ptr;
1294 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1295 ptr, outlen, NULL, NULL);
1296 ptr += len;
1297 outlen -= len;
1299 if (piW->pParameters) {
1300 piA->pParameters = ptr;
1301 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1302 ptr, outlen, NULL, NULL);
1303 ptr += len;
1304 outlen -= len;
1306 if (piW->pSecurityDescriptor) {
1307 piA->pSecurityDescriptor = NULL;
1308 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1310 break;
1313 case 4:
1315 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1316 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1318 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1320 if (piW->pPrinterName) {
1321 piA->pPrinterName = ptr;
1322 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1323 ptr, outlen, NULL, NULL);
1324 ptr += len;
1325 outlen -= len;
1327 if (piW->pServerName) {
1328 piA->pServerName = ptr;
1329 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1330 ptr, outlen, NULL, NULL);
1331 ptr += len;
1332 outlen -= len;
1334 break;
1337 case 5:
1339 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1340 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1342 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1344 if (piW->pPrinterName) {
1345 piA->pPrinterName = ptr;
1346 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1347 ptr, outlen, NULL, NULL);
1348 ptr += len;
1349 outlen -= len;
1351 if (piW->pPortName) {
1352 piA->pPortName = ptr;
1353 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1354 ptr, outlen, NULL, NULL);
1355 ptr += len;
1356 outlen -= len;
1358 break;
1361 default:
1362 FIXME("for level %u\n", level);
1364 pPrintersW += pi_sizeof[level];
1365 out += pi_sizeof[level];
1366 id++;
1370 /***********************************************************
1371 * PRINTER_INFO_2AtoW
1372 * Creates a unicode copy of PRINTER_INFO_2A on heap
1374 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1376 LPPRINTER_INFO_2W piW;
1377 UNICODE_STRING usBuffer;
1379 if(!piA) return NULL;
1380 piW = HeapAlloc(heap, 0, sizeof(*piW));
1381 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1383 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1384 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1385 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1386 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1387 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1388 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1389 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1390 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1391 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1392 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1393 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1394 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1395 return piW;
1398 /***********************************************************
1399 * FREE_PRINTER_INFO_2W
1400 * Free PRINTER_INFO_2W and all strings
1402 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1404 if(!piW) return;
1406 HeapFree(heap,0,piW->pServerName);
1407 HeapFree(heap,0,piW->pPrinterName);
1408 HeapFree(heap,0,piW->pShareName);
1409 HeapFree(heap,0,piW->pPortName);
1410 HeapFree(heap,0,piW->pDriverName);
1411 HeapFree(heap,0,piW->pComment);
1412 HeapFree(heap,0,piW->pLocation);
1413 HeapFree(heap,0,piW->pDevMode);
1414 HeapFree(heap,0,piW->pSepFile);
1415 HeapFree(heap,0,piW->pPrintProcessor);
1416 HeapFree(heap,0,piW->pDatatype);
1417 HeapFree(heap,0,piW->pParameters);
1418 HeapFree(heap,0,piW);
1419 return;
1422 /******************************************************************
1423 * DeviceCapabilities [WINSPOOL.@]
1424 * DeviceCapabilitiesA [WINSPOOL.@]
1427 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1428 LPSTR pOutput, LPDEVMODEA lpdm)
1430 INT ret;
1432 if (!GDI_CallDeviceCapabilities16)
1434 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1435 (LPCSTR)104 );
1436 if (!GDI_CallDeviceCapabilities16) return -1;
1438 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1440 /* If DC_PAPERSIZE map POINT16s to POINTs */
1441 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1442 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1443 POINT *pt = (POINT *)pOutput;
1444 INT i;
1445 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1446 for(i = 0; i < ret; i++, pt++)
1448 pt->x = tmp[i].x;
1449 pt->y = tmp[i].y;
1451 HeapFree( GetProcessHeap(), 0, tmp );
1453 return ret;
1457 /*****************************************************************************
1458 * DeviceCapabilitiesW [WINSPOOL.@]
1460 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1463 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1464 WORD fwCapability, LPWSTR pOutput,
1465 const DEVMODEW *pDevMode)
1467 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1468 LPSTR pDeviceA = strdupWtoA(pDevice);
1469 LPSTR pPortA = strdupWtoA(pPort);
1470 INT ret;
1472 if(pOutput && (fwCapability == DC_BINNAMES ||
1473 fwCapability == DC_FILEDEPENDENCIES ||
1474 fwCapability == DC_PAPERNAMES)) {
1475 /* These need A -> W translation */
1476 INT size = 0, i;
1477 LPSTR pOutputA;
1478 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1479 dmA);
1480 if(ret == -1)
1481 return ret;
1482 switch(fwCapability) {
1483 case DC_BINNAMES:
1484 size = 24;
1485 break;
1486 case DC_PAPERNAMES:
1487 case DC_FILEDEPENDENCIES:
1488 size = 64;
1489 break;
1491 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1492 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1493 dmA);
1494 for(i = 0; i < ret; i++)
1495 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1496 pOutput + (i * size), size);
1497 HeapFree(GetProcessHeap(), 0, pOutputA);
1498 } else {
1499 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1500 (LPSTR)pOutput, dmA);
1502 HeapFree(GetProcessHeap(),0,pPortA);
1503 HeapFree(GetProcessHeap(),0,pDeviceA);
1504 HeapFree(GetProcessHeap(),0,dmA);
1505 return ret;
1508 /******************************************************************
1509 * DocumentPropertiesA [WINSPOOL.@]
1511 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1513 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1514 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1515 LPDEVMODEA pDevModeInput,DWORD fMode )
1517 LPSTR lpName = pDeviceName;
1518 static CHAR port[] = "LPT1:";
1519 LONG ret;
1521 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1522 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1525 if(!pDeviceName) {
1526 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1527 if(!lpNameW) {
1528 ERR("no name from hPrinter?\n");
1529 SetLastError(ERROR_INVALID_HANDLE);
1530 return -1;
1532 lpName = strdupWtoA(lpNameW);
1535 if (!GDI_CallExtDeviceMode16)
1537 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1538 (LPCSTR)102 );
1539 if (!GDI_CallExtDeviceMode16) {
1540 ERR("No CallExtDeviceMode16?\n");
1541 return -1;
1544 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1545 pDevModeInput, NULL, fMode);
1547 if(!pDeviceName)
1548 HeapFree(GetProcessHeap(),0,lpName);
1549 return ret;
1553 /*****************************************************************************
1554 * DocumentPropertiesW (WINSPOOL.@)
1556 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1558 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1559 LPWSTR pDeviceName,
1560 LPDEVMODEW pDevModeOutput,
1561 LPDEVMODEW pDevModeInput, DWORD fMode)
1564 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1565 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1566 LPDEVMODEA pDevModeOutputA = NULL;
1567 LONG ret;
1569 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1570 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1571 fMode);
1572 if(pDevModeOutput) {
1573 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1574 if(ret < 0) return ret;
1575 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1577 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1578 pDevModeInputA, fMode);
1579 if(pDevModeOutput) {
1580 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1581 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1583 if(fMode == 0 && ret > 0)
1584 ret += (CCHDEVICENAME + CCHFORMNAME);
1585 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1586 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1587 return ret;
1590 /******************************************************************
1591 * OpenPrinterA [WINSPOOL.@]
1593 * See OpenPrinterW.
1596 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1597 LPPRINTER_DEFAULTSA pDefault)
1599 UNICODE_STRING lpPrinterNameW;
1600 UNICODE_STRING usBuffer;
1601 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1602 PWSTR pwstrPrinterNameW;
1603 BOOL ret;
1605 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1607 if(pDefault) {
1608 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1609 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1610 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1611 pDefaultW = &DefaultW;
1613 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1614 if(pDefault) {
1615 RtlFreeUnicodeString(&usBuffer);
1616 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1618 RtlFreeUnicodeString(&lpPrinterNameW);
1619 return ret;
1622 /******************************************************************
1623 * OpenPrinterW [WINSPOOL.@]
1625 * Open a Printer / Printserver or a Printer-Object
1627 * PARAMS
1628 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1629 * phPrinter [O] The resulting Handle is stored here
1630 * pDefault [I] PTR to Default Printer Settings or NULL
1632 * RETURNS
1633 * Success: TRUE
1634 * Failure: FALSE
1636 * NOTES
1637 * lpPrinterName is one of:
1638 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1639 *| Printer: "PrinterName"
1640 *| Printer-Object: "PrinterName,Job xxx"
1641 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1642 *| XcvPort: "Servername,XcvPort PortName"
1644 * BUGS
1645 *| Printer-Object not supported
1646 *| pDefaults is ignored
1649 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1652 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1653 if (pDefault) {
1654 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1655 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1658 if(!phPrinter) {
1659 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1660 SetLastError(ERROR_INVALID_PARAMETER);
1661 return FALSE;
1664 /* Get the unique handle of the printer or Printserver */
1665 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1666 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1667 return (*phPrinter != 0);
1670 /******************************************************************
1671 * AddMonitorA [WINSPOOL.@]
1673 * See AddMonitorW.
1676 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1678 LPWSTR nameW = NULL;
1679 INT len;
1680 BOOL res;
1681 LPMONITOR_INFO_2A mi2a;
1682 MONITOR_INFO_2W mi2w;
1684 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1685 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1686 debugstr_a(mi2a ? mi2a->pName : NULL),
1687 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1688 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1690 if (Level != 2) {
1691 SetLastError(ERROR_INVALID_LEVEL);
1692 return FALSE;
1695 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1696 if (mi2a == NULL) {
1697 return FALSE;
1700 if (pName) {
1701 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1702 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1703 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1706 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1707 if (mi2a->pName) {
1708 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1709 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1710 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1712 if (mi2a->pEnvironment) {
1713 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1714 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1715 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1717 if (mi2a->pDLLName) {
1718 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1719 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1720 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1723 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1725 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1726 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1727 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1729 HeapFree(GetProcessHeap(), 0, nameW);
1730 return (res);
1733 /******************************************************************************
1734 * AddMonitorW [WINSPOOL.@]
1736 * Install a Printmonitor
1738 * PARAMS
1739 * pName [I] Servername or NULL (local Computer)
1740 * Level [I] Structure-Level (Must be 2)
1741 * pMonitors [I] PTR to MONITOR_INFO_2
1743 * RETURNS
1744 * Success: TRUE
1745 * Failure: FALSE
1747 * NOTES
1748 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1751 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1753 LPMONITOR_INFO_2W mi2w;
1755 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1756 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1757 debugstr_w(mi2w ? mi2w->pName : NULL),
1758 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1759 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1761 if ((backend == NULL) && !load_backend()) return FALSE;
1763 if (Level != 2) {
1764 SetLastError(ERROR_INVALID_LEVEL);
1765 return FALSE;
1768 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1769 if (mi2w == NULL) {
1770 return FALSE;
1773 return backend->fpAddMonitor(pName, Level, pMonitors);
1776 /******************************************************************
1777 * DeletePrinterDriverA [WINSPOOL.@]
1780 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1782 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1785 /******************************************************************
1786 * DeletePrinterDriverW [WINSPOOL.@]
1789 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1791 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
1794 /******************************************************************
1795 * DeleteMonitorA [WINSPOOL.@]
1797 * See DeleteMonitorW.
1800 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1802 LPWSTR nameW = NULL;
1803 LPWSTR EnvironmentW = NULL;
1804 LPWSTR MonitorNameW = NULL;
1805 BOOL res;
1806 INT len;
1808 if (pName) {
1809 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1810 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1811 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1814 if (pEnvironment) {
1815 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1816 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1817 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1819 if (pMonitorName) {
1820 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1821 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1822 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1825 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1827 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1828 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1829 HeapFree(GetProcessHeap(), 0, nameW);
1830 return (res);
1833 /******************************************************************
1834 * DeleteMonitorW [WINSPOOL.@]
1836 * Delete a specific Printmonitor from a Printing-Environment
1838 * PARAMS
1839 * pName [I] Servername or NULL (local Computer)
1840 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1841 * pMonitorName [I] Name of the Monitor, that should be deleted
1843 * RETURNS
1844 * Success: TRUE
1845 * Failure: FALSE
1847 * NOTES
1848 * pEnvironment is ignored in Windows for the local Computer.
1851 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1854 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1855 debugstr_w(pMonitorName));
1857 if ((backend == NULL) && !load_backend()) return FALSE;
1859 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
1863 /******************************************************************
1864 * DeletePortA [WINSPOOL.@]
1866 * See DeletePortW.
1869 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1871 LPWSTR nameW = NULL;
1872 LPWSTR portW = NULL;
1873 INT len;
1874 DWORD res;
1876 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
1878 /* convert servername to unicode */
1879 if (pName) {
1880 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1881 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1882 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1885 /* convert portname to unicode */
1886 if (pPortName) {
1887 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
1888 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1889 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
1892 res = DeletePortW(nameW, hWnd, portW);
1893 HeapFree(GetProcessHeap(), 0, nameW);
1894 HeapFree(GetProcessHeap(), 0, portW);
1895 return res;
1898 /******************************************************************
1899 * DeletePortW [WINSPOOL.@]
1901 * Delete a specific Port
1903 * PARAMS
1904 * pName [I] Servername or NULL (local Computer)
1905 * hWnd [I] Handle to parent Window for the Dialog-Box
1906 * pPortName [I] Name of the Port, that should be deleted
1908 * RETURNS
1909 * Success: TRUE
1910 * Failure: FALSE
1913 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1915 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1917 if ((backend == NULL) && !load_backend()) return FALSE;
1919 if (!pPortName) {
1920 SetLastError(RPC_X_NULL_REF_POINTER);
1921 return FALSE;
1924 return backend->fpDeletePort(pName, hWnd, pPortName);
1927 /******************************************************************************
1928 * SetPrinterW [WINSPOOL.@]
1930 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1932 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
1933 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1934 return FALSE;
1937 /******************************************************************************
1938 * WritePrinter [WINSPOOL.@]
1940 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1942 opened_printer_t *printer;
1943 BOOL ret = FALSE;
1945 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1947 EnterCriticalSection(&printer_handles_cs);
1948 printer = get_opened_printer(hPrinter);
1949 if(!printer)
1951 SetLastError(ERROR_INVALID_HANDLE);
1952 goto end;
1955 if(!printer->doc)
1957 SetLastError(ERROR_SPL_NO_STARTDOC);
1958 goto end;
1961 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1962 end:
1963 LeaveCriticalSection(&printer_handles_cs);
1964 return ret;
1967 /*****************************************************************************
1968 * AddFormA [WINSPOOL.@]
1970 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1972 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1973 return 1;
1976 /*****************************************************************************
1977 * AddFormW [WINSPOOL.@]
1979 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1981 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1982 return 1;
1985 /*****************************************************************************
1986 * AddJobA [WINSPOOL.@]
1988 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1990 BOOL ret;
1991 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1992 DWORD needed;
1994 if(Level != 1) {
1995 SetLastError(ERROR_INVALID_LEVEL);
1996 return FALSE;
1999 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2001 if(ret) {
2002 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2003 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2004 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2005 if(*pcbNeeded > cbBuf) {
2006 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2007 ret = FALSE;
2008 } else {
2009 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2010 addjobA->JobId = addjobW->JobId;
2011 addjobA->Path = (char *)(addjobA + 1);
2012 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2015 return ret;
2018 /*****************************************************************************
2019 * AddJobW [WINSPOOL.@]
2021 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2023 opened_printer_t *printer;
2024 job_t *job;
2025 BOOL ret = FALSE;
2026 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2027 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2028 WCHAR path[MAX_PATH], filename[MAX_PATH];
2029 DWORD len;
2030 ADDJOB_INFO_1W *addjob;
2032 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2034 EnterCriticalSection(&printer_handles_cs);
2036 printer = get_opened_printer(hPrinter);
2038 if(!printer) {
2039 SetLastError(ERROR_INVALID_HANDLE);
2040 goto end;
2043 if(Level != 1) {
2044 SetLastError(ERROR_INVALID_LEVEL);
2045 goto end;
2048 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2049 if(!job)
2050 goto end;
2052 job->job_id = InterlockedIncrement(&next_job_id);
2054 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2055 if(path[len - 1] != '\\')
2056 path[len++] = '\\';
2057 memcpy(path + len, spool_path, sizeof(spool_path));
2058 sprintfW(filename, fmtW, path, job->job_id);
2060 len = strlenW(filename);
2061 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2062 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2063 job->document_title = strdupW(default_doc_title);
2064 list_add_tail(&printer->queue->jobs, &job->entry);
2066 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2067 if(*pcbNeeded <= cbBuf) {
2068 addjob = (ADDJOB_INFO_1W*)pData;
2069 addjob->JobId = job->job_id;
2070 addjob->Path = (WCHAR *)(addjob + 1);
2071 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2072 ret = TRUE;
2073 } else
2074 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2076 end:
2077 LeaveCriticalSection(&printer_handles_cs);
2078 return ret;
2081 /*****************************************************************************
2082 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2084 * Return the PATH for the Print-Processors
2086 * See GetPrintProcessorDirectoryW.
2090 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2091 DWORD level, LPBYTE Info,
2092 DWORD cbBuf, LPDWORD pcbNeeded)
2094 LPWSTR serverW = NULL;
2095 LPWSTR envW = NULL;
2096 BOOL ret;
2097 INT len;
2099 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2100 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2103 if (server) {
2104 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2105 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2106 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2109 if (env) {
2110 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2111 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2112 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2115 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2116 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2118 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2119 cbBuf, pcbNeeded);
2121 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2122 cbBuf, NULL, NULL) > 0;
2125 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2126 HeapFree(GetProcessHeap(), 0, envW);
2127 HeapFree(GetProcessHeap(), 0, serverW);
2128 return ret;
2131 /*****************************************************************************
2132 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2134 * Return the PATH for the Print-Processors
2136 * PARAMS
2137 * server [I] Servername (NT only) or NULL (local Computer)
2138 * env [I] Printing-Environment (see below) or NULL (Default)
2139 * level [I] Structure-Level (must be 1)
2140 * Info [O] PTR to Buffer that receives the Result
2141 * cbBuf [I] Size of Buffer at "Info"
2142 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2143 * required for the Buffer at "Info"
2145 * RETURNS
2146 * Success: TRUE and in pcbNeeded the Bytes used in Info
2147 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2148 * if cbBuf is too small
2150 * Native Values returned in Info on Success:
2151 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2152 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2153 *| win9x(Windows 4.0): "%winsysdir%"
2155 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2157 * BUGS
2158 * Only NULL or "" is supported for server
2161 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2162 DWORD level, LPBYTE Info,
2163 DWORD cbBuf, LPDWORD pcbNeeded)
2165 DWORD needed;
2166 const printenv_t * env_t;
2168 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2169 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2171 if(server != NULL && server[0]) {
2172 FIXME("server not supported: %s\n", debugstr_w(server));
2173 SetLastError(ERROR_INVALID_PARAMETER);
2174 return FALSE;
2177 env_t = validate_envW(env);
2178 if(!env_t) return FALSE; /* environment invalid or unsupported */
2180 if(level != 1) {
2181 WARN("(Level: %d) is ignored in win9x\n", level);
2182 SetLastError(ERROR_INVALID_LEVEL);
2183 return FALSE;
2186 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2187 needed = GetSystemDirectoryW(NULL, 0);
2188 /* add the Size for the Subdirectories */
2189 needed += lstrlenW(spoolprtprocsW);
2190 needed += lstrlenW(env_t->subdir);
2191 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2193 if(pcbNeeded) *pcbNeeded = needed;
2194 TRACE ("required: 0x%x/%d\n", needed, needed);
2195 if (needed > cbBuf) {
2196 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2197 return FALSE;
2199 if(pcbNeeded == NULL) {
2200 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2201 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2202 SetLastError(RPC_X_NULL_REF_POINTER);
2203 return FALSE;
2205 if(Info == NULL) {
2206 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2207 SetLastError(RPC_X_NULL_REF_POINTER);
2208 return FALSE;
2211 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2212 /* add the Subdirectories */
2213 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2214 lstrcatW((LPWSTR) Info, env_t->subdir);
2215 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2216 return TRUE;
2219 /*****************************************************************************
2220 * WINSPOOL_OpenDriverReg [internal]
2222 * opens the registry for the printer drivers depending on the given input
2223 * variable pEnvironment
2225 * RETURNS:
2226 * the opened hkey on success
2227 * NULL on error
2229 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2231 HKEY retval = NULL;
2232 LPWSTR buffer;
2233 const printenv_t * env;
2235 TRACE("(%s, %d)\n",
2236 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2238 if (!pEnvironment || unicode) {
2239 /* pEnvironment was NULL or a Unicode-String: use it direct */
2240 env = validate_envW(pEnvironment);
2242 else
2244 /* pEnvironment was an ANSI-String: convert to unicode first */
2245 LPWSTR buffer;
2246 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2247 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2248 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2249 env = validate_envW(buffer);
2250 HeapFree(GetProcessHeap(), 0, buffer);
2252 if (!env) return NULL;
2254 buffer = HeapAlloc( GetProcessHeap(), 0,
2255 (strlenW(DriversW) + strlenW(env->envname) +
2256 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2257 if(buffer) {
2258 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2259 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2260 HeapFree(GetProcessHeap(), 0, buffer);
2262 return retval;
2265 /*****************************************************************************
2266 * AddPrinterW [WINSPOOL.@]
2268 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2270 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2271 LPDEVMODEA dmA;
2272 LPDEVMODEW dmW;
2273 HANDLE retval;
2274 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2275 LONG size;
2276 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2277 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2278 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2279 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2280 statusW[] = {'S','t','a','t','u','s',0},
2281 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2283 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2285 if(pName != NULL) {
2286 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2287 SetLastError(ERROR_INVALID_PARAMETER);
2288 return 0;
2290 if(Level != 2) {
2291 ERR("Level = %d, unsupported!\n", Level);
2292 SetLastError(ERROR_INVALID_LEVEL);
2293 return 0;
2295 if(!pPrinter) {
2296 SetLastError(ERROR_INVALID_PARAMETER);
2297 return 0;
2299 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2300 ERROR_SUCCESS) {
2301 ERR("Can't create Printers key\n");
2302 return 0;
2304 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2305 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2306 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2307 RegCloseKey(hkeyPrinter);
2308 RegCloseKey(hkeyPrinters);
2309 return 0;
2311 RegCloseKey(hkeyPrinter);
2313 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2314 if(!hkeyDrivers) {
2315 ERR("Can't create Drivers key\n");
2316 RegCloseKey(hkeyPrinters);
2317 return 0;
2319 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2320 ERROR_SUCCESS) {
2321 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2322 RegCloseKey(hkeyPrinters);
2323 RegCloseKey(hkeyDrivers);
2324 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2325 return 0;
2327 RegCloseKey(hkeyDriver);
2328 RegCloseKey(hkeyDrivers);
2330 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2331 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2332 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2333 RegCloseKey(hkeyPrinters);
2334 return 0;
2337 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2338 ERROR_SUCCESS) {
2339 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2340 SetLastError(ERROR_INVALID_PRINTER_NAME);
2341 RegCloseKey(hkeyPrinters);
2342 return 0;
2344 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2345 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2346 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2348 /* See if we can load the driver. We may need the devmode structure anyway
2350 * FIXME:
2351 * Note that DocumentPropertiesW will briefly try to open the printer we
2352 * just create to find a DEVMODEA struct (it will use the WINEPS default
2353 * one in case it is not there, so we are ok).
2355 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2357 if(size < 0) {
2358 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2359 size = sizeof(DEVMODEW);
2361 if(pi->pDevMode)
2362 dmW = pi->pDevMode;
2363 else
2365 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2366 dmW->dmSize = size;
2367 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2369 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2370 HeapFree(GetProcessHeap(),0,dmW);
2371 dmW=NULL;
2373 else
2375 /* set devmode to printer name */
2376 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2380 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2381 and we support these drivers. NT writes DEVMODEW so somehow
2382 we'll need to distinguish between these when we support NT
2383 drivers */
2384 if (dmW)
2386 dmA = DEVMODEdupWtoA(dmW);
2387 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2388 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2389 HeapFree(GetProcessHeap(), 0, dmA);
2390 if(!pi->pDevMode)
2391 HeapFree(GetProcessHeap(), 0, dmW);
2393 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2394 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2395 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2396 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2398 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2399 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2400 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2401 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2402 (LPBYTE)&pi->Priority, sizeof(DWORD));
2403 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2404 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2405 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2406 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2407 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2408 (LPBYTE)&pi->Status, sizeof(DWORD));
2409 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2410 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2412 RegCloseKey(hkeyPrinter);
2413 RegCloseKey(hkeyPrinters);
2414 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2415 ERR("OpenPrinter failing\n");
2416 return 0;
2418 return retval;
2421 /*****************************************************************************
2422 * AddPrinterA [WINSPOOL.@]
2424 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2426 UNICODE_STRING pNameW;
2427 PWSTR pwstrNameW;
2428 PRINTER_INFO_2W *piW;
2429 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2430 HANDLE ret;
2432 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2433 if(Level != 2) {
2434 ERR("Level = %d, unsupported!\n", Level);
2435 SetLastError(ERROR_INVALID_LEVEL);
2436 return 0;
2438 pwstrNameW = asciitounicode(&pNameW,pName);
2439 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2441 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2443 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2444 RtlFreeUnicodeString(&pNameW);
2445 return ret;
2449 /*****************************************************************************
2450 * ClosePrinter [WINSPOOL.@]
2452 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2454 UINT_PTR i = (UINT_PTR)hPrinter;
2455 opened_printer_t *printer = NULL;
2456 BOOL ret = FALSE;
2458 TRACE("(%p)\n", hPrinter);
2460 EnterCriticalSection(&printer_handles_cs);
2462 if ((i > 0) && (i <= nb_printer_handles))
2463 printer = printer_handles[i - 1];
2466 if(printer)
2468 struct list *cursor, *cursor2;
2470 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2472 if (printer->backend_printer) {
2473 backend->fpClosePrinter(printer->backend_printer);
2476 if(printer->doc)
2477 EndDocPrinter(hPrinter);
2479 if(InterlockedDecrement(&printer->queue->ref) == 0)
2481 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2483 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2484 ScheduleJob(hPrinter, job->job_id);
2486 HeapFree(GetProcessHeap(), 0, printer->queue);
2489 HeapFree(GetProcessHeap(), 0, printer->printername);
2490 HeapFree(GetProcessHeap(), 0, printer->name);
2491 HeapFree(GetProcessHeap(), 0, printer);
2492 printer_handles[i - 1] = NULL;
2493 ret = TRUE;
2495 LeaveCriticalSection(&printer_handles_cs);
2496 return ret;
2499 /*****************************************************************************
2500 * DeleteFormA [WINSPOOL.@]
2502 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2504 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2505 return 1;
2508 /*****************************************************************************
2509 * DeleteFormW [WINSPOOL.@]
2511 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2513 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2514 return 1;
2517 /*****************************************************************************
2518 * DeletePrinter [WINSPOOL.@]
2520 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2522 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2523 HKEY hkeyPrinters, hkey;
2525 if(!lpNameW) {
2526 SetLastError(ERROR_INVALID_HANDLE);
2527 return FALSE;
2529 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2530 RegDeleteTreeW(hkeyPrinters, lpNameW);
2531 RegCloseKey(hkeyPrinters);
2533 WriteProfileStringW(devicesW, lpNameW, NULL);
2534 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2536 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2537 RegDeleteValueW(hkey, lpNameW);
2538 RegCloseKey(hkey);
2541 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2542 RegDeleteValueW(hkey, lpNameW);
2543 RegCloseKey(hkey);
2545 return TRUE;
2548 /*****************************************************************************
2549 * SetPrinterA [WINSPOOL.@]
2551 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2552 DWORD Command)
2554 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2555 return FALSE;
2558 /*****************************************************************************
2559 * SetJobA [WINSPOOL.@]
2561 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2562 LPBYTE pJob, DWORD Command)
2564 BOOL ret;
2565 LPBYTE JobW;
2566 UNICODE_STRING usBuffer;
2568 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2570 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2571 are all ignored by SetJob, so we don't bother copying them */
2572 switch(Level)
2574 case 0:
2575 JobW = NULL;
2576 break;
2577 case 1:
2579 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2580 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2582 JobW = (LPBYTE)info1W;
2583 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2584 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2585 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2586 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2587 info1W->Status = info1A->Status;
2588 info1W->Priority = info1A->Priority;
2589 info1W->Position = info1A->Position;
2590 info1W->PagesPrinted = info1A->PagesPrinted;
2591 break;
2593 case 2:
2595 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2596 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2598 JobW = (LPBYTE)info2W;
2599 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2600 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2601 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2602 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2603 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2604 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2605 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2606 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2607 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2608 info2W->Status = info2A->Status;
2609 info2W->Priority = info2A->Priority;
2610 info2W->Position = info2A->Position;
2611 info2W->StartTime = info2A->StartTime;
2612 info2W->UntilTime = info2A->UntilTime;
2613 info2W->PagesPrinted = info2A->PagesPrinted;
2614 break;
2616 case 3:
2617 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2618 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2619 break;
2620 default:
2621 SetLastError(ERROR_INVALID_LEVEL);
2622 return FALSE;
2625 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2627 switch(Level)
2629 case 1:
2631 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2632 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2633 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2634 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2635 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2636 break;
2638 case 2:
2640 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2641 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2642 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2643 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2644 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2645 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2646 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2647 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2648 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2649 break;
2652 HeapFree(GetProcessHeap(), 0, JobW);
2654 return ret;
2657 /*****************************************************************************
2658 * SetJobW [WINSPOOL.@]
2660 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2661 LPBYTE pJob, DWORD Command)
2663 BOOL ret = FALSE;
2664 job_t *job;
2666 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2667 FIXME("Ignoring everything other than document title\n");
2669 EnterCriticalSection(&printer_handles_cs);
2670 job = get_job(hPrinter, JobId);
2671 if(!job)
2672 goto end;
2674 switch(Level)
2676 case 0:
2677 break;
2678 case 1:
2680 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2681 HeapFree(GetProcessHeap(), 0, job->document_title);
2682 job->document_title = strdupW(info1->pDocument);
2683 break;
2685 case 2:
2687 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2688 HeapFree(GetProcessHeap(), 0, job->document_title);
2689 job->document_title = strdupW(info2->pDocument);
2690 break;
2692 case 3:
2693 break;
2694 default:
2695 SetLastError(ERROR_INVALID_LEVEL);
2696 goto end;
2698 ret = TRUE;
2699 end:
2700 LeaveCriticalSection(&printer_handles_cs);
2701 return ret;
2704 /*****************************************************************************
2705 * EndDocPrinter [WINSPOOL.@]
2707 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2709 opened_printer_t *printer;
2710 BOOL ret = FALSE;
2711 TRACE("(%p)\n", hPrinter);
2713 EnterCriticalSection(&printer_handles_cs);
2715 printer = get_opened_printer(hPrinter);
2716 if(!printer)
2718 SetLastError(ERROR_INVALID_HANDLE);
2719 goto end;
2722 if(!printer->doc)
2724 SetLastError(ERROR_SPL_NO_STARTDOC);
2725 goto end;
2728 CloseHandle(printer->doc->hf);
2729 ScheduleJob(hPrinter, printer->doc->job_id);
2730 HeapFree(GetProcessHeap(), 0, printer->doc);
2731 printer->doc = NULL;
2732 ret = TRUE;
2733 end:
2734 LeaveCriticalSection(&printer_handles_cs);
2735 return ret;
2738 /*****************************************************************************
2739 * EndPagePrinter [WINSPOOL.@]
2741 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2743 FIXME("(%p): stub\n", hPrinter);
2744 return TRUE;
2747 /*****************************************************************************
2748 * StartDocPrinterA [WINSPOOL.@]
2750 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2752 UNICODE_STRING usBuffer;
2753 DOC_INFO_2W doc2W;
2754 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2755 DWORD ret;
2757 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2758 or one (DOC_INFO_3) extra DWORDs */
2760 switch(Level) {
2761 case 2:
2762 doc2W.JobId = doc2->JobId;
2763 /* fall through */
2764 case 3:
2765 doc2W.dwMode = doc2->dwMode;
2766 /* fall through */
2767 case 1:
2768 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2769 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2770 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2771 break;
2773 default:
2774 SetLastError(ERROR_INVALID_LEVEL);
2775 return FALSE;
2778 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2780 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2781 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2782 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2784 return ret;
2787 /*****************************************************************************
2788 * StartDocPrinterW [WINSPOOL.@]
2790 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2792 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2793 opened_printer_t *printer;
2794 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2795 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2796 JOB_INFO_1W job_info;
2797 DWORD needed, ret = 0;
2798 HANDLE hf;
2799 WCHAR *filename;
2801 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2802 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2803 debugstr_w(doc->pDatatype));
2805 if(Level < 1 || Level > 3)
2807 SetLastError(ERROR_INVALID_LEVEL);
2808 return 0;
2811 EnterCriticalSection(&printer_handles_cs);
2812 printer = get_opened_printer(hPrinter);
2813 if(!printer)
2815 SetLastError(ERROR_INVALID_HANDLE);
2816 goto end;
2819 if(printer->doc)
2821 SetLastError(ERROR_INVALID_PRINTER_STATE);
2822 goto end;
2825 /* Even if we're printing to a file we still add a print job, we'll
2826 just ignore the spool file name */
2828 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2830 ERR("AddJob failed gle %u\n", GetLastError());
2831 goto end;
2834 if(doc->pOutputFile)
2835 filename = doc->pOutputFile;
2836 else
2837 filename = addjob->Path;
2839 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2840 if(hf == INVALID_HANDLE_VALUE)
2841 goto end;
2843 memset(&job_info, 0, sizeof(job_info));
2844 job_info.pDocument = doc->pDocName;
2845 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2847 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2848 printer->doc->hf = hf;
2849 ret = printer->doc->job_id = addjob->JobId;
2850 end:
2851 LeaveCriticalSection(&printer_handles_cs);
2853 return ret;
2856 /*****************************************************************************
2857 * StartPagePrinter [WINSPOOL.@]
2859 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2861 FIXME("(%p): stub\n", hPrinter);
2862 return TRUE;
2865 /*****************************************************************************
2866 * GetFormA [WINSPOOL.@]
2868 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2869 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2871 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
2872 Level,pForm,cbBuf,pcbNeeded);
2873 return FALSE;
2876 /*****************************************************************************
2877 * GetFormW [WINSPOOL.@]
2879 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2880 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2882 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
2883 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2884 return FALSE;
2887 /*****************************************************************************
2888 * SetFormA [WINSPOOL.@]
2890 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2891 LPBYTE pForm)
2893 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2894 return FALSE;
2897 /*****************************************************************************
2898 * SetFormW [WINSPOOL.@]
2900 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2901 LPBYTE pForm)
2903 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2904 return FALSE;
2907 /*****************************************************************************
2908 * ReadPrinter [WINSPOOL.@]
2910 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2911 LPDWORD pNoBytesRead)
2913 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2914 return FALSE;
2917 /*****************************************************************************
2918 * ResetPrinterA [WINSPOOL.@]
2920 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2922 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2923 return FALSE;
2926 /*****************************************************************************
2927 * ResetPrinterW [WINSPOOL.@]
2929 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2931 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2932 return FALSE;
2935 /*****************************************************************************
2936 * WINSPOOL_GetDWORDFromReg
2938 * Return DWORD associated with ValueName from hkey.
2940 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2942 DWORD sz = sizeof(DWORD), type, value = 0;
2943 LONG ret;
2945 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2947 if(ret != ERROR_SUCCESS) {
2948 WARN("Got ret = %d on name %s\n", ret, ValueName);
2949 return 0;
2951 if(type != REG_DWORD) {
2952 ERR("Got type %d\n", type);
2953 return 0;
2955 return value;
2959 /*****************************************************************************
2960 * get_filename_from_reg [internal]
2962 * Get ValueName from hkey storing result in out
2963 * when the Value in the registry has only a filename, use driverdir as prefix
2964 * outlen is space left in out
2965 * String is stored either as unicode or ascii
2969 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
2970 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
2972 WCHAR filename[MAX_PATH];
2973 DWORD size;
2974 DWORD type;
2975 LONG ret;
2976 LPWSTR buffer = filename;
2977 LPWSTR ptr;
2979 *needed = 0;
2980 size = sizeof(filename);
2981 buffer[0] = '\0';
2982 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
2983 if (ret == ERROR_MORE_DATA) {
2984 TRACE("need dynamic buffer: %u\n", size);
2985 buffer = HeapAlloc(GetProcessHeap(), 0, size);
2986 if (!buffer) {
2987 /* No Memory is bad */
2988 return FALSE;
2990 buffer[0] = '\0';
2991 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
2994 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
2995 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
2996 return FALSE;
2999 ptr = buffer;
3000 while (ptr) {
3001 /* do we have a full path ? */
3002 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3003 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3005 if (!ret) {
3006 /* we must build the full Path */
3007 *needed += dirlen;
3008 if ((out) && (outlen > dirlen)) {
3009 if (unicode) {
3010 lstrcpyW((LPWSTR)out, driverdir);
3012 else
3014 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3016 out += dirlen;
3017 outlen -= dirlen;
3019 else
3020 out = NULL;
3023 /* write the filename */
3024 if (unicode) {
3025 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3026 if ((out) && (outlen >= size)) {
3027 lstrcpyW((LPWSTR)out, ptr);
3028 out += size;
3029 outlen -= size;
3031 else
3032 out = NULL;
3034 else
3036 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3037 if ((out) && (outlen >= size)) {
3038 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3039 out += size;
3040 outlen -= size;
3042 else
3043 out = NULL;
3045 *needed += size;
3046 ptr += lstrlenW(ptr)+1;
3047 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3050 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3052 /* write the multisz-termination */
3053 if (type == REG_MULTI_SZ) {
3054 size = (unicode) ? sizeof(WCHAR) : 1;
3056 *needed += size;
3057 if (out && (outlen >= size)) {
3058 memset (out, 0, size);
3061 return TRUE;
3064 /*****************************************************************************
3065 * WINSPOOL_GetStringFromReg
3067 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3068 * String is stored either as unicode or ascii.
3069 * Bit of a hack here to get the ValueName if we want ascii.
3071 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3072 DWORD buflen, DWORD *needed,
3073 BOOL unicode)
3075 DWORD sz = buflen, type;
3076 LONG ret;
3078 if(unicode)
3079 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3080 else {
3081 LPSTR ValueNameA = strdupWtoA(ValueName);
3082 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3083 HeapFree(GetProcessHeap(),0,ValueNameA);
3085 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3086 WARN("Got ret = %d\n", ret);
3087 *needed = 0;
3088 return FALSE;
3090 /* add space for terminating '\0' */
3091 sz += unicode ? sizeof(WCHAR) : 1;
3092 *needed = sz;
3094 if (ptr)
3095 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3097 return TRUE;
3100 /*****************************************************************************
3101 * WINSPOOL_GetDefaultDevMode
3103 * Get a default DevMode values for wineps.
3104 * FIXME - use ppd.
3107 static void WINSPOOL_GetDefaultDevMode(
3108 LPBYTE ptr,
3109 DWORD buflen, DWORD *needed,
3110 BOOL unicode)
3112 DEVMODEA dm;
3113 static const char szwps[] = "wineps.drv";
3115 /* fill default DEVMODE - should be read from ppd... */
3116 ZeroMemory( &dm, sizeof(dm) );
3117 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3118 dm.dmSpecVersion = DM_SPECVERSION;
3119 dm.dmDriverVersion = 1;
3120 dm.dmSize = sizeof(DEVMODEA);
3121 dm.dmDriverExtra = 0;
3122 dm.dmFields =
3123 DM_ORIENTATION | DM_PAPERSIZE |
3124 DM_PAPERLENGTH | DM_PAPERWIDTH |
3125 DM_SCALE |
3126 DM_COPIES |
3127 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3128 DM_YRESOLUTION | DM_TTOPTION;
3130 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3131 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3132 dm.u1.s1.dmPaperLength = 2970;
3133 dm.u1.s1.dmPaperWidth = 2100;
3135 dm.u1.s1.dmScale = 100;
3136 dm.u1.s1.dmCopies = 1;
3137 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3138 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3139 /* dm.dmColor */
3140 /* dm.dmDuplex */
3141 dm.dmYResolution = 300; /* 300dpi */
3142 dm.dmTTOption = DMTT_BITMAP;
3143 /* dm.dmCollate */
3144 /* dm.dmFormName */
3145 /* dm.dmLogPixels */
3146 /* dm.dmBitsPerPel */
3147 /* dm.dmPelsWidth */
3148 /* dm.dmPelsHeight */
3149 /* dm.u2.dmDisplayFlags */
3150 /* dm.dmDisplayFrequency */
3151 /* dm.dmICMMethod */
3152 /* dm.dmICMIntent */
3153 /* dm.dmMediaType */
3154 /* dm.dmDitherType */
3155 /* dm.dmReserved1 */
3156 /* dm.dmReserved2 */
3157 /* dm.dmPanningWidth */
3158 /* dm.dmPanningHeight */
3160 if(unicode) {
3161 if(buflen >= sizeof(DEVMODEW)) {
3162 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3163 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3164 HeapFree(GetProcessHeap(),0,pdmW);
3166 *needed = sizeof(DEVMODEW);
3168 else
3170 if(buflen >= sizeof(DEVMODEA)) {
3171 memcpy(ptr, &dm, sizeof(DEVMODEA));
3173 *needed = sizeof(DEVMODEA);
3177 /*****************************************************************************
3178 * WINSPOOL_GetDevModeFromReg
3180 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3181 * DevMode is stored either as unicode or ascii.
3183 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3184 LPBYTE ptr,
3185 DWORD buflen, DWORD *needed,
3186 BOOL unicode)
3188 DWORD sz = buflen, type;
3189 LONG ret;
3191 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3192 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3193 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3194 if (sz < sizeof(DEVMODEA))
3196 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3197 return FALSE;
3199 /* ensures that dmSize is not erratically bogus if registry is invalid */
3200 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3201 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3202 if(unicode) {
3203 sz += (CCHDEVICENAME + CCHFORMNAME);
3204 if(buflen >= sz) {
3205 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3206 memcpy(ptr, dmW, sz);
3207 HeapFree(GetProcessHeap(),0,dmW);
3210 *needed = sz;
3211 return TRUE;
3214 /*********************************************************************
3215 * WINSPOOL_GetPrinter_1
3217 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3218 * The strings are either stored as unicode or ascii.
3220 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3221 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3222 BOOL unicode)
3224 DWORD size, left = cbBuf;
3225 BOOL space = (cbBuf > 0);
3226 LPBYTE ptr = buf;
3228 *pcbNeeded = 0;
3230 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3231 unicode)) {
3232 if(space && size <= left) {
3233 pi1->pName = (LPWSTR)ptr;
3234 ptr += size;
3235 left -= size;
3236 } else
3237 space = FALSE;
3238 *pcbNeeded += size;
3241 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3242 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3243 unicode)) {
3244 if(space && size <= left) {
3245 pi1->pDescription = (LPWSTR)ptr;
3246 ptr += size;
3247 left -= size;
3248 } else
3249 space = FALSE;
3250 *pcbNeeded += size;
3253 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3254 unicode)) {
3255 if(space && size <= left) {
3256 pi1->pComment = (LPWSTR)ptr;
3257 ptr += size;
3258 left -= size;
3259 } else
3260 space = FALSE;
3261 *pcbNeeded += size;
3264 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3266 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3267 memset(pi1, 0, sizeof(*pi1));
3269 return space;
3271 /*********************************************************************
3272 * WINSPOOL_GetPrinter_2
3274 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3275 * The strings are either stored as unicode or ascii.
3277 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3278 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3279 BOOL unicode)
3281 DWORD size, left = cbBuf;
3282 BOOL space = (cbBuf > 0);
3283 LPBYTE ptr = buf;
3285 *pcbNeeded = 0;
3287 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3288 unicode)) {
3289 if(space && size <= left) {
3290 pi2->pPrinterName = (LPWSTR)ptr;
3291 ptr += size;
3292 left -= size;
3293 } else
3294 space = FALSE;
3295 *pcbNeeded += size;
3297 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3298 unicode)) {
3299 if(space && size <= left) {
3300 pi2->pShareName = (LPWSTR)ptr;
3301 ptr += size;
3302 left -= size;
3303 } else
3304 space = FALSE;
3305 *pcbNeeded += size;
3307 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3308 unicode)) {
3309 if(space && size <= left) {
3310 pi2->pPortName = (LPWSTR)ptr;
3311 ptr += size;
3312 left -= size;
3313 } else
3314 space = FALSE;
3315 *pcbNeeded += size;
3317 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3318 &size, unicode)) {
3319 if(space && size <= left) {
3320 pi2->pDriverName = (LPWSTR)ptr;
3321 ptr += size;
3322 left -= size;
3323 } else
3324 space = FALSE;
3325 *pcbNeeded += size;
3327 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3328 unicode)) {
3329 if(space && size <= left) {
3330 pi2->pComment = (LPWSTR)ptr;
3331 ptr += size;
3332 left -= size;
3333 } else
3334 space = FALSE;
3335 *pcbNeeded += size;
3337 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3338 unicode)) {
3339 if(space && size <= left) {
3340 pi2->pLocation = (LPWSTR)ptr;
3341 ptr += size;
3342 left -= size;
3343 } else
3344 space = FALSE;
3345 *pcbNeeded += size;
3347 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3348 &size, unicode)) {
3349 if(space && size <= left) {
3350 pi2->pDevMode = (LPDEVMODEW)ptr;
3351 ptr += size;
3352 left -= size;
3353 } else
3354 space = FALSE;
3355 *pcbNeeded += size;
3357 else
3359 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3360 if(space && size <= left) {
3361 pi2->pDevMode = (LPDEVMODEW)ptr;
3362 ptr += size;
3363 left -= size;
3364 } else
3365 space = FALSE;
3366 *pcbNeeded += size;
3368 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3369 &size, unicode)) {
3370 if(space && size <= left) {
3371 pi2->pSepFile = (LPWSTR)ptr;
3372 ptr += size;
3373 left -= size;
3374 } else
3375 space = FALSE;
3376 *pcbNeeded += size;
3378 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3379 &size, unicode)) {
3380 if(space && size <= left) {
3381 pi2->pPrintProcessor = (LPWSTR)ptr;
3382 ptr += size;
3383 left -= size;
3384 } else
3385 space = FALSE;
3386 *pcbNeeded += size;
3388 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3389 &size, unicode)) {
3390 if(space && size <= left) {
3391 pi2->pDatatype = (LPWSTR)ptr;
3392 ptr += size;
3393 left -= size;
3394 } else
3395 space = FALSE;
3396 *pcbNeeded += size;
3398 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3399 &size, unicode)) {
3400 if(space && size <= left) {
3401 pi2->pParameters = (LPWSTR)ptr;
3402 ptr += size;
3403 left -= size;
3404 } else
3405 space = FALSE;
3406 *pcbNeeded += size;
3408 if(pi2) {
3409 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3410 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3411 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3412 "Default Priority");
3413 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3414 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3417 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3418 memset(pi2, 0, sizeof(*pi2));
3420 return space;
3423 /*********************************************************************
3424 * WINSPOOL_GetPrinter_4
3426 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3428 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3429 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3430 BOOL unicode)
3432 DWORD size, left = cbBuf;
3433 BOOL space = (cbBuf > 0);
3434 LPBYTE ptr = buf;
3436 *pcbNeeded = 0;
3438 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3439 unicode)) {
3440 if(space && size <= left) {
3441 pi4->pPrinterName = (LPWSTR)ptr;
3442 ptr += size;
3443 left -= size;
3444 } else
3445 space = FALSE;
3446 *pcbNeeded += size;
3448 if(pi4) {
3449 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3452 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3453 memset(pi4, 0, sizeof(*pi4));
3455 return space;
3458 /*********************************************************************
3459 * WINSPOOL_GetPrinter_5
3461 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3463 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3464 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3465 BOOL unicode)
3467 DWORD size, left = cbBuf;
3468 BOOL space = (cbBuf > 0);
3469 LPBYTE ptr = buf;
3471 *pcbNeeded = 0;
3473 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3474 unicode)) {
3475 if(space && size <= left) {
3476 pi5->pPrinterName = (LPWSTR)ptr;
3477 ptr += size;
3478 left -= size;
3479 } else
3480 space = FALSE;
3481 *pcbNeeded += size;
3483 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3484 unicode)) {
3485 if(space && size <= left) {
3486 pi5->pPortName = (LPWSTR)ptr;
3487 ptr += size;
3488 left -= size;
3489 } else
3490 space = FALSE;
3491 *pcbNeeded += size;
3493 if(pi5) {
3494 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3495 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3496 "dnsTimeout");
3497 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3498 "txTimeout");
3501 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3502 memset(pi5, 0, sizeof(*pi5));
3504 return space;
3507 /*********************************************************************
3508 * WINSPOOL_GetPrinter_7
3510 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3512 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3513 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3515 DWORD size, left = cbBuf;
3516 BOOL space = (cbBuf > 0);
3517 LPBYTE ptr = buf;
3519 *pcbNeeded = 0;
3521 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3523 if (space && size <= left) {
3524 pi7->pszObjectGUID = (LPWSTR)ptr;
3525 ptr += size;
3526 left -= size;
3527 } else
3528 space = FALSE;
3529 *pcbNeeded += size;
3531 if (pi7) {
3532 /* We do not have a Directory Service */
3533 pi7->dwAction = DSPRINT_UNPUBLISH;
3536 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3537 memset(pi7, 0, sizeof(*pi7));
3539 return space;
3542 /*********************************************************************
3543 * WINSPOOL_GetPrinter_9
3545 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3546 * The strings are either stored as unicode or ascii.
3548 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3549 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3551 DWORD size;
3552 BOOL space = (cbBuf > 0);
3554 *pcbNeeded = 0;
3556 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3557 if(space && size <= cbBuf) {
3558 pi9->pDevMode = (LPDEVMODEW)buf;
3559 } else
3560 space = FALSE;
3561 *pcbNeeded += size;
3563 else
3565 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3566 if(space && size <= cbBuf) {
3567 pi9->pDevMode = (LPDEVMODEW)buf;
3568 } else
3569 space = FALSE;
3570 *pcbNeeded += size;
3573 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3574 memset(pi9, 0, sizeof(*pi9));
3576 return space;
3579 /*****************************************************************************
3580 * WINSPOOL_GetPrinter
3582 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3583 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3584 * just a collection of pointers to strings.
3586 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3587 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3589 LPCWSTR name;
3590 DWORD size, needed = 0;
3591 LPBYTE ptr = NULL;
3592 HKEY hkeyPrinter, hkeyPrinters;
3593 BOOL ret;
3595 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3597 if (!(name = get_opened_printer_name(hPrinter))) {
3598 SetLastError(ERROR_INVALID_HANDLE);
3599 return FALSE;
3602 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3603 ERROR_SUCCESS) {
3604 ERR("Can't create Printers key\n");
3605 return FALSE;
3607 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3609 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3610 RegCloseKey(hkeyPrinters);
3611 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3612 return FALSE;
3615 switch(Level) {
3616 case 2:
3618 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3620 size = sizeof(PRINTER_INFO_2W);
3621 if(size <= cbBuf) {
3622 ptr = pPrinter + size;
3623 cbBuf -= size;
3624 memset(pPrinter, 0, size);
3625 } else {
3626 pi2 = NULL;
3627 cbBuf = 0;
3629 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3630 unicode);
3631 needed += size;
3632 break;
3635 case 4:
3637 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3639 size = sizeof(PRINTER_INFO_4W);
3640 if(size <= cbBuf) {
3641 ptr = pPrinter + size;
3642 cbBuf -= size;
3643 memset(pPrinter, 0, size);
3644 } else {
3645 pi4 = NULL;
3646 cbBuf = 0;
3648 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3649 unicode);
3650 needed += size;
3651 break;
3655 case 5:
3657 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3659 size = sizeof(PRINTER_INFO_5W);
3660 if(size <= cbBuf) {
3661 ptr = pPrinter + size;
3662 cbBuf -= size;
3663 memset(pPrinter, 0, size);
3664 } else {
3665 pi5 = NULL;
3666 cbBuf = 0;
3669 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3670 unicode);
3671 needed += size;
3672 break;
3676 case 6:
3678 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3680 size = sizeof(PRINTER_INFO_6);
3681 if (size <= cbBuf) {
3682 /* FIXME: We do not update the status yet */
3683 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3684 ret = TRUE;
3685 } else {
3686 ret = FALSE;
3689 needed += size;
3690 break;
3693 case 7:
3695 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3697 size = sizeof(PRINTER_INFO_7W);
3698 if (size <= cbBuf) {
3699 ptr = pPrinter + size;
3700 cbBuf -= size;
3701 memset(pPrinter, 0, size);
3702 } else {
3703 pi7 = NULL;
3704 cbBuf = 0;
3707 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
3708 needed += size;
3709 break;
3713 case 9:
3715 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3717 size = sizeof(PRINTER_INFO_9W);
3718 if(size <= cbBuf) {
3719 ptr = pPrinter + size;
3720 cbBuf -= size;
3721 memset(pPrinter, 0, size);
3722 } else {
3723 pi9 = NULL;
3724 cbBuf = 0;
3727 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
3728 needed += size;
3729 break;
3733 default:
3734 FIXME("Unimplemented level %d\n", Level);
3735 SetLastError(ERROR_INVALID_LEVEL);
3736 RegCloseKey(hkeyPrinters);
3737 RegCloseKey(hkeyPrinter);
3738 return FALSE;
3741 RegCloseKey(hkeyPrinter);
3742 RegCloseKey(hkeyPrinters);
3744 TRACE("returning %d needed = %d\n", ret, needed);
3745 if(pcbNeeded) *pcbNeeded = needed;
3746 if(!ret)
3747 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3748 return ret;
3751 /*****************************************************************************
3752 * GetPrinterW [WINSPOOL.@]
3754 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3755 DWORD cbBuf, LPDWORD pcbNeeded)
3757 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3758 TRUE);
3761 /*****************************************************************************
3762 * GetPrinterA [WINSPOOL.@]
3764 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3765 DWORD cbBuf, LPDWORD pcbNeeded)
3767 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3768 FALSE);
3771 /*****************************************************************************
3772 * WINSPOOL_EnumPrinters
3774 * Implementation of EnumPrintersA|W
3776 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3777 DWORD dwLevel, LPBYTE lpbPrinters,
3778 DWORD cbBuf, LPDWORD lpdwNeeded,
3779 LPDWORD lpdwReturned, BOOL unicode)
3782 HKEY hkeyPrinters, hkeyPrinter;
3783 WCHAR PrinterName[255];
3784 DWORD needed = 0, number = 0;
3785 DWORD used, i, left;
3786 PBYTE pi, buf;
3788 if(lpbPrinters)
3789 memset(lpbPrinters, 0, cbBuf);
3790 if(lpdwReturned)
3791 *lpdwReturned = 0;
3792 if(lpdwNeeded)
3793 *lpdwNeeded = 0;
3795 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3796 if(dwType == PRINTER_ENUM_DEFAULT)
3797 return TRUE;
3799 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3800 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3801 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3802 if (!dwType) {
3803 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3804 *lpdwNeeded = 0;
3805 *lpdwReturned = 0;
3806 return TRUE;
3811 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3812 FIXME("dwType = %08x\n", dwType);
3813 SetLastError(ERROR_INVALID_FLAGS);
3814 return FALSE;
3817 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3818 ERROR_SUCCESS) {
3819 ERR("Can't create Printers key\n");
3820 return FALSE;
3823 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3824 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3825 RegCloseKey(hkeyPrinters);
3826 ERR("Can't query Printers key\n");
3827 return FALSE;
3829 TRACE("Found %d printers\n", number);
3831 switch(dwLevel) {
3832 case 1:
3833 used = number * sizeof(PRINTER_INFO_1W);
3834 break;
3835 case 2:
3836 used = number * sizeof(PRINTER_INFO_2W);
3837 break;
3838 case 4:
3839 used = number * sizeof(PRINTER_INFO_4W);
3840 break;
3841 case 5:
3842 used = number * sizeof(PRINTER_INFO_5W);
3843 break;
3845 default:
3846 SetLastError(ERROR_INVALID_LEVEL);
3847 RegCloseKey(hkeyPrinters);
3848 return FALSE;
3850 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3852 for(i = 0; i < number; i++) {
3853 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3854 ERROR_SUCCESS) {
3855 ERR("Can't enum key number %d\n", i);
3856 RegCloseKey(hkeyPrinters);
3857 return FALSE;
3859 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3860 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3861 ERROR_SUCCESS) {
3862 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3863 RegCloseKey(hkeyPrinters);
3864 return FALSE;
3867 if(cbBuf > used) {
3868 buf = lpbPrinters + used;
3869 left = cbBuf - used;
3870 } else {
3871 buf = NULL;
3872 left = 0;
3875 switch(dwLevel) {
3876 case 1:
3877 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3878 left, &needed, unicode);
3879 used += needed;
3880 if(pi) pi += sizeof(PRINTER_INFO_1W);
3881 break;
3882 case 2:
3883 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3884 left, &needed, unicode);
3885 used += needed;
3886 if(pi) pi += sizeof(PRINTER_INFO_2W);
3887 break;
3888 case 4:
3889 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3890 left, &needed, unicode);
3891 used += needed;
3892 if(pi) pi += sizeof(PRINTER_INFO_4W);
3893 break;
3894 case 5:
3895 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3896 left, &needed, unicode);
3897 used += needed;
3898 if(pi) pi += sizeof(PRINTER_INFO_5W);
3899 break;
3900 default:
3901 ERR("Shouldn't be here!\n");
3902 RegCloseKey(hkeyPrinter);
3903 RegCloseKey(hkeyPrinters);
3904 return FALSE;
3906 RegCloseKey(hkeyPrinter);
3908 RegCloseKey(hkeyPrinters);
3910 if(lpdwNeeded)
3911 *lpdwNeeded = used;
3913 if(used > cbBuf) {
3914 if(lpbPrinters)
3915 memset(lpbPrinters, 0, cbBuf);
3916 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3917 return FALSE;
3919 if(lpdwReturned)
3920 *lpdwReturned = number;
3921 SetLastError(ERROR_SUCCESS);
3922 return TRUE;
3926 /******************************************************************
3927 * EnumPrintersW [WINSPOOL.@]
3929 * Enumerates the available printers, print servers and print
3930 * providers, depending on the specified flags, name and level.
3932 * RETURNS:
3934 * If level is set to 1:
3935 * Returns an array of PRINTER_INFO_1 data structures in the
3936 * lpbPrinters buffer.
3938 * If level is set to 2:
3939 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3940 * Returns an array of PRINTER_INFO_2 data structures in the
3941 * lpbPrinters buffer. Note that according to MSDN also an
3942 * OpenPrinter should be performed on every remote printer.
3944 * If level is set to 4 (officially WinNT only):
3945 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3946 * Fast: Only the registry is queried to retrieve printer names,
3947 * no connection to the driver is made.
3948 * Returns an array of PRINTER_INFO_4 data structures in the
3949 * lpbPrinters buffer.
3951 * If level is set to 5 (officially WinNT4/Win9x only):
3952 * Fast: Only the registry is queried to retrieve printer names,
3953 * no connection to the driver is made.
3954 * Returns an array of PRINTER_INFO_5 data structures in the
3955 * lpbPrinters buffer.
3957 * If level set to 3 or 6+:
3958 * returns zero (failure!)
3960 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3961 * for information.
3963 * BUGS:
3964 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3965 * - Only levels 2, 4 and 5 are implemented at the moment.
3966 * - 16-bit printer drivers are not enumerated.
3967 * - Returned amount of bytes used/needed does not match the real Windoze
3968 * implementation (as in this implementation, all strings are part
3969 * of the buffer, whereas Win32 keeps them somewhere else)
3970 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3972 * NOTE:
3973 * - In a regular Wine installation, no registry settings for printers
3974 * exist, which makes this function return an empty list.
3976 BOOL WINAPI EnumPrintersW(
3977 DWORD dwType, /* [in] Types of print objects to enumerate */
3978 LPWSTR lpszName, /* [in] name of objects to enumerate */
3979 DWORD dwLevel, /* [in] type of printer info structure */
3980 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3981 DWORD cbBuf, /* [in] max size of buffer in bytes */
3982 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3983 LPDWORD lpdwReturned /* [out] number of entries returned */
3986 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3987 lpdwNeeded, lpdwReturned, TRUE);
3990 /******************************************************************
3991 * EnumPrintersA [WINSPOOL.@]
3993 * See EnumPrintersW
3996 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
3997 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
3999 BOOL ret;
4000 UNICODE_STRING pNameU;
4001 LPWSTR pNameW;
4002 LPBYTE pPrintersW;
4004 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4005 pPrinters, cbBuf, pcbNeeded, pcReturned);
4007 pNameW = asciitounicode(&pNameU, pName);
4009 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4010 MS Office need this */
4011 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4013 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4015 RtlFreeUnicodeString(&pNameU);
4016 if (ret) {
4017 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4019 HeapFree(GetProcessHeap(), 0, pPrintersW);
4020 return ret;
4023 /*****************************************************************************
4024 * WINSPOOL_GetDriverInfoFromReg [internal]
4026 * Enters the information from the registry into the DRIVER_INFO struct
4028 * RETURNS
4029 * zero if the printer driver does not exist in the registry
4030 * (only if Level > 1) otherwise nonzero
4032 static BOOL WINSPOOL_GetDriverInfoFromReg(
4033 HKEY hkeyDrivers,
4034 LPWSTR DriverName,
4035 const printenv_t * env,
4036 DWORD Level,
4037 LPBYTE ptr, /* DRIVER_INFO */
4038 LPBYTE pDriverStrings, /* strings buffer */
4039 DWORD cbBuf, /* size of string buffer */
4040 LPDWORD pcbNeeded, /* space needed for str. */
4041 BOOL unicode) /* type of strings */
4043 DWORD size, tmp;
4044 HKEY hkeyDriver;
4045 WCHAR driverdir[MAX_PATH];
4046 DWORD dirlen;
4047 LPBYTE strPtr = pDriverStrings;
4048 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4050 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4051 debugstr_w(DriverName), env,
4052 Level, di, pDriverStrings, cbBuf, unicode);
4054 if (di) ZeroMemory(di, di_sizeof[Level]);
4056 if (unicode) {
4057 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4058 if (*pcbNeeded <= cbBuf)
4059 strcpyW((LPWSTR)strPtr, DriverName);
4061 else
4063 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4064 if (*pcbNeeded <= cbBuf)
4065 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4068 /* pName for level 1 has a different offset! */
4069 if (Level == 1) {
4070 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4071 return TRUE;
4074 /* .cVersion and .pName for level > 1 */
4075 if (di) {
4076 di->cVersion = env->driverversion;
4077 di->pName = (LPWSTR) strPtr;
4078 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4081 /* Reserve Space for the largest subdir and a Backslash*/
4082 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4083 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4084 /* Should never Fail */
4085 return FALSE;
4087 lstrcatW(driverdir, env->versionsubdir);
4088 lstrcatW(driverdir, backslashW);
4090 /* dirlen must not include the terminating zero */
4091 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4092 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4094 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4095 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4096 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4097 return FALSE;
4100 /* pEnvironment */
4101 if (unicode)
4102 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4103 else
4104 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4106 *pcbNeeded += size;
4107 if (*pcbNeeded <= cbBuf) {
4108 if (unicode) {
4109 lstrcpyW((LPWSTR)strPtr, env->envname);
4111 else
4113 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4115 if (di) di->pEnvironment = (LPWSTR)strPtr;
4116 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4119 /* .pDriverPath is the Graphics rendering engine.
4120 The full Path is required to avoid a crash in some apps */
4121 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4122 *pcbNeeded += size;
4123 if (*pcbNeeded <= cbBuf)
4124 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4126 if (di) di->pDriverPath = (LPWSTR)strPtr;
4127 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4130 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4131 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4132 *pcbNeeded += size;
4133 if (*pcbNeeded <= cbBuf)
4134 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4136 if (di) di->pDataFile = (LPWSTR)strPtr;
4137 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4140 /* .pConfigFile is the Driver user Interface */
4141 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4142 *pcbNeeded += size;
4143 if (*pcbNeeded <= cbBuf)
4144 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4146 if (di) di->pConfigFile = (LPWSTR)strPtr;
4147 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4150 if (Level == 2 ) {
4151 RegCloseKey(hkeyDriver);
4152 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4153 return TRUE;
4156 if (Level == 5 ) {
4157 RegCloseKey(hkeyDriver);
4158 FIXME("level 5: incomplete\n");
4159 return TRUE;
4162 /* .pHelpFile */
4163 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4164 *pcbNeeded += size;
4165 if (*pcbNeeded <= cbBuf)
4166 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4168 if (di) di->pHelpFile = (LPWSTR)strPtr;
4169 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4172 /* .pDependentFiles */
4173 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4174 *pcbNeeded += size;
4175 if (*pcbNeeded <= cbBuf)
4176 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4178 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4179 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4181 else if (GetVersion() & 0x80000000) {
4182 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4183 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4184 *pcbNeeded += size;
4185 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4187 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4188 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4191 /* .pMonitorName is the optional Language Monitor */
4192 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4193 *pcbNeeded += size;
4194 if (*pcbNeeded <= cbBuf)
4195 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4197 if (di) di->pMonitorName = (LPWSTR)strPtr;
4198 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4201 /* .pDefaultDataType */
4202 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4203 *pcbNeeded += size;
4204 if(*pcbNeeded <= cbBuf)
4205 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4207 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4208 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4211 if (Level == 3 ) {
4212 RegCloseKey(hkeyDriver);
4213 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4214 return TRUE;
4217 /* .pszzPreviousNames */
4218 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4219 *pcbNeeded += size;
4220 if(*pcbNeeded <= cbBuf)
4221 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4223 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4224 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4227 if (Level == 4 ) {
4228 RegCloseKey(hkeyDriver);
4229 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4230 return TRUE;
4233 /* support is missing, but not important enough for a FIXME */
4234 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4236 /* .pszMfgName */
4237 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4238 *pcbNeeded += size;
4239 if(*pcbNeeded <= cbBuf)
4240 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4242 if (di) di->pszMfgName = (LPWSTR)strPtr;
4243 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4246 /* .pszOEMUrl */
4247 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4248 *pcbNeeded += size;
4249 if(*pcbNeeded <= cbBuf)
4250 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4252 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4253 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4256 /* .pszHardwareID */
4257 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4258 *pcbNeeded += size;
4259 if(*pcbNeeded <= cbBuf)
4260 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4262 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4263 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4266 /* .pszProvider */
4267 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4268 *pcbNeeded += size;
4269 if(*pcbNeeded <= cbBuf)
4270 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4272 if (di) di->pszProvider = (LPWSTR)strPtr;
4273 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4276 if (Level == 6 ) {
4277 RegCloseKey(hkeyDriver);
4278 return TRUE;
4281 /* support is missing, but not important enough for a FIXME */
4282 TRACE("level 8: incomplete\n");
4284 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4285 RegCloseKey(hkeyDriver);
4286 return TRUE;
4289 /*****************************************************************************
4290 * WINSPOOL_GetPrinterDriver
4292 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4293 DWORD Level, LPBYTE pDriverInfo,
4294 DWORD cbBuf, LPDWORD pcbNeeded,
4295 BOOL unicode)
4297 LPCWSTR name;
4298 WCHAR DriverName[100];
4299 DWORD ret, type, size, needed = 0;
4300 LPBYTE ptr = NULL;
4301 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4302 const printenv_t * env;
4304 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4305 Level,pDriverInfo,cbBuf, pcbNeeded);
4308 if (!(name = get_opened_printer_name(hPrinter))) {
4309 SetLastError(ERROR_INVALID_HANDLE);
4310 return FALSE;
4313 if (Level < 1 || Level == 7 || Level > 8) {
4314 SetLastError(ERROR_INVALID_LEVEL);
4315 return FALSE;
4318 env = validate_envW(pEnvironment);
4319 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4321 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4322 ERROR_SUCCESS) {
4323 ERR("Can't create Printers key\n");
4324 return FALSE;
4326 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4327 != ERROR_SUCCESS) {
4328 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4329 RegCloseKey(hkeyPrinters);
4330 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4331 return FALSE;
4333 size = sizeof(DriverName);
4334 DriverName[0] = 0;
4335 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4336 (LPBYTE)DriverName, &size);
4337 RegCloseKey(hkeyPrinter);
4338 RegCloseKey(hkeyPrinters);
4339 if(ret != ERROR_SUCCESS) {
4340 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4341 return FALSE;
4344 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4345 if(!hkeyDrivers) {
4346 ERR("Can't create Drivers key\n");
4347 return FALSE;
4350 size = di_sizeof[Level];
4351 if ((size <= cbBuf) && pDriverInfo)
4352 ptr = pDriverInfo + size;
4354 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4355 env, Level, pDriverInfo, ptr,
4356 (cbBuf < size) ? 0 : cbBuf - size,
4357 &needed, unicode)) {
4358 RegCloseKey(hkeyDrivers);
4359 return FALSE;
4362 RegCloseKey(hkeyDrivers);
4364 if(pcbNeeded) *pcbNeeded = size + needed;
4365 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4366 if(cbBuf >= needed) return TRUE;
4367 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4368 return FALSE;
4371 /*****************************************************************************
4372 * GetPrinterDriverA [WINSPOOL.@]
4374 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4375 DWORD Level, LPBYTE pDriverInfo,
4376 DWORD cbBuf, LPDWORD pcbNeeded)
4378 BOOL ret;
4379 UNICODE_STRING pEnvW;
4380 PWSTR pwstrEnvW;
4382 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4383 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4384 cbBuf, pcbNeeded, FALSE);
4385 RtlFreeUnicodeString(&pEnvW);
4386 return ret;
4388 /*****************************************************************************
4389 * GetPrinterDriverW [WINSPOOL.@]
4391 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4392 DWORD Level, LPBYTE pDriverInfo,
4393 DWORD cbBuf, LPDWORD pcbNeeded)
4395 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4396 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4399 /*****************************************************************************
4400 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4402 * Return the PATH for the Printer-Drivers (UNICODE)
4404 * PARAMS
4405 * pName [I] Servername (NT only) or NULL (local Computer)
4406 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4407 * Level [I] Structure-Level (must be 1)
4408 * pDriverDirectory [O] PTR to Buffer that receives the Result
4409 * cbBuf [I] Size of Buffer at pDriverDirectory
4410 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4411 * required for pDriverDirectory
4413 * RETURNS
4414 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4415 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4416 * if cbBuf is too small
4418 * Native Values returned in pDriverDirectory on Success:
4419 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4420 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4421 *| win9x(Windows 4.0): "%winsysdir%"
4423 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4425 * FIXME
4426 *- Only NULL or "" is supported for pName
4429 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4430 DWORD Level, LPBYTE pDriverDirectory,
4431 DWORD cbBuf, LPDWORD pcbNeeded)
4433 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4434 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4436 if ((backend == NULL) && !load_backend()) return FALSE;
4438 if (Level != 1) {
4439 /* (Level != 1) is ignored in win9x */
4440 SetLastError(ERROR_INVALID_LEVEL);
4441 return FALSE;
4443 if (pcbNeeded == NULL) {
4444 /* (pcbNeeded == NULL) is ignored in win9x */
4445 SetLastError(RPC_X_NULL_REF_POINTER);
4446 return FALSE;
4449 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4450 pDriverDirectory, cbBuf, pcbNeeded);
4455 /*****************************************************************************
4456 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4458 * Return the PATH for the Printer-Drivers (ANSI)
4460 * See GetPrinterDriverDirectoryW.
4462 * NOTES
4463 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4466 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4467 DWORD Level, LPBYTE pDriverDirectory,
4468 DWORD cbBuf, LPDWORD pcbNeeded)
4470 UNICODE_STRING nameW, environmentW;
4471 BOOL ret;
4472 DWORD pcbNeededW;
4473 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4474 WCHAR *driverDirectoryW = NULL;
4476 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4477 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4479 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4481 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4482 else nameW.Buffer = NULL;
4483 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4484 else environmentW.Buffer = NULL;
4486 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4487 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4488 if (ret) {
4489 DWORD needed;
4490 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4491 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4492 if(pcbNeeded)
4493 *pcbNeeded = needed;
4494 ret = (needed <= cbBuf) ? TRUE : FALSE;
4495 } else
4496 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4498 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4500 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4501 RtlFreeUnicodeString(&environmentW);
4502 RtlFreeUnicodeString(&nameW);
4504 return ret;
4507 /*****************************************************************************
4508 * AddPrinterDriverA [WINSPOOL.@]
4510 * See AddPrinterDriverW.
4513 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4515 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4516 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4519 /******************************************************************************
4520 * AddPrinterDriverW (WINSPOOL.@)
4522 * Install a Printer Driver
4524 * PARAMS
4525 * pName [I] Servername or NULL (local Computer)
4526 * level [I] Level for the supplied DRIVER_INFO_*W struct
4527 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4529 * RESULTS
4530 * Success: TRUE
4531 * Failure: FALSE
4534 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4536 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4537 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4540 /*****************************************************************************
4541 * AddPrintProcessorA [WINSPOOL.@]
4543 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4544 LPSTR pPrintProcessorName)
4546 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4547 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4548 return FALSE;
4551 /*****************************************************************************
4552 * AddPrintProcessorW [WINSPOOL.@]
4554 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4555 LPWSTR pPrintProcessorName)
4557 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4558 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4559 return FALSE;
4562 /*****************************************************************************
4563 * AddPrintProvidorA [WINSPOOL.@]
4565 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4567 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4568 return FALSE;
4571 /*****************************************************************************
4572 * AddPrintProvidorW [WINSPOOL.@]
4574 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4576 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4577 return FALSE;
4580 /*****************************************************************************
4581 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4583 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4584 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4586 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4587 pDevModeOutput, pDevModeInput);
4588 return 0;
4591 /*****************************************************************************
4592 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4594 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4595 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4597 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4598 pDevModeOutput, pDevModeInput);
4599 return 0;
4602 /*****************************************************************************
4603 * PrinterProperties [WINSPOOL.@]
4605 * Displays a dialog to set the properties of the printer.
4607 * RETURNS
4608 * nonzero on success or zero on failure
4610 * BUGS
4611 * implemented as stub only
4613 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4614 HANDLE hPrinter /* [in] handle to printer object */
4616 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4617 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4618 return FALSE;
4621 /*****************************************************************************
4622 * EnumJobsA [WINSPOOL.@]
4625 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4626 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4627 LPDWORD pcReturned)
4629 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4630 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4632 if(pcbNeeded) *pcbNeeded = 0;
4633 if(pcReturned) *pcReturned = 0;
4634 return FALSE;
4638 /*****************************************************************************
4639 * EnumJobsW [WINSPOOL.@]
4642 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4643 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4644 LPDWORD pcReturned)
4646 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4647 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4649 if(pcbNeeded) *pcbNeeded = 0;
4650 if(pcReturned) *pcReturned = 0;
4651 return FALSE;
4654 /*****************************************************************************
4655 * WINSPOOL_EnumPrinterDrivers [internal]
4657 * Delivers information about all printer drivers installed on the
4658 * localhost or a given server
4660 * RETURNS
4661 * nonzero on success or zero on failure. If the buffer for the returned
4662 * information is too small the function will return an error
4664 * BUGS
4665 * - only implemented for localhost, foreign hosts will return an error
4667 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4668 DWORD Level, LPBYTE pDriverInfo,
4669 DWORD cbBuf, LPDWORD pcbNeeded,
4670 LPDWORD pcReturned, BOOL unicode)
4672 { HKEY hkeyDrivers;
4673 DWORD i, needed, number = 0, size = 0;
4674 WCHAR DriverNameW[255];
4675 PBYTE ptr;
4676 const printenv_t * env;
4678 TRACE("%s,%s,%d,%p,%d,%d\n",
4679 debugstr_w(pName), debugstr_w(pEnvironment),
4680 Level, pDriverInfo, cbBuf, unicode);
4682 /* check for local drivers */
4683 if((pName) && (pName[0])) {
4684 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4685 SetLastError(ERROR_ACCESS_DENIED);
4686 return FALSE;
4689 env = validate_envW(pEnvironment);
4690 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4692 /* check input parameter */
4693 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4694 SetLastError(ERROR_INVALID_LEVEL);
4695 return FALSE;
4698 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
4699 SetLastError(RPC_X_NULL_REF_POINTER);
4700 return FALSE;
4703 /* initialize return values */
4704 if(pDriverInfo)
4705 memset( pDriverInfo, 0, cbBuf);
4706 *pcbNeeded = 0;
4707 *pcReturned = 0;
4709 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4710 if(!hkeyDrivers) {
4711 ERR("Can't open Drivers key\n");
4712 return FALSE;
4715 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4716 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4717 RegCloseKey(hkeyDrivers);
4718 ERR("Can't query Drivers key\n");
4719 return FALSE;
4721 TRACE("Found %d Drivers\n", number);
4723 /* get size of single struct
4724 * unicode and ascii structure have the same size
4726 size = di_sizeof[Level];
4728 /* calculate required buffer size */
4729 *pcbNeeded = size * number;
4731 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4732 i < number;
4733 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4734 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4735 != ERROR_SUCCESS) {
4736 ERR("Can't enum key number %d\n", i);
4737 RegCloseKey(hkeyDrivers);
4738 return FALSE;
4740 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4741 env, Level, ptr,
4742 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4743 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4744 &needed, unicode)) {
4745 RegCloseKey(hkeyDrivers);
4746 return FALSE;
4748 *pcbNeeded += needed;
4751 RegCloseKey(hkeyDrivers);
4753 if(cbBuf < *pcbNeeded){
4754 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4755 return FALSE;
4758 *pcReturned = number;
4759 return TRUE;
4762 /*****************************************************************************
4763 * EnumPrinterDriversW [WINSPOOL.@]
4765 * see function EnumPrinterDrivers for RETURNS, BUGS
4767 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4768 LPBYTE pDriverInfo, DWORD cbBuf,
4769 LPDWORD pcbNeeded, LPDWORD pcReturned)
4771 static const WCHAR allW[] = {'a','l','l',0};
4773 if (pEnvironment && !strcmpW(pEnvironment, allW))
4775 BOOL ret;
4776 DWORD i, needed, returned, bufsize = cbBuf;
4778 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4780 needed = returned = 0;
4781 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4782 pDriverInfo, bufsize, &needed, &returned, TRUE);
4783 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4784 else if (ret)
4786 bufsize -= needed;
4787 if (pDriverInfo) pDriverInfo += needed;
4788 if (pcReturned) *pcReturned += returned;
4790 if (pcbNeeded) *pcbNeeded += needed;
4792 return ret;
4794 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4795 cbBuf, pcbNeeded, pcReturned, TRUE);
4798 /*****************************************************************************
4799 * EnumPrinterDriversA [WINSPOOL.@]
4801 * see function EnumPrinterDrivers for RETURNS, BUGS
4803 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4804 LPBYTE pDriverInfo, DWORD cbBuf,
4805 LPDWORD pcbNeeded, LPDWORD pcReturned)
4807 BOOL ret;
4808 UNICODE_STRING pNameW, pEnvironmentW;
4809 PWSTR pwstrNameW, pwstrEnvironmentW;
4811 pwstrNameW = asciitounicode(&pNameW, pName);
4812 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4814 if (pEnvironment && !strcmp(pEnvironment, "all"))
4816 DWORD i, needed, returned, bufsize = cbBuf;
4818 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4820 needed = returned = 0;
4821 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
4822 pDriverInfo, bufsize, &needed, &returned, FALSE);
4823 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
4824 else if (ret)
4826 bufsize -= needed;
4827 if (pDriverInfo) pDriverInfo += needed;
4828 if (pcReturned) *pcReturned += returned;
4830 if (pcbNeeded) *pcbNeeded += needed;
4833 else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4834 Level, pDriverInfo, cbBuf, pcbNeeded,
4835 pcReturned, FALSE);
4836 RtlFreeUnicodeString(&pNameW);
4837 RtlFreeUnicodeString(&pEnvironmentW);
4839 return ret;
4842 /******************************************************************************
4843 * EnumPortsA (WINSPOOL.@)
4845 * See EnumPortsW.
4848 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4849 LPDWORD pcbNeeded, LPDWORD pcReturned)
4851 BOOL res;
4852 LPBYTE bufferW = NULL;
4853 LPWSTR nameW = NULL;
4854 DWORD needed = 0;
4855 DWORD numentries = 0;
4856 INT len;
4858 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4859 cbBuf, pcbNeeded, pcReturned);
4861 /* convert servername to unicode */
4862 if (pName) {
4863 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4864 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4865 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4867 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4868 needed = cbBuf * sizeof(WCHAR);
4869 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4870 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4872 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4873 if (pcbNeeded) needed = *pcbNeeded;
4874 /* HeapReAlloc return NULL, when bufferW was NULL */
4875 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4876 HeapAlloc(GetProcessHeap(), 0, needed);
4878 /* Try again with the large Buffer */
4879 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4881 needed = pcbNeeded ? *pcbNeeded : 0;
4882 numentries = pcReturned ? *pcReturned : 0;
4885 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4886 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4888 if (res) {
4889 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
4890 DWORD entrysize = 0;
4891 DWORD index;
4892 LPSTR ptr;
4893 LPPORT_INFO_2W pi2w;
4894 LPPORT_INFO_2A pi2a;
4896 needed = 0;
4897 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
4899 /* First pass: calculate the size for all Entries */
4900 pi2w = (LPPORT_INFO_2W) bufferW;
4901 pi2a = (LPPORT_INFO_2A) pPorts;
4902 index = 0;
4903 while (index < numentries) {
4904 index++;
4905 needed += entrysize; /* PORT_INFO_?A */
4906 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
4908 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4909 NULL, 0, NULL, NULL);
4910 if (Level > 1) {
4911 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4912 NULL, 0, NULL, NULL);
4913 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4914 NULL, 0, NULL, NULL);
4916 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4917 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4918 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4921 /* check for errors and quit on failure */
4922 if (cbBuf < needed) {
4923 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4924 res = FALSE;
4925 goto cleanup;
4927 len = entrysize * numentries; /* room for all PORT_INFO_?A */
4928 ptr = (LPSTR) &pPorts[len]; /* room for strings */
4929 cbBuf -= len ; /* free Bytes in the user-Buffer */
4930 pi2w = (LPPORT_INFO_2W) bufferW;
4931 pi2a = (LPPORT_INFO_2A) pPorts;
4932 index = 0;
4933 /* Second Pass: Fill the User Buffer (if we have one) */
4934 while ((index < numentries) && pPorts) {
4935 index++;
4936 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
4937 pi2a->pPortName = ptr;
4938 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4939 ptr, cbBuf , NULL, NULL);
4940 ptr += len;
4941 cbBuf -= len;
4942 if (Level > 1) {
4943 pi2a->pMonitorName = ptr;
4944 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4945 ptr, cbBuf, NULL, NULL);
4946 ptr += len;
4947 cbBuf -= len;
4949 pi2a->pDescription = ptr;
4950 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4951 ptr, cbBuf, NULL, NULL);
4952 ptr += len;
4953 cbBuf -= len;
4955 pi2a->fPortType = pi2w->fPortType;
4956 pi2a->Reserved = 0; /* documented: "must be zero" */
4959 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4960 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4961 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4965 cleanup:
4966 if (pcbNeeded) *pcbNeeded = needed;
4967 if (pcReturned) *pcReturned = (res) ? numentries : 0;
4969 HeapFree(GetProcessHeap(), 0, nameW);
4970 HeapFree(GetProcessHeap(), 0, bufferW);
4972 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4973 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4975 return (res);
4979 /******************************************************************************
4980 * EnumPortsW (WINSPOOL.@)
4982 * Enumerate available Ports
4984 * PARAMS
4985 * pName [I] Servername or NULL (local Computer)
4986 * Level [I] Structure-Level (1 or 2)
4987 * pPorts [O] PTR to Buffer that receives the Result
4988 * cbBuf [I] Size of Buffer at pPorts
4989 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
4990 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
4992 * RETURNS
4993 * Success: TRUE
4994 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
4997 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5000 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5001 cbBuf, pcbNeeded, pcReturned);
5003 if ((backend == NULL) && !load_backend()) return FALSE;
5005 /* Level is not checked in win9x */
5006 if (!Level || (Level > 2)) {
5007 WARN("level (%d) is ignored in win9x\n", Level);
5008 SetLastError(ERROR_INVALID_LEVEL);
5009 return FALSE;
5011 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5012 SetLastError(RPC_X_NULL_REF_POINTER);
5013 return FALSE;
5016 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5019 /******************************************************************************
5020 * GetDefaultPrinterW (WINSPOOL.@)
5022 * FIXME
5023 * This function must read the value from data 'device' of key
5024 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5026 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5028 BOOL retval = TRUE;
5029 DWORD insize, len;
5030 WCHAR *buffer, *ptr;
5032 if (!namesize)
5034 SetLastError(ERROR_INVALID_PARAMETER);
5035 return FALSE;
5038 /* make the buffer big enough for the stuff from the profile/registry,
5039 * the content must fit into the local buffer to compute the correct
5040 * size even if the extern buffer is too small or not given.
5041 * (20 for ,driver,port) */
5042 insize = *namesize;
5043 len = max(100, (insize + 20));
5044 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5046 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5048 SetLastError (ERROR_FILE_NOT_FOUND);
5049 retval = FALSE;
5050 goto end;
5052 TRACE("%s\n", debugstr_w(buffer));
5054 if ((ptr = strchrW(buffer, ',')) == NULL)
5056 SetLastError(ERROR_INVALID_NAME);
5057 retval = FALSE;
5058 goto end;
5061 *ptr = 0;
5062 *namesize = strlenW(buffer) + 1;
5063 if(!name || (*namesize > insize))
5065 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5066 retval = FALSE;
5067 goto end;
5069 strcpyW(name, buffer);
5071 end:
5072 HeapFree( GetProcessHeap(), 0, buffer);
5073 return retval;
5077 /******************************************************************************
5078 * GetDefaultPrinterA (WINSPOOL.@)
5080 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5082 BOOL retval = TRUE;
5083 DWORD insize = 0;
5084 WCHAR *bufferW = NULL;
5086 if (!namesize)
5088 SetLastError(ERROR_INVALID_PARAMETER);
5089 return FALSE;
5092 if(name && *namesize) {
5093 insize = *namesize;
5094 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5097 if(!GetDefaultPrinterW( bufferW, namesize)) {
5098 retval = FALSE;
5099 goto end;
5102 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5103 NULL, NULL);
5104 if (!*namesize)
5106 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5107 retval = FALSE;
5109 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5111 end:
5112 HeapFree( GetProcessHeap(), 0, bufferW);
5113 return retval;
5117 /******************************************************************************
5118 * SetDefaultPrinterW (WINSPOOL.204)
5120 * Set the Name of the Default Printer
5122 * PARAMS
5123 * pszPrinter [I] Name of the Printer or NULL
5125 * RETURNS
5126 * Success: True
5127 * Failure: FALSE
5129 * NOTES
5130 * When the Parameter is NULL or points to an Empty String and
5131 * a Default Printer was already present, then this Function changes nothing.
5132 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5133 * the First enumerated local Printer is used.
5136 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5139 TRACE("(%s)\n", debugstr_w(pszPrinter));
5141 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5142 return FALSE;
5145 /******************************************************************************
5146 * SetDefaultPrinterA (WINSPOOL.202)
5148 * See SetDefaultPrinterW.
5151 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5154 TRACE("(%s)\n", debugstr_a(pszPrinter));
5156 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5157 return FALSE;
5161 /******************************************************************************
5162 * SetPrinterDataExA (WINSPOOL.@)
5164 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5165 LPCSTR pValueName, DWORD Type,
5166 LPBYTE pData, DWORD cbData)
5168 HKEY hkeyPrinter, hkeySubkey;
5169 DWORD ret;
5171 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5172 debugstr_a(pValueName), Type, pData, cbData);
5174 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5175 != ERROR_SUCCESS)
5176 return ret;
5178 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5179 != ERROR_SUCCESS) {
5180 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5181 RegCloseKey(hkeyPrinter);
5182 return ret;
5184 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5185 RegCloseKey(hkeySubkey);
5186 RegCloseKey(hkeyPrinter);
5187 return ret;
5190 /******************************************************************************
5191 * SetPrinterDataExW (WINSPOOL.@)
5193 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5194 LPCWSTR pValueName, DWORD Type,
5195 LPBYTE pData, DWORD cbData)
5197 HKEY hkeyPrinter, hkeySubkey;
5198 DWORD ret;
5200 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5201 debugstr_w(pValueName), Type, pData, cbData);
5203 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5204 != ERROR_SUCCESS)
5205 return ret;
5207 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5208 != ERROR_SUCCESS) {
5209 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5210 RegCloseKey(hkeyPrinter);
5211 return ret;
5213 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5214 RegCloseKey(hkeySubkey);
5215 RegCloseKey(hkeyPrinter);
5216 return ret;
5219 /******************************************************************************
5220 * SetPrinterDataA (WINSPOOL.@)
5222 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5223 LPBYTE pData, DWORD cbData)
5225 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5226 pData, cbData);
5229 /******************************************************************************
5230 * SetPrinterDataW (WINSPOOL.@)
5232 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5233 LPBYTE pData, DWORD cbData)
5235 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5236 pData, cbData);
5239 /******************************************************************************
5240 * GetPrinterDataExA (WINSPOOL.@)
5242 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5243 LPCSTR pValueName, LPDWORD pType,
5244 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5246 HKEY hkeyPrinter, hkeySubkey;
5247 DWORD ret;
5249 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5250 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5251 pcbNeeded);
5253 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5254 != ERROR_SUCCESS)
5255 return ret;
5257 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5258 != ERROR_SUCCESS) {
5259 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5260 RegCloseKey(hkeyPrinter);
5261 return ret;
5263 *pcbNeeded = nSize;
5264 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5265 RegCloseKey(hkeySubkey);
5266 RegCloseKey(hkeyPrinter);
5267 return ret;
5270 /******************************************************************************
5271 * GetPrinterDataExW (WINSPOOL.@)
5273 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5274 LPCWSTR pValueName, LPDWORD pType,
5275 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5277 HKEY hkeyPrinter, hkeySubkey;
5278 DWORD ret;
5280 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5281 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5282 pcbNeeded);
5284 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5285 != ERROR_SUCCESS)
5286 return ret;
5288 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5289 != ERROR_SUCCESS) {
5290 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5291 RegCloseKey(hkeyPrinter);
5292 return ret;
5294 *pcbNeeded = nSize;
5295 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5296 RegCloseKey(hkeySubkey);
5297 RegCloseKey(hkeyPrinter);
5298 return ret;
5301 /******************************************************************************
5302 * GetPrinterDataA (WINSPOOL.@)
5304 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5305 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5307 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5308 pData, nSize, pcbNeeded);
5311 /******************************************************************************
5312 * GetPrinterDataW (WINSPOOL.@)
5314 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5315 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5317 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5318 pData, nSize, pcbNeeded);
5321 /*******************************************************************************
5322 * EnumPrinterDataExW [WINSPOOL.@]
5324 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5325 LPBYTE pEnumValues, DWORD cbEnumValues,
5326 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5328 HKEY hkPrinter, hkSubKey;
5329 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5330 cbValueNameLen, cbMaxValueLen, cbValueLen,
5331 cbBufSize, dwType;
5332 LPWSTR lpValueName;
5333 HANDLE hHeap;
5334 PBYTE lpValue;
5335 PPRINTER_ENUM_VALUESW ppev;
5337 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5339 if (pKeyName == NULL || *pKeyName == 0)
5340 return ERROR_INVALID_PARAMETER;
5342 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5343 if (ret != ERROR_SUCCESS)
5345 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5346 hPrinter, ret);
5347 return ret;
5350 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5351 if (ret != ERROR_SUCCESS)
5353 r = RegCloseKey (hkPrinter);
5354 if (r != ERROR_SUCCESS)
5355 WARN ("RegCloseKey returned %i\n", r);
5356 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5357 debugstr_w (pKeyName), ret);
5358 return ret;
5361 ret = RegCloseKey (hkPrinter);
5362 if (ret != ERROR_SUCCESS)
5364 ERR ("RegCloseKey returned %i\n", ret);
5365 r = RegCloseKey (hkSubKey);
5366 if (r != ERROR_SUCCESS)
5367 WARN ("RegCloseKey returned %i\n", r);
5368 return ret;
5371 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5372 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5373 if (ret != ERROR_SUCCESS)
5375 r = RegCloseKey (hkSubKey);
5376 if (r != ERROR_SUCCESS)
5377 WARN ("RegCloseKey returned %i\n", r);
5378 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5379 return ret;
5382 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5383 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5385 if (cValues == 0) /* empty key */
5387 r = RegCloseKey (hkSubKey);
5388 if (r != ERROR_SUCCESS)
5389 WARN ("RegCloseKey returned %i\n", r);
5390 *pcbEnumValues = *pnEnumValues = 0;
5391 return ERROR_SUCCESS;
5394 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5396 hHeap = GetProcessHeap ();
5397 if (hHeap == NULL)
5399 ERR ("GetProcessHeap failed\n");
5400 r = RegCloseKey (hkSubKey);
5401 if (r != ERROR_SUCCESS)
5402 WARN ("RegCloseKey returned %i\n", r);
5403 return ERROR_OUTOFMEMORY;
5406 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5407 if (lpValueName == NULL)
5409 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5410 r = RegCloseKey (hkSubKey);
5411 if (r != ERROR_SUCCESS)
5412 WARN ("RegCloseKey returned %i\n", r);
5413 return ERROR_OUTOFMEMORY;
5416 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5417 if (lpValue == NULL)
5419 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5420 if (HeapFree (hHeap, 0, lpValueName) == 0)
5421 WARN ("HeapFree failed with code %i\n", GetLastError ());
5422 r = RegCloseKey (hkSubKey);
5423 if (r != ERROR_SUCCESS)
5424 WARN ("RegCloseKey returned %i\n", r);
5425 return ERROR_OUTOFMEMORY;
5428 TRACE ("pass 1: calculating buffer required for all names and values\n");
5430 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5432 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5434 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5436 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5437 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5438 NULL, NULL, lpValue, &cbValueLen);
5439 if (ret != ERROR_SUCCESS)
5441 if (HeapFree (hHeap, 0, lpValue) == 0)
5442 WARN ("HeapFree failed with code %i\n", GetLastError ());
5443 if (HeapFree (hHeap, 0, lpValueName) == 0)
5444 WARN ("HeapFree failed with code %i\n", GetLastError ());
5445 r = RegCloseKey (hkSubKey);
5446 if (r != ERROR_SUCCESS)
5447 WARN ("RegCloseKey returned %i\n", r);
5448 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5449 return ret;
5452 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5453 debugstr_w (lpValueName), dwIndex,
5454 cbValueNameLen + 1, cbValueLen);
5456 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5457 cbBufSize += cbValueLen;
5460 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5462 *pcbEnumValues = cbBufSize;
5463 *pnEnumValues = cValues;
5465 if (cbEnumValues < cbBufSize) /* buffer too small */
5467 if (HeapFree (hHeap, 0, lpValue) == 0)
5468 WARN ("HeapFree failed with code %i\n", GetLastError ());
5469 if (HeapFree (hHeap, 0, lpValueName) == 0)
5470 WARN ("HeapFree failed with code %i\n", GetLastError ());
5471 r = RegCloseKey (hkSubKey);
5472 if (r != ERROR_SUCCESS)
5473 WARN ("RegCloseKey returned %i\n", r);
5474 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5475 return ERROR_MORE_DATA;
5478 TRACE ("pass 2: copying all names and values to buffer\n");
5480 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5481 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5483 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5485 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5486 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5487 NULL, &dwType, lpValue, &cbValueLen);
5488 if (ret != ERROR_SUCCESS)
5490 if (HeapFree (hHeap, 0, lpValue) == 0)
5491 WARN ("HeapFree failed with code %i\n", GetLastError ());
5492 if (HeapFree (hHeap, 0, lpValueName) == 0)
5493 WARN ("HeapFree failed with code %i\n", GetLastError ());
5494 r = RegCloseKey (hkSubKey);
5495 if (r != ERROR_SUCCESS)
5496 WARN ("RegCloseKey returned %i\n", r);
5497 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5498 return ret;
5501 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5502 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5503 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5504 pEnumValues += cbValueNameLen;
5506 /* return # of *bytes* (including trailing \0), not # of chars */
5507 ppev[dwIndex].cbValueName = cbValueNameLen;
5509 ppev[dwIndex].dwType = dwType;
5511 memcpy (pEnumValues, lpValue, cbValueLen);
5512 ppev[dwIndex].pData = pEnumValues;
5513 pEnumValues += cbValueLen;
5515 ppev[dwIndex].cbData = cbValueLen;
5517 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5518 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5521 if (HeapFree (hHeap, 0, lpValue) == 0)
5523 ret = GetLastError ();
5524 ERR ("HeapFree failed with code %i\n", ret);
5525 if (HeapFree (hHeap, 0, lpValueName) == 0)
5526 WARN ("HeapFree failed with code %i\n", GetLastError ());
5527 r = RegCloseKey (hkSubKey);
5528 if (r != ERROR_SUCCESS)
5529 WARN ("RegCloseKey returned %i\n", r);
5530 return ret;
5533 if (HeapFree (hHeap, 0, lpValueName) == 0)
5535 ret = GetLastError ();
5536 ERR ("HeapFree failed with code %i\n", ret);
5537 r = RegCloseKey (hkSubKey);
5538 if (r != ERROR_SUCCESS)
5539 WARN ("RegCloseKey returned %i\n", r);
5540 return ret;
5543 ret = RegCloseKey (hkSubKey);
5544 if (ret != ERROR_SUCCESS)
5546 ERR ("RegCloseKey returned %i\n", ret);
5547 return ret;
5550 return ERROR_SUCCESS;
5553 /*******************************************************************************
5554 * EnumPrinterDataExA [WINSPOOL.@]
5556 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5557 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5558 * what Windows 2000 SP1 does.
5561 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5562 LPBYTE pEnumValues, DWORD cbEnumValues,
5563 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5565 INT len;
5566 LPWSTR pKeyNameW;
5567 DWORD ret, dwIndex, dwBufSize;
5568 HANDLE hHeap;
5569 LPSTR pBuffer;
5571 TRACE ("%p %s\n", hPrinter, pKeyName);
5573 if (pKeyName == NULL || *pKeyName == 0)
5574 return ERROR_INVALID_PARAMETER;
5576 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5577 if (len == 0)
5579 ret = GetLastError ();
5580 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5581 return ret;
5584 hHeap = GetProcessHeap ();
5585 if (hHeap == NULL)
5587 ERR ("GetProcessHeap failed\n");
5588 return ERROR_OUTOFMEMORY;
5591 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5592 if (pKeyNameW == NULL)
5594 ERR ("Failed to allocate %i bytes from process heap\n",
5595 (LONG)(len * sizeof (WCHAR)));
5596 return ERROR_OUTOFMEMORY;
5599 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5601 ret = GetLastError ();
5602 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5603 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5604 WARN ("HeapFree failed with code %i\n", GetLastError ());
5605 return ret;
5608 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5609 pcbEnumValues, pnEnumValues);
5610 if (ret != ERROR_SUCCESS)
5612 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5613 WARN ("HeapFree failed with code %i\n", GetLastError ());
5614 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5615 return ret;
5618 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5620 ret = GetLastError ();
5621 ERR ("HeapFree failed with code %i\n", ret);
5622 return ret;
5625 if (*pnEnumValues == 0) /* empty key */
5626 return ERROR_SUCCESS;
5628 dwBufSize = 0;
5629 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5631 PPRINTER_ENUM_VALUESW ppev =
5632 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5634 if (dwBufSize < ppev->cbValueName)
5635 dwBufSize = ppev->cbValueName;
5637 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5638 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5639 dwBufSize = ppev->cbData;
5642 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5644 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5645 if (pBuffer == NULL)
5647 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5648 return ERROR_OUTOFMEMORY;
5651 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5653 PPRINTER_ENUM_VALUESW ppev =
5654 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5656 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5657 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5658 NULL);
5659 if (len == 0)
5661 ret = GetLastError ();
5662 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5663 if (HeapFree (hHeap, 0, pBuffer) == 0)
5664 WARN ("HeapFree failed with code %i\n", GetLastError ());
5665 return ret;
5668 memcpy (ppev->pValueName, pBuffer, len);
5670 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5672 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5673 ppev->dwType != REG_MULTI_SZ)
5674 continue;
5676 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5677 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5678 if (len == 0)
5680 ret = GetLastError ();
5681 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5682 if (HeapFree (hHeap, 0, pBuffer) == 0)
5683 WARN ("HeapFree failed with code %i\n", GetLastError ());
5684 return ret;
5687 memcpy (ppev->pData, pBuffer, len);
5689 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5690 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5693 if (HeapFree (hHeap, 0, pBuffer) == 0)
5695 ret = GetLastError ();
5696 ERR ("HeapFree failed with code %i\n", ret);
5697 return ret;
5700 return ERROR_SUCCESS;
5703 /******************************************************************************
5704 * AbortPrinter (WINSPOOL.@)
5706 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5708 FIXME("(%p), stub!\n", hPrinter);
5709 return TRUE;
5712 /******************************************************************************
5713 * AddPortA (WINSPOOL.@)
5715 * See AddPortW.
5718 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5720 LPWSTR nameW = NULL;
5721 LPWSTR monitorW = NULL;
5722 DWORD len;
5723 BOOL res;
5725 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5727 if (pName) {
5728 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5729 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5730 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5733 if (pMonitorName) {
5734 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5735 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5736 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5738 res = AddPortW(nameW, hWnd, monitorW);
5739 HeapFree(GetProcessHeap(), 0, nameW);
5740 HeapFree(GetProcessHeap(), 0, monitorW);
5741 return res;
5744 /******************************************************************************
5745 * AddPortW (WINSPOOL.@)
5747 * Add a Port for a specific Monitor
5749 * PARAMS
5750 * pName [I] Servername or NULL (local Computer)
5751 * hWnd [I] Handle to parent Window for the Dialog-Box
5752 * pMonitorName [I] Name of the Monitor that manage the Port
5754 * RETURNS
5755 * Success: TRUE
5756 * Failure: FALSE
5759 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5761 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5763 if ((backend == NULL) && !load_backend()) return FALSE;
5765 if (!pMonitorName) {
5766 SetLastError(RPC_X_NULL_REF_POINTER);
5767 return FALSE;
5770 return backend->fpAddPort(pName, hWnd, pMonitorName);
5773 /******************************************************************************
5774 * AddPortExA (WINSPOOL.@)
5776 * See AddPortExW.
5779 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5781 PORT_INFO_2W pi2W;
5782 PORT_INFO_2A * pi2A;
5783 LPWSTR nameW = NULL;
5784 LPWSTR monitorW = NULL;
5785 DWORD len;
5786 BOOL res;
5788 pi2A = (PORT_INFO_2A *) pBuffer;
5790 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5791 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5793 if ((level < 1) || (level > 2)) {
5794 SetLastError(ERROR_INVALID_LEVEL);
5795 return FALSE;
5798 if (!pi2A) {
5799 SetLastError(ERROR_INVALID_PARAMETER);
5800 return FALSE;
5803 if (pName) {
5804 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5805 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5806 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5809 if (pMonitorName) {
5810 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5811 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5812 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5815 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5817 if (pi2A->pPortName) {
5818 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5819 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5820 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5823 if (level > 1) {
5824 if (pi2A->pMonitorName) {
5825 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5826 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5827 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5830 if (pi2A->pDescription) {
5831 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5832 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5833 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5835 pi2W.fPortType = pi2A->fPortType;
5836 pi2W.Reserved = pi2A->Reserved;
5839 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
5841 HeapFree(GetProcessHeap(), 0, nameW);
5842 HeapFree(GetProcessHeap(), 0, monitorW);
5843 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
5844 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
5845 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
5846 return res;
5850 /******************************************************************************
5851 * AddPortExW (WINSPOOL.@)
5853 * Add a Port for a specific Monitor, without presenting a user interface
5855 * PARAMS
5856 * pName [I] Servername or NULL (local Computer)
5857 * level [I] Structure-Level (1 or 2) for pBuffer
5858 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5859 * pMonitorName [I] Name of the Monitor that manage the Port
5861 * RETURNS
5862 * Success: TRUE
5863 * Failure: FALSE
5866 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
5868 PORT_INFO_2W * pi2;
5870 pi2 = (PORT_INFO_2W *) pBuffer;
5872 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
5873 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
5874 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
5875 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
5877 if ((backend == NULL) && !load_backend()) return FALSE;
5879 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
5880 SetLastError(ERROR_INVALID_PARAMETER);
5881 return FALSE;
5884 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
5887 /******************************************************************************
5888 * AddPrinterConnectionA (WINSPOOL.@)
5890 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5892 FIXME("%s\n", debugstr_a(pName));
5893 return FALSE;
5896 /******************************************************************************
5897 * AddPrinterConnectionW (WINSPOOL.@)
5899 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5901 FIXME("%s\n", debugstr_w(pName));
5902 return FALSE;
5905 /******************************************************************************
5906 * AddPrinterDriverExW (WINSPOOL.@)
5908 * Install a Printer Driver with the Option to upgrade / downgrade the Files
5910 * PARAMS
5911 * pName [I] Servername or NULL (local Computer)
5912 * level [I] Level for the supplied DRIVER_INFO_*W struct
5913 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5914 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
5916 * RESULTS
5917 * Success: TRUE
5918 * Failure: FALSE
5921 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5923 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
5925 if ((backend == NULL) && !load_backend()) return FALSE;
5927 if (level < 2 || level == 5 || level == 7 || level > 8) {
5928 SetLastError(ERROR_INVALID_LEVEL);
5929 return FALSE;
5932 if (!pDriverInfo) {
5933 SetLastError(ERROR_INVALID_PARAMETER);
5934 return FALSE;
5937 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
5940 /******************************************************************************
5941 * AddPrinterDriverExA (WINSPOOL.@)
5943 * See AddPrinterDriverExW.
5946 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5948 DRIVER_INFO_8A *diA;
5949 DRIVER_INFO_8W diW;
5950 LPWSTR nameW = NULL;
5951 DWORD lenA;
5952 DWORD len;
5953 DWORD res = FALSE;
5955 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
5957 diA = (DRIVER_INFO_8A *) pDriverInfo;
5958 ZeroMemory(&diW, sizeof(diW));
5960 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
5961 SetLastError(ERROR_INVALID_LEVEL);
5962 return FALSE;
5965 if (diA == NULL) {
5966 SetLastError(ERROR_INVALID_PARAMETER);
5967 return FALSE;
5970 /* convert servername to unicode */
5971 if (pName) {
5972 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5973 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5974 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5977 /* common fields */
5978 diW.cVersion = diA->cVersion;
5980 if (diA->pName) {
5981 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
5982 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5983 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
5986 if (diA->pEnvironment) {
5987 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
5988 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5989 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
5992 if (diA->pDriverPath) {
5993 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
5994 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5995 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
5998 if (diA->pDataFile) {
5999 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6000 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6001 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6004 if (diA->pConfigFile) {
6005 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6006 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6007 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6010 if ((Level > 2) && diA->pDependentFiles) {
6011 lenA = multi_sz_lenA(diA->pDependentFiles);
6012 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6013 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6014 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6017 if ((Level > 2) && diA->pMonitorName) {
6018 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6019 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6020 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6023 if ((Level > 3) && diA->pDefaultDataType) {
6024 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6025 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6026 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6029 if ((Level > 3) && diA->pszzPreviousNames) {
6030 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6031 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6032 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6033 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6036 if ((Level > 5) && diA->pszMfgName) {
6037 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6038 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6039 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6042 if ((Level > 5) && diA->pszOEMUrl) {
6043 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6044 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6045 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6048 if ((Level > 5) && diA->pszHardwareID) {
6049 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6050 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6051 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6054 if ((Level > 5) && diA->pszProvider) {
6055 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6056 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6057 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6060 if (Level > 7) {
6061 FIXME("level %u is incomplete\n", Level);
6064 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6065 TRACE("got %u with %u\n", res, GetLastError());
6066 HeapFree(GetProcessHeap(), 0, nameW);
6067 HeapFree(GetProcessHeap(), 0, diW.pName);
6068 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6069 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6070 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6071 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6072 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6073 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6074 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6075 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6076 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6077 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6078 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6079 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6081 TRACE("=> %u with %u\n", res, GetLastError());
6082 return res;
6085 /******************************************************************************
6086 * ConfigurePortA (WINSPOOL.@)
6088 * See ConfigurePortW.
6091 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6093 LPWSTR nameW = NULL;
6094 LPWSTR portW = NULL;
6095 INT len;
6096 DWORD res;
6098 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6100 /* convert servername to unicode */
6101 if (pName) {
6102 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6103 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6104 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6107 /* convert portname to unicode */
6108 if (pPortName) {
6109 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6110 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6111 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6114 res = ConfigurePortW(nameW, hWnd, portW);
6115 HeapFree(GetProcessHeap(), 0, nameW);
6116 HeapFree(GetProcessHeap(), 0, portW);
6117 return res;
6120 /******************************************************************************
6121 * ConfigurePortW (WINSPOOL.@)
6123 * Display the Configuration-Dialog for a specific Port
6125 * PARAMS
6126 * pName [I] Servername or NULL (local Computer)
6127 * hWnd [I] Handle to parent Window for the Dialog-Box
6128 * pPortName [I] Name of the Port, that should be configured
6130 * RETURNS
6131 * Success: TRUE
6132 * Failure: FALSE
6135 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6138 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6140 if ((backend == NULL) && !load_backend()) return FALSE;
6142 if (!pPortName) {
6143 SetLastError(RPC_X_NULL_REF_POINTER);
6144 return FALSE;
6147 return backend->fpConfigurePort(pName, hWnd, pPortName);
6150 /******************************************************************************
6151 * ConnectToPrinterDlg (WINSPOOL.@)
6153 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6155 FIXME("%p %x\n", hWnd, Flags);
6156 return NULL;
6159 /******************************************************************************
6160 * DeletePrinterConnectionA (WINSPOOL.@)
6162 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6164 FIXME("%s\n", debugstr_a(pName));
6165 return TRUE;
6168 /******************************************************************************
6169 * DeletePrinterConnectionW (WINSPOOL.@)
6171 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6173 FIXME("%s\n", debugstr_w(pName));
6174 return TRUE;
6177 /******************************************************************************
6178 * DeletePrinterDriverExW (WINSPOOL.@)
6180 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6181 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6183 HKEY hkey_drivers;
6184 BOOL ret = FALSE;
6186 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6187 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6189 if(pName && pName[0])
6191 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6192 SetLastError(ERROR_INVALID_PARAMETER);
6193 return FALSE;
6196 if(dwDeleteFlag)
6198 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6199 SetLastError(ERROR_INVALID_PARAMETER);
6200 return FALSE;
6203 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6205 if(!hkey_drivers)
6207 ERR("Can't open drivers key\n");
6208 return FALSE;
6211 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6212 ret = TRUE;
6214 RegCloseKey(hkey_drivers);
6216 return ret;
6219 /******************************************************************************
6220 * DeletePrinterDriverExA (WINSPOOL.@)
6222 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6223 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6225 UNICODE_STRING NameW, EnvW, DriverW;
6226 BOOL ret;
6228 asciitounicode(&NameW, pName);
6229 asciitounicode(&EnvW, pEnvironment);
6230 asciitounicode(&DriverW, pDriverName);
6232 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6234 RtlFreeUnicodeString(&DriverW);
6235 RtlFreeUnicodeString(&EnvW);
6236 RtlFreeUnicodeString(&NameW);
6238 return ret;
6241 /******************************************************************************
6242 * DeletePrinterDataExW (WINSPOOL.@)
6244 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6245 LPCWSTR pValueName)
6247 FIXME("%p %s %s\n", hPrinter,
6248 debugstr_w(pKeyName), debugstr_w(pValueName));
6249 return ERROR_INVALID_PARAMETER;
6252 /******************************************************************************
6253 * DeletePrinterDataExA (WINSPOOL.@)
6255 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6256 LPCSTR pValueName)
6258 FIXME("%p %s %s\n", hPrinter,
6259 debugstr_a(pKeyName), debugstr_a(pValueName));
6260 return ERROR_INVALID_PARAMETER;
6263 /******************************************************************************
6264 * DeletePrintProcessorA (WINSPOOL.@)
6266 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6268 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6269 debugstr_a(pPrintProcessorName));
6270 return TRUE;
6273 /******************************************************************************
6274 * DeletePrintProcessorW (WINSPOOL.@)
6276 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6278 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6279 debugstr_w(pPrintProcessorName));
6280 return TRUE;
6283 /******************************************************************************
6284 * DeletePrintProvidorA (WINSPOOL.@)
6286 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6288 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6289 debugstr_a(pPrintProviderName));
6290 return TRUE;
6293 /******************************************************************************
6294 * DeletePrintProvidorW (WINSPOOL.@)
6296 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6298 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6299 debugstr_w(pPrintProviderName));
6300 return TRUE;
6303 /******************************************************************************
6304 * EnumFormsA (WINSPOOL.@)
6306 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6307 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6309 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6310 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6311 return FALSE;
6314 /******************************************************************************
6315 * EnumFormsW (WINSPOOL.@)
6317 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6318 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6320 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6321 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6322 return FALSE;
6325 /*****************************************************************************
6326 * EnumMonitorsA [WINSPOOL.@]
6328 * See EnumMonitorsW.
6331 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6332 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6334 BOOL res;
6335 LPBYTE bufferW = NULL;
6336 LPWSTR nameW = NULL;
6337 DWORD needed = 0;
6338 DWORD numentries = 0;
6339 INT len;
6341 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6342 cbBuf, pcbNeeded, pcReturned);
6344 /* convert servername to unicode */
6345 if (pName) {
6346 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6347 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6348 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6350 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6351 needed = cbBuf * sizeof(WCHAR);
6352 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6353 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6355 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6356 if (pcbNeeded) needed = *pcbNeeded;
6357 /* HeapReAlloc return NULL, when bufferW was NULL */
6358 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6359 HeapAlloc(GetProcessHeap(), 0, needed);
6361 /* Try again with the large Buffer */
6362 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6364 numentries = pcReturned ? *pcReturned : 0;
6365 needed = 0;
6367 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6368 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6370 if (res) {
6371 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6372 DWORD entrysize = 0;
6373 DWORD index;
6374 LPSTR ptr;
6375 LPMONITOR_INFO_2W mi2w;
6376 LPMONITOR_INFO_2A mi2a;
6378 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6379 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6381 /* First pass: calculate the size for all Entries */
6382 mi2w = (LPMONITOR_INFO_2W) bufferW;
6383 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6384 index = 0;
6385 while (index < numentries) {
6386 index++;
6387 needed += entrysize; /* MONITOR_INFO_?A */
6388 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6390 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6391 NULL, 0, NULL, NULL);
6392 if (Level > 1) {
6393 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6394 NULL, 0, NULL, NULL);
6395 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6396 NULL, 0, NULL, NULL);
6398 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6399 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6400 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6403 /* check for errors and quit on failure */
6404 if (cbBuf < needed) {
6405 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6406 res = FALSE;
6407 goto emA_cleanup;
6409 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6410 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6411 cbBuf -= len ; /* free Bytes in the user-Buffer */
6412 mi2w = (LPMONITOR_INFO_2W) bufferW;
6413 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6414 index = 0;
6415 /* Second Pass: Fill the User Buffer (if we have one) */
6416 while ((index < numentries) && pMonitors) {
6417 index++;
6418 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6419 mi2a->pName = ptr;
6420 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6421 ptr, cbBuf , NULL, NULL);
6422 ptr += len;
6423 cbBuf -= len;
6424 if (Level > 1) {
6425 mi2a->pEnvironment = ptr;
6426 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6427 ptr, cbBuf, NULL, NULL);
6428 ptr += len;
6429 cbBuf -= len;
6431 mi2a->pDLLName = ptr;
6432 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6433 ptr, cbBuf, NULL, NULL);
6434 ptr += len;
6435 cbBuf -= len;
6437 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6438 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6439 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6442 emA_cleanup:
6443 if (pcbNeeded) *pcbNeeded = needed;
6444 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6446 HeapFree(GetProcessHeap(), 0, nameW);
6447 HeapFree(GetProcessHeap(), 0, bufferW);
6449 TRACE("returning %d with %d (%d byte for %d entries)\n",
6450 (res), GetLastError(), needed, numentries);
6452 return (res);
6456 /*****************************************************************************
6457 * EnumMonitorsW [WINSPOOL.@]
6459 * Enumerate available Port-Monitors
6461 * PARAMS
6462 * pName [I] Servername or NULL (local Computer)
6463 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6464 * pMonitors [O] PTR to Buffer that receives the Result
6465 * cbBuf [I] Size of Buffer at pMonitors
6466 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6467 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6469 * RETURNS
6470 * Success: TRUE
6471 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6474 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6475 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6478 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6479 cbBuf, pcbNeeded, pcReturned);
6481 if ((backend == NULL) && !load_backend()) return FALSE;
6483 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6484 SetLastError(RPC_X_NULL_REF_POINTER);
6485 return FALSE;
6488 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6491 /******************************************************************************
6492 * SpoolerInit (WINSPOOL.@)
6494 * Initialize the Spooler
6496 * RETURNS
6497 * Success: TRUE
6498 * Failure: FALSE
6500 * NOTES
6501 * The function fails on windows, when the spooler service is not running
6504 BOOL WINAPI SpoolerInit(void)
6507 if ((backend == NULL) && !load_backend()) return FALSE;
6508 return TRUE;
6511 /******************************************************************************
6512 * XcvDataW (WINSPOOL.@)
6514 * Execute commands in the Printmonitor DLL
6516 * PARAMS
6517 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6518 * pszDataName [i] Name of the command to execute
6519 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6520 * cbInputData [i] Size in Bytes of Buffer at pInputData
6521 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6522 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6523 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6524 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6526 * RETURNS
6527 * Success: TRUE
6528 * Failure: FALSE
6530 * NOTES
6531 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6532 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6534 * Minimal List of commands, that a Printmonitor DLL should support:
6536 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6537 *| "AddPort" : Add a Port
6538 *| "DeletePort": Delete a Port
6540 * Many Printmonitors support additional commands. Examples for localspl.dll:
6541 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6542 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6545 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6546 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6547 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6549 opened_printer_t *printer;
6551 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6552 pInputData, cbInputData, pOutputData,
6553 cbOutputData, pcbOutputNeeded, pdwStatus);
6555 if ((backend == NULL) && !load_backend()) return FALSE;
6557 printer = get_opened_printer(hXcv);
6558 if (!printer || (!printer->backend_printer)) {
6559 SetLastError(ERROR_INVALID_HANDLE);
6560 return FALSE;
6563 if (!pcbOutputNeeded) {
6564 SetLastError(ERROR_INVALID_PARAMETER);
6565 return FALSE;
6568 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6569 SetLastError(RPC_X_NULL_REF_POINTER);
6570 return FALSE;
6573 *pcbOutputNeeded = 0;
6575 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6576 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6580 /*****************************************************************************
6581 * EnumPrinterDataA [WINSPOOL.@]
6584 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6585 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6586 DWORD cbData, LPDWORD pcbData )
6588 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6589 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6590 return ERROR_NO_MORE_ITEMS;
6593 /*****************************************************************************
6594 * EnumPrinterDataW [WINSPOOL.@]
6597 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6598 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6599 DWORD cbData, LPDWORD pcbData )
6601 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6602 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6603 return ERROR_NO_MORE_ITEMS;
6606 /*****************************************************************************
6607 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6610 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6611 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6612 LPDWORD pcbNeeded, LPDWORD pcReturned)
6614 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6615 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6616 pcbNeeded, pcReturned);
6617 return FALSE;
6620 /*****************************************************************************
6621 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6624 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6625 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6626 LPDWORD pcbNeeded, LPDWORD pcReturned)
6628 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6629 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6630 pcbNeeded, pcReturned);
6631 return FALSE;
6634 /*****************************************************************************
6635 * EnumPrintProcessorsA [WINSPOOL.@]
6638 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6639 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6641 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6642 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6643 return FALSE;
6646 /*****************************************************************************
6647 * EnumPrintProcessorsW [WINSPOOL.@]
6650 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6651 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6653 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6654 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6655 cbBuf, pcbNeeded, pcbReturned);
6656 return FALSE;
6659 /*****************************************************************************
6660 * ExtDeviceMode [WINSPOOL.@]
6663 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6664 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6665 DWORD fMode)
6667 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6668 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6669 debugstr_a(pProfile), fMode);
6670 return -1;
6673 /*****************************************************************************
6674 * FindClosePrinterChangeNotification [WINSPOOL.@]
6677 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6679 FIXME("Stub: %p\n", hChange);
6680 return TRUE;
6683 /*****************************************************************************
6684 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6687 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6688 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6690 FIXME("Stub: %p %x %x %p\n",
6691 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6692 return INVALID_HANDLE_VALUE;
6695 /*****************************************************************************
6696 * FindNextPrinterChangeNotification [WINSPOOL.@]
6699 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6700 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6702 FIXME("Stub: %p %p %p %p\n",
6703 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6704 return FALSE;
6707 /*****************************************************************************
6708 * FreePrinterNotifyInfo [WINSPOOL.@]
6711 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6713 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6714 return TRUE;
6717 /*****************************************************************************
6718 * string_to_buf
6720 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6721 * ansi depending on the unicode parameter.
6723 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6725 if(!str)
6727 *size = 0;
6728 return TRUE;
6731 if(unicode)
6733 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6734 if(*size <= cb)
6736 memcpy(ptr, str, *size);
6737 return TRUE;
6739 return FALSE;
6741 else
6743 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6744 if(*size <= cb)
6746 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6747 return TRUE;
6749 return FALSE;
6753 /*****************************************************************************
6754 * get_job_info_1
6756 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6757 LPDWORD pcbNeeded, BOOL unicode)
6759 DWORD size, left = cbBuf;
6760 BOOL space = (cbBuf > 0);
6761 LPBYTE ptr = buf;
6763 *pcbNeeded = 0;
6765 if(space)
6767 ji1->JobId = job->job_id;
6770 string_to_buf(job->document_title, ptr, left, &size, unicode);
6771 if(space && size <= left)
6773 ji1->pDocument = (LPWSTR)ptr;
6774 ptr += size;
6775 left -= size;
6777 else
6778 space = FALSE;
6779 *pcbNeeded += size;
6781 return space;
6784 /*****************************************************************************
6785 * get_job_info_2
6787 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6788 LPDWORD pcbNeeded, BOOL unicode)
6790 DWORD size, left = cbBuf;
6791 BOOL space = (cbBuf > 0);
6792 LPBYTE ptr = buf;
6794 *pcbNeeded = 0;
6796 if(space)
6798 ji2->JobId = job->job_id;
6801 string_to_buf(job->document_title, ptr, left, &size, unicode);
6802 if(space && size <= left)
6804 ji2->pDocument = (LPWSTR)ptr;
6805 ptr += size;
6806 left -= size;
6808 else
6809 space = FALSE;
6810 *pcbNeeded += size;
6812 return space;
6815 /*****************************************************************************
6816 * get_job_info
6818 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6819 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6821 BOOL ret = FALSE;
6822 DWORD needed = 0, size;
6823 job_t *job;
6824 LPBYTE ptr = pJob;
6826 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6828 EnterCriticalSection(&printer_handles_cs);
6829 job = get_job(hPrinter, JobId);
6830 if(!job)
6831 goto end;
6833 switch(Level)
6835 case 1:
6836 size = sizeof(JOB_INFO_1W);
6837 if(cbBuf >= size)
6839 cbBuf -= size;
6840 ptr += size;
6841 memset(pJob, 0, size);
6843 else
6844 cbBuf = 0;
6845 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6846 needed += size;
6847 break;
6849 case 2:
6850 size = sizeof(JOB_INFO_2W);
6851 if(cbBuf >= size)
6853 cbBuf -= size;
6854 ptr += size;
6855 memset(pJob, 0, size);
6857 else
6858 cbBuf = 0;
6859 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6860 needed += size;
6861 break;
6863 case 3:
6864 size = sizeof(JOB_INFO_3);
6865 if(cbBuf >= size)
6867 cbBuf -= size;
6868 memset(pJob, 0, size);
6869 ret = TRUE;
6871 else
6872 cbBuf = 0;
6873 needed = size;
6874 break;
6876 default:
6877 SetLastError(ERROR_INVALID_LEVEL);
6878 goto end;
6880 if(pcbNeeded)
6881 *pcbNeeded = needed;
6882 end:
6883 LeaveCriticalSection(&printer_handles_cs);
6884 return ret;
6887 /*****************************************************************************
6888 * GetJobA [WINSPOOL.@]
6891 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6892 DWORD cbBuf, LPDWORD pcbNeeded)
6894 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6897 /*****************************************************************************
6898 * GetJobW [WINSPOOL.@]
6901 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6902 DWORD cbBuf, LPDWORD pcbNeeded)
6904 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6907 /*****************************************************************************
6908 * schedule_lpr
6910 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6912 char *unixname, *queue, *cmd;
6913 char fmt[] = "lpr -P%s %s";
6914 DWORD len;
6915 int r;
6917 if(!(unixname = wine_get_unix_file_name(filename)))
6918 return FALSE;
6920 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6921 queue = HeapAlloc(GetProcessHeap(), 0, len);
6922 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6924 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6925 sprintf(cmd, fmt, queue, unixname);
6927 TRACE("printing with: %s\n", cmd);
6928 r = system(cmd);
6930 HeapFree(GetProcessHeap(), 0, cmd);
6931 HeapFree(GetProcessHeap(), 0, queue);
6932 HeapFree(GetProcessHeap(), 0, unixname);
6933 return (r == 0);
6936 /*****************************************************************************
6937 * schedule_cups
6939 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6941 #ifdef SONAME_LIBCUPS
6942 if(pcupsPrintFile)
6944 char *unixname, *queue, *unix_doc_title;
6945 DWORD len;
6946 BOOL ret;
6948 if(!(unixname = wine_get_unix_file_name(filename)))
6949 return FALSE;
6951 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6952 queue = HeapAlloc(GetProcessHeap(), 0, len);
6953 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
6955 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
6956 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
6957 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
6959 TRACE("printing via cups\n");
6960 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
6961 HeapFree(GetProcessHeap(), 0, unix_doc_title);
6962 HeapFree(GetProcessHeap(), 0, queue);
6963 HeapFree(GetProcessHeap(), 0, unixname);
6964 return ret;
6966 else
6967 #endif
6969 return schedule_lpr(printer_name, filename);
6973 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6975 LPWSTR filename;
6977 switch(msg)
6979 case WM_INITDIALOG:
6980 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6981 return TRUE;
6983 case WM_COMMAND:
6984 if(HIWORD(wparam) == BN_CLICKED)
6986 if(LOWORD(wparam) == IDOK)
6988 HANDLE hf;
6989 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6990 LPWSTR *output;
6992 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6993 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6995 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6997 WCHAR caption[200], message[200];
6998 int mb_ret;
7000 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7001 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7002 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7003 if(mb_ret == IDCANCEL)
7005 HeapFree(GetProcessHeap(), 0, filename);
7006 return TRUE;
7009 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7010 if(hf == INVALID_HANDLE_VALUE)
7012 WCHAR caption[200], message[200];
7014 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7015 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7016 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7017 HeapFree(GetProcessHeap(), 0, filename);
7018 return TRUE;
7020 CloseHandle(hf);
7021 DeleteFileW(filename);
7022 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7023 *output = filename;
7024 EndDialog(hwnd, IDOK);
7025 return TRUE;
7027 if(LOWORD(wparam) == IDCANCEL)
7029 EndDialog(hwnd, IDCANCEL);
7030 return TRUE;
7033 return FALSE;
7035 return FALSE;
7038 /*****************************************************************************
7039 * get_filename
7041 static BOOL get_filename(LPWSTR *filename)
7043 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7044 file_dlg_proc, (LPARAM)filename) == IDOK;
7047 /*****************************************************************************
7048 * schedule_file
7050 static BOOL schedule_file(LPCWSTR filename)
7052 LPWSTR output = NULL;
7054 if(get_filename(&output))
7056 BOOL r;
7057 TRACE("copy to %s\n", debugstr_w(output));
7058 r = CopyFileW(filename, output, FALSE);
7059 HeapFree(GetProcessHeap(), 0, output);
7060 return r;
7062 return FALSE;
7065 /*****************************************************************************
7066 * schedule_pipe
7068 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7070 #ifdef HAVE_FORK
7071 char *unixname, *cmdA;
7072 DWORD len;
7073 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7074 BOOL ret = FALSE;
7075 char buf[1024];
7077 if(!(unixname = wine_get_unix_file_name(filename)))
7078 return FALSE;
7080 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7081 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7082 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7084 TRACE("printing with: %s\n", cmdA);
7086 if((file_fd = open(unixname, O_RDONLY)) == -1)
7087 goto end;
7089 if (pipe(fds))
7091 ERR("pipe() failed!\n");
7092 goto end;
7095 if (fork() == 0)
7097 close(0);
7098 dup2(fds[0], 0);
7099 close(fds[1]);
7101 /* reset signals that we previously set to SIG_IGN */
7102 signal(SIGPIPE, SIG_DFL);
7103 signal(SIGCHLD, SIG_DFL);
7105 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7106 _exit(1);
7109 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7110 write(fds[1], buf, no_read);
7112 ret = TRUE;
7114 end:
7115 if(file_fd != -1) close(file_fd);
7116 if(fds[0] != -1) close(fds[0]);
7117 if(fds[1] != -1) close(fds[1]);
7119 HeapFree(GetProcessHeap(), 0, cmdA);
7120 HeapFree(GetProcessHeap(), 0, unixname);
7121 return ret;
7122 #else
7123 return FALSE;
7124 #endif
7127 /*****************************************************************************
7128 * schedule_unixfile
7130 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7132 int in_fd, out_fd, no_read;
7133 char buf[1024];
7134 BOOL ret = FALSE;
7135 char *unixname, *outputA;
7136 DWORD len;
7138 if(!(unixname = wine_get_unix_file_name(filename)))
7139 return FALSE;
7141 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7142 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7143 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7145 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7146 in_fd = open(unixname, O_RDONLY);
7147 if(out_fd == -1 || in_fd == -1)
7148 goto end;
7150 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7151 write(out_fd, buf, no_read);
7153 ret = TRUE;
7154 end:
7155 if(in_fd != -1) close(in_fd);
7156 if(out_fd != -1) close(out_fd);
7157 HeapFree(GetProcessHeap(), 0, outputA);
7158 HeapFree(GetProcessHeap(), 0, unixname);
7159 return ret;
7162 /*****************************************************************************
7163 * ScheduleJob [WINSPOOL.@]
7166 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7168 opened_printer_t *printer;
7169 BOOL ret = FALSE;
7170 struct list *cursor, *cursor2;
7172 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7173 EnterCriticalSection(&printer_handles_cs);
7174 printer = get_opened_printer(hPrinter);
7175 if(!printer)
7176 goto end;
7178 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7180 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7181 HANDLE hf;
7183 if(job->job_id != dwJobID) continue;
7185 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7186 if(hf != INVALID_HANDLE_VALUE)
7188 PRINTER_INFO_5W *pi5;
7189 DWORD needed;
7190 HKEY hkey;
7191 WCHAR output[1024];
7192 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7193 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7195 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7196 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7197 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7198 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7199 debugstr_w(pi5->pPortName));
7201 output[0] = 0;
7203 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7204 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7206 DWORD type, count = sizeof(output);
7207 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7208 RegCloseKey(hkey);
7210 if(output[0] == '|')
7212 ret = schedule_pipe(output + 1, job->filename);
7214 else if(output[0])
7216 ret = schedule_unixfile(output, job->filename);
7218 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7220 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7222 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7224 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7226 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7228 ret = schedule_file(job->filename);
7230 else
7232 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7234 HeapFree(GetProcessHeap(), 0, pi5);
7235 CloseHandle(hf);
7236 DeleteFileW(job->filename);
7238 list_remove(cursor);
7239 HeapFree(GetProcessHeap(), 0, job->document_title);
7240 HeapFree(GetProcessHeap(), 0, job->filename);
7241 HeapFree(GetProcessHeap(), 0, job);
7242 break;
7244 end:
7245 LeaveCriticalSection(&printer_handles_cs);
7246 return ret;
7249 /*****************************************************************************
7250 * StartDocDlgA [WINSPOOL.@]
7252 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7254 UNICODE_STRING usBuffer;
7255 DOCINFOW docW;
7256 LPWSTR retW;
7257 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7258 LPSTR ret = NULL;
7260 docW.cbSize = sizeof(docW);
7261 if (doc->lpszDocName)
7263 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7264 if (!(docW.lpszDocName = docnameW)) return NULL;
7266 if (doc->lpszOutput)
7268 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7269 if (!(docW.lpszOutput = outputW)) return NULL;
7271 if (doc->lpszDatatype)
7273 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7274 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7276 docW.fwType = doc->fwType;
7278 retW = StartDocDlgW(hPrinter, &docW);
7280 if(retW)
7282 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7283 ret = HeapAlloc(GetProcessHeap(), 0, len);
7284 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7285 HeapFree(GetProcessHeap(), 0, retW);
7288 HeapFree(GetProcessHeap(), 0, datatypeW);
7289 HeapFree(GetProcessHeap(), 0, outputW);
7290 HeapFree(GetProcessHeap(), 0, docnameW);
7292 return ret;
7295 /*****************************************************************************
7296 * StartDocDlgW [WINSPOOL.@]
7298 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7299 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7300 * port is "FILE:". Also returns the full path if passed a relative path.
7302 * The caller should free the returned string from the process heap.
7304 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7306 LPWSTR ret = NULL;
7307 DWORD len, attr;
7309 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7311 PRINTER_INFO_5W *pi5;
7312 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7313 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7314 return NULL;
7315 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7316 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7317 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7319 HeapFree(GetProcessHeap(), 0, pi5);
7320 return NULL;
7322 HeapFree(GetProcessHeap(), 0, pi5);
7325 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7327 LPWSTR name;
7329 if (get_filename(&name))
7331 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7333 HeapFree(GetProcessHeap(), 0, name);
7334 return NULL;
7336 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7337 GetFullPathNameW(name, len, ret, NULL);
7338 HeapFree(GetProcessHeap(), 0, name);
7340 return ret;
7343 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7344 return NULL;
7346 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7347 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7349 attr = GetFileAttributesW(ret);
7350 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7352 HeapFree(GetProcessHeap(), 0, ret);
7353 ret = NULL;
7355 return ret;