wined3d: Get rid of the useless "isPBuffer" bitfield in struct wined3d_context.
[wine.git] / dlls / winspool.drv / info.c
blob7dac2b66501cf92f107eca73d2afb95c28879ca6
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2009 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
76 /* ############################### */
78 typedef struct {
79 DWORD job_id;
80 HANDLE hf;
81 } started_doc_t;
83 typedef struct {
84 struct list jobs;
85 LONG ref;
86 } jobqueue_t;
88 typedef struct {
89 LPWSTR name;
90 LPWSTR printername;
91 HANDLE backend_printer;
92 jobqueue_t *queue;
93 started_doc_t *doc;
94 } opened_printer_t;
96 typedef struct {
97 struct list entry;
98 DWORD job_id;
99 WCHAR *filename;
100 WCHAR *document_title;
101 } job_t;
104 typedef struct {
105 LPCWSTR envname;
106 LPCWSTR subdir;
107 DWORD driverversion;
108 LPCWSTR versionregpath;
109 LPCWSTR versionsubdir;
110 } printenv_t;
112 /* ############################### */
114 static opened_printer_t **printer_handles;
115 static UINT nb_printer_handles;
116 static LONG next_job_id = 1;
118 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
119 WORD fwCapability, LPSTR lpszOutput,
120 LPDEVMODEA lpdm );
121 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
122 LPSTR lpszDevice, LPSTR lpszPort,
123 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
124 DWORD fwMode );
126 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
127 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
128 'c','o','n','t','r','o','l','\\',
129 'P','r','i','n','t','\\',
130 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
131 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
133 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
134 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
135 'C','o','n','t','r','o','l','\\',
136 'P','r','i','n','t','\\',
137 'P','r','i','n','t','e','r','s',0};
139 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
141 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
142 'M','i','c','r','o','s','o','f','t','\\',
143 'W','i','n','d','o','w','s',' ','N','T','\\',
144 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
145 'W','i','n','d','o','w','s',0};
147 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
148 'M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s',' ','N','T','\\',
150 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
151 'D','e','v','i','c','e','s',0};
153 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
154 'M','i','c','r','o','s','o','f','t','\\',
155 'W','i','n','d','o','w','s',' ','N','T','\\',
156 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
157 'P','o','r','t','s',0};
159 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
160 'M','i','c','r','o','s','o','f','t','\\',
161 'W','i','n','d','o','w','s',' ','N','T','\\',
162 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
163 'P','r','i','n','t','e','r','P','o','r','t','s',0};
165 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
166 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
167 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
168 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
169 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
170 static const WCHAR subdir_x64W[] = {'x','6','4',0};
171 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
172 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
173 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
174 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
175 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
177 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
178 static const WCHAR backslashW[] = {'\\',0};
179 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
180 'i','o','n',' ','F','i','l','e',0};
181 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
182 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
183 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
184 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
185 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
186 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
187 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
188 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
189 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
190 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
191 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
192 static const WCHAR NameW[] = {'N','a','m','e',0};
193 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
194 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
195 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
196 static const WCHAR PortW[] = {'P','o','r','t',0};
197 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
198 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
199 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
200 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
201 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
202 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
203 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
204 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
205 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
206 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
207 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
208 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
209 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
210 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
211 static const WCHAR emptyStringW[] = {0};
213 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
215 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
216 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
217 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
219 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
220 'D','o','c','u','m','e','n','t',0};
222 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
223 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
224 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
225 0, sizeof(DRIVER_INFO_8W)};
228 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
229 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
230 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
231 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
232 sizeof(PRINTER_INFO_9W)};
234 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
235 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
236 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
238 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
240 /******************************************************************
241 * validate the user-supplied printing-environment [internal]
243 * PARAMS
244 * env [I] PTR to Environment-String or NULL
246 * RETURNS
247 * Failure: NULL
248 * Success: PTR to printenv_t
250 * NOTES
251 * An empty string is handled the same way as NULL.
252 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
256 static const printenv_t * validate_envW(LPCWSTR env)
258 const printenv_t *result = NULL;
259 unsigned int i;
261 TRACE("testing %s\n", debugstr_w(env));
262 if (env && env[0])
264 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
266 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
268 result = all_printenv[i];
269 break;
273 if (result == NULL) {
274 FIXME("unsupported Environment: %s\n", debugstr_w(env));
275 SetLastError(ERROR_INVALID_ENVIRONMENT);
277 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
279 else
281 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
283 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
285 return result;
289 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
290 if passed a NULL string. This returns NULLs to the result.
292 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
294 if ( (src) )
296 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
297 return usBufferPtr->Buffer;
299 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
300 return NULL;
303 static LPWSTR strdupW(LPCWSTR p)
305 LPWSTR ret;
306 DWORD len;
308 if(!p) return NULL;
309 len = (strlenW(p) + 1) * sizeof(WCHAR);
310 ret = HeapAlloc(GetProcessHeap(), 0, len);
311 memcpy(ret, p, len);
312 return ret;
315 static LPSTR strdupWtoA( LPCWSTR str )
317 LPSTR ret;
318 INT len;
320 if (!str) return NULL;
321 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
322 ret = HeapAlloc( GetProcessHeap(), 0, len );
323 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
324 return ret;
327 /******************************************************************
328 * Return the number of bytes for an multi_sz string.
329 * The result includes all \0s
330 * (specifically the extra \0, that is needed as multi_sz terminator).
332 #if 0
333 static int multi_sz_lenW(const WCHAR *str)
335 const WCHAR *ptr = str;
336 if(!str) return 0;
339 ptr += lstrlenW(ptr) + 1;
340 } while(*ptr);
342 return (ptr - str + 1) * sizeof(WCHAR);
344 #endif
345 /* ################################ */
347 static int multi_sz_lenA(const char *str)
349 const char *ptr = str;
350 if(!str) return 0;
353 ptr += lstrlenA(ptr) + 1;
354 } while(*ptr);
356 return ptr - str + 1;
359 static void
360 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
361 char qbuf[200];
363 /* If forcing, or no profile string entry for device yet, set the entry
365 * The always change entry if not WINEPS yet is discussable.
367 if (force ||
368 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
369 !strcmp(qbuf,"*") ||
370 !strstr(qbuf,"WINEPS.DRV")
372 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
373 HKEY hkey;
375 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
376 WriteProfileStringA("windows","device",buf);
377 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
378 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
379 RegCloseKey(hkey);
381 HeapFree(GetProcessHeap(),0,buf);
385 static BOOL add_printer_driver(const char *name)
387 DRIVER_INFO_3A di3a;
389 static char driver_9x[] = "wineps16.drv",
390 driver_nt[] = "wineps.drv",
391 env_9x[] = "Windows 4.0",
392 env_nt[] = "Windows NT x86",
393 data_file[] = "generic.ppd",
394 default_data_type[] = "RAW";
396 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
397 di3a.cVersion = 3;
398 di3a.pName = (char *)name;
399 di3a.pEnvironment = env_nt;
400 di3a.pDriverPath = driver_nt;
401 di3a.pDataFile = data_file;
402 di3a.pConfigFile = driver_nt;
403 di3a.pDefaultDataType = default_data_type;
405 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
406 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
408 di3a.cVersion = 0;
409 di3a.pEnvironment = env_9x;
410 di3a.pDriverPath = driver_9x;
411 di3a.pConfigFile = driver_9x;
412 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
413 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
415 return TRUE;
418 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
419 debugstr_a(di3a.pEnvironment), GetLastError());
420 return FALSE;
423 #ifdef SONAME_LIBCUPS
424 static typeof(cupsFreeDests) *pcupsFreeDests;
425 static typeof(cupsGetDests) *pcupsGetDests;
426 static typeof(cupsGetPPD) *pcupsGetPPD;
427 static typeof(cupsPrintFile) *pcupsPrintFile;
428 static void *cupshandle;
430 static BOOL CUPS_LoadPrinters(void)
432 int i, nrofdests;
433 BOOL hadprinter = FALSE, haddefault = FALSE;
434 cups_dest_t *dests;
435 PRINTER_INFO_2A pinfo2a;
436 char *port,*devline;
437 HKEY hkeyPrinter, hkeyPrinters, hkey;
438 char loaderror[256];
440 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
441 if (!cupshandle) {
442 TRACE("%s\n", loaderror);
443 return FALSE;
445 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
447 #define DYNCUPS(x) \
448 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
449 if (!p##x) return FALSE;
451 DYNCUPS(cupsFreeDests);
452 DYNCUPS(cupsGetPPD);
453 DYNCUPS(cupsGetDests);
454 DYNCUPS(cupsPrintFile);
455 #undef DYNCUPS
457 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
458 ERROR_SUCCESS) {
459 ERR("Can't create Printers key\n");
460 return FALSE;
463 nrofdests = pcupsGetDests(&dests);
464 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
465 for (i=0;i<nrofdests;i++) {
466 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
467 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
468 sprintf(port,"LPR:%s", dests[i].name);
469 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
470 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
471 sprintf(devline, "WINEPS.DRV,%s", port);
472 WriteProfileStringA("devices", dests[i].name, devline);
473 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
474 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
475 RegCloseKey(hkey);
478 lstrcatA(devline, ",15,45");
479 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
480 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
481 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
482 RegCloseKey(hkey);
485 HeapFree(GetProcessHeap(), 0, devline);
487 TRACE("Printer %d: %s\n", i, dests[i].name);
488 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
489 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
490 and continue */
491 TRACE("Printer already exists\n");
492 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
493 RegCloseKey(hkeyPrinter);
494 } else {
495 static CHAR data_type[] = "RAW",
496 print_proc[] = "WinPrint",
497 comment[] = "WINEPS Printer using CUPS",
498 location[] = "<physical location of printer>",
499 params[] = "<parameters?>",
500 share_name[] = "<share name?>",
501 sep_file[] = "<sep file?>";
503 add_printer_driver(dests[i].name);
505 memset(&pinfo2a,0,sizeof(pinfo2a));
506 pinfo2a.pPrinterName = dests[i].name;
507 pinfo2a.pDatatype = data_type;
508 pinfo2a.pPrintProcessor = print_proc;
509 pinfo2a.pDriverName = dests[i].name;
510 pinfo2a.pComment = comment;
511 pinfo2a.pLocation = location;
512 pinfo2a.pPortName = port;
513 pinfo2a.pParameters = params;
514 pinfo2a.pShareName = share_name;
515 pinfo2a.pSepFile = sep_file;
517 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
518 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
519 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
522 HeapFree(GetProcessHeap(),0,port);
524 hadprinter = TRUE;
525 if (dests[i].is_default) {
526 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
527 haddefault = TRUE;
530 if (hadprinter & !haddefault)
531 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
532 pcupsFreeDests(nrofdests, dests);
533 RegCloseKey(hkeyPrinters);
534 return hadprinter;
536 #endif
538 static BOOL
539 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
540 PRINTER_INFO_2A pinfo2a;
541 char *e,*s,*name,*prettyname,*devname;
542 BOOL ret = FALSE, set_default = FALSE;
543 char *port = NULL, *devline,*env_default;
544 HKEY hkeyPrinter, hkeyPrinters, hkey;
546 while (isspace(*pent)) pent++;
547 s = strchr(pent,':');
548 if(s) *s='\0';
549 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
550 strcpy(name,pent);
551 if(s) {
552 *s=':';
553 pent = s;
554 } else
555 pent = "";
557 TRACE("name=%s entry=%s\n",name, pent);
559 if(ispunct(*name)) { /* a tc entry, not a real printer */
560 TRACE("skipping tc entry\n");
561 goto end;
564 if(strstr(pent,":server")) { /* server only version so skip */
565 TRACE("skipping server entry\n");
566 goto end;
569 /* Determine whether this is a postscript printer. */
571 ret = TRUE;
572 env_default = getenv("PRINTER");
573 prettyname = name;
574 /* Get longest name, usually the one at the right for later display. */
575 while((s=strchr(prettyname,'|'))) {
576 *s = '\0';
577 e = s;
578 while(isspace(*--e)) *e = '\0';
579 TRACE("\t%s\n", debugstr_a(prettyname));
580 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
581 for(prettyname = s+1; isspace(*prettyname); prettyname++)
584 e = prettyname + strlen(prettyname);
585 while(isspace(*--e)) *e = '\0';
586 TRACE("\t%s\n", debugstr_a(prettyname));
587 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
589 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
590 * if it is too long, we use it as comment below. */
591 devname = prettyname;
592 if (strlen(devname)>=CCHDEVICENAME-1)
593 devname = name;
594 if (strlen(devname)>=CCHDEVICENAME-1) {
595 ret = FALSE;
596 goto end;
599 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
600 sprintf(port,"LPR:%s",name);
602 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
603 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
604 sprintf(devline, "WINEPS.DRV,%s", port);
605 WriteProfileStringA("devices", devname, devline);
606 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
607 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
608 RegCloseKey(hkey);
611 lstrcatA(devline, ",15,45");
612 WriteProfileStringA("PrinterPorts", devname, devline);
613 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
614 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
615 RegCloseKey(hkey);
618 HeapFree(GetProcessHeap(),0,devline);
620 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
621 ERROR_SUCCESS) {
622 ERR("Can't create Printers key\n");
623 ret = FALSE;
624 goto end;
626 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
627 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
628 and continue */
629 TRACE("Printer already exists\n");
630 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
631 RegCloseKey(hkeyPrinter);
632 } else {
633 static CHAR data_type[] = "RAW",
634 print_proc[] = "WinPrint",
635 comment[] = "WINEPS Printer using LPR",
636 params[] = "<parameters?>",
637 share_name[] = "<share name?>",
638 sep_file[] = "<sep file?>";
640 add_printer_driver(devname);
642 memset(&pinfo2a,0,sizeof(pinfo2a));
643 pinfo2a.pPrinterName = devname;
644 pinfo2a.pDatatype = data_type;
645 pinfo2a.pPrintProcessor = print_proc;
646 pinfo2a.pDriverName = devname;
647 pinfo2a.pComment = comment;
648 pinfo2a.pLocation = prettyname;
649 pinfo2a.pPortName = port;
650 pinfo2a.pParameters = params;
651 pinfo2a.pShareName = share_name;
652 pinfo2a.pSepFile = sep_file;
654 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
655 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
656 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
659 RegCloseKey(hkeyPrinters);
661 if (isfirst || set_default)
662 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
664 end:
665 HeapFree(GetProcessHeap(), 0, port);
666 HeapFree(GetProcessHeap(), 0, name);
667 return ret;
670 static BOOL
671 PRINTCAP_LoadPrinters(void) {
672 BOOL hadprinter = FALSE;
673 char buf[200];
674 FILE *f;
675 char *pent = NULL;
676 BOOL had_bash = FALSE;
678 f = fopen("/etc/printcap","r");
679 if (!f)
680 return FALSE;
682 while(fgets(buf,sizeof(buf),f)) {
683 char *start, *end;
685 end=strchr(buf,'\n');
686 if (end) *end='\0';
688 start = buf;
689 while(isspace(*start)) start++;
690 if(*start == '#' || *start == '\0')
691 continue;
693 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
694 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
695 HeapFree(GetProcessHeap(),0,pent);
696 pent = NULL;
699 if (end && *--end == '\\') {
700 *end = '\0';
701 had_bash = TRUE;
702 } else
703 had_bash = FALSE;
705 if (pent) {
706 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
707 strcat(pent,start);
708 } else {
709 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
710 strcpy(pent,start);
714 if(pent) {
715 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
716 HeapFree(GetProcessHeap(),0,pent);
718 fclose(f);
719 return hadprinter;
722 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
724 if (value)
725 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
726 (lstrlenW(value) + 1) * sizeof(WCHAR));
727 else
728 return ERROR_FILE_NOT_FOUND;
731 /******************************************************************
732 * get_servername_from_name (internal)
734 * for an external server, a copy of the serverpart from the full name is returned
737 static LPWSTR get_servername_from_name(LPCWSTR name)
739 LPWSTR server;
740 LPWSTR ptr;
741 WCHAR buffer[MAX_PATH];
742 DWORD len;
744 if (name == NULL) return NULL;
745 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
747 server = strdupW(&name[2]); /* skip over both backslash */
748 if (server == NULL) return NULL;
750 /* strip '\' and the printername */
751 ptr = strchrW(server, '\\');
752 if (ptr) ptr[0] = '\0';
754 TRACE("found %s\n", debugstr_w(server));
756 len = sizeof(buffer)/sizeof(buffer[0]);
757 if (GetComputerNameW(buffer, &len)) {
758 if (lstrcmpW(buffer, server) == 0) {
759 /* The requested Servername is our computername */
760 HeapFree(GetProcessHeap(), 0, server);
761 return NULL;
764 return server;
767 /******************************************************************
768 * get_basename_from_name (internal)
770 * skip over the serverpart from the full name
773 static LPCWSTR get_basename_from_name(LPCWSTR name)
775 if (name == NULL) return NULL;
776 if ((name[0] == '\\') && (name[1] == '\\')) {
777 /* skip over the servername and search for the following '\' */
778 name = strchrW(&name[2], '\\');
779 if ((name) && (name[1])) {
780 /* found a separator ('\') followed by a name:
781 skip over the separator and return the rest */
782 name++;
784 else
786 /* no basename present (we found only a servername) */
787 return NULL;
790 return name;
793 /******************************************************************
794 * get_opened_printer_entry
795 * Get the first place empty in the opened printer table
797 * ToDo:
798 * - pDefault is ignored
800 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
802 UINT_PTR handle = nb_printer_handles, i;
803 jobqueue_t *queue = NULL;
804 opened_printer_t *printer = NULL;
805 LPWSTR servername;
806 LPCWSTR printername;
808 if ((backend == NULL) && !load_backend()) return NULL;
810 servername = get_servername_from_name(name);
811 if (servername) {
812 FIXME("server %s not supported\n", debugstr_w(servername));
813 HeapFree(GetProcessHeap(), 0, servername);
814 SetLastError(ERROR_INVALID_PRINTER_NAME);
815 return NULL;
818 printername = get_basename_from_name(name);
819 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
821 /* an empty printername is invalid */
822 if (printername && (!printername[0])) {
823 SetLastError(ERROR_INVALID_PARAMETER);
824 return NULL;
827 EnterCriticalSection(&printer_handles_cs);
829 for (i = 0; i < nb_printer_handles; i++)
831 if (!printer_handles[i])
833 if(handle == nb_printer_handles)
834 handle = i;
836 else
838 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
839 queue = printer_handles[i]->queue;
843 if (handle >= nb_printer_handles)
845 opened_printer_t **new_array;
846 if (printer_handles)
847 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
848 (nb_printer_handles + 16) * sizeof(*new_array) );
849 else
850 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
851 (nb_printer_handles + 16) * sizeof(*new_array) );
853 if (!new_array)
855 handle = 0;
856 goto end;
858 printer_handles = new_array;
859 nb_printer_handles += 16;
862 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
864 handle = 0;
865 goto end;
868 /* get a printer handle from the backend */
869 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
870 handle = 0;
871 goto end;
874 /* clone the base name. This is NULL for the printserver */
875 printer->printername = strdupW(printername);
877 /* clone the full name */
878 printer->name = strdupW(name);
879 if (name && (!printer->name)) {
880 handle = 0;
881 goto end;
884 if(queue)
885 printer->queue = queue;
886 else
888 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
889 if (!printer->queue) {
890 handle = 0;
891 goto end;
893 list_init(&printer->queue->jobs);
894 printer->queue->ref = 0;
896 InterlockedIncrement(&printer->queue->ref);
898 printer_handles[handle] = printer;
899 handle++;
900 end:
901 LeaveCriticalSection(&printer_handles_cs);
902 if (!handle && printer) {
903 /* Something failed: Free all resources */
904 HeapFree(GetProcessHeap(), 0, printer->printername);
905 HeapFree(GetProcessHeap(), 0, printer->name);
906 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
907 HeapFree(GetProcessHeap(), 0, printer);
910 return (HANDLE)handle;
913 /******************************************************************
914 * get_opened_printer
915 * Get the pointer to the opened printer referred by the handle
917 static opened_printer_t *get_opened_printer(HANDLE hprn)
919 UINT_PTR idx = (UINT_PTR)hprn;
920 opened_printer_t *ret = NULL;
922 EnterCriticalSection(&printer_handles_cs);
924 if ((idx > 0) && (idx <= nb_printer_handles)) {
925 ret = printer_handles[idx - 1];
927 LeaveCriticalSection(&printer_handles_cs);
928 return ret;
931 /******************************************************************
932 * get_opened_printer_name
933 * Get the pointer to the opened printer name referred by the handle
935 static LPCWSTR get_opened_printer_name(HANDLE hprn)
937 opened_printer_t *printer = get_opened_printer(hprn);
938 if(!printer) return NULL;
939 return printer->name;
942 /******************************************************************
943 * WINSPOOL_GetOpenedPrinterRegKey
946 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
948 LPCWSTR name = get_opened_printer_name(hPrinter);
949 DWORD ret;
950 HKEY hkeyPrinters;
952 if(!name) return ERROR_INVALID_HANDLE;
954 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
955 ERROR_SUCCESS)
956 return ret;
958 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
960 ERR("Can't find opened printer %s in registry\n",
961 debugstr_w(name));
962 RegCloseKey(hkeyPrinters);
963 return ERROR_INVALID_PRINTER_NAME; /* ? */
965 RegCloseKey(hkeyPrinters);
966 return ERROR_SUCCESS;
969 void WINSPOOL_LoadSystemPrinters(void)
971 HKEY hkey, hkeyPrinters;
972 HANDLE hprn;
973 DWORD needed, num, i;
974 WCHAR PrinterName[256];
975 BOOL done = FALSE;
977 /* This ensures that all printer entries have a valid Name value. If causes
978 problems later if they don't. If one is found to be missed we create one
979 and set it equal to the name of the key */
980 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
981 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
982 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
983 for(i = 0; i < num; i++) {
984 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
985 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
986 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
987 set_reg_szW(hkey, NameW, PrinterName);
989 RegCloseKey(hkey);
994 RegCloseKey(hkeyPrinters);
997 /* We want to avoid calling AddPrinter on printers as much as
998 possible, because on cups printers this will (eventually) lead
999 to a call to cupsGetPPD which takes forever, even with non-cups
1000 printers AddPrinter takes a while. So we'll tag all printers that
1001 were automatically added last time around, if they still exist
1002 we'll leave them be otherwise we'll delete them. */
1003 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1004 if(needed) {
1005 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1006 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1007 for(i = 0; i < num; i++) {
1008 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1009 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1010 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1011 DWORD dw = 1;
1012 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1013 RegCloseKey(hkey);
1015 ClosePrinter(hprn);
1020 HeapFree(GetProcessHeap(), 0, pi);
1024 #ifdef SONAME_LIBCUPS
1025 done = CUPS_LoadPrinters();
1026 #endif
1028 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1029 PRINTCAP_LoadPrinters();
1031 /* Now enumerate the list again and delete any printers that are still tagged */
1032 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1033 if(needed) {
1034 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1035 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1036 for(i = 0; i < num; i++) {
1037 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1038 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1039 BOOL delete_driver = FALSE;
1040 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1041 DWORD dw, type, size = sizeof(dw);
1042 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1043 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1044 DeletePrinter(hprn);
1045 delete_driver = TRUE;
1047 RegCloseKey(hkey);
1049 ClosePrinter(hprn);
1050 if(delete_driver)
1051 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1056 HeapFree(GetProcessHeap(), 0, pi);
1059 return;
1063 /******************************************************************
1064 * get_job
1066 * Get the pointer to the specified job.
1067 * Should hold the printer_handles_cs before calling.
1069 static job_t *get_job(HANDLE hprn, DWORD JobId)
1071 opened_printer_t *printer = get_opened_printer(hprn);
1072 job_t *job;
1074 if(!printer) return NULL;
1075 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1077 if(job->job_id == JobId)
1078 return job;
1080 return NULL;
1083 /***********************************************************
1084 * DEVMODEcpyAtoW
1086 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1088 BOOL Formname;
1089 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1090 DWORD size;
1092 Formname = (dmA->dmSize > off_formname);
1093 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1094 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1095 dmW->dmDeviceName, CCHDEVICENAME);
1096 if(!Formname) {
1097 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1098 dmA->dmSize - CCHDEVICENAME);
1099 } else {
1100 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1101 off_formname - CCHDEVICENAME);
1102 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1103 dmW->dmFormName, CCHFORMNAME);
1104 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1105 (off_formname + CCHFORMNAME));
1107 dmW->dmSize = size;
1108 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1109 dmA->dmDriverExtra);
1110 return dmW;
1113 /***********************************************************
1114 * DEVMODEdupWtoA
1115 * Creates an ansi copy of supplied devmode
1117 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1119 LPDEVMODEA dmA;
1120 DWORD size;
1122 if (!dmW) return NULL;
1123 size = dmW->dmSize - CCHDEVICENAME -
1124 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1126 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1127 if (!dmA) return NULL;
1129 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1130 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1132 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1133 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1134 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1136 else
1138 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1139 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1140 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1141 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1143 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1146 dmA->dmSize = size;
1147 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1148 return dmA;
1151 /******************************************************************
1152 * convert_printerinfo_W_to_A [internal]
1155 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1156 DWORD level, DWORD outlen, DWORD numentries)
1158 DWORD id = 0;
1159 LPSTR ptr;
1160 INT len;
1162 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1164 len = pi_sizeof[level] * numentries;
1165 ptr = (LPSTR) out + len;
1166 outlen -= len;
1168 /* copy the numbers of all PRINTER_INFO_* first */
1169 memcpy(out, pPrintersW, len);
1171 while (id < numentries) {
1172 switch (level) {
1173 case 1:
1175 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1176 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1178 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1179 if (piW->pDescription) {
1180 piA->pDescription = ptr;
1181 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1182 ptr, outlen, NULL, NULL);
1183 ptr += len;
1184 outlen -= len;
1186 if (piW->pName) {
1187 piA->pName = ptr;
1188 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1189 ptr, outlen, NULL, NULL);
1190 ptr += len;
1191 outlen -= len;
1193 if (piW->pComment) {
1194 piA->pComment = ptr;
1195 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1196 ptr, outlen, NULL, NULL);
1197 ptr += len;
1198 outlen -= len;
1200 break;
1203 case 2:
1205 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1206 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1207 LPDEVMODEA dmA;
1209 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1210 if (piW->pServerName) {
1211 piA->pServerName = ptr;
1212 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1213 ptr, outlen, NULL, NULL);
1214 ptr += len;
1215 outlen -= len;
1217 if (piW->pPrinterName) {
1218 piA->pPrinterName = ptr;
1219 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1220 ptr, outlen, NULL, NULL);
1221 ptr += len;
1222 outlen -= len;
1224 if (piW->pShareName) {
1225 piA->pShareName = ptr;
1226 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1227 ptr, outlen, NULL, NULL);
1228 ptr += len;
1229 outlen -= len;
1231 if (piW->pPortName) {
1232 piA->pPortName = ptr;
1233 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1234 ptr, outlen, NULL, NULL);
1235 ptr += len;
1236 outlen -= len;
1238 if (piW->pDriverName) {
1239 piA->pDriverName = ptr;
1240 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1241 ptr, outlen, NULL, NULL);
1242 ptr += len;
1243 outlen -= len;
1245 if (piW->pComment) {
1246 piA->pComment = ptr;
1247 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1248 ptr, outlen, NULL, NULL);
1249 ptr += len;
1250 outlen -= len;
1252 if (piW->pLocation) {
1253 piA->pLocation = ptr;
1254 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1255 ptr, outlen, NULL, NULL);
1256 ptr += len;
1257 outlen -= len;
1260 dmA = DEVMODEdupWtoA(piW->pDevMode);
1261 if (dmA) {
1262 /* align DEVMODEA to a DWORD boundary */
1263 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1264 ptr += len;
1265 outlen -= len;
1267 piA->pDevMode = (LPDEVMODEA) ptr;
1268 len = dmA->dmSize + dmA->dmDriverExtra;
1269 memcpy(ptr, dmA, len);
1270 HeapFree(GetProcessHeap(), 0, dmA);
1272 ptr += len;
1273 outlen -= len;
1276 if (piW->pSepFile) {
1277 piA->pSepFile = ptr;
1278 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1279 ptr, outlen, NULL, NULL);
1280 ptr += len;
1281 outlen -= len;
1283 if (piW->pPrintProcessor) {
1284 piA->pPrintProcessor = ptr;
1285 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1286 ptr, outlen, NULL, NULL);
1287 ptr += len;
1288 outlen -= len;
1290 if (piW->pDatatype) {
1291 piA->pDatatype = ptr;
1292 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1293 ptr, outlen, NULL, NULL);
1294 ptr += len;
1295 outlen -= len;
1297 if (piW->pParameters) {
1298 piA->pParameters = ptr;
1299 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1300 ptr, outlen, NULL, NULL);
1301 ptr += len;
1302 outlen -= len;
1304 if (piW->pSecurityDescriptor) {
1305 piA->pSecurityDescriptor = NULL;
1306 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1308 break;
1311 case 4:
1313 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1314 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1316 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1318 if (piW->pPrinterName) {
1319 piA->pPrinterName = ptr;
1320 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1321 ptr, outlen, NULL, NULL);
1322 ptr += len;
1323 outlen -= len;
1325 if (piW->pServerName) {
1326 piA->pServerName = ptr;
1327 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1328 ptr, outlen, NULL, NULL);
1329 ptr += len;
1330 outlen -= len;
1332 break;
1335 case 5:
1337 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1338 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1340 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1342 if (piW->pPrinterName) {
1343 piA->pPrinterName = ptr;
1344 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1345 ptr, outlen, NULL, NULL);
1346 ptr += len;
1347 outlen -= len;
1349 if (piW->pPortName) {
1350 piA->pPortName = ptr;
1351 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1352 ptr, outlen, NULL, NULL);
1353 ptr += len;
1354 outlen -= len;
1356 break;
1359 default:
1360 FIXME("for level %u\n", level);
1362 pPrintersW += pi_sizeof[level];
1363 out += pi_sizeof[level];
1364 id++;
1368 /***********************************************************
1369 * PRINTER_INFO_2AtoW
1370 * Creates a unicode copy of PRINTER_INFO_2A on heap
1372 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1374 LPPRINTER_INFO_2W piW;
1375 UNICODE_STRING usBuffer;
1377 if(!piA) return NULL;
1378 piW = HeapAlloc(heap, 0, sizeof(*piW));
1379 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1381 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1382 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1383 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1384 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1385 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1386 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1387 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1388 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1389 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1390 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1391 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1392 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1393 return piW;
1396 /***********************************************************
1397 * FREE_PRINTER_INFO_2W
1398 * Free PRINTER_INFO_2W and all strings
1400 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1402 if(!piW) return;
1404 HeapFree(heap,0,piW->pServerName);
1405 HeapFree(heap,0,piW->pPrinterName);
1406 HeapFree(heap,0,piW->pShareName);
1407 HeapFree(heap,0,piW->pPortName);
1408 HeapFree(heap,0,piW->pDriverName);
1409 HeapFree(heap,0,piW->pComment);
1410 HeapFree(heap,0,piW->pLocation);
1411 HeapFree(heap,0,piW->pDevMode);
1412 HeapFree(heap,0,piW->pSepFile);
1413 HeapFree(heap,0,piW->pPrintProcessor);
1414 HeapFree(heap,0,piW->pDatatype);
1415 HeapFree(heap,0,piW->pParameters);
1416 HeapFree(heap,0,piW);
1417 return;
1420 /******************************************************************
1421 * DeviceCapabilities [WINSPOOL.@]
1422 * DeviceCapabilitiesA [WINSPOOL.@]
1425 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1426 LPSTR pOutput, LPDEVMODEA lpdm)
1428 INT ret;
1430 if (!GDI_CallDeviceCapabilities16)
1432 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1433 (LPCSTR)104 );
1434 if (!GDI_CallDeviceCapabilities16) return -1;
1436 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1438 /* If DC_PAPERSIZE map POINT16s to POINTs */
1439 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1440 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1441 POINT *pt = (POINT *)pOutput;
1442 INT i;
1443 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1444 for(i = 0; i < ret; i++, pt++)
1446 pt->x = tmp[i].x;
1447 pt->y = tmp[i].y;
1449 HeapFree( GetProcessHeap(), 0, tmp );
1451 return ret;
1455 /*****************************************************************************
1456 * DeviceCapabilitiesW [WINSPOOL.@]
1458 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1461 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1462 WORD fwCapability, LPWSTR pOutput,
1463 const DEVMODEW *pDevMode)
1465 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1466 LPSTR pDeviceA = strdupWtoA(pDevice);
1467 LPSTR pPortA = strdupWtoA(pPort);
1468 INT ret;
1470 if(pOutput && (fwCapability == DC_BINNAMES ||
1471 fwCapability == DC_FILEDEPENDENCIES ||
1472 fwCapability == DC_PAPERNAMES)) {
1473 /* These need A -> W translation */
1474 INT size = 0, i;
1475 LPSTR pOutputA;
1476 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1477 dmA);
1478 if(ret == -1)
1479 return ret;
1480 switch(fwCapability) {
1481 case DC_BINNAMES:
1482 size = 24;
1483 break;
1484 case DC_PAPERNAMES:
1485 case DC_FILEDEPENDENCIES:
1486 size = 64;
1487 break;
1489 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1490 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1491 dmA);
1492 for(i = 0; i < ret; i++)
1493 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1494 pOutput + (i * size), size);
1495 HeapFree(GetProcessHeap(), 0, pOutputA);
1496 } else {
1497 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1498 (LPSTR)pOutput, dmA);
1500 HeapFree(GetProcessHeap(),0,pPortA);
1501 HeapFree(GetProcessHeap(),0,pDeviceA);
1502 HeapFree(GetProcessHeap(),0,dmA);
1503 return ret;
1506 /******************************************************************
1507 * DocumentPropertiesA [WINSPOOL.@]
1509 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1511 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1512 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1513 LPDEVMODEA pDevModeInput,DWORD fMode )
1515 LPSTR lpName = pDeviceName;
1516 static CHAR port[] = "LPT1:";
1517 LONG ret;
1519 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1520 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1523 if(!pDeviceName) {
1524 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1525 if(!lpNameW) {
1526 ERR("no name from hPrinter?\n");
1527 SetLastError(ERROR_INVALID_HANDLE);
1528 return -1;
1530 lpName = strdupWtoA(lpNameW);
1533 if (!GDI_CallExtDeviceMode16)
1535 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1536 (LPCSTR)102 );
1537 if (!GDI_CallExtDeviceMode16) {
1538 ERR("No CallExtDeviceMode16?\n");
1539 return -1;
1542 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1543 pDevModeInput, NULL, fMode);
1545 if(!pDeviceName)
1546 HeapFree(GetProcessHeap(),0,lpName);
1547 return ret;
1551 /*****************************************************************************
1552 * DocumentPropertiesW (WINSPOOL.@)
1554 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1556 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1557 LPWSTR pDeviceName,
1558 LPDEVMODEW pDevModeOutput,
1559 LPDEVMODEW pDevModeInput, DWORD fMode)
1562 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1563 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1564 LPDEVMODEA pDevModeOutputA = NULL;
1565 LONG ret;
1567 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1568 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1569 fMode);
1570 if(pDevModeOutput) {
1571 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1572 if(ret < 0) return ret;
1573 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1575 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1576 pDevModeInputA, fMode);
1577 if(pDevModeOutput) {
1578 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1579 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1581 if(fMode == 0 && ret > 0)
1582 ret += (CCHDEVICENAME + CCHFORMNAME);
1583 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1584 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1585 return ret;
1588 /******************************************************************
1589 * OpenPrinterA [WINSPOOL.@]
1591 * See OpenPrinterW.
1594 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1595 LPPRINTER_DEFAULTSA pDefault)
1597 UNICODE_STRING lpPrinterNameW;
1598 UNICODE_STRING usBuffer;
1599 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1600 PWSTR pwstrPrinterNameW;
1601 BOOL ret;
1603 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1605 if(pDefault) {
1606 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1607 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1608 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1609 pDefaultW = &DefaultW;
1611 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1612 if(pDefault) {
1613 RtlFreeUnicodeString(&usBuffer);
1614 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1616 RtlFreeUnicodeString(&lpPrinterNameW);
1617 return ret;
1620 /******************************************************************
1621 * OpenPrinterW [WINSPOOL.@]
1623 * Open a Printer / Printserver or a Printer-Object
1625 * PARAMS
1626 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1627 * phPrinter [O] The resulting Handle is stored here
1628 * pDefault [I] PTR to Default Printer Settings or NULL
1630 * RETURNS
1631 * Success: TRUE
1632 * Failure: FALSE
1634 * NOTES
1635 * lpPrinterName is one of:
1636 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1637 *| Printer: "PrinterName"
1638 *| Printer-Object: "PrinterName,Job xxx"
1639 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1640 *| XcvPort: "Servername,XcvPort PortName"
1642 * BUGS
1643 *| Printer-Object not supported
1644 *| pDefaults is ignored
1647 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1650 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1651 if (pDefault) {
1652 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1653 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1656 if(!phPrinter) {
1657 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1658 SetLastError(ERROR_INVALID_PARAMETER);
1659 return FALSE;
1662 /* Get the unique handle of the printer or Printserver */
1663 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1664 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1665 return (*phPrinter != 0);
1668 /******************************************************************
1669 * AddMonitorA [WINSPOOL.@]
1671 * See AddMonitorW.
1674 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1676 LPWSTR nameW = NULL;
1677 INT len;
1678 BOOL res;
1679 LPMONITOR_INFO_2A mi2a;
1680 MONITOR_INFO_2W mi2w;
1682 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1683 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1684 debugstr_a(mi2a ? mi2a->pName : NULL),
1685 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1686 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1688 if (Level != 2) {
1689 SetLastError(ERROR_INVALID_LEVEL);
1690 return FALSE;
1693 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1694 if (mi2a == NULL) {
1695 return FALSE;
1698 if (pName) {
1699 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1700 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1701 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1704 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1705 if (mi2a->pName) {
1706 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1707 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1708 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1710 if (mi2a->pEnvironment) {
1711 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1712 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1713 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1715 if (mi2a->pDLLName) {
1716 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1717 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1718 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1721 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1723 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1724 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1725 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1727 HeapFree(GetProcessHeap(), 0, nameW);
1728 return (res);
1731 /******************************************************************************
1732 * AddMonitorW [WINSPOOL.@]
1734 * Install a Printmonitor
1736 * PARAMS
1737 * pName [I] Servername or NULL (local Computer)
1738 * Level [I] Structure-Level (Must be 2)
1739 * pMonitors [I] PTR to MONITOR_INFO_2
1741 * RETURNS
1742 * Success: TRUE
1743 * Failure: FALSE
1745 * NOTES
1746 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1749 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1751 LPMONITOR_INFO_2W mi2w;
1753 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1754 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1755 debugstr_w(mi2w ? mi2w->pName : NULL),
1756 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1757 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1759 if ((backend == NULL) && !load_backend()) return FALSE;
1761 if (Level != 2) {
1762 SetLastError(ERROR_INVALID_LEVEL);
1763 return FALSE;
1766 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1767 if (mi2w == NULL) {
1768 return FALSE;
1771 return backend->fpAddMonitor(pName, Level, pMonitors);
1774 /******************************************************************
1775 * DeletePrinterDriverA [WINSPOOL.@]
1778 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1780 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1783 /******************************************************************
1784 * DeletePrinterDriverW [WINSPOOL.@]
1787 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1789 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
1792 /******************************************************************
1793 * DeleteMonitorA [WINSPOOL.@]
1795 * See DeleteMonitorW.
1798 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1800 LPWSTR nameW = NULL;
1801 LPWSTR EnvironmentW = NULL;
1802 LPWSTR MonitorNameW = NULL;
1803 BOOL res;
1804 INT len;
1806 if (pName) {
1807 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1808 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1809 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1812 if (pEnvironment) {
1813 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1814 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1815 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1817 if (pMonitorName) {
1818 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1819 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1820 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1823 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1825 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1826 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1827 HeapFree(GetProcessHeap(), 0, nameW);
1828 return (res);
1831 /******************************************************************
1832 * DeleteMonitorW [WINSPOOL.@]
1834 * Delete a specific Printmonitor from a Printing-Environment
1836 * PARAMS
1837 * pName [I] Servername or NULL (local Computer)
1838 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1839 * pMonitorName [I] Name of the Monitor, that should be deleted
1841 * RETURNS
1842 * Success: TRUE
1843 * Failure: FALSE
1845 * NOTES
1846 * pEnvironment is ignored in Windows for the local Computer.
1849 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1852 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1853 debugstr_w(pMonitorName));
1855 if ((backend == NULL) && !load_backend()) return FALSE;
1857 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
1861 /******************************************************************
1862 * DeletePortA [WINSPOOL.@]
1864 * See DeletePortW.
1867 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1869 LPWSTR nameW = NULL;
1870 LPWSTR portW = NULL;
1871 INT len;
1872 DWORD res;
1874 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
1876 /* convert servername to unicode */
1877 if (pName) {
1878 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1879 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1880 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1883 /* convert portname to unicode */
1884 if (pPortName) {
1885 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
1886 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1887 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
1890 res = DeletePortW(nameW, hWnd, portW);
1891 HeapFree(GetProcessHeap(), 0, nameW);
1892 HeapFree(GetProcessHeap(), 0, portW);
1893 return res;
1896 /******************************************************************
1897 * DeletePortW [WINSPOOL.@]
1899 * Delete a specific Port
1901 * PARAMS
1902 * pName [I] Servername or NULL (local Computer)
1903 * hWnd [I] Handle to parent Window for the Dialog-Box
1904 * pPortName [I] Name of the Port, that should be deleted
1906 * RETURNS
1907 * Success: TRUE
1908 * Failure: FALSE
1911 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1913 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1915 if ((backend == NULL) && !load_backend()) return FALSE;
1917 if (!pPortName) {
1918 SetLastError(RPC_X_NULL_REF_POINTER);
1919 return FALSE;
1922 return backend->fpDeletePort(pName, hWnd, pPortName);
1925 /******************************************************************************
1926 * SetPrinterW [WINSPOOL.@]
1928 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1930 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
1931 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1932 return FALSE;
1935 /******************************************************************************
1936 * WritePrinter [WINSPOOL.@]
1938 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1940 opened_printer_t *printer;
1941 BOOL ret = FALSE;
1943 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1945 EnterCriticalSection(&printer_handles_cs);
1946 printer = get_opened_printer(hPrinter);
1947 if(!printer)
1949 SetLastError(ERROR_INVALID_HANDLE);
1950 goto end;
1953 if(!printer->doc)
1955 SetLastError(ERROR_SPL_NO_STARTDOC);
1956 goto end;
1959 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1960 end:
1961 LeaveCriticalSection(&printer_handles_cs);
1962 return ret;
1965 /*****************************************************************************
1966 * AddFormA [WINSPOOL.@]
1968 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1970 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1971 return 1;
1974 /*****************************************************************************
1975 * AddFormW [WINSPOOL.@]
1977 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1979 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1980 return 1;
1983 /*****************************************************************************
1984 * AddJobA [WINSPOOL.@]
1986 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1988 BOOL ret;
1989 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1990 DWORD needed;
1992 if(Level != 1) {
1993 SetLastError(ERROR_INVALID_LEVEL);
1994 return FALSE;
1997 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1999 if(ret) {
2000 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2001 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2002 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2003 if(*pcbNeeded > cbBuf) {
2004 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2005 ret = FALSE;
2006 } else {
2007 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2008 addjobA->JobId = addjobW->JobId;
2009 addjobA->Path = (char *)(addjobA + 1);
2010 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2013 return ret;
2016 /*****************************************************************************
2017 * AddJobW [WINSPOOL.@]
2019 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2021 opened_printer_t *printer;
2022 job_t *job;
2023 BOOL ret = FALSE;
2024 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2025 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2026 WCHAR path[MAX_PATH], filename[MAX_PATH];
2027 DWORD len;
2028 ADDJOB_INFO_1W *addjob;
2030 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2032 EnterCriticalSection(&printer_handles_cs);
2034 printer = get_opened_printer(hPrinter);
2036 if(!printer) {
2037 SetLastError(ERROR_INVALID_HANDLE);
2038 goto end;
2041 if(Level != 1) {
2042 SetLastError(ERROR_INVALID_LEVEL);
2043 goto end;
2046 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2047 if(!job)
2048 goto end;
2050 job->job_id = InterlockedIncrement(&next_job_id);
2052 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2053 if(path[len - 1] != '\\')
2054 path[len++] = '\\';
2055 memcpy(path + len, spool_path, sizeof(spool_path));
2056 sprintfW(filename, fmtW, path, job->job_id);
2058 len = strlenW(filename);
2059 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2060 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2061 job->document_title = strdupW(default_doc_title);
2062 list_add_tail(&printer->queue->jobs, &job->entry);
2064 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2065 if(*pcbNeeded <= cbBuf) {
2066 addjob = (ADDJOB_INFO_1W*)pData;
2067 addjob->JobId = job->job_id;
2068 addjob->Path = (WCHAR *)(addjob + 1);
2069 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2070 ret = TRUE;
2071 } else
2072 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2074 end:
2075 LeaveCriticalSection(&printer_handles_cs);
2076 return ret;
2079 /*****************************************************************************
2080 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2082 * Return the PATH for the Print-Processors
2084 * See GetPrintProcessorDirectoryW.
2088 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2089 DWORD level, LPBYTE Info,
2090 DWORD cbBuf, LPDWORD pcbNeeded)
2092 LPWSTR serverW = NULL;
2093 LPWSTR envW = NULL;
2094 BOOL ret;
2095 INT len;
2097 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2098 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2101 if (server) {
2102 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2103 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2104 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2107 if (env) {
2108 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2109 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2110 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2113 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2114 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2116 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2117 cbBuf, pcbNeeded);
2119 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2120 cbBuf, NULL, NULL) > 0;
2123 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2124 HeapFree(GetProcessHeap(), 0, envW);
2125 HeapFree(GetProcessHeap(), 0, serverW);
2126 return ret;
2129 /*****************************************************************************
2130 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2132 * Return the PATH for the Print-Processors
2134 * PARAMS
2135 * server [I] Servername (NT only) or NULL (local Computer)
2136 * env [I] Printing-Environment (see below) or NULL (Default)
2137 * level [I] Structure-Level (must be 1)
2138 * Info [O] PTR to Buffer that receives the Result
2139 * cbBuf [I] Size of Buffer at "Info"
2140 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2141 * required for the Buffer at "Info"
2143 * RETURNS
2144 * Success: TRUE and in pcbNeeded the Bytes used in Info
2145 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2146 * if cbBuf is too small
2148 * Native Values returned in Info on Success:
2149 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2150 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2151 *| win9x(Windows 4.0): "%winsysdir%"
2153 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2155 * BUGS
2156 * Only NULL or "" is supported for server
2159 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2160 DWORD level, LPBYTE Info,
2161 DWORD cbBuf, LPDWORD pcbNeeded)
2164 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2165 Info, cbBuf, pcbNeeded);
2167 if ((backend == NULL) && !load_backend()) return FALSE;
2169 if (level != 1) {
2170 /* (Level != 1) is ignored in win9x */
2171 SetLastError(ERROR_INVALID_LEVEL);
2172 return FALSE;
2175 if (pcbNeeded == NULL) {
2176 /* (pcbNeeded == NULL) is ignored in win9x */
2177 SetLastError(RPC_X_NULL_REF_POINTER);
2178 return FALSE;
2181 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2184 /*****************************************************************************
2185 * WINSPOOL_OpenDriverReg [internal]
2187 * opens the registry for the printer drivers depending on the given input
2188 * variable pEnvironment
2190 * RETURNS:
2191 * the opened hkey on success
2192 * NULL on error
2194 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2196 HKEY retval = NULL;
2197 LPWSTR buffer;
2198 const printenv_t * env;
2200 TRACE("(%s, %d)\n",
2201 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2203 if (!pEnvironment || unicode) {
2204 /* pEnvironment was NULL or a Unicode-String: use it direct */
2205 env = validate_envW(pEnvironment);
2207 else
2209 /* pEnvironment was an ANSI-String: convert to unicode first */
2210 LPWSTR buffer;
2211 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2212 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2213 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2214 env = validate_envW(buffer);
2215 HeapFree(GetProcessHeap(), 0, buffer);
2217 if (!env) return NULL;
2219 buffer = HeapAlloc( GetProcessHeap(), 0,
2220 (strlenW(DriversW) + strlenW(env->envname) +
2221 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2222 if(buffer) {
2223 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2224 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2225 HeapFree(GetProcessHeap(), 0, buffer);
2227 return retval;
2230 /*****************************************************************************
2231 * AddPrinterW [WINSPOOL.@]
2233 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2235 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2236 LPDEVMODEA dmA;
2237 LPDEVMODEW dmW;
2238 HANDLE retval;
2239 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2240 LONG size;
2241 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2242 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2243 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2244 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2245 statusW[] = {'S','t','a','t','u','s',0},
2246 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2248 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2250 if(pName != NULL) {
2251 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2252 SetLastError(ERROR_INVALID_PARAMETER);
2253 return 0;
2255 if(Level != 2) {
2256 ERR("Level = %d, unsupported!\n", Level);
2257 SetLastError(ERROR_INVALID_LEVEL);
2258 return 0;
2260 if(!pPrinter) {
2261 SetLastError(ERROR_INVALID_PARAMETER);
2262 return 0;
2264 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2265 ERROR_SUCCESS) {
2266 ERR("Can't create Printers key\n");
2267 return 0;
2269 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2270 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2271 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2272 RegCloseKey(hkeyPrinter);
2273 RegCloseKey(hkeyPrinters);
2274 return 0;
2276 RegCloseKey(hkeyPrinter);
2278 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2279 if(!hkeyDrivers) {
2280 ERR("Can't create Drivers key\n");
2281 RegCloseKey(hkeyPrinters);
2282 return 0;
2284 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2285 ERROR_SUCCESS) {
2286 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2287 RegCloseKey(hkeyPrinters);
2288 RegCloseKey(hkeyDrivers);
2289 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2290 return 0;
2292 RegCloseKey(hkeyDriver);
2293 RegCloseKey(hkeyDrivers);
2295 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2296 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2297 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2298 RegCloseKey(hkeyPrinters);
2299 return 0;
2302 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2303 ERROR_SUCCESS) {
2304 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2305 SetLastError(ERROR_INVALID_PRINTER_NAME);
2306 RegCloseKey(hkeyPrinters);
2307 return 0;
2309 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2310 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2311 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2313 /* See if we can load the driver. We may need the devmode structure anyway
2315 * FIXME:
2316 * Note that DocumentPropertiesW will briefly try to open the printer we
2317 * just create to find a DEVMODEA struct (it will use the WINEPS default
2318 * one in case it is not there, so we are ok).
2320 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2322 if(size < 0) {
2323 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2324 size = sizeof(DEVMODEW);
2326 if(pi->pDevMode)
2327 dmW = pi->pDevMode;
2328 else
2330 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2331 dmW->dmSize = size;
2332 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2334 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2335 HeapFree(GetProcessHeap(),0,dmW);
2336 dmW=NULL;
2338 else
2340 /* set devmode to printer name */
2341 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2345 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2346 and we support these drivers. NT writes DEVMODEW so somehow
2347 we'll need to distinguish between these when we support NT
2348 drivers */
2349 if (dmW)
2351 dmA = DEVMODEdupWtoA(dmW);
2352 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2353 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2354 HeapFree(GetProcessHeap(), 0, dmA);
2355 if(!pi->pDevMode)
2356 HeapFree(GetProcessHeap(), 0, dmW);
2358 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2359 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2360 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2361 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2363 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2364 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2365 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2366 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2367 (LPBYTE)&pi->Priority, sizeof(DWORD));
2368 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2369 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2370 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2371 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2372 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2373 (LPBYTE)&pi->Status, sizeof(DWORD));
2374 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2375 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2377 RegCloseKey(hkeyPrinter);
2378 RegCloseKey(hkeyPrinters);
2379 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2380 ERR("OpenPrinter failing\n");
2381 return 0;
2383 return retval;
2386 /*****************************************************************************
2387 * AddPrinterA [WINSPOOL.@]
2389 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2391 UNICODE_STRING pNameW;
2392 PWSTR pwstrNameW;
2393 PRINTER_INFO_2W *piW;
2394 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2395 HANDLE ret;
2397 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2398 if(Level != 2) {
2399 ERR("Level = %d, unsupported!\n", Level);
2400 SetLastError(ERROR_INVALID_LEVEL);
2401 return 0;
2403 pwstrNameW = asciitounicode(&pNameW,pName);
2404 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2406 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2408 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2409 RtlFreeUnicodeString(&pNameW);
2410 return ret;
2414 /*****************************************************************************
2415 * ClosePrinter [WINSPOOL.@]
2417 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2419 UINT_PTR i = (UINT_PTR)hPrinter;
2420 opened_printer_t *printer = NULL;
2421 BOOL ret = FALSE;
2423 TRACE("(%p)\n", hPrinter);
2425 EnterCriticalSection(&printer_handles_cs);
2427 if ((i > 0) && (i <= nb_printer_handles))
2428 printer = printer_handles[i - 1];
2431 if(printer)
2433 struct list *cursor, *cursor2;
2435 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2437 if (printer->backend_printer) {
2438 backend->fpClosePrinter(printer->backend_printer);
2441 if(printer->doc)
2442 EndDocPrinter(hPrinter);
2444 if(InterlockedDecrement(&printer->queue->ref) == 0)
2446 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2448 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2449 ScheduleJob(hPrinter, job->job_id);
2451 HeapFree(GetProcessHeap(), 0, printer->queue);
2454 HeapFree(GetProcessHeap(), 0, printer->printername);
2455 HeapFree(GetProcessHeap(), 0, printer->name);
2456 HeapFree(GetProcessHeap(), 0, printer);
2457 printer_handles[i - 1] = NULL;
2458 ret = TRUE;
2460 LeaveCriticalSection(&printer_handles_cs);
2461 return ret;
2464 /*****************************************************************************
2465 * DeleteFormA [WINSPOOL.@]
2467 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2469 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2470 return 1;
2473 /*****************************************************************************
2474 * DeleteFormW [WINSPOOL.@]
2476 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2478 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2479 return 1;
2482 /*****************************************************************************
2483 * DeletePrinter [WINSPOOL.@]
2485 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2487 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2488 HKEY hkeyPrinters, hkey;
2490 if(!lpNameW) {
2491 SetLastError(ERROR_INVALID_HANDLE);
2492 return FALSE;
2494 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2495 RegDeleteTreeW(hkeyPrinters, lpNameW);
2496 RegCloseKey(hkeyPrinters);
2498 WriteProfileStringW(devicesW, lpNameW, NULL);
2499 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2501 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2502 RegDeleteValueW(hkey, lpNameW);
2503 RegCloseKey(hkey);
2506 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2507 RegDeleteValueW(hkey, lpNameW);
2508 RegCloseKey(hkey);
2510 return TRUE;
2513 /*****************************************************************************
2514 * SetPrinterA [WINSPOOL.@]
2516 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2517 DWORD Command)
2519 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2520 return FALSE;
2523 /*****************************************************************************
2524 * SetJobA [WINSPOOL.@]
2526 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2527 LPBYTE pJob, DWORD Command)
2529 BOOL ret;
2530 LPBYTE JobW;
2531 UNICODE_STRING usBuffer;
2533 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2535 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2536 are all ignored by SetJob, so we don't bother copying them */
2537 switch(Level)
2539 case 0:
2540 JobW = NULL;
2541 break;
2542 case 1:
2544 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2545 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2547 JobW = (LPBYTE)info1W;
2548 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2549 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2550 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2551 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2552 info1W->Status = info1A->Status;
2553 info1W->Priority = info1A->Priority;
2554 info1W->Position = info1A->Position;
2555 info1W->PagesPrinted = info1A->PagesPrinted;
2556 break;
2558 case 2:
2560 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2561 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2563 JobW = (LPBYTE)info2W;
2564 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2565 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2566 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2567 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2568 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2569 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2570 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2571 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2572 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2573 info2W->Status = info2A->Status;
2574 info2W->Priority = info2A->Priority;
2575 info2W->Position = info2A->Position;
2576 info2W->StartTime = info2A->StartTime;
2577 info2W->UntilTime = info2A->UntilTime;
2578 info2W->PagesPrinted = info2A->PagesPrinted;
2579 break;
2581 case 3:
2582 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2583 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2584 break;
2585 default:
2586 SetLastError(ERROR_INVALID_LEVEL);
2587 return FALSE;
2590 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2592 switch(Level)
2594 case 1:
2596 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2597 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2598 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2599 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2600 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2601 break;
2603 case 2:
2605 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2606 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2607 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2608 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2609 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2610 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2611 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2612 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2613 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2614 break;
2617 HeapFree(GetProcessHeap(), 0, JobW);
2619 return ret;
2622 /*****************************************************************************
2623 * SetJobW [WINSPOOL.@]
2625 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2626 LPBYTE pJob, DWORD Command)
2628 BOOL ret = FALSE;
2629 job_t *job;
2631 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2632 FIXME("Ignoring everything other than document title\n");
2634 EnterCriticalSection(&printer_handles_cs);
2635 job = get_job(hPrinter, JobId);
2636 if(!job)
2637 goto end;
2639 switch(Level)
2641 case 0:
2642 break;
2643 case 1:
2645 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2646 HeapFree(GetProcessHeap(), 0, job->document_title);
2647 job->document_title = strdupW(info1->pDocument);
2648 break;
2650 case 2:
2652 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2653 HeapFree(GetProcessHeap(), 0, job->document_title);
2654 job->document_title = strdupW(info2->pDocument);
2655 break;
2657 case 3:
2658 break;
2659 default:
2660 SetLastError(ERROR_INVALID_LEVEL);
2661 goto end;
2663 ret = TRUE;
2664 end:
2665 LeaveCriticalSection(&printer_handles_cs);
2666 return ret;
2669 /*****************************************************************************
2670 * EndDocPrinter [WINSPOOL.@]
2672 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2674 opened_printer_t *printer;
2675 BOOL ret = FALSE;
2676 TRACE("(%p)\n", hPrinter);
2678 EnterCriticalSection(&printer_handles_cs);
2680 printer = get_opened_printer(hPrinter);
2681 if(!printer)
2683 SetLastError(ERROR_INVALID_HANDLE);
2684 goto end;
2687 if(!printer->doc)
2689 SetLastError(ERROR_SPL_NO_STARTDOC);
2690 goto end;
2693 CloseHandle(printer->doc->hf);
2694 ScheduleJob(hPrinter, printer->doc->job_id);
2695 HeapFree(GetProcessHeap(), 0, printer->doc);
2696 printer->doc = NULL;
2697 ret = TRUE;
2698 end:
2699 LeaveCriticalSection(&printer_handles_cs);
2700 return ret;
2703 /*****************************************************************************
2704 * EndPagePrinter [WINSPOOL.@]
2706 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2708 FIXME("(%p): stub\n", hPrinter);
2709 return TRUE;
2712 /*****************************************************************************
2713 * StartDocPrinterA [WINSPOOL.@]
2715 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2717 UNICODE_STRING usBuffer;
2718 DOC_INFO_2W doc2W;
2719 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2720 DWORD ret;
2722 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2723 or one (DOC_INFO_3) extra DWORDs */
2725 switch(Level) {
2726 case 2:
2727 doc2W.JobId = doc2->JobId;
2728 /* fall through */
2729 case 3:
2730 doc2W.dwMode = doc2->dwMode;
2731 /* fall through */
2732 case 1:
2733 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2734 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2735 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2736 break;
2738 default:
2739 SetLastError(ERROR_INVALID_LEVEL);
2740 return FALSE;
2743 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2745 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2746 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2747 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2749 return ret;
2752 /*****************************************************************************
2753 * StartDocPrinterW [WINSPOOL.@]
2755 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2757 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2758 opened_printer_t *printer;
2759 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2760 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2761 JOB_INFO_1W job_info;
2762 DWORD needed, ret = 0;
2763 HANDLE hf;
2764 WCHAR *filename;
2766 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2767 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2768 debugstr_w(doc->pDatatype));
2770 if(Level < 1 || Level > 3)
2772 SetLastError(ERROR_INVALID_LEVEL);
2773 return 0;
2776 EnterCriticalSection(&printer_handles_cs);
2777 printer = get_opened_printer(hPrinter);
2778 if(!printer)
2780 SetLastError(ERROR_INVALID_HANDLE);
2781 goto end;
2784 if(printer->doc)
2786 SetLastError(ERROR_INVALID_PRINTER_STATE);
2787 goto end;
2790 /* Even if we're printing to a file we still add a print job, we'll
2791 just ignore the spool file name */
2793 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2795 ERR("AddJob failed gle %u\n", GetLastError());
2796 goto end;
2799 if(doc->pOutputFile)
2800 filename = doc->pOutputFile;
2801 else
2802 filename = addjob->Path;
2804 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2805 if(hf == INVALID_HANDLE_VALUE)
2806 goto end;
2808 memset(&job_info, 0, sizeof(job_info));
2809 job_info.pDocument = doc->pDocName;
2810 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2812 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2813 printer->doc->hf = hf;
2814 ret = printer->doc->job_id = addjob->JobId;
2815 end:
2816 LeaveCriticalSection(&printer_handles_cs);
2818 return ret;
2821 /*****************************************************************************
2822 * StartPagePrinter [WINSPOOL.@]
2824 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2826 FIXME("(%p): stub\n", hPrinter);
2827 return TRUE;
2830 /*****************************************************************************
2831 * GetFormA [WINSPOOL.@]
2833 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2834 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2836 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
2837 Level,pForm,cbBuf,pcbNeeded);
2838 return FALSE;
2841 /*****************************************************************************
2842 * GetFormW [WINSPOOL.@]
2844 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2845 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2847 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
2848 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2849 return FALSE;
2852 /*****************************************************************************
2853 * SetFormA [WINSPOOL.@]
2855 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2856 LPBYTE pForm)
2858 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2859 return FALSE;
2862 /*****************************************************************************
2863 * SetFormW [WINSPOOL.@]
2865 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2866 LPBYTE pForm)
2868 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2869 return FALSE;
2872 /*****************************************************************************
2873 * ReadPrinter [WINSPOOL.@]
2875 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2876 LPDWORD pNoBytesRead)
2878 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2879 return FALSE;
2882 /*****************************************************************************
2883 * ResetPrinterA [WINSPOOL.@]
2885 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2887 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2888 return FALSE;
2891 /*****************************************************************************
2892 * ResetPrinterW [WINSPOOL.@]
2894 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2896 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2897 return FALSE;
2900 /*****************************************************************************
2901 * WINSPOOL_GetDWORDFromReg
2903 * Return DWORD associated with ValueName from hkey.
2905 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2907 DWORD sz = sizeof(DWORD), type, value = 0;
2908 LONG ret;
2910 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2912 if(ret != ERROR_SUCCESS) {
2913 WARN("Got ret = %d on name %s\n", ret, ValueName);
2914 return 0;
2916 if(type != REG_DWORD) {
2917 ERR("Got type %d\n", type);
2918 return 0;
2920 return value;
2924 /*****************************************************************************
2925 * get_filename_from_reg [internal]
2927 * Get ValueName from hkey storing result in out
2928 * when the Value in the registry has only a filename, use driverdir as prefix
2929 * outlen is space left in out
2930 * String is stored either as unicode or ascii
2934 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
2935 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
2937 WCHAR filename[MAX_PATH];
2938 DWORD size;
2939 DWORD type;
2940 LONG ret;
2941 LPWSTR buffer = filename;
2942 LPWSTR ptr;
2944 *needed = 0;
2945 size = sizeof(filename);
2946 buffer[0] = '\0';
2947 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
2948 if (ret == ERROR_MORE_DATA) {
2949 TRACE("need dynamic buffer: %u\n", size);
2950 buffer = HeapAlloc(GetProcessHeap(), 0, size);
2951 if (!buffer) {
2952 /* No Memory is bad */
2953 return FALSE;
2955 buffer[0] = '\0';
2956 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
2959 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
2960 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
2961 return FALSE;
2964 ptr = buffer;
2965 while (ptr) {
2966 /* do we have a full path ? */
2967 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
2968 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
2970 if (!ret) {
2971 /* we must build the full Path */
2972 *needed += dirlen;
2973 if ((out) && (outlen > dirlen)) {
2974 if (unicode) {
2975 lstrcpyW((LPWSTR)out, driverdir);
2977 else
2979 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
2981 out += dirlen;
2982 outlen -= dirlen;
2984 else
2985 out = NULL;
2988 /* write the filename */
2989 if (unicode) {
2990 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
2991 if ((out) && (outlen >= size)) {
2992 lstrcpyW((LPWSTR)out, ptr);
2993 out += size;
2994 outlen -= size;
2996 else
2997 out = NULL;
2999 else
3001 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3002 if ((out) && (outlen >= size)) {
3003 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3004 out += size;
3005 outlen -= size;
3007 else
3008 out = NULL;
3010 *needed += size;
3011 ptr += lstrlenW(ptr)+1;
3012 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3015 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3017 /* write the multisz-termination */
3018 if (type == REG_MULTI_SZ) {
3019 size = (unicode) ? sizeof(WCHAR) : 1;
3021 *needed += size;
3022 if (out && (outlen >= size)) {
3023 memset (out, 0, size);
3026 return TRUE;
3029 /*****************************************************************************
3030 * WINSPOOL_GetStringFromReg
3032 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3033 * String is stored either as unicode or ascii.
3034 * Bit of a hack here to get the ValueName if we want ascii.
3036 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3037 DWORD buflen, DWORD *needed,
3038 BOOL unicode)
3040 DWORD sz = buflen, type;
3041 LONG ret;
3043 if(unicode)
3044 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3045 else {
3046 LPSTR ValueNameA = strdupWtoA(ValueName);
3047 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3048 HeapFree(GetProcessHeap(),0,ValueNameA);
3050 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3051 WARN("Got ret = %d\n", ret);
3052 *needed = 0;
3053 return FALSE;
3055 /* add space for terminating '\0' */
3056 sz += unicode ? sizeof(WCHAR) : 1;
3057 *needed = sz;
3059 if (ptr)
3060 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3062 return TRUE;
3065 /*****************************************************************************
3066 * WINSPOOL_GetDefaultDevMode
3068 * Get a default DevMode values for wineps.
3069 * FIXME - use ppd.
3072 static void WINSPOOL_GetDefaultDevMode(
3073 LPBYTE ptr,
3074 DWORD buflen, DWORD *needed,
3075 BOOL unicode)
3077 DEVMODEA dm;
3078 static const char szwps[] = "wineps.drv";
3080 /* fill default DEVMODE - should be read from ppd... */
3081 ZeroMemory( &dm, sizeof(dm) );
3082 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3083 dm.dmSpecVersion = DM_SPECVERSION;
3084 dm.dmDriverVersion = 1;
3085 dm.dmSize = sizeof(DEVMODEA);
3086 dm.dmDriverExtra = 0;
3087 dm.dmFields =
3088 DM_ORIENTATION | DM_PAPERSIZE |
3089 DM_PAPERLENGTH | DM_PAPERWIDTH |
3090 DM_SCALE |
3091 DM_COPIES |
3092 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3093 DM_YRESOLUTION | DM_TTOPTION;
3095 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3096 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3097 dm.u1.s1.dmPaperLength = 2970;
3098 dm.u1.s1.dmPaperWidth = 2100;
3100 dm.u1.s1.dmScale = 100;
3101 dm.u1.s1.dmCopies = 1;
3102 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3103 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3104 /* dm.dmColor */
3105 /* dm.dmDuplex */
3106 dm.dmYResolution = 300; /* 300dpi */
3107 dm.dmTTOption = DMTT_BITMAP;
3108 /* dm.dmCollate */
3109 /* dm.dmFormName */
3110 /* dm.dmLogPixels */
3111 /* dm.dmBitsPerPel */
3112 /* dm.dmPelsWidth */
3113 /* dm.dmPelsHeight */
3114 /* dm.u2.dmDisplayFlags */
3115 /* dm.dmDisplayFrequency */
3116 /* dm.dmICMMethod */
3117 /* dm.dmICMIntent */
3118 /* dm.dmMediaType */
3119 /* dm.dmDitherType */
3120 /* dm.dmReserved1 */
3121 /* dm.dmReserved2 */
3122 /* dm.dmPanningWidth */
3123 /* dm.dmPanningHeight */
3125 if(unicode) {
3126 if(buflen >= sizeof(DEVMODEW)) {
3127 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3128 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3129 HeapFree(GetProcessHeap(),0,pdmW);
3131 *needed = sizeof(DEVMODEW);
3133 else
3135 if(buflen >= sizeof(DEVMODEA)) {
3136 memcpy(ptr, &dm, sizeof(DEVMODEA));
3138 *needed = sizeof(DEVMODEA);
3142 /*****************************************************************************
3143 * WINSPOOL_GetDevModeFromReg
3145 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3146 * DevMode is stored either as unicode or ascii.
3148 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3149 LPBYTE ptr,
3150 DWORD buflen, DWORD *needed,
3151 BOOL unicode)
3153 DWORD sz = buflen, type;
3154 LONG ret;
3156 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3157 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3158 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3159 if (sz < sizeof(DEVMODEA))
3161 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3162 return FALSE;
3164 /* ensures that dmSize is not erratically bogus if registry is invalid */
3165 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3166 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3167 if(unicode) {
3168 sz += (CCHDEVICENAME + CCHFORMNAME);
3169 if(buflen >= sz) {
3170 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3171 memcpy(ptr, dmW, sz);
3172 HeapFree(GetProcessHeap(),0,dmW);
3175 *needed = sz;
3176 return TRUE;
3179 /*********************************************************************
3180 * WINSPOOL_GetPrinter_1
3182 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3183 * The strings are either stored as unicode or ascii.
3185 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3186 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3187 BOOL unicode)
3189 DWORD size, left = cbBuf;
3190 BOOL space = (cbBuf > 0);
3191 LPBYTE ptr = buf;
3193 *pcbNeeded = 0;
3195 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3196 unicode)) {
3197 if(space && size <= left) {
3198 pi1->pName = (LPWSTR)ptr;
3199 ptr += size;
3200 left -= size;
3201 } else
3202 space = FALSE;
3203 *pcbNeeded += size;
3206 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3207 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3208 unicode)) {
3209 if(space && size <= left) {
3210 pi1->pDescription = (LPWSTR)ptr;
3211 ptr += size;
3212 left -= size;
3213 } else
3214 space = FALSE;
3215 *pcbNeeded += size;
3218 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3219 unicode)) {
3220 if(space && size <= left) {
3221 pi1->pComment = (LPWSTR)ptr;
3222 ptr += size;
3223 left -= size;
3224 } else
3225 space = FALSE;
3226 *pcbNeeded += size;
3229 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3231 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3232 memset(pi1, 0, sizeof(*pi1));
3234 return space;
3236 /*********************************************************************
3237 * WINSPOOL_GetPrinter_2
3239 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3240 * The strings are either stored as unicode or ascii.
3242 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3243 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3244 BOOL unicode)
3246 DWORD size, left = cbBuf;
3247 BOOL space = (cbBuf > 0);
3248 LPBYTE ptr = buf;
3250 *pcbNeeded = 0;
3252 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3253 unicode)) {
3254 if(space && size <= left) {
3255 pi2->pPrinterName = (LPWSTR)ptr;
3256 ptr += size;
3257 left -= size;
3258 } else
3259 space = FALSE;
3260 *pcbNeeded += size;
3262 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3263 unicode)) {
3264 if(space && size <= left) {
3265 pi2->pShareName = (LPWSTR)ptr;
3266 ptr += size;
3267 left -= size;
3268 } else
3269 space = FALSE;
3270 *pcbNeeded += size;
3272 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3273 unicode)) {
3274 if(space && size <= left) {
3275 pi2->pPortName = (LPWSTR)ptr;
3276 ptr += size;
3277 left -= size;
3278 } else
3279 space = FALSE;
3280 *pcbNeeded += size;
3282 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3283 &size, unicode)) {
3284 if(space && size <= left) {
3285 pi2->pDriverName = (LPWSTR)ptr;
3286 ptr += size;
3287 left -= size;
3288 } else
3289 space = FALSE;
3290 *pcbNeeded += size;
3292 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3293 unicode)) {
3294 if(space && size <= left) {
3295 pi2->pComment = (LPWSTR)ptr;
3296 ptr += size;
3297 left -= size;
3298 } else
3299 space = FALSE;
3300 *pcbNeeded += size;
3302 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3303 unicode)) {
3304 if(space && size <= left) {
3305 pi2->pLocation = (LPWSTR)ptr;
3306 ptr += size;
3307 left -= size;
3308 } else
3309 space = FALSE;
3310 *pcbNeeded += size;
3312 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3313 &size, unicode)) {
3314 if(space && size <= left) {
3315 pi2->pDevMode = (LPDEVMODEW)ptr;
3316 ptr += size;
3317 left -= size;
3318 } else
3319 space = FALSE;
3320 *pcbNeeded += size;
3322 else
3324 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3325 if(space && size <= left) {
3326 pi2->pDevMode = (LPDEVMODEW)ptr;
3327 ptr += size;
3328 left -= size;
3329 } else
3330 space = FALSE;
3331 *pcbNeeded += size;
3333 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3334 &size, unicode)) {
3335 if(space && size <= left) {
3336 pi2->pSepFile = (LPWSTR)ptr;
3337 ptr += size;
3338 left -= size;
3339 } else
3340 space = FALSE;
3341 *pcbNeeded += size;
3343 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3344 &size, unicode)) {
3345 if(space && size <= left) {
3346 pi2->pPrintProcessor = (LPWSTR)ptr;
3347 ptr += size;
3348 left -= size;
3349 } else
3350 space = FALSE;
3351 *pcbNeeded += size;
3353 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3354 &size, unicode)) {
3355 if(space && size <= left) {
3356 pi2->pDatatype = (LPWSTR)ptr;
3357 ptr += size;
3358 left -= size;
3359 } else
3360 space = FALSE;
3361 *pcbNeeded += size;
3363 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3364 &size, unicode)) {
3365 if(space && size <= left) {
3366 pi2->pParameters = (LPWSTR)ptr;
3367 ptr += size;
3368 left -= size;
3369 } else
3370 space = FALSE;
3371 *pcbNeeded += size;
3373 if(pi2) {
3374 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3375 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3376 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3377 "Default Priority");
3378 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3379 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3382 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3383 memset(pi2, 0, sizeof(*pi2));
3385 return space;
3388 /*********************************************************************
3389 * WINSPOOL_GetPrinter_4
3391 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3393 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3394 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3395 BOOL unicode)
3397 DWORD size, left = cbBuf;
3398 BOOL space = (cbBuf > 0);
3399 LPBYTE ptr = buf;
3401 *pcbNeeded = 0;
3403 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3404 unicode)) {
3405 if(space && size <= left) {
3406 pi4->pPrinterName = (LPWSTR)ptr;
3407 ptr += size;
3408 left -= size;
3409 } else
3410 space = FALSE;
3411 *pcbNeeded += size;
3413 if(pi4) {
3414 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3417 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3418 memset(pi4, 0, sizeof(*pi4));
3420 return space;
3423 /*********************************************************************
3424 * WINSPOOL_GetPrinter_5
3426 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3428 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
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 pi5->pPrinterName = (LPWSTR)ptr;
3442 ptr += size;
3443 left -= size;
3444 } else
3445 space = FALSE;
3446 *pcbNeeded += size;
3448 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3449 unicode)) {
3450 if(space && size <= left) {
3451 pi5->pPortName = (LPWSTR)ptr;
3452 ptr += size;
3453 left -= size;
3454 } else
3455 space = FALSE;
3456 *pcbNeeded += size;
3458 if(pi5) {
3459 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3460 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3461 "dnsTimeout");
3462 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3463 "txTimeout");
3466 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3467 memset(pi5, 0, sizeof(*pi5));
3469 return space;
3472 /*********************************************************************
3473 * WINSPOOL_GetPrinter_7
3475 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3477 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3478 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3480 DWORD size, left = cbBuf;
3481 BOOL space = (cbBuf > 0);
3482 LPBYTE ptr = buf;
3484 *pcbNeeded = 0;
3486 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3488 if (space && size <= left) {
3489 pi7->pszObjectGUID = (LPWSTR)ptr;
3490 ptr += size;
3491 left -= size;
3492 } else
3493 space = FALSE;
3494 *pcbNeeded += size;
3496 if (pi7) {
3497 /* We do not have a Directory Service */
3498 pi7->dwAction = DSPRINT_UNPUBLISH;
3501 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3502 memset(pi7, 0, sizeof(*pi7));
3504 return space;
3507 /*********************************************************************
3508 * WINSPOOL_GetPrinter_9
3510 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3511 * The strings are either stored as unicode or ascii.
3513 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3514 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3516 DWORD size;
3517 BOOL space = (cbBuf > 0);
3519 *pcbNeeded = 0;
3521 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3522 if(space && size <= cbBuf) {
3523 pi9->pDevMode = (LPDEVMODEW)buf;
3524 } else
3525 space = FALSE;
3526 *pcbNeeded += size;
3528 else
3530 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3531 if(space && size <= cbBuf) {
3532 pi9->pDevMode = (LPDEVMODEW)buf;
3533 } else
3534 space = FALSE;
3535 *pcbNeeded += size;
3538 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3539 memset(pi9, 0, sizeof(*pi9));
3541 return space;
3544 /*****************************************************************************
3545 * WINSPOOL_GetPrinter
3547 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3548 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3549 * just a collection of pointers to strings.
3551 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3552 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3554 LPCWSTR name;
3555 DWORD size, needed = 0;
3556 LPBYTE ptr = NULL;
3557 HKEY hkeyPrinter, hkeyPrinters;
3558 BOOL ret;
3560 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3562 if (!(name = get_opened_printer_name(hPrinter))) {
3563 SetLastError(ERROR_INVALID_HANDLE);
3564 return FALSE;
3567 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3568 ERROR_SUCCESS) {
3569 ERR("Can't create Printers key\n");
3570 return FALSE;
3572 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3574 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3575 RegCloseKey(hkeyPrinters);
3576 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3577 return FALSE;
3580 switch(Level) {
3581 case 2:
3583 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3585 size = sizeof(PRINTER_INFO_2W);
3586 if(size <= cbBuf) {
3587 ptr = pPrinter + size;
3588 cbBuf -= size;
3589 memset(pPrinter, 0, size);
3590 } else {
3591 pi2 = NULL;
3592 cbBuf = 0;
3594 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3595 unicode);
3596 needed += size;
3597 break;
3600 case 4:
3602 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3604 size = sizeof(PRINTER_INFO_4W);
3605 if(size <= cbBuf) {
3606 ptr = pPrinter + size;
3607 cbBuf -= size;
3608 memset(pPrinter, 0, size);
3609 } else {
3610 pi4 = NULL;
3611 cbBuf = 0;
3613 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3614 unicode);
3615 needed += size;
3616 break;
3620 case 5:
3622 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3624 size = sizeof(PRINTER_INFO_5W);
3625 if(size <= cbBuf) {
3626 ptr = pPrinter + size;
3627 cbBuf -= size;
3628 memset(pPrinter, 0, size);
3629 } else {
3630 pi5 = NULL;
3631 cbBuf = 0;
3634 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3635 unicode);
3636 needed += size;
3637 break;
3641 case 6:
3643 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3645 size = sizeof(PRINTER_INFO_6);
3646 if (size <= cbBuf) {
3647 /* FIXME: We do not update the status yet */
3648 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3649 ret = TRUE;
3650 } else {
3651 ret = FALSE;
3654 needed += size;
3655 break;
3658 case 7:
3660 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3662 size = sizeof(PRINTER_INFO_7W);
3663 if (size <= cbBuf) {
3664 ptr = pPrinter + size;
3665 cbBuf -= size;
3666 memset(pPrinter, 0, size);
3667 } else {
3668 pi7 = NULL;
3669 cbBuf = 0;
3672 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
3673 needed += size;
3674 break;
3678 case 9:
3680 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3682 size = sizeof(PRINTER_INFO_9W);
3683 if(size <= cbBuf) {
3684 ptr = pPrinter + size;
3685 cbBuf -= size;
3686 memset(pPrinter, 0, size);
3687 } else {
3688 pi9 = NULL;
3689 cbBuf = 0;
3692 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
3693 needed += size;
3694 break;
3698 default:
3699 FIXME("Unimplemented level %d\n", Level);
3700 SetLastError(ERROR_INVALID_LEVEL);
3701 RegCloseKey(hkeyPrinters);
3702 RegCloseKey(hkeyPrinter);
3703 return FALSE;
3706 RegCloseKey(hkeyPrinter);
3707 RegCloseKey(hkeyPrinters);
3709 TRACE("returning %d needed = %d\n", ret, needed);
3710 if(pcbNeeded) *pcbNeeded = needed;
3711 if(!ret)
3712 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3713 return ret;
3716 /*****************************************************************************
3717 * GetPrinterW [WINSPOOL.@]
3719 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3720 DWORD cbBuf, LPDWORD pcbNeeded)
3722 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3723 TRUE);
3726 /*****************************************************************************
3727 * GetPrinterA [WINSPOOL.@]
3729 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3730 DWORD cbBuf, LPDWORD pcbNeeded)
3732 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3733 FALSE);
3736 /*****************************************************************************
3737 * WINSPOOL_EnumPrinters
3739 * Implementation of EnumPrintersA|W
3741 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3742 DWORD dwLevel, LPBYTE lpbPrinters,
3743 DWORD cbBuf, LPDWORD lpdwNeeded,
3744 LPDWORD lpdwReturned, BOOL unicode)
3747 HKEY hkeyPrinters, hkeyPrinter;
3748 WCHAR PrinterName[255];
3749 DWORD needed = 0, number = 0;
3750 DWORD used, i, left;
3751 PBYTE pi, buf;
3753 if(lpbPrinters)
3754 memset(lpbPrinters, 0, cbBuf);
3755 if(lpdwReturned)
3756 *lpdwReturned = 0;
3757 if(lpdwNeeded)
3758 *lpdwNeeded = 0;
3760 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3761 if(dwType == PRINTER_ENUM_DEFAULT)
3762 return TRUE;
3764 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3765 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3766 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3767 if (!dwType) {
3768 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3769 *lpdwNeeded = 0;
3770 *lpdwReturned = 0;
3771 return TRUE;
3776 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3777 FIXME("dwType = %08x\n", dwType);
3778 SetLastError(ERROR_INVALID_FLAGS);
3779 return FALSE;
3782 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3783 ERROR_SUCCESS) {
3784 ERR("Can't create Printers key\n");
3785 return FALSE;
3788 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3789 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3790 RegCloseKey(hkeyPrinters);
3791 ERR("Can't query Printers key\n");
3792 return FALSE;
3794 TRACE("Found %d printers\n", number);
3796 switch(dwLevel) {
3797 case 1:
3798 used = number * sizeof(PRINTER_INFO_1W);
3799 break;
3800 case 2:
3801 used = number * sizeof(PRINTER_INFO_2W);
3802 break;
3803 case 4:
3804 used = number * sizeof(PRINTER_INFO_4W);
3805 break;
3806 case 5:
3807 used = number * sizeof(PRINTER_INFO_5W);
3808 break;
3810 default:
3811 SetLastError(ERROR_INVALID_LEVEL);
3812 RegCloseKey(hkeyPrinters);
3813 return FALSE;
3815 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3817 for(i = 0; i < number; i++) {
3818 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3819 ERROR_SUCCESS) {
3820 ERR("Can't enum key number %d\n", i);
3821 RegCloseKey(hkeyPrinters);
3822 return FALSE;
3824 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3825 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3826 ERROR_SUCCESS) {
3827 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3828 RegCloseKey(hkeyPrinters);
3829 return FALSE;
3832 if(cbBuf > used) {
3833 buf = lpbPrinters + used;
3834 left = cbBuf - used;
3835 } else {
3836 buf = NULL;
3837 left = 0;
3840 switch(dwLevel) {
3841 case 1:
3842 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3843 left, &needed, unicode);
3844 used += needed;
3845 if(pi) pi += sizeof(PRINTER_INFO_1W);
3846 break;
3847 case 2:
3848 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3849 left, &needed, unicode);
3850 used += needed;
3851 if(pi) pi += sizeof(PRINTER_INFO_2W);
3852 break;
3853 case 4:
3854 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3855 left, &needed, unicode);
3856 used += needed;
3857 if(pi) pi += sizeof(PRINTER_INFO_4W);
3858 break;
3859 case 5:
3860 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3861 left, &needed, unicode);
3862 used += needed;
3863 if(pi) pi += sizeof(PRINTER_INFO_5W);
3864 break;
3865 default:
3866 ERR("Shouldn't be here!\n");
3867 RegCloseKey(hkeyPrinter);
3868 RegCloseKey(hkeyPrinters);
3869 return FALSE;
3871 RegCloseKey(hkeyPrinter);
3873 RegCloseKey(hkeyPrinters);
3875 if(lpdwNeeded)
3876 *lpdwNeeded = used;
3878 if(used > cbBuf) {
3879 if(lpbPrinters)
3880 memset(lpbPrinters, 0, cbBuf);
3881 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3882 return FALSE;
3884 if(lpdwReturned)
3885 *lpdwReturned = number;
3886 SetLastError(ERROR_SUCCESS);
3887 return TRUE;
3891 /******************************************************************
3892 * EnumPrintersW [WINSPOOL.@]
3894 * Enumerates the available printers, print servers and print
3895 * providers, depending on the specified flags, name and level.
3897 * RETURNS:
3899 * If level is set to 1:
3900 * Returns an array of PRINTER_INFO_1 data structures in the
3901 * lpbPrinters buffer.
3903 * If level is set to 2:
3904 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3905 * Returns an array of PRINTER_INFO_2 data structures in the
3906 * lpbPrinters buffer. Note that according to MSDN also an
3907 * OpenPrinter should be performed on every remote printer.
3909 * If level is set to 4 (officially WinNT only):
3910 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3911 * Fast: Only the registry is queried to retrieve printer names,
3912 * no connection to the driver is made.
3913 * Returns an array of PRINTER_INFO_4 data structures in the
3914 * lpbPrinters buffer.
3916 * If level is set to 5 (officially WinNT4/Win9x only):
3917 * Fast: Only the registry is queried to retrieve printer names,
3918 * no connection to the driver is made.
3919 * Returns an array of PRINTER_INFO_5 data structures in the
3920 * lpbPrinters buffer.
3922 * If level set to 3 or 6+:
3923 * returns zero (failure!)
3925 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3926 * for information.
3928 * BUGS:
3929 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3930 * - Only levels 2, 4 and 5 are implemented at the moment.
3931 * - 16-bit printer drivers are not enumerated.
3932 * - Returned amount of bytes used/needed does not match the real Windoze
3933 * implementation (as in this implementation, all strings are part
3934 * of the buffer, whereas Win32 keeps them somewhere else)
3935 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3937 * NOTE:
3938 * - In a regular Wine installation, no registry settings for printers
3939 * exist, which makes this function return an empty list.
3941 BOOL WINAPI EnumPrintersW(
3942 DWORD dwType, /* [in] Types of print objects to enumerate */
3943 LPWSTR lpszName, /* [in] name of objects to enumerate */
3944 DWORD dwLevel, /* [in] type of printer info structure */
3945 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3946 DWORD cbBuf, /* [in] max size of buffer in bytes */
3947 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3948 LPDWORD lpdwReturned /* [out] number of entries returned */
3951 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3952 lpdwNeeded, lpdwReturned, TRUE);
3955 /******************************************************************
3956 * EnumPrintersA [WINSPOOL.@]
3958 * See EnumPrintersW
3961 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
3962 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
3964 BOOL ret;
3965 UNICODE_STRING pNameU;
3966 LPWSTR pNameW;
3967 LPBYTE pPrintersW;
3969 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
3970 pPrinters, cbBuf, pcbNeeded, pcReturned);
3972 pNameW = asciitounicode(&pNameU, pName);
3974 /* Request a buffer with a size, that is big enough for EnumPrintersW.
3975 MS Office need this */
3976 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
3978 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
3980 RtlFreeUnicodeString(&pNameU);
3981 if (ret) {
3982 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
3984 HeapFree(GetProcessHeap(), 0, pPrintersW);
3985 return ret;
3988 /*****************************************************************************
3989 * WINSPOOL_GetDriverInfoFromReg [internal]
3991 * Enters the information from the registry into the DRIVER_INFO struct
3993 * RETURNS
3994 * zero if the printer driver does not exist in the registry
3995 * (only if Level > 1) otherwise nonzero
3997 static BOOL WINSPOOL_GetDriverInfoFromReg(
3998 HKEY hkeyDrivers,
3999 LPWSTR DriverName,
4000 const printenv_t * env,
4001 DWORD Level,
4002 LPBYTE ptr, /* DRIVER_INFO */
4003 LPBYTE pDriverStrings, /* strings buffer */
4004 DWORD cbBuf, /* size of string buffer */
4005 LPDWORD pcbNeeded, /* space needed for str. */
4006 BOOL unicode) /* type of strings */
4008 DWORD size, tmp;
4009 HKEY hkeyDriver;
4010 WCHAR driverdir[MAX_PATH];
4011 DWORD dirlen;
4012 LPBYTE strPtr = pDriverStrings;
4013 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4015 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4016 debugstr_w(DriverName), env,
4017 Level, di, pDriverStrings, cbBuf, unicode);
4019 if (di) ZeroMemory(di, di_sizeof[Level]);
4021 if (unicode) {
4022 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4023 if (*pcbNeeded <= cbBuf)
4024 strcpyW((LPWSTR)strPtr, DriverName);
4026 else
4028 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4029 if (*pcbNeeded <= cbBuf)
4030 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4033 /* pName for level 1 has a different offset! */
4034 if (Level == 1) {
4035 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4036 return TRUE;
4039 /* .cVersion and .pName for level > 1 */
4040 if (di) {
4041 di->cVersion = env->driverversion;
4042 di->pName = (LPWSTR) strPtr;
4043 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4046 /* Reserve Space for the largest subdir and a Backslash*/
4047 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4048 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4049 /* Should never Fail */
4050 return FALSE;
4052 lstrcatW(driverdir, env->versionsubdir);
4053 lstrcatW(driverdir, backslashW);
4055 /* dirlen must not include the terminating zero */
4056 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4057 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4059 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4060 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4061 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4062 return FALSE;
4065 /* pEnvironment */
4066 if (unicode)
4067 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4068 else
4069 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4071 *pcbNeeded += size;
4072 if (*pcbNeeded <= cbBuf) {
4073 if (unicode) {
4074 lstrcpyW((LPWSTR)strPtr, env->envname);
4076 else
4078 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4080 if (di) di->pEnvironment = (LPWSTR)strPtr;
4081 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4084 /* .pDriverPath is the Graphics rendering engine.
4085 The full Path is required to avoid a crash in some apps */
4086 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4087 *pcbNeeded += size;
4088 if (*pcbNeeded <= cbBuf)
4089 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4091 if (di) di->pDriverPath = (LPWSTR)strPtr;
4092 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4095 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4096 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4097 *pcbNeeded += size;
4098 if (*pcbNeeded <= cbBuf)
4099 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4101 if (di) di->pDataFile = (LPWSTR)strPtr;
4102 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4105 /* .pConfigFile is the Driver user Interface */
4106 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4107 *pcbNeeded += size;
4108 if (*pcbNeeded <= cbBuf)
4109 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4111 if (di) di->pConfigFile = (LPWSTR)strPtr;
4112 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4115 if (Level == 2 ) {
4116 RegCloseKey(hkeyDriver);
4117 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4118 return TRUE;
4121 if (Level == 5 ) {
4122 RegCloseKey(hkeyDriver);
4123 FIXME("level 5: incomplete\n");
4124 return TRUE;
4127 /* .pHelpFile */
4128 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4129 *pcbNeeded += size;
4130 if (*pcbNeeded <= cbBuf)
4131 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4133 if (di) di->pHelpFile = (LPWSTR)strPtr;
4134 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4137 /* .pDependentFiles */
4138 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4139 *pcbNeeded += size;
4140 if (*pcbNeeded <= cbBuf)
4141 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4143 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4144 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4146 else if (GetVersion() & 0x80000000) {
4147 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4148 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4149 *pcbNeeded += size;
4150 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4152 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4153 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4156 /* .pMonitorName is the optional Language Monitor */
4157 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4158 *pcbNeeded += size;
4159 if (*pcbNeeded <= cbBuf)
4160 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4162 if (di) di->pMonitorName = (LPWSTR)strPtr;
4163 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4166 /* .pDefaultDataType */
4167 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4168 *pcbNeeded += size;
4169 if(*pcbNeeded <= cbBuf)
4170 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4172 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4173 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4176 if (Level == 3 ) {
4177 RegCloseKey(hkeyDriver);
4178 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4179 return TRUE;
4182 /* .pszzPreviousNames */
4183 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4184 *pcbNeeded += size;
4185 if(*pcbNeeded <= cbBuf)
4186 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4188 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4189 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4192 if (Level == 4 ) {
4193 RegCloseKey(hkeyDriver);
4194 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4195 return TRUE;
4198 /* support is missing, but not important enough for a FIXME */
4199 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4201 /* .pszMfgName */
4202 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4203 *pcbNeeded += size;
4204 if(*pcbNeeded <= cbBuf)
4205 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4207 if (di) di->pszMfgName = (LPWSTR)strPtr;
4208 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4211 /* .pszOEMUrl */
4212 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4213 *pcbNeeded += size;
4214 if(*pcbNeeded <= cbBuf)
4215 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4217 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4218 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4221 /* .pszHardwareID */
4222 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4223 *pcbNeeded += size;
4224 if(*pcbNeeded <= cbBuf)
4225 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4227 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4228 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4231 /* .pszProvider */
4232 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4233 *pcbNeeded += size;
4234 if(*pcbNeeded <= cbBuf)
4235 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4237 if (di) di->pszProvider = (LPWSTR)strPtr;
4238 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4241 if (Level == 6 ) {
4242 RegCloseKey(hkeyDriver);
4243 return TRUE;
4246 /* support is missing, but not important enough for a FIXME */
4247 TRACE("level 8: incomplete\n");
4249 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4250 RegCloseKey(hkeyDriver);
4251 return TRUE;
4254 /*****************************************************************************
4255 * WINSPOOL_GetPrinterDriver
4257 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4258 DWORD Level, LPBYTE pDriverInfo,
4259 DWORD cbBuf, LPDWORD pcbNeeded,
4260 BOOL unicode)
4262 LPCWSTR name;
4263 WCHAR DriverName[100];
4264 DWORD ret, type, size, needed = 0;
4265 LPBYTE ptr = NULL;
4266 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4267 const printenv_t * env;
4269 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4270 Level,pDriverInfo,cbBuf, pcbNeeded);
4273 if (!(name = get_opened_printer_name(hPrinter))) {
4274 SetLastError(ERROR_INVALID_HANDLE);
4275 return FALSE;
4278 if (Level < 1 || Level == 7 || Level > 8) {
4279 SetLastError(ERROR_INVALID_LEVEL);
4280 return FALSE;
4283 env = validate_envW(pEnvironment);
4284 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4286 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4287 ERROR_SUCCESS) {
4288 ERR("Can't create Printers key\n");
4289 return FALSE;
4291 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4292 != ERROR_SUCCESS) {
4293 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4294 RegCloseKey(hkeyPrinters);
4295 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4296 return FALSE;
4298 size = sizeof(DriverName);
4299 DriverName[0] = 0;
4300 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4301 (LPBYTE)DriverName, &size);
4302 RegCloseKey(hkeyPrinter);
4303 RegCloseKey(hkeyPrinters);
4304 if(ret != ERROR_SUCCESS) {
4305 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4306 return FALSE;
4309 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4310 if(!hkeyDrivers) {
4311 ERR("Can't create Drivers key\n");
4312 return FALSE;
4315 size = di_sizeof[Level];
4316 if ((size <= cbBuf) && pDriverInfo)
4317 ptr = pDriverInfo + size;
4319 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4320 env, Level, pDriverInfo, ptr,
4321 (cbBuf < size) ? 0 : cbBuf - size,
4322 &needed, unicode)) {
4323 RegCloseKey(hkeyDrivers);
4324 return FALSE;
4327 RegCloseKey(hkeyDrivers);
4329 if(pcbNeeded) *pcbNeeded = size + needed;
4330 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4331 if(cbBuf >= needed) return TRUE;
4332 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4333 return FALSE;
4336 /*****************************************************************************
4337 * GetPrinterDriverA [WINSPOOL.@]
4339 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4340 DWORD Level, LPBYTE pDriverInfo,
4341 DWORD cbBuf, LPDWORD pcbNeeded)
4343 BOOL ret;
4344 UNICODE_STRING pEnvW;
4345 PWSTR pwstrEnvW;
4347 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4348 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4349 cbBuf, pcbNeeded, FALSE);
4350 RtlFreeUnicodeString(&pEnvW);
4351 return ret;
4353 /*****************************************************************************
4354 * GetPrinterDriverW [WINSPOOL.@]
4356 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4357 DWORD Level, LPBYTE pDriverInfo,
4358 DWORD cbBuf, LPDWORD pcbNeeded)
4360 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4361 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4364 /*****************************************************************************
4365 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4367 * Return the PATH for the Printer-Drivers (UNICODE)
4369 * PARAMS
4370 * pName [I] Servername (NT only) or NULL (local Computer)
4371 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4372 * Level [I] Structure-Level (must be 1)
4373 * pDriverDirectory [O] PTR to Buffer that receives the Result
4374 * cbBuf [I] Size of Buffer at pDriverDirectory
4375 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4376 * required for pDriverDirectory
4378 * RETURNS
4379 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4380 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4381 * if cbBuf is too small
4383 * Native Values returned in pDriverDirectory on Success:
4384 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4385 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4386 *| win9x(Windows 4.0): "%winsysdir%"
4388 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4390 * FIXME
4391 *- Only NULL or "" is supported for pName
4394 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4395 DWORD Level, LPBYTE pDriverDirectory,
4396 DWORD cbBuf, LPDWORD pcbNeeded)
4398 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4399 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4401 if ((backend == NULL) && !load_backend()) return FALSE;
4403 if (Level != 1) {
4404 /* (Level != 1) is ignored in win9x */
4405 SetLastError(ERROR_INVALID_LEVEL);
4406 return FALSE;
4408 if (pcbNeeded == NULL) {
4409 /* (pcbNeeded == NULL) is ignored in win9x */
4410 SetLastError(RPC_X_NULL_REF_POINTER);
4411 return FALSE;
4414 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4415 pDriverDirectory, cbBuf, pcbNeeded);
4420 /*****************************************************************************
4421 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4423 * Return the PATH for the Printer-Drivers (ANSI)
4425 * See GetPrinterDriverDirectoryW.
4427 * NOTES
4428 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4431 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4432 DWORD Level, LPBYTE pDriverDirectory,
4433 DWORD cbBuf, LPDWORD pcbNeeded)
4435 UNICODE_STRING nameW, environmentW;
4436 BOOL ret;
4437 DWORD pcbNeededW;
4438 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4439 WCHAR *driverDirectoryW = NULL;
4441 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4442 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4444 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4446 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4447 else nameW.Buffer = NULL;
4448 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4449 else environmentW.Buffer = NULL;
4451 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4452 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4453 if (ret) {
4454 DWORD needed;
4455 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4456 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4457 if(pcbNeeded)
4458 *pcbNeeded = needed;
4459 ret = (needed <= cbBuf) ? TRUE : FALSE;
4460 } else
4461 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4463 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4465 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4466 RtlFreeUnicodeString(&environmentW);
4467 RtlFreeUnicodeString(&nameW);
4469 return ret;
4472 /*****************************************************************************
4473 * AddPrinterDriverA [WINSPOOL.@]
4475 * See AddPrinterDriverW.
4478 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4480 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4481 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4484 /******************************************************************************
4485 * AddPrinterDriverW (WINSPOOL.@)
4487 * Install a Printer Driver
4489 * PARAMS
4490 * pName [I] Servername or NULL (local Computer)
4491 * level [I] Level for the supplied DRIVER_INFO_*W struct
4492 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4494 * RESULTS
4495 * Success: TRUE
4496 * Failure: FALSE
4499 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4501 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4502 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4505 /*****************************************************************************
4506 * AddPrintProcessorA [WINSPOOL.@]
4508 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4509 LPSTR pPrintProcessorName)
4511 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4512 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4513 return FALSE;
4516 /*****************************************************************************
4517 * AddPrintProcessorW [WINSPOOL.@]
4519 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4520 LPWSTR pPrintProcessorName)
4522 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4523 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4524 return FALSE;
4527 /*****************************************************************************
4528 * AddPrintProvidorA [WINSPOOL.@]
4530 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4532 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4533 return FALSE;
4536 /*****************************************************************************
4537 * AddPrintProvidorW [WINSPOOL.@]
4539 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4541 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4542 return FALSE;
4545 /*****************************************************************************
4546 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4548 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4549 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4551 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4552 pDevModeOutput, pDevModeInput);
4553 return 0;
4556 /*****************************************************************************
4557 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4559 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4560 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4562 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4563 pDevModeOutput, pDevModeInput);
4564 return 0;
4567 /*****************************************************************************
4568 * PrinterProperties [WINSPOOL.@]
4570 * Displays a dialog to set the properties of the printer.
4572 * RETURNS
4573 * nonzero on success or zero on failure
4575 * BUGS
4576 * implemented as stub only
4578 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4579 HANDLE hPrinter /* [in] handle to printer object */
4581 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4582 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4583 return FALSE;
4586 /*****************************************************************************
4587 * EnumJobsA [WINSPOOL.@]
4590 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4591 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4592 LPDWORD pcReturned)
4594 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4595 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4597 if(pcbNeeded) *pcbNeeded = 0;
4598 if(pcReturned) *pcReturned = 0;
4599 return FALSE;
4603 /*****************************************************************************
4604 * EnumJobsW [WINSPOOL.@]
4607 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4608 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4609 LPDWORD pcReturned)
4611 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4612 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4614 if(pcbNeeded) *pcbNeeded = 0;
4615 if(pcReturned) *pcReturned = 0;
4616 return FALSE;
4619 /*****************************************************************************
4620 * WINSPOOL_EnumPrinterDrivers [internal]
4622 * Delivers information about all printer drivers installed on the
4623 * localhost or a given server
4625 * RETURNS
4626 * nonzero on success or zero on failure. If the buffer for the returned
4627 * information is too small the function will return an error
4629 * BUGS
4630 * - only implemented for localhost, foreign hosts will return an error
4632 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4633 DWORD Level, LPBYTE pDriverInfo,
4634 DWORD cbBuf, LPDWORD pcbNeeded,
4635 LPDWORD pcReturned, BOOL unicode)
4637 { HKEY hkeyDrivers;
4638 DWORD i, needed, number = 0, size = 0;
4639 WCHAR DriverNameW[255];
4640 PBYTE ptr;
4641 const printenv_t * env;
4643 TRACE("%s,%s,%d,%p,%d,%d\n",
4644 debugstr_w(pName), debugstr_w(pEnvironment),
4645 Level, pDriverInfo, cbBuf, unicode);
4647 /* check for local drivers */
4648 if((pName) && (pName[0])) {
4649 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4650 SetLastError(ERROR_ACCESS_DENIED);
4651 return FALSE;
4654 env = validate_envW(pEnvironment);
4655 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4657 /* check input parameter */
4658 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4659 SetLastError(ERROR_INVALID_LEVEL);
4660 return FALSE;
4663 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
4664 SetLastError(RPC_X_NULL_REF_POINTER);
4665 return FALSE;
4668 /* initialize return values */
4669 if(pDriverInfo)
4670 memset( pDriverInfo, 0, cbBuf);
4671 *pcbNeeded = 0;
4672 *pcReturned = 0;
4674 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4675 if(!hkeyDrivers) {
4676 ERR("Can't open Drivers key\n");
4677 return FALSE;
4680 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4681 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4682 RegCloseKey(hkeyDrivers);
4683 ERR("Can't query Drivers key\n");
4684 return FALSE;
4686 TRACE("Found %d Drivers\n", number);
4688 /* get size of single struct
4689 * unicode and ascii structure have the same size
4691 size = di_sizeof[Level];
4693 /* calculate required buffer size */
4694 *pcbNeeded = size * number;
4696 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4697 i < number;
4698 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4699 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4700 != ERROR_SUCCESS) {
4701 ERR("Can't enum key number %d\n", i);
4702 RegCloseKey(hkeyDrivers);
4703 return FALSE;
4705 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4706 env, Level, ptr,
4707 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4708 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4709 &needed, unicode)) {
4710 RegCloseKey(hkeyDrivers);
4711 return FALSE;
4713 *pcbNeeded += needed;
4716 RegCloseKey(hkeyDrivers);
4718 if(cbBuf < *pcbNeeded){
4719 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4720 return FALSE;
4723 *pcReturned = number;
4724 return TRUE;
4727 /*****************************************************************************
4728 * EnumPrinterDriversW [WINSPOOL.@]
4730 * see function EnumPrinterDrivers for RETURNS, BUGS
4732 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4733 LPBYTE pDriverInfo, DWORD cbBuf,
4734 LPDWORD pcbNeeded, LPDWORD pcReturned)
4736 static const WCHAR allW[] = {'a','l','l',0};
4738 if (pEnvironment && !strcmpW(pEnvironment, allW))
4740 BOOL ret;
4741 DWORD i, needed, returned, bufsize = cbBuf;
4743 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4745 needed = returned = 0;
4746 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4747 pDriverInfo, bufsize, &needed, &returned, TRUE);
4748 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4749 else if (ret)
4751 bufsize -= needed;
4752 if (pDriverInfo) pDriverInfo += needed;
4753 if (pcReturned) *pcReturned += returned;
4755 if (pcbNeeded) *pcbNeeded += needed;
4757 return ret;
4759 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4760 cbBuf, pcbNeeded, pcReturned, TRUE);
4763 /*****************************************************************************
4764 * EnumPrinterDriversA [WINSPOOL.@]
4766 * see function EnumPrinterDrivers for RETURNS, BUGS
4768 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4769 LPBYTE pDriverInfo, DWORD cbBuf,
4770 LPDWORD pcbNeeded, LPDWORD pcReturned)
4772 BOOL ret;
4773 UNICODE_STRING pNameW, pEnvironmentW;
4774 PWSTR pwstrNameW, pwstrEnvironmentW;
4776 pwstrNameW = asciitounicode(&pNameW, pName);
4777 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4779 if (pEnvironment && !strcmp(pEnvironment, "all"))
4781 DWORD i, needed, returned, bufsize = cbBuf;
4783 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4785 needed = returned = 0;
4786 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
4787 pDriverInfo, bufsize, &needed, &returned, FALSE);
4788 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
4789 else if (ret)
4791 bufsize -= needed;
4792 if (pDriverInfo) pDriverInfo += needed;
4793 if (pcReturned) *pcReturned += returned;
4795 if (pcbNeeded) *pcbNeeded += needed;
4798 else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4799 Level, pDriverInfo, cbBuf, pcbNeeded,
4800 pcReturned, FALSE);
4801 RtlFreeUnicodeString(&pNameW);
4802 RtlFreeUnicodeString(&pEnvironmentW);
4804 return ret;
4807 /******************************************************************************
4808 * EnumPortsA (WINSPOOL.@)
4810 * See EnumPortsW.
4813 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4814 LPDWORD pcbNeeded, LPDWORD pcReturned)
4816 BOOL res;
4817 LPBYTE bufferW = NULL;
4818 LPWSTR nameW = NULL;
4819 DWORD needed = 0;
4820 DWORD numentries = 0;
4821 INT len;
4823 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4824 cbBuf, pcbNeeded, pcReturned);
4826 /* convert servername to unicode */
4827 if (pName) {
4828 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4829 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4830 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4832 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4833 needed = cbBuf * sizeof(WCHAR);
4834 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4835 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4837 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4838 if (pcbNeeded) needed = *pcbNeeded;
4839 /* HeapReAlloc return NULL, when bufferW was NULL */
4840 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4841 HeapAlloc(GetProcessHeap(), 0, needed);
4843 /* Try again with the large Buffer */
4844 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4846 needed = pcbNeeded ? *pcbNeeded : 0;
4847 numentries = pcReturned ? *pcReturned : 0;
4850 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4851 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4853 if (res) {
4854 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
4855 DWORD entrysize = 0;
4856 DWORD index;
4857 LPSTR ptr;
4858 LPPORT_INFO_2W pi2w;
4859 LPPORT_INFO_2A pi2a;
4861 needed = 0;
4862 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
4864 /* First pass: calculate the size for all Entries */
4865 pi2w = (LPPORT_INFO_2W) bufferW;
4866 pi2a = (LPPORT_INFO_2A) pPorts;
4867 index = 0;
4868 while (index < numentries) {
4869 index++;
4870 needed += entrysize; /* PORT_INFO_?A */
4871 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
4873 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4874 NULL, 0, NULL, NULL);
4875 if (Level > 1) {
4876 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4877 NULL, 0, NULL, NULL);
4878 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4879 NULL, 0, NULL, NULL);
4881 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4882 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4883 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4886 /* check for errors and quit on failure */
4887 if (cbBuf < needed) {
4888 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4889 res = FALSE;
4890 goto cleanup;
4892 len = entrysize * numentries; /* room for all PORT_INFO_?A */
4893 ptr = (LPSTR) &pPorts[len]; /* room for strings */
4894 cbBuf -= len ; /* free Bytes in the user-Buffer */
4895 pi2w = (LPPORT_INFO_2W) bufferW;
4896 pi2a = (LPPORT_INFO_2A) pPorts;
4897 index = 0;
4898 /* Second Pass: Fill the User Buffer (if we have one) */
4899 while ((index < numentries) && pPorts) {
4900 index++;
4901 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
4902 pi2a->pPortName = ptr;
4903 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4904 ptr, cbBuf , NULL, NULL);
4905 ptr += len;
4906 cbBuf -= len;
4907 if (Level > 1) {
4908 pi2a->pMonitorName = ptr;
4909 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4910 ptr, cbBuf, NULL, NULL);
4911 ptr += len;
4912 cbBuf -= len;
4914 pi2a->pDescription = ptr;
4915 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4916 ptr, cbBuf, NULL, NULL);
4917 ptr += len;
4918 cbBuf -= len;
4920 pi2a->fPortType = pi2w->fPortType;
4921 pi2a->Reserved = 0; /* documented: "must be zero" */
4924 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4925 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4926 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4930 cleanup:
4931 if (pcbNeeded) *pcbNeeded = needed;
4932 if (pcReturned) *pcReturned = (res) ? numentries : 0;
4934 HeapFree(GetProcessHeap(), 0, nameW);
4935 HeapFree(GetProcessHeap(), 0, bufferW);
4937 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4938 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4940 return (res);
4944 /******************************************************************************
4945 * EnumPortsW (WINSPOOL.@)
4947 * Enumerate available Ports
4949 * PARAMS
4950 * pName [I] Servername or NULL (local Computer)
4951 * Level [I] Structure-Level (1 or 2)
4952 * pPorts [O] PTR to Buffer that receives the Result
4953 * cbBuf [I] Size of Buffer at pPorts
4954 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
4955 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
4957 * RETURNS
4958 * Success: TRUE
4959 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
4962 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4965 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
4966 cbBuf, pcbNeeded, pcReturned);
4968 if ((backend == NULL) && !load_backend()) return FALSE;
4970 /* Level is not checked in win9x */
4971 if (!Level || (Level > 2)) {
4972 WARN("level (%d) is ignored in win9x\n", Level);
4973 SetLastError(ERROR_INVALID_LEVEL);
4974 return FALSE;
4976 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
4977 SetLastError(RPC_X_NULL_REF_POINTER);
4978 return FALSE;
4981 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
4984 /******************************************************************************
4985 * GetDefaultPrinterW (WINSPOOL.@)
4987 * FIXME
4988 * This function must read the value from data 'device' of key
4989 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4991 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4993 BOOL retval = TRUE;
4994 DWORD insize, len;
4995 WCHAR *buffer, *ptr;
4997 if (!namesize)
4999 SetLastError(ERROR_INVALID_PARAMETER);
5000 return FALSE;
5003 /* make the buffer big enough for the stuff from the profile/registry,
5004 * the content must fit into the local buffer to compute the correct
5005 * size even if the extern buffer is too small or not given.
5006 * (20 for ,driver,port) */
5007 insize = *namesize;
5008 len = max(100, (insize + 20));
5009 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5011 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5013 SetLastError (ERROR_FILE_NOT_FOUND);
5014 retval = FALSE;
5015 goto end;
5017 TRACE("%s\n", debugstr_w(buffer));
5019 if ((ptr = strchrW(buffer, ',')) == NULL)
5021 SetLastError(ERROR_INVALID_NAME);
5022 retval = FALSE;
5023 goto end;
5026 *ptr = 0;
5027 *namesize = strlenW(buffer) + 1;
5028 if(!name || (*namesize > insize))
5030 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5031 retval = FALSE;
5032 goto end;
5034 strcpyW(name, buffer);
5036 end:
5037 HeapFree( GetProcessHeap(), 0, buffer);
5038 return retval;
5042 /******************************************************************************
5043 * GetDefaultPrinterA (WINSPOOL.@)
5045 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5047 BOOL retval = TRUE;
5048 DWORD insize = 0;
5049 WCHAR *bufferW = NULL;
5051 if (!namesize)
5053 SetLastError(ERROR_INVALID_PARAMETER);
5054 return FALSE;
5057 if(name && *namesize) {
5058 insize = *namesize;
5059 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5062 if(!GetDefaultPrinterW( bufferW, namesize)) {
5063 retval = FALSE;
5064 goto end;
5067 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5068 NULL, NULL);
5069 if (!*namesize)
5071 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5072 retval = FALSE;
5074 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5076 end:
5077 HeapFree( GetProcessHeap(), 0, bufferW);
5078 return retval;
5082 /******************************************************************************
5083 * SetDefaultPrinterW (WINSPOOL.204)
5085 * Set the Name of the Default Printer
5087 * PARAMS
5088 * pszPrinter [I] Name of the Printer or NULL
5090 * RETURNS
5091 * Success: True
5092 * Failure: FALSE
5094 * NOTES
5095 * When the Parameter is NULL or points to an Empty String and
5096 * a Default Printer was already present, then this Function changes nothing.
5097 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5098 * the First enumerated local Printer is used.
5101 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5104 TRACE("(%s)\n", debugstr_w(pszPrinter));
5106 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5107 return FALSE;
5110 /******************************************************************************
5111 * SetDefaultPrinterA (WINSPOOL.202)
5113 * See SetDefaultPrinterW.
5116 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5119 TRACE("(%s)\n", debugstr_a(pszPrinter));
5121 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5122 return FALSE;
5126 /******************************************************************************
5127 * SetPrinterDataExA (WINSPOOL.@)
5129 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5130 LPCSTR pValueName, DWORD Type,
5131 LPBYTE pData, DWORD cbData)
5133 HKEY hkeyPrinter, hkeySubkey;
5134 DWORD ret;
5136 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5137 debugstr_a(pValueName), Type, pData, cbData);
5139 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5140 != ERROR_SUCCESS)
5141 return ret;
5143 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5144 != ERROR_SUCCESS) {
5145 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5146 RegCloseKey(hkeyPrinter);
5147 return ret;
5149 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5150 RegCloseKey(hkeySubkey);
5151 RegCloseKey(hkeyPrinter);
5152 return ret;
5155 /******************************************************************************
5156 * SetPrinterDataExW (WINSPOOL.@)
5158 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5159 LPCWSTR pValueName, DWORD Type,
5160 LPBYTE pData, DWORD cbData)
5162 HKEY hkeyPrinter, hkeySubkey;
5163 DWORD ret;
5165 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5166 debugstr_w(pValueName), Type, pData, cbData);
5168 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5169 != ERROR_SUCCESS)
5170 return ret;
5172 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5173 != ERROR_SUCCESS) {
5174 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5175 RegCloseKey(hkeyPrinter);
5176 return ret;
5178 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5179 RegCloseKey(hkeySubkey);
5180 RegCloseKey(hkeyPrinter);
5181 return ret;
5184 /******************************************************************************
5185 * SetPrinterDataA (WINSPOOL.@)
5187 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5188 LPBYTE pData, DWORD cbData)
5190 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5191 pData, cbData);
5194 /******************************************************************************
5195 * SetPrinterDataW (WINSPOOL.@)
5197 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5198 LPBYTE pData, DWORD cbData)
5200 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5201 pData, cbData);
5204 /******************************************************************************
5205 * GetPrinterDataExA (WINSPOOL.@)
5207 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5208 LPCSTR pValueName, LPDWORD pType,
5209 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5211 HKEY hkeyPrinter, hkeySubkey;
5212 DWORD ret;
5214 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5215 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5216 pcbNeeded);
5218 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5219 != ERROR_SUCCESS)
5220 return ret;
5222 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5223 != ERROR_SUCCESS) {
5224 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5225 RegCloseKey(hkeyPrinter);
5226 return ret;
5228 *pcbNeeded = nSize;
5229 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5230 RegCloseKey(hkeySubkey);
5231 RegCloseKey(hkeyPrinter);
5232 return ret;
5235 /******************************************************************************
5236 * GetPrinterDataExW (WINSPOOL.@)
5238 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5239 LPCWSTR pValueName, LPDWORD pType,
5240 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5242 HKEY hkeyPrinter, hkeySubkey;
5243 DWORD ret;
5245 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5246 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5247 pcbNeeded);
5249 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5250 != ERROR_SUCCESS)
5251 return ret;
5253 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5254 != ERROR_SUCCESS) {
5255 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5256 RegCloseKey(hkeyPrinter);
5257 return ret;
5259 *pcbNeeded = nSize;
5260 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5261 RegCloseKey(hkeySubkey);
5262 RegCloseKey(hkeyPrinter);
5263 return ret;
5266 /******************************************************************************
5267 * GetPrinterDataA (WINSPOOL.@)
5269 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5270 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5272 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5273 pData, nSize, pcbNeeded);
5276 /******************************************************************************
5277 * GetPrinterDataW (WINSPOOL.@)
5279 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5280 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5282 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5283 pData, nSize, pcbNeeded);
5286 /*******************************************************************************
5287 * EnumPrinterDataExW [WINSPOOL.@]
5289 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5290 LPBYTE pEnumValues, DWORD cbEnumValues,
5291 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5293 HKEY hkPrinter, hkSubKey;
5294 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5295 cbValueNameLen, cbMaxValueLen, cbValueLen,
5296 cbBufSize, dwType;
5297 LPWSTR lpValueName;
5298 HANDLE hHeap;
5299 PBYTE lpValue;
5300 PPRINTER_ENUM_VALUESW ppev;
5302 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5304 if (pKeyName == NULL || *pKeyName == 0)
5305 return ERROR_INVALID_PARAMETER;
5307 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5308 if (ret != ERROR_SUCCESS)
5310 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5311 hPrinter, ret);
5312 return ret;
5315 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5316 if (ret != ERROR_SUCCESS)
5318 r = RegCloseKey (hkPrinter);
5319 if (r != ERROR_SUCCESS)
5320 WARN ("RegCloseKey returned %i\n", r);
5321 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5322 debugstr_w (pKeyName), ret);
5323 return ret;
5326 ret = RegCloseKey (hkPrinter);
5327 if (ret != ERROR_SUCCESS)
5329 ERR ("RegCloseKey returned %i\n", ret);
5330 r = RegCloseKey (hkSubKey);
5331 if (r != ERROR_SUCCESS)
5332 WARN ("RegCloseKey returned %i\n", r);
5333 return ret;
5336 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5337 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5338 if (ret != ERROR_SUCCESS)
5340 r = RegCloseKey (hkSubKey);
5341 if (r != ERROR_SUCCESS)
5342 WARN ("RegCloseKey returned %i\n", r);
5343 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5344 return ret;
5347 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5348 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5350 if (cValues == 0) /* empty key */
5352 r = RegCloseKey (hkSubKey);
5353 if (r != ERROR_SUCCESS)
5354 WARN ("RegCloseKey returned %i\n", r);
5355 *pcbEnumValues = *pnEnumValues = 0;
5356 return ERROR_SUCCESS;
5359 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5361 hHeap = GetProcessHeap ();
5362 if (hHeap == NULL)
5364 ERR ("GetProcessHeap failed\n");
5365 r = RegCloseKey (hkSubKey);
5366 if (r != ERROR_SUCCESS)
5367 WARN ("RegCloseKey returned %i\n", r);
5368 return ERROR_OUTOFMEMORY;
5371 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5372 if (lpValueName == NULL)
5374 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5375 r = RegCloseKey (hkSubKey);
5376 if (r != ERROR_SUCCESS)
5377 WARN ("RegCloseKey returned %i\n", r);
5378 return ERROR_OUTOFMEMORY;
5381 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5382 if (lpValue == NULL)
5384 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5385 if (HeapFree (hHeap, 0, lpValueName) == 0)
5386 WARN ("HeapFree failed with code %i\n", GetLastError ());
5387 r = RegCloseKey (hkSubKey);
5388 if (r != ERROR_SUCCESS)
5389 WARN ("RegCloseKey returned %i\n", r);
5390 return ERROR_OUTOFMEMORY;
5393 TRACE ("pass 1: calculating buffer required for all names and values\n");
5395 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5397 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5399 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5401 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5402 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5403 NULL, NULL, lpValue, &cbValueLen);
5404 if (ret != ERROR_SUCCESS)
5406 if (HeapFree (hHeap, 0, lpValue) == 0)
5407 WARN ("HeapFree failed with code %i\n", GetLastError ());
5408 if (HeapFree (hHeap, 0, lpValueName) == 0)
5409 WARN ("HeapFree failed with code %i\n", GetLastError ());
5410 r = RegCloseKey (hkSubKey);
5411 if (r != ERROR_SUCCESS)
5412 WARN ("RegCloseKey returned %i\n", r);
5413 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5414 return ret;
5417 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5418 debugstr_w (lpValueName), dwIndex,
5419 cbValueNameLen + 1, cbValueLen);
5421 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5422 cbBufSize += cbValueLen;
5425 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5427 *pcbEnumValues = cbBufSize;
5428 *pnEnumValues = cValues;
5430 if (cbEnumValues < cbBufSize) /* buffer too small */
5432 if (HeapFree (hHeap, 0, lpValue) == 0)
5433 WARN ("HeapFree failed with code %i\n", GetLastError ());
5434 if (HeapFree (hHeap, 0, lpValueName) == 0)
5435 WARN ("HeapFree failed with code %i\n", GetLastError ());
5436 r = RegCloseKey (hkSubKey);
5437 if (r != ERROR_SUCCESS)
5438 WARN ("RegCloseKey returned %i\n", r);
5439 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5440 return ERROR_MORE_DATA;
5443 TRACE ("pass 2: copying all names and values to buffer\n");
5445 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5446 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5448 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5450 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5451 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5452 NULL, &dwType, lpValue, &cbValueLen);
5453 if (ret != ERROR_SUCCESS)
5455 if (HeapFree (hHeap, 0, lpValue) == 0)
5456 WARN ("HeapFree failed with code %i\n", GetLastError ());
5457 if (HeapFree (hHeap, 0, lpValueName) == 0)
5458 WARN ("HeapFree failed with code %i\n", GetLastError ());
5459 r = RegCloseKey (hkSubKey);
5460 if (r != ERROR_SUCCESS)
5461 WARN ("RegCloseKey returned %i\n", r);
5462 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5463 return ret;
5466 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5467 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5468 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5469 pEnumValues += cbValueNameLen;
5471 /* return # of *bytes* (including trailing \0), not # of chars */
5472 ppev[dwIndex].cbValueName = cbValueNameLen;
5474 ppev[dwIndex].dwType = dwType;
5476 memcpy (pEnumValues, lpValue, cbValueLen);
5477 ppev[dwIndex].pData = pEnumValues;
5478 pEnumValues += cbValueLen;
5480 ppev[dwIndex].cbData = cbValueLen;
5482 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5483 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5486 if (HeapFree (hHeap, 0, lpValue) == 0)
5488 ret = GetLastError ();
5489 ERR ("HeapFree failed with code %i\n", ret);
5490 if (HeapFree (hHeap, 0, lpValueName) == 0)
5491 WARN ("HeapFree failed with code %i\n", GetLastError ());
5492 r = RegCloseKey (hkSubKey);
5493 if (r != ERROR_SUCCESS)
5494 WARN ("RegCloseKey returned %i\n", r);
5495 return ret;
5498 if (HeapFree (hHeap, 0, lpValueName) == 0)
5500 ret = GetLastError ();
5501 ERR ("HeapFree failed with code %i\n", ret);
5502 r = RegCloseKey (hkSubKey);
5503 if (r != ERROR_SUCCESS)
5504 WARN ("RegCloseKey returned %i\n", r);
5505 return ret;
5508 ret = RegCloseKey (hkSubKey);
5509 if (ret != ERROR_SUCCESS)
5511 ERR ("RegCloseKey returned %i\n", ret);
5512 return ret;
5515 return ERROR_SUCCESS;
5518 /*******************************************************************************
5519 * EnumPrinterDataExA [WINSPOOL.@]
5521 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5522 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5523 * what Windows 2000 SP1 does.
5526 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5527 LPBYTE pEnumValues, DWORD cbEnumValues,
5528 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5530 INT len;
5531 LPWSTR pKeyNameW;
5532 DWORD ret, dwIndex, dwBufSize;
5533 HANDLE hHeap;
5534 LPSTR pBuffer;
5536 TRACE ("%p %s\n", hPrinter, pKeyName);
5538 if (pKeyName == NULL || *pKeyName == 0)
5539 return ERROR_INVALID_PARAMETER;
5541 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5542 if (len == 0)
5544 ret = GetLastError ();
5545 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5546 return ret;
5549 hHeap = GetProcessHeap ();
5550 if (hHeap == NULL)
5552 ERR ("GetProcessHeap failed\n");
5553 return ERROR_OUTOFMEMORY;
5556 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5557 if (pKeyNameW == NULL)
5559 ERR ("Failed to allocate %i bytes from process heap\n",
5560 (LONG)(len * sizeof (WCHAR)));
5561 return ERROR_OUTOFMEMORY;
5564 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5566 ret = GetLastError ();
5567 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5568 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5569 WARN ("HeapFree failed with code %i\n", GetLastError ());
5570 return ret;
5573 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5574 pcbEnumValues, pnEnumValues);
5575 if (ret != ERROR_SUCCESS)
5577 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5578 WARN ("HeapFree failed with code %i\n", GetLastError ());
5579 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5580 return ret;
5583 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5585 ret = GetLastError ();
5586 ERR ("HeapFree failed with code %i\n", ret);
5587 return ret;
5590 if (*pnEnumValues == 0) /* empty key */
5591 return ERROR_SUCCESS;
5593 dwBufSize = 0;
5594 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5596 PPRINTER_ENUM_VALUESW ppev =
5597 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5599 if (dwBufSize < ppev->cbValueName)
5600 dwBufSize = ppev->cbValueName;
5602 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5603 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5604 dwBufSize = ppev->cbData;
5607 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5609 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5610 if (pBuffer == NULL)
5612 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5613 return ERROR_OUTOFMEMORY;
5616 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5618 PPRINTER_ENUM_VALUESW ppev =
5619 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5621 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5622 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5623 NULL);
5624 if (len == 0)
5626 ret = GetLastError ();
5627 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5628 if (HeapFree (hHeap, 0, pBuffer) == 0)
5629 WARN ("HeapFree failed with code %i\n", GetLastError ());
5630 return ret;
5633 memcpy (ppev->pValueName, pBuffer, len);
5635 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5637 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5638 ppev->dwType != REG_MULTI_SZ)
5639 continue;
5641 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5642 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5643 if (len == 0)
5645 ret = GetLastError ();
5646 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5647 if (HeapFree (hHeap, 0, pBuffer) == 0)
5648 WARN ("HeapFree failed with code %i\n", GetLastError ());
5649 return ret;
5652 memcpy (ppev->pData, pBuffer, len);
5654 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5655 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5658 if (HeapFree (hHeap, 0, pBuffer) == 0)
5660 ret = GetLastError ();
5661 ERR ("HeapFree failed with code %i\n", ret);
5662 return ret;
5665 return ERROR_SUCCESS;
5668 /******************************************************************************
5669 * AbortPrinter (WINSPOOL.@)
5671 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5673 FIXME("(%p), stub!\n", hPrinter);
5674 return TRUE;
5677 /******************************************************************************
5678 * AddPortA (WINSPOOL.@)
5680 * See AddPortW.
5683 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5685 LPWSTR nameW = NULL;
5686 LPWSTR monitorW = NULL;
5687 DWORD len;
5688 BOOL res;
5690 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5692 if (pName) {
5693 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5694 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5695 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5698 if (pMonitorName) {
5699 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5700 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5701 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5703 res = AddPortW(nameW, hWnd, monitorW);
5704 HeapFree(GetProcessHeap(), 0, nameW);
5705 HeapFree(GetProcessHeap(), 0, monitorW);
5706 return res;
5709 /******************************************************************************
5710 * AddPortW (WINSPOOL.@)
5712 * Add a Port for a specific Monitor
5714 * PARAMS
5715 * pName [I] Servername or NULL (local Computer)
5716 * hWnd [I] Handle to parent Window for the Dialog-Box
5717 * pMonitorName [I] Name of the Monitor that manage the Port
5719 * RETURNS
5720 * Success: TRUE
5721 * Failure: FALSE
5724 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5726 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5728 if ((backend == NULL) && !load_backend()) return FALSE;
5730 if (!pMonitorName) {
5731 SetLastError(RPC_X_NULL_REF_POINTER);
5732 return FALSE;
5735 return backend->fpAddPort(pName, hWnd, pMonitorName);
5738 /******************************************************************************
5739 * AddPortExA (WINSPOOL.@)
5741 * See AddPortExW.
5744 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5746 PORT_INFO_2W pi2W;
5747 PORT_INFO_2A * pi2A;
5748 LPWSTR nameW = NULL;
5749 LPWSTR monitorW = NULL;
5750 DWORD len;
5751 BOOL res;
5753 pi2A = (PORT_INFO_2A *) pBuffer;
5755 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5756 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5758 if ((level < 1) || (level > 2)) {
5759 SetLastError(ERROR_INVALID_LEVEL);
5760 return FALSE;
5763 if (!pi2A) {
5764 SetLastError(ERROR_INVALID_PARAMETER);
5765 return FALSE;
5768 if (pName) {
5769 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5770 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5771 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5774 if (pMonitorName) {
5775 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5776 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5777 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5780 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5782 if (pi2A->pPortName) {
5783 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5784 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5785 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5788 if (level > 1) {
5789 if (pi2A->pMonitorName) {
5790 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5791 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5792 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5795 if (pi2A->pDescription) {
5796 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5797 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5798 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5800 pi2W.fPortType = pi2A->fPortType;
5801 pi2W.Reserved = pi2A->Reserved;
5804 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
5806 HeapFree(GetProcessHeap(), 0, nameW);
5807 HeapFree(GetProcessHeap(), 0, monitorW);
5808 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
5809 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
5810 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
5811 return res;
5815 /******************************************************************************
5816 * AddPortExW (WINSPOOL.@)
5818 * Add a Port for a specific Monitor, without presenting a user interface
5820 * PARAMS
5821 * pName [I] Servername or NULL (local Computer)
5822 * level [I] Structure-Level (1 or 2) for pBuffer
5823 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5824 * pMonitorName [I] Name of the Monitor that manage the Port
5826 * RETURNS
5827 * Success: TRUE
5828 * Failure: FALSE
5831 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
5833 PORT_INFO_2W * pi2;
5835 pi2 = (PORT_INFO_2W *) pBuffer;
5837 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
5838 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
5839 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
5840 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
5842 if ((backend == NULL) && !load_backend()) return FALSE;
5844 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
5845 SetLastError(ERROR_INVALID_PARAMETER);
5846 return FALSE;
5849 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
5852 /******************************************************************************
5853 * AddPrinterConnectionA (WINSPOOL.@)
5855 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5857 FIXME("%s\n", debugstr_a(pName));
5858 return FALSE;
5861 /******************************************************************************
5862 * AddPrinterConnectionW (WINSPOOL.@)
5864 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5866 FIXME("%s\n", debugstr_w(pName));
5867 return FALSE;
5870 /******************************************************************************
5871 * AddPrinterDriverExW (WINSPOOL.@)
5873 * Install a Printer Driver with the Option to upgrade / downgrade the Files
5875 * PARAMS
5876 * pName [I] Servername or NULL (local Computer)
5877 * level [I] Level for the supplied DRIVER_INFO_*W struct
5878 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5879 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
5881 * RESULTS
5882 * Success: TRUE
5883 * Failure: FALSE
5886 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5888 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
5890 if ((backend == NULL) && !load_backend()) return FALSE;
5892 if (level < 2 || level == 5 || level == 7 || level > 8) {
5893 SetLastError(ERROR_INVALID_LEVEL);
5894 return FALSE;
5897 if (!pDriverInfo) {
5898 SetLastError(ERROR_INVALID_PARAMETER);
5899 return FALSE;
5902 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
5905 /******************************************************************************
5906 * AddPrinterDriverExA (WINSPOOL.@)
5908 * See AddPrinterDriverExW.
5911 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5913 DRIVER_INFO_8A *diA;
5914 DRIVER_INFO_8W diW;
5915 LPWSTR nameW = NULL;
5916 DWORD lenA;
5917 DWORD len;
5918 DWORD res = FALSE;
5920 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
5922 diA = (DRIVER_INFO_8A *) pDriverInfo;
5923 ZeroMemory(&diW, sizeof(diW));
5925 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
5926 SetLastError(ERROR_INVALID_LEVEL);
5927 return FALSE;
5930 if (diA == NULL) {
5931 SetLastError(ERROR_INVALID_PARAMETER);
5932 return FALSE;
5935 /* convert servername to unicode */
5936 if (pName) {
5937 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5938 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5939 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5942 /* common fields */
5943 diW.cVersion = diA->cVersion;
5945 if (diA->pName) {
5946 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
5947 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5948 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
5951 if (diA->pEnvironment) {
5952 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
5953 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5954 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
5957 if (diA->pDriverPath) {
5958 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
5959 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5960 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
5963 if (diA->pDataFile) {
5964 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
5965 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5966 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
5969 if (diA->pConfigFile) {
5970 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
5971 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5972 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
5975 if ((Level > 2) && diA->pDependentFiles) {
5976 lenA = multi_sz_lenA(diA->pDependentFiles);
5977 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
5978 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5979 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
5982 if ((Level > 2) && diA->pMonitorName) {
5983 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
5984 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5985 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
5988 if ((Level > 3) && diA->pDefaultDataType) {
5989 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
5990 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5991 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
5994 if ((Level > 3) && diA->pszzPreviousNames) {
5995 lenA = multi_sz_lenA(diA->pszzPreviousNames);
5996 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
5997 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5998 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6001 if ((Level > 5) && diA->pszMfgName) {
6002 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6003 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6004 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6007 if ((Level > 5) && diA->pszOEMUrl) {
6008 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6009 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6010 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6013 if ((Level > 5) && diA->pszHardwareID) {
6014 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6015 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6016 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6019 if ((Level > 5) && diA->pszProvider) {
6020 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6021 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6022 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6025 if (Level > 7) {
6026 FIXME("level %u is incomplete\n", Level);
6029 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6030 TRACE("got %u with %u\n", res, GetLastError());
6031 HeapFree(GetProcessHeap(), 0, nameW);
6032 HeapFree(GetProcessHeap(), 0, diW.pName);
6033 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6034 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6035 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6036 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6037 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6038 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6039 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6040 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6041 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6042 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6043 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6044 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6046 TRACE("=> %u with %u\n", res, GetLastError());
6047 return res;
6050 /******************************************************************************
6051 * ConfigurePortA (WINSPOOL.@)
6053 * See ConfigurePortW.
6056 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6058 LPWSTR nameW = NULL;
6059 LPWSTR portW = NULL;
6060 INT len;
6061 DWORD res;
6063 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6065 /* convert servername to unicode */
6066 if (pName) {
6067 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6068 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6069 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6072 /* convert portname to unicode */
6073 if (pPortName) {
6074 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6075 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6076 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6079 res = ConfigurePortW(nameW, hWnd, portW);
6080 HeapFree(GetProcessHeap(), 0, nameW);
6081 HeapFree(GetProcessHeap(), 0, portW);
6082 return res;
6085 /******************************************************************************
6086 * ConfigurePortW (WINSPOOL.@)
6088 * Display the Configuration-Dialog for a specific Port
6090 * PARAMS
6091 * pName [I] Servername or NULL (local Computer)
6092 * hWnd [I] Handle to parent Window for the Dialog-Box
6093 * pPortName [I] Name of the Port, that should be configured
6095 * RETURNS
6096 * Success: TRUE
6097 * Failure: FALSE
6100 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6103 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6105 if ((backend == NULL) && !load_backend()) return FALSE;
6107 if (!pPortName) {
6108 SetLastError(RPC_X_NULL_REF_POINTER);
6109 return FALSE;
6112 return backend->fpConfigurePort(pName, hWnd, pPortName);
6115 /******************************************************************************
6116 * ConnectToPrinterDlg (WINSPOOL.@)
6118 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6120 FIXME("%p %x\n", hWnd, Flags);
6121 return NULL;
6124 /******************************************************************************
6125 * DeletePrinterConnectionA (WINSPOOL.@)
6127 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6129 FIXME("%s\n", debugstr_a(pName));
6130 return TRUE;
6133 /******************************************************************************
6134 * DeletePrinterConnectionW (WINSPOOL.@)
6136 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6138 FIXME("%s\n", debugstr_w(pName));
6139 return TRUE;
6142 /******************************************************************************
6143 * DeletePrinterDriverExW (WINSPOOL.@)
6145 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6146 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6148 HKEY hkey_drivers;
6149 BOOL ret = FALSE;
6151 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6152 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6154 if(pName && pName[0])
6156 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6157 SetLastError(ERROR_INVALID_PARAMETER);
6158 return FALSE;
6161 if(dwDeleteFlag)
6163 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6164 SetLastError(ERROR_INVALID_PARAMETER);
6165 return FALSE;
6168 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6170 if(!hkey_drivers)
6172 ERR("Can't open drivers key\n");
6173 return FALSE;
6176 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6177 ret = TRUE;
6179 RegCloseKey(hkey_drivers);
6181 return ret;
6184 /******************************************************************************
6185 * DeletePrinterDriverExA (WINSPOOL.@)
6187 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6188 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6190 UNICODE_STRING NameW, EnvW, DriverW;
6191 BOOL ret;
6193 asciitounicode(&NameW, pName);
6194 asciitounicode(&EnvW, pEnvironment);
6195 asciitounicode(&DriverW, pDriverName);
6197 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6199 RtlFreeUnicodeString(&DriverW);
6200 RtlFreeUnicodeString(&EnvW);
6201 RtlFreeUnicodeString(&NameW);
6203 return ret;
6206 /******************************************************************************
6207 * DeletePrinterDataExW (WINSPOOL.@)
6209 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6210 LPCWSTR pValueName)
6212 FIXME("%p %s %s\n", hPrinter,
6213 debugstr_w(pKeyName), debugstr_w(pValueName));
6214 return ERROR_INVALID_PARAMETER;
6217 /******************************************************************************
6218 * DeletePrinterDataExA (WINSPOOL.@)
6220 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6221 LPCSTR pValueName)
6223 FIXME("%p %s %s\n", hPrinter,
6224 debugstr_a(pKeyName), debugstr_a(pValueName));
6225 return ERROR_INVALID_PARAMETER;
6228 /******************************************************************************
6229 * DeletePrintProcessorA (WINSPOOL.@)
6231 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6233 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6234 debugstr_a(pPrintProcessorName));
6235 return TRUE;
6238 /******************************************************************************
6239 * DeletePrintProcessorW (WINSPOOL.@)
6241 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6243 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6244 debugstr_w(pPrintProcessorName));
6245 return TRUE;
6248 /******************************************************************************
6249 * DeletePrintProvidorA (WINSPOOL.@)
6251 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6253 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6254 debugstr_a(pPrintProviderName));
6255 return TRUE;
6258 /******************************************************************************
6259 * DeletePrintProvidorW (WINSPOOL.@)
6261 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6263 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6264 debugstr_w(pPrintProviderName));
6265 return TRUE;
6268 /******************************************************************************
6269 * EnumFormsA (WINSPOOL.@)
6271 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6272 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6274 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6275 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6276 return FALSE;
6279 /******************************************************************************
6280 * EnumFormsW (WINSPOOL.@)
6282 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6283 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6285 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6286 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6287 return FALSE;
6290 /*****************************************************************************
6291 * EnumMonitorsA [WINSPOOL.@]
6293 * See EnumMonitorsW.
6296 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6297 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6299 BOOL res;
6300 LPBYTE bufferW = NULL;
6301 LPWSTR nameW = NULL;
6302 DWORD needed = 0;
6303 DWORD numentries = 0;
6304 INT len;
6306 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6307 cbBuf, pcbNeeded, pcReturned);
6309 /* convert servername to unicode */
6310 if (pName) {
6311 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6312 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6313 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6315 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6316 needed = cbBuf * sizeof(WCHAR);
6317 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6318 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6320 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6321 if (pcbNeeded) needed = *pcbNeeded;
6322 /* HeapReAlloc return NULL, when bufferW was NULL */
6323 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6324 HeapAlloc(GetProcessHeap(), 0, needed);
6326 /* Try again with the large Buffer */
6327 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6329 numentries = pcReturned ? *pcReturned : 0;
6330 needed = 0;
6332 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6333 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6335 if (res) {
6336 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6337 DWORD entrysize = 0;
6338 DWORD index;
6339 LPSTR ptr;
6340 LPMONITOR_INFO_2W mi2w;
6341 LPMONITOR_INFO_2A mi2a;
6343 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6344 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6346 /* First pass: calculate the size for all Entries */
6347 mi2w = (LPMONITOR_INFO_2W) bufferW;
6348 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6349 index = 0;
6350 while (index < numentries) {
6351 index++;
6352 needed += entrysize; /* MONITOR_INFO_?A */
6353 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6355 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6356 NULL, 0, NULL, NULL);
6357 if (Level > 1) {
6358 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6359 NULL, 0, NULL, NULL);
6360 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6361 NULL, 0, NULL, NULL);
6363 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6364 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6365 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6368 /* check for errors and quit on failure */
6369 if (cbBuf < needed) {
6370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6371 res = FALSE;
6372 goto emA_cleanup;
6374 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6375 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6376 cbBuf -= len ; /* free Bytes in the user-Buffer */
6377 mi2w = (LPMONITOR_INFO_2W) bufferW;
6378 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6379 index = 0;
6380 /* Second Pass: Fill the User Buffer (if we have one) */
6381 while ((index < numentries) && pMonitors) {
6382 index++;
6383 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6384 mi2a->pName = ptr;
6385 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6386 ptr, cbBuf , NULL, NULL);
6387 ptr += len;
6388 cbBuf -= len;
6389 if (Level > 1) {
6390 mi2a->pEnvironment = ptr;
6391 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6392 ptr, cbBuf, NULL, NULL);
6393 ptr += len;
6394 cbBuf -= len;
6396 mi2a->pDLLName = ptr;
6397 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6398 ptr, cbBuf, NULL, NULL);
6399 ptr += len;
6400 cbBuf -= len;
6402 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6403 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6404 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6407 emA_cleanup:
6408 if (pcbNeeded) *pcbNeeded = needed;
6409 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6411 HeapFree(GetProcessHeap(), 0, nameW);
6412 HeapFree(GetProcessHeap(), 0, bufferW);
6414 TRACE("returning %d with %d (%d byte for %d entries)\n",
6415 (res), GetLastError(), needed, numentries);
6417 return (res);
6421 /*****************************************************************************
6422 * EnumMonitorsW [WINSPOOL.@]
6424 * Enumerate available Port-Monitors
6426 * PARAMS
6427 * pName [I] Servername or NULL (local Computer)
6428 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6429 * pMonitors [O] PTR to Buffer that receives the Result
6430 * cbBuf [I] Size of Buffer at pMonitors
6431 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6432 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6434 * RETURNS
6435 * Success: TRUE
6436 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6439 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6440 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6443 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6444 cbBuf, pcbNeeded, pcReturned);
6446 if ((backend == NULL) && !load_backend()) return FALSE;
6448 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6449 SetLastError(RPC_X_NULL_REF_POINTER);
6450 return FALSE;
6453 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6456 /******************************************************************************
6457 * SpoolerInit (WINSPOOL.@)
6459 * Initialize the Spooler
6461 * RETURNS
6462 * Success: TRUE
6463 * Failure: FALSE
6465 * NOTES
6466 * The function fails on windows, when the spooler service is not running
6469 BOOL WINAPI SpoolerInit(void)
6472 if ((backend == NULL) && !load_backend()) return FALSE;
6473 return TRUE;
6476 /******************************************************************************
6477 * XcvDataW (WINSPOOL.@)
6479 * Execute commands in the Printmonitor DLL
6481 * PARAMS
6482 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6483 * pszDataName [i] Name of the command to execute
6484 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6485 * cbInputData [i] Size in Bytes of Buffer at pInputData
6486 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6487 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6488 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6489 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6491 * RETURNS
6492 * Success: TRUE
6493 * Failure: FALSE
6495 * NOTES
6496 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6497 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6499 * Minimal List of commands, that a Printmonitor DLL should support:
6501 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6502 *| "AddPort" : Add a Port
6503 *| "DeletePort": Delete a Port
6505 * Many Printmonitors support additional commands. Examples for localspl.dll:
6506 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6507 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6510 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6511 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6512 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6514 opened_printer_t *printer;
6516 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6517 pInputData, cbInputData, pOutputData,
6518 cbOutputData, pcbOutputNeeded, pdwStatus);
6520 if ((backend == NULL) && !load_backend()) return FALSE;
6522 printer = get_opened_printer(hXcv);
6523 if (!printer || (!printer->backend_printer)) {
6524 SetLastError(ERROR_INVALID_HANDLE);
6525 return FALSE;
6528 if (!pcbOutputNeeded) {
6529 SetLastError(ERROR_INVALID_PARAMETER);
6530 return FALSE;
6533 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6534 SetLastError(RPC_X_NULL_REF_POINTER);
6535 return FALSE;
6538 *pcbOutputNeeded = 0;
6540 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6541 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6545 /*****************************************************************************
6546 * EnumPrinterDataA [WINSPOOL.@]
6549 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6550 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6551 DWORD cbData, LPDWORD pcbData )
6553 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6554 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6555 return ERROR_NO_MORE_ITEMS;
6558 /*****************************************************************************
6559 * EnumPrinterDataW [WINSPOOL.@]
6562 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6563 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6564 DWORD cbData, LPDWORD pcbData )
6566 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6567 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6568 return ERROR_NO_MORE_ITEMS;
6571 /*****************************************************************************
6572 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6575 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6576 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6577 LPDWORD pcbNeeded, LPDWORD pcReturned)
6579 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6580 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6581 pcbNeeded, pcReturned);
6582 return FALSE;
6585 /*****************************************************************************
6586 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6589 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6590 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6591 LPDWORD pcbNeeded, LPDWORD pcReturned)
6593 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6594 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6595 pcbNeeded, pcReturned);
6596 return FALSE;
6599 /*****************************************************************************
6600 * EnumPrintProcessorsA [WINSPOOL.@]
6602 * See EnumPrintProcessorsW.
6605 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6606 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6608 BOOL res;
6609 LPBYTE bufferW = NULL;
6610 LPWSTR nameW = NULL;
6611 LPWSTR envW = NULL;
6612 DWORD needed = 0;
6613 DWORD numentries = 0;
6614 INT len;
6616 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6617 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6619 /* convert names to unicode */
6620 if (pName) {
6621 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6622 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6623 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6625 if (pEnvironment) {
6626 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6627 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6628 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6631 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6632 needed = cbBuf * sizeof(WCHAR);
6633 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6634 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6636 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6637 if (pcbNeeded) needed = *pcbNeeded;
6638 /* HeapReAlloc return NULL, when bufferW was NULL */
6639 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6640 HeapAlloc(GetProcessHeap(), 0, needed);
6642 /* Try again with the large Buffer */
6643 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6645 numentries = pcReturned ? *pcReturned : 0;
6646 needed = 0;
6648 if (res) {
6649 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6650 DWORD index;
6651 LPSTR ptr;
6652 PPRINTPROCESSOR_INFO_1W ppiw;
6653 PPRINTPROCESSOR_INFO_1A ppia;
6655 /* First pass: calculate the size for all Entries */
6656 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6657 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6658 index = 0;
6659 while (index < numentries) {
6660 index++;
6661 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6662 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6664 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6665 NULL, 0, NULL, NULL);
6667 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6668 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6671 /* check for errors and quit on failure */
6672 if (cbBuf < needed) {
6673 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6674 res = FALSE;
6675 goto epp_cleanup;
6678 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6679 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6680 cbBuf -= len ; /* free Bytes in the user-Buffer */
6681 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6682 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6683 index = 0;
6684 /* Second Pass: Fill the User Buffer (if we have one) */
6685 while ((index < numentries) && pPPInfo) {
6686 index++;
6687 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6688 ppia->pName = ptr;
6689 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6690 ptr, cbBuf , NULL, NULL);
6691 ptr += len;
6692 cbBuf -= len;
6694 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6695 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6699 epp_cleanup:
6700 if (pcbNeeded) *pcbNeeded = needed;
6701 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6703 HeapFree(GetProcessHeap(), 0, nameW);
6704 HeapFree(GetProcessHeap(), 0, envW);
6705 HeapFree(GetProcessHeap(), 0, bufferW);
6707 TRACE("returning %d with %d (%d byte for %d entries)\n",
6708 (res), GetLastError(), needed, numentries);
6710 return (res);
6713 /*****************************************************************************
6714 * EnumPrintProcessorsW [WINSPOOL.@]
6716 * Enumerate available Print Processors
6718 * PARAMS
6719 * pName [I] Servername or NULL (local Computer)
6720 * pEnvironment [I] Printing-Environment or NULL (Default)
6721 * Level [I] Structure-Level (Only 1 is allowed)
6722 * pPPInfo [O] PTR to Buffer that receives the Result
6723 * cbBuf [I] Size of Buffer at pPPInfo
6724 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6725 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6727 * RETURNS
6728 * Success: TRUE
6729 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6732 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6733 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6736 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6737 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6739 if ((backend == NULL) && !load_backend()) return FALSE;
6741 if (!pcbNeeded || !pcReturned) {
6742 SetLastError(RPC_X_NULL_REF_POINTER);
6743 return FALSE;
6746 if (!pPPInfo && (cbBuf > 0)) {
6747 SetLastError(ERROR_INVALID_USER_BUFFER);
6748 return FALSE;
6751 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6752 cbBuf, pcbNeeded, pcReturned);
6755 /*****************************************************************************
6756 * ExtDeviceMode [WINSPOOL.@]
6759 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6760 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6761 DWORD fMode)
6763 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6764 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6765 debugstr_a(pProfile), fMode);
6766 return -1;
6769 /*****************************************************************************
6770 * FindClosePrinterChangeNotification [WINSPOOL.@]
6773 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6775 FIXME("Stub: %p\n", hChange);
6776 return TRUE;
6779 /*****************************************************************************
6780 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6783 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6784 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6786 FIXME("Stub: %p %x %x %p\n",
6787 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6788 return INVALID_HANDLE_VALUE;
6791 /*****************************************************************************
6792 * FindNextPrinterChangeNotification [WINSPOOL.@]
6795 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6796 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6798 FIXME("Stub: %p %p %p %p\n",
6799 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6800 return FALSE;
6803 /*****************************************************************************
6804 * FreePrinterNotifyInfo [WINSPOOL.@]
6807 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6809 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6810 return TRUE;
6813 /*****************************************************************************
6814 * string_to_buf
6816 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6817 * ansi depending on the unicode parameter.
6819 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6821 if(!str)
6823 *size = 0;
6824 return TRUE;
6827 if(unicode)
6829 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6830 if(*size <= cb)
6832 memcpy(ptr, str, *size);
6833 return TRUE;
6835 return FALSE;
6837 else
6839 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6840 if(*size <= cb)
6842 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6843 return TRUE;
6845 return FALSE;
6849 /*****************************************************************************
6850 * get_job_info_1
6852 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6853 LPDWORD pcbNeeded, BOOL unicode)
6855 DWORD size, left = cbBuf;
6856 BOOL space = (cbBuf > 0);
6857 LPBYTE ptr = buf;
6859 *pcbNeeded = 0;
6861 if(space)
6863 ji1->JobId = job->job_id;
6866 string_to_buf(job->document_title, ptr, left, &size, unicode);
6867 if(space && size <= left)
6869 ji1->pDocument = (LPWSTR)ptr;
6870 ptr += size;
6871 left -= size;
6873 else
6874 space = FALSE;
6875 *pcbNeeded += size;
6877 return space;
6880 /*****************************************************************************
6881 * get_job_info_2
6883 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6884 LPDWORD pcbNeeded, BOOL unicode)
6886 DWORD size, left = cbBuf;
6887 BOOL space = (cbBuf > 0);
6888 LPBYTE ptr = buf;
6890 *pcbNeeded = 0;
6892 if(space)
6894 ji2->JobId = job->job_id;
6897 string_to_buf(job->document_title, ptr, left, &size, unicode);
6898 if(space && size <= left)
6900 ji2->pDocument = (LPWSTR)ptr;
6901 ptr += size;
6902 left -= size;
6904 else
6905 space = FALSE;
6906 *pcbNeeded += size;
6908 return space;
6911 /*****************************************************************************
6912 * get_job_info
6914 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6915 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6917 BOOL ret = FALSE;
6918 DWORD needed = 0, size;
6919 job_t *job;
6920 LPBYTE ptr = pJob;
6922 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6924 EnterCriticalSection(&printer_handles_cs);
6925 job = get_job(hPrinter, JobId);
6926 if(!job)
6927 goto end;
6929 switch(Level)
6931 case 1:
6932 size = sizeof(JOB_INFO_1W);
6933 if(cbBuf >= size)
6935 cbBuf -= size;
6936 ptr += size;
6937 memset(pJob, 0, size);
6939 else
6940 cbBuf = 0;
6941 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6942 needed += size;
6943 break;
6945 case 2:
6946 size = sizeof(JOB_INFO_2W);
6947 if(cbBuf >= size)
6949 cbBuf -= size;
6950 ptr += size;
6951 memset(pJob, 0, size);
6953 else
6954 cbBuf = 0;
6955 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6956 needed += size;
6957 break;
6959 case 3:
6960 size = sizeof(JOB_INFO_3);
6961 if(cbBuf >= size)
6963 cbBuf -= size;
6964 memset(pJob, 0, size);
6965 ret = TRUE;
6967 else
6968 cbBuf = 0;
6969 needed = size;
6970 break;
6972 default:
6973 SetLastError(ERROR_INVALID_LEVEL);
6974 goto end;
6976 if(pcbNeeded)
6977 *pcbNeeded = needed;
6978 end:
6979 LeaveCriticalSection(&printer_handles_cs);
6980 return ret;
6983 /*****************************************************************************
6984 * GetJobA [WINSPOOL.@]
6987 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6988 DWORD cbBuf, LPDWORD pcbNeeded)
6990 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6993 /*****************************************************************************
6994 * GetJobW [WINSPOOL.@]
6997 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6998 DWORD cbBuf, LPDWORD pcbNeeded)
7000 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7003 /*****************************************************************************
7004 * schedule_lpr
7006 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7008 char *unixname, *queue, *cmd;
7009 char fmt[] = "lpr -P%s %s";
7010 DWORD len;
7011 int r;
7013 if(!(unixname = wine_get_unix_file_name(filename)))
7014 return FALSE;
7016 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7017 queue = HeapAlloc(GetProcessHeap(), 0, len);
7018 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7020 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7021 sprintf(cmd, fmt, queue, unixname);
7023 TRACE("printing with: %s\n", cmd);
7024 r = system(cmd);
7026 HeapFree(GetProcessHeap(), 0, cmd);
7027 HeapFree(GetProcessHeap(), 0, queue);
7028 HeapFree(GetProcessHeap(), 0, unixname);
7029 return (r == 0);
7032 /*****************************************************************************
7033 * schedule_cups
7035 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7037 #ifdef SONAME_LIBCUPS
7038 if(pcupsPrintFile)
7040 char *unixname, *queue, *unix_doc_title;
7041 DWORD len;
7042 BOOL ret;
7044 if(!(unixname = wine_get_unix_file_name(filename)))
7045 return FALSE;
7047 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7048 queue = HeapAlloc(GetProcessHeap(), 0, len);
7049 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7051 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7052 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7053 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7055 TRACE("printing via cups\n");
7056 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7057 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7058 HeapFree(GetProcessHeap(), 0, queue);
7059 HeapFree(GetProcessHeap(), 0, unixname);
7060 return ret;
7062 else
7063 #endif
7065 return schedule_lpr(printer_name, filename);
7069 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7071 LPWSTR filename;
7073 switch(msg)
7075 case WM_INITDIALOG:
7076 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7077 return TRUE;
7079 case WM_COMMAND:
7080 if(HIWORD(wparam) == BN_CLICKED)
7082 if(LOWORD(wparam) == IDOK)
7084 HANDLE hf;
7085 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7086 LPWSTR *output;
7088 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7089 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7091 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7093 WCHAR caption[200], message[200];
7094 int mb_ret;
7096 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7097 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7098 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7099 if(mb_ret == IDCANCEL)
7101 HeapFree(GetProcessHeap(), 0, filename);
7102 return TRUE;
7105 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7106 if(hf == INVALID_HANDLE_VALUE)
7108 WCHAR caption[200], message[200];
7110 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7111 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7112 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7113 HeapFree(GetProcessHeap(), 0, filename);
7114 return TRUE;
7116 CloseHandle(hf);
7117 DeleteFileW(filename);
7118 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7119 *output = filename;
7120 EndDialog(hwnd, IDOK);
7121 return TRUE;
7123 if(LOWORD(wparam) == IDCANCEL)
7125 EndDialog(hwnd, IDCANCEL);
7126 return TRUE;
7129 return FALSE;
7131 return FALSE;
7134 /*****************************************************************************
7135 * get_filename
7137 static BOOL get_filename(LPWSTR *filename)
7139 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7140 file_dlg_proc, (LPARAM)filename) == IDOK;
7143 /*****************************************************************************
7144 * schedule_file
7146 static BOOL schedule_file(LPCWSTR filename)
7148 LPWSTR output = NULL;
7150 if(get_filename(&output))
7152 BOOL r;
7153 TRACE("copy to %s\n", debugstr_w(output));
7154 r = CopyFileW(filename, output, FALSE);
7155 HeapFree(GetProcessHeap(), 0, output);
7156 return r;
7158 return FALSE;
7161 /*****************************************************************************
7162 * schedule_pipe
7164 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7166 #ifdef HAVE_FORK
7167 char *unixname, *cmdA;
7168 DWORD len;
7169 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7170 BOOL ret = FALSE;
7171 char buf[1024];
7173 if(!(unixname = wine_get_unix_file_name(filename)))
7174 return FALSE;
7176 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7177 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7178 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7180 TRACE("printing with: %s\n", cmdA);
7182 if((file_fd = open(unixname, O_RDONLY)) == -1)
7183 goto end;
7185 if (pipe(fds))
7187 ERR("pipe() failed!\n");
7188 goto end;
7191 if (fork() == 0)
7193 close(0);
7194 dup2(fds[0], 0);
7195 close(fds[1]);
7197 /* reset signals that we previously set to SIG_IGN */
7198 signal(SIGPIPE, SIG_DFL);
7199 signal(SIGCHLD, SIG_DFL);
7201 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7202 _exit(1);
7205 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7206 write(fds[1], buf, no_read);
7208 ret = TRUE;
7210 end:
7211 if(file_fd != -1) close(file_fd);
7212 if(fds[0] != -1) close(fds[0]);
7213 if(fds[1] != -1) close(fds[1]);
7215 HeapFree(GetProcessHeap(), 0, cmdA);
7216 HeapFree(GetProcessHeap(), 0, unixname);
7217 return ret;
7218 #else
7219 return FALSE;
7220 #endif
7223 /*****************************************************************************
7224 * schedule_unixfile
7226 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7228 int in_fd, out_fd, no_read;
7229 char buf[1024];
7230 BOOL ret = FALSE;
7231 char *unixname, *outputA;
7232 DWORD len;
7234 if(!(unixname = wine_get_unix_file_name(filename)))
7235 return FALSE;
7237 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7238 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7239 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7241 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7242 in_fd = open(unixname, O_RDONLY);
7243 if(out_fd == -1 || in_fd == -1)
7244 goto end;
7246 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7247 write(out_fd, buf, no_read);
7249 ret = TRUE;
7250 end:
7251 if(in_fd != -1) close(in_fd);
7252 if(out_fd != -1) close(out_fd);
7253 HeapFree(GetProcessHeap(), 0, outputA);
7254 HeapFree(GetProcessHeap(), 0, unixname);
7255 return ret;
7258 /*****************************************************************************
7259 * ScheduleJob [WINSPOOL.@]
7262 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7264 opened_printer_t *printer;
7265 BOOL ret = FALSE;
7266 struct list *cursor, *cursor2;
7268 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7269 EnterCriticalSection(&printer_handles_cs);
7270 printer = get_opened_printer(hPrinter);
7271 if(!printer)
7272 goto end;
7274 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7276 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7277 HANDLE hf;
7279 if(job->job_id != dwJobID) continue;
7281 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7282 if(hf != INVALID_HANDLE_VALUE)
7284 PRINTER_INFO_5W *pi5;
7285 DWORD needed;
7286 HKEY hkey;
7287 WCHAR output[1024];
7288 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7289 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7291 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7292 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7293 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7294 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7295 debugstr_w(pi5->pPortName));
7297 output[0] = 0;
7299 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7300 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7302 DWORD type, count = sizeof(output);
7303 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7304 RegCloseKey(hkey);
7306 if(output[0] == '|')
7308 ret = schedule_pipe(output + 1, job->filename);
7310 else if(output[0])
7312 ret = schedule_unixfile(output, job->filename);
7314 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7316 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7318 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7320 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7322 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7324 ret = schedule_file(job->filename);
7326 else
7328 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7330 HeapFree(GetProcessHeap(), 0, pi5);
7331 CloseHandle(hf);
7332 DeleteFileW(job->filename);
7334 list_remove(cursor);
7335 HeapFree(GetProcessHeap(), 0, job->document_title);
7336 HeapFree(GetProcessHeap(), 0, job->filename);
7337 HeapFree(GetProcessHeap(), 0, job);
7338 break;
7340 end:
7341 LeaveCriticalSection(&printer_handles_cs);
7342 return ret;
7345 /*****************************************************************************
7346 * StartDocDlgA [WINSPOOL.@]
7348 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7350 UNICODE_STRING usBuffer;
7351 DOCINFOW docW;
7352 LPWSTR retW;
7353 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7354 LPSTR ret = NULL;
7356 docW.cbSize = sizeof(docW);
7357 if (doc->lpszDocName)
7359 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7360 if (!(docW.lpszDocName = docnameW)) return NULL;
7362 if (doc->lpszOutput)
7364 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7365 if (!(docW.lpszOutput = outputW)) return NULL;
7367 if (doc->lpszDatatype)
7369 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7370 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7372 docW.fwType = doc->fwType;
7374 retW = StartDocDlgW(hPrinter, &docW);
7376 if(retW)
7378 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7379 ret = HeapAlloc(GetProcessHeap(), 0, len);
7380 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7381 HeapFree(GetProcessHeap(), 0, retW);
7384 HeapFree(GetProcessHeap(), 0, datatypeW);
7385 HeapFree(GetProcessHeap(), 0, outputW);
7386 HeapFree(GetProcessHeap(), 0, docnameW);
7388 return ret;
7391 /*****************************************************************************
7392 * StartDocDlgW [WINSPOOL.@]
7394 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7395 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7396 * port is "FILE:". Also returns the full path if passed a relative path.
7398 * The caller should free the returned string from the process heap.
7400 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7402 LPWSTR ret = NULL;
7403 DWORD len, attr;
7405 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7407 PRINTER_INFO_5W *pi5;
7408 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7409 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7410 return NULL;
7411 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7412 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7413 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7415 HeapFree(GetProcessHeap(), 0, pi5);
7416 return NULL;
7418 HeapFree(GetProcessHeap(), 0, pi5);
7421 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7423 LPWSTR name;
7425 if (get_filename(&name))
7427 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7429 HeapFree(GetProcessHeap(), 0, name);
7430 return NULL;
7432 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7433 GetFullPathNameW(name, len, ret, NULL);
7434 HeapFree(GetProcessHeap(), 0, name);
7436 return ret;
7439 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7440 return NULL;
7442 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7443 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7445 attr = GetFileAttributesW(ret);
7446 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7448 HeapFree(GetProcessHeap(), 0, ret);
7449 ret = NULL;
7451 return ret;