dplayx: Handling for "add forward" and "player enumeration" replies
[wine/gsoc_dplay.git] / dlls / winspool.drv / info.c
blob95908b368c3440313dddfceb0e898a0f8b392cd5
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 monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 HANDLE backend_printer;
113 jobqueue_t *queue;
114 started_doc_t *doc;
115 } opened_printer_t;
117 typedef struct {
118 struct list entry;
119 DWORD job_id;
120 WCHAR *filename;
121 WCHAR *document_title;
122 } job_t;
125 typedef struct {
126 LPCWSTR envname;
127 LPCWSTR subdir;
128 DWORD driverversion;
129 LPCWSTR versionregpath;
130 LPCWSTR versionsubdir;
131 } printenv_t;
133 /* ############################### */
135 static struct list monitor_handles = LIST_INIT( monitor_handles );
136 static monitor_t * pm_localport;
138 static opened_printer_t **printer_handles;
139 static UINT nb_printer_handles;
140 static LONG next_job_id = 1;
142 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
143 WORD fwCapability, LPSTR lpszOutput,
144 LPDEVMODEA lpdm );
145 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
146 LPSTR lpszDevice, LPSTR lpszPort,
147 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
148 DWORD fwMode );
150 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
151 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
152 'c','o','n','t','r','o','l','\\',
153 'P','r','i','n','t','\\',
154 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
155 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
157 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
158 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
159 'C','o','n','t','r','o','l','\\',
160 'P','r','i','n','t','\\',
161 'M','o','n','i','t','o','r','s','\\',0};
163 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
164 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
165 'C','o','n','t','r','o','l','\\',
166 'P','r','i','n','t','\\',
167 'P','r','i','n','t','e','r','s',0};
169 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
171 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
172 'M','i','c','r','o','s','o','f','t','\\',
173 'W','i','n','d','o','w','s',' ','N','T','\\',
174 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175 'W','i','n','d','o','w','s',0};
177 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
178 'M','i','c','r','o','s','o','f','t','\\',
179 'W','i','n','d','o','w','s',' ','N','T','\\',
180 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
181 'D','e','v','i','c','e','s',0};
183 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
184 'M','i','c','r','o','s','o','f','t','\\',
185 'W','i','n','d','o','w','s',' ','N','T','\\',
186 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
187 'P','o','r','t','s',0};
189 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
190 'M','i','c','r','o','s','o','f','t','\\',
191 'W','i','n','d','o','w','s',' ','N','T','\\',
192 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
193 'P','r','i','n','t','e','r','P','o','r','t','s',0};
195 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
196 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
197 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
198 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x64W[] = {'x','6','4',0};
201 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
202 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
203 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
204 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
205 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
207 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
208 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
210 static const WCHAR backslashW[] = {'\\',0};
211 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
212 'i','o','n',' ','F','i','l','e',0};
213 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
214 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
215 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
216 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
217 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
218 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
219 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
220 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
221 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
222 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
223 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
224 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
225 static const WCHAR NameW[] = {'N','a','m','e',0};
226 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
227 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
228 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
229 static const WCHAR PortW[] = {'P','o','r','t',0};
230 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
231 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
232 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
233 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
234 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
235 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
236 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
237 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
238 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
239 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
240 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
241 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
242 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
243 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
244 static const WCHAR emptyStringW[] = {0};
246 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
248 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
249 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
250 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
252 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
253 'D','o','c','u','m','e','n','t',0};
255 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
256 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
257 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
258 0, sizeof(DRIVER_INFO_8W)};
261 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
262 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
263 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
264 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
265 sizeof(PRINTER_INFO_9W)};
267 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
268 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
269 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
271 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
273 /******************************************************************
274 * validate the user-supplied printing-environment [internal]
276 * PARAMS
277 * env [I] PTR to Environment-String or NULL
279 * RETURNS
280 * Failure: NULL
281 * Success: PTR to printenv_t
283 * NOTES
284 * An empty string is handled the same way as NULL.
285 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
289 static const printenv_t * validate_envW(LPCWSTR env)
291 const printenv_t *result = NULL;
292 unsigned int i;
294 TRACE("testing %s\n", debugstr_w(env));
295 if (env && env[0])
297 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
299 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
301 result = all_printenv[i];
302 break;
306 if (result == NULL) {
307 FIXME("unsupported Environment: %s\n", debugstr_w(env));
308 SetLastError(ERROR_INVALID_ENVIRONMENT);
310 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
312 else
314 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
316 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
318 return result;
322 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
323 if passed a NULL string. This returns NULLs to the result.
325 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
327 if ( (src) )
329 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
330 return usBufferPtr->Buffer;
332 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
333 return NULL;
336 static LPWSTR strdupW(LPCWSTR p)
338 LPWSTR ret;
339 DWORD len;
341 if(!p) return NULL;
342 len = (strlenW(p) + 1) * sizeof(WCHAR);
343 ret = HeapAlloc(GetProcessHeap(), 0, len);
344 memcpy(ret, p, len);
345 return ret;
348 static LPSTR strdupWtoA( LPCWSTR str )
350 LPSTR ret;
351 INT len;
353 if (!str) return NULL;
354 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
355 ret = HeapAlloc( GetProcessHeap(), 0, len );
356 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
357 return ret;
360 /******************************************************************
361 * Return the number of bytes for an multi_sz string.
362 * The result includes all \0s
363 * (specifically the extra \0, that is needed as multi_sz terminator).
365 #if 0
366 static int multi_sz_lenW(const WCHAR *str)
368 const WCHAR *ptr = str;
369 if(!str) return 0;
372 ptr += lstrlenW(ptr) + 1;
373 } while(*ptr);
375 return (ptr - str + 1) * sizeof(WCHAR);
377 #endif
378 /* ################################ */
380 static int multi_sz_lenA(const char *str)
382 const char *ptr = str;
383 if(!str) return 0;
386 ptr += lstrlenA(ptr) + 1;
387 } while(*ptr);
389 return ptr - str + 1;
392 static void
393 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
394 char qbuf[200];
396 /* If forcing, or no profile string entry for device yet, set the entry
398 * The always change entry if not WINEPS yet is discussable.
400 if (force ||
401 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
402 !strcmp(qbuf,"*") ||
403 !strstr(qbuf,"WINEPS.DRV")
405 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
406 HKEY hkey;
408 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
409 WriteProfileStringA("windows","device",buf);
410 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
411 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
412 RegCloseKey(hkey);
414 HeapFree(GetProcessHeap(),0,buf);
418 static BOOL add_printer_driver(const char *name)
420 DRIVER_INFO_3A di3a;
422 static char driver_9x[] = "wineps16.drv",
423 driver_nt[] = "wineps.drv",
424 env_9x[] = "Windows 4.0",
425 env_nt[] = "Windows NT x86",
426 data_file[] = "generic.ppd",
427 default_data_type[] = "RAW";
429 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
430 di3a.cVersion = 3;
431 di3a.pName = (char *)name;
432 di3a.pEnvironment = env_nt;
433 di3a.pDriverPath = driver_nt;
434 di3a.pDataFile = data_file;
435 di3a.pConfigFile = driver_nt;
436 di3a.pDefaultDataType = default_data_type;
438 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
439 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
441 di3a.cVersion = 0;
442 di3a.pEnvironment = env_9x;
443 di3a.pDriverPath = driver_9x;
444 di3a.pConfigFile = driver_9x;
445 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
446 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
448 return TRUE;
451 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
452 debugstr_a(di3a.pEnvironment), GetLastError());
453 return FALSE;
456 #ifdef SONAME_LIBCUPS
457 static typeof(cupsFreeDests) *pcupsFreeDests;
458 static typeof(cupsGetDests) *pcupsGetDests;
459 static typeof(cupsGetPPD) *pcupsGetPPD;
460 static typeof(cupsPrintFile) *pcupsPrintFile;
461 static void *cupshandle;
463 static BOOL CUPS_LoadPrinters(void)
465 int i, nrofdests;
466 BOOL hadprinter = FALSE, haddefault = FALSE;
467 cups_dest_t *dests;
468 PRINTER_INFO_2A pinfo2a;
469 char *port,*devline;
470 HKEY hkeyPrinter, hkeyPrinters, hkey;
471 char loaderror[256];
473 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
474 if (!cupshandle) {
475 TRACE("%s\n", loaderror);
476 return FALSE;
478 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
480 #define DYNCUPS(x) \
481 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
482 if (!p##x) return FALSE;
484 DYNCUPS(cupsFreeDests);
485 DYNCUPS(cupsGetPPD);
486 DYNCUPS(cupsGetDests);
487 DYNCUPS(cupsPrintFile);
488 #undef DYNCUPS
490 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
491 ERROR_SUCCESS) {
492 ERR("Can't create Printers key\n");
493 return FALSE;
496 nrofdests = pcupsGetDests(&dests);
497 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
498 for (i=0;i<nrofdests;i++) {
499 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
500 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
501 sprintf(port,"LPR:%s", dests[i].name);
502 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
503 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
504 sprintf(devline, "WINEPS.DRV,%s", port);
505 WriteProfileStringA("devices", dests[i].name, devline);
506 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
507 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
508 RegCloseKey(hkey);
511 lstrcatA(devline, ",15,45");
512 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
513 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
514 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
515 RegCloseKey(hkey);
518 HeapFree(GetProcessHeap(), 0, devline);
520 TRACE("Printer %d: %s\n", i, dests[i].name);
521 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
522 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
523 and continue */
524 TRACE("Printer already exists\n");
525 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
526 RegCloseKey(hkeyPrinter);
527 } else {
528 static CHAR data_type[] = "RAW",
529 print_proc[] = "WinPrint",
530 comment[] = "WINEPS Printer using CUPS",
531 location[] = "<physical location of printer>",
532 params[] = "<parameters?>",
533 share_name[] = "<share name?>",
534 sep_file[] = "<sep file?>";
536 add_printer_driver(dests[i].name);
538 memset(&pinfo2a,0,sizeof(pinfo2a));
539 pinfo2a.pPrinterName = dests[i].name;
540 pinfo2a.pDatatype = data_type;
541 pinfo2a.pPrintProcessor = print_proc;
542 pinfo2a.pDriverName = dests[i].name;
543 pinfo2a.pComment = comment;
544 pinfo2a.pLocation = location;
545 pinfo2a.pPortName = port;
546 pinfo2a.pParameters = params;
547 pinfo2a.pShareName = share_name;
548 pinfo2a.pSepFile = sep_file;
550 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
551 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
552 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
555 HeapFree(GetProcessHeap(),0,port);
557 hadprinter = TRUE;
558 if (dests[i].is_default) {
559 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
560 haddefault = TRUE;
563 if (hadprinter & !haddefault)
564 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
565 pcupsFreeDests(nrofdests, dests);
566 RegCloseKey(hkeyPrinters);
567 return hadprinter;
569 #endif
571 static BOOL
572 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
573 PRINTER_INFO_2A pinfo2a;
574 char *e,*s,*name,*prettyname,*devname;
575 BOOL ret = FALSE, set_default = FALSE;
576 char *port = NULL, *devline,*env_default;
577 HKEY hkeyPrinter, hkeyPrinters, hkey;
579 while (isspace(*pent)) pent++;
580 s = strchr(pent,':');
581 if(s) *s='\0';
582 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
583 strcpy(name,pent);
584 if(s) {
585 *s=':';
586 pent = s;
587 } else
588 pent = "";
590 TRACE("name=%s entry=%s\n",name, pent);
592 if(ispunct(*name)) { /* a tc entry, not a real printer */
593 TRACE("skipping tc entry\n");
594 goto end;
597 if(strstr(pent,":server")) { /* server only version so skip */
598 TRACE("skipping server entry\n");
599 goto end;
602 /* Determine whether this is a postscript printer. */
604 ret = TRUE;
605 env_default = getenv("PRINTER");
606 prettyname = name;
607 /* Get longest name, usually the one at the right for later display. */
608 while((s=strchr(prettyname,'|'))) {
609 *s = '\0';
610 e = s;
611 while(isspace(*--e)) *e = '\0';
612 TRACE("\t%s\n", debugstr_a(prettyname));
613 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
614 for(prettyname = s+1; isspace(*prettyname); prettyname++)
617 e = prettyname + strlen(prettyname);
618 while(isspace(*--e)) *e = '\0';
619 TRACE("\t%s\n", debugstr_a(prettyname));
620 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
622 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
623 * if it is too long, we use it as comment below. */
624 devname = prettyname;
625 if (strlen(devname)>=CCHDEVICENAME-1)
626 devname = name;
627 if (strlen(devname)>=CCHDEVICENAME-1) {
628 ret = FALSE;
629 goto end;
632 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
633 sprintf(port,"LPR:%s",name);
635 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
636 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
637 sprintf(devline, "WINEPS.DRV,%s", port);
638 WriteProfileStringA("devices", devname, devline);
639 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
640 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
641 RegCloseKey(hkey);
644 lstrcatA(devline, ",15,45");
645 WriteProfileStringA("PrinterPorts", devname, devline);
646 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
647 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
648 RegCloseKey(hkey);
651 HeapFree(GetProcessHeap(),0,devline);
653 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
654 ERROR_SUCCESS) {
655 ERR("Can't create Printers key\n");
656 ret = FALSE;
657 goto end;
659 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
660 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
661 and continue */
662 TRACE("Printer already exists\n");
663 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
664 RegCloseKey(hkeyPrinter);
665 } else {
666 static CHAR data_type[] = "RAW",
667 print_proc[] = "WinPrint",
668 comment[] = "WINEPS Printer using LPR",
669 params[] = "<parameters?>",
670 share_name[] = "<share name?>",
671 sep_file[] = "<sep file?>";
673 add_printer_driver(devname);
675 memset(&pinfo2a,0,sizeof(pinfo2a));
676 pinfo2a.pPrinterName = devname;
677 pinfo2a.pDatatype = data_type;
678 pinfo2a.pPrintProcessor = print_proc;
679 pinfo2a.pDriverName = devname;
680 pinfo2a.pComment = comment;
681 pinfo2a.pLocation = prettyname;
682 pinfo2a.pPortName = port;
683 pinfo2a.pParameters = params;
684 pinfo2a.pShareName = share_name;
685 pinfo2a.pSepFile = sep_file;
687 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
688 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
689 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
692 RegCloseKey(hkeyPrinters);
694 if (isfirst || set_default)
695 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
697 end:
698 HeapFree(GetProcessHeap(), 0, port);
699 HeapFree(GetProcessHeap(), 0, name);
700 return ret;
703 static BOOL
704 PRINTCAP_LoadPrinters(void) {
705 BOOL hadprinter = FALSE;
706 char buf[200];
707 FILE *f;
708 char *pent = NULL;
709 BOOL had_bash = FALSE;
711 f = fopen("/etc/printcap","r");
712 if (!f)
713 return FALSE;
715 while(fgets(buf,sizeof(buf),f)) {
716 char *start, *end;
718 end=strchr(buf,'\n');
719 if (end) *end='\0';
721 start = buf;
722 while(isspace(*start)) start++;
723 if(*start == '#' || *start == '\0')
724 continue;
726 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
727 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
728 HeapFree(GetProcessHeap(),0,pent);
729 pent = NULL;
732 if (end && *--end == '\\') {
733 *end = '\0';
734 had_bash = TRUE;
735 } else
736 had_bash = FALSE;
738 if (pent) {
739 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
740 strcat(pent,start);
741 } else {
742 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
743 strcpy(pent,start);
747 if(pent) {
748 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
749 HeapFree(GetProcessHeap(),0,pent);
751 fclose(f);
752 return hadprinter;
755 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
757 if (value)
758 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
759 (lstrlenW(value) + 1) * sizeof(WCHAR));
760 else
761 return ERROR_FILE_NOT_FOUND;
764 /******************************************************************
765 * monitor_unload [internal]
767 * release a printmonitor and unload it from memory, when needed
770 static void monitor_unload(monitor_t * pm)
772 if (pm == NULL) return;
773 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
775 EnterCriticalSection(&monitor_handles_cs);
777 if (pm->refcount) pm->refcount--;
779 if (pm->refcount == 0) {
780 list_remove(&pm->entry);
781 FreeLibrary(pm->hdll);
782 HeapFree(GetProcessHeap(), 0, pm->name);
783 HeapFree(GetProcessHeap(), 0, pm->dllname);
784 HeapFree(GetProcessHeap(), 0, pm);
786 LeaveCriticalSection(&monitor_handles_cs);
789 /******************************************************************
790 * monitor_load [internal]
792 * load a printmonitor, get the dllname from the registry, when needed
793 * initialize the monitor and dump found function-pointers
795 * On failure, SetLastError() is called and NULL is returned
798 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
800 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
801 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
802 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
803 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
804 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
806 monitor_t * pm = NULL;
807 monitor_t * cursor;
808 LPWSTR regroot = NULL;
809 LPWSTR driver = dllname;
811 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
812 /* Is the Monitor already loaded? */
813 EnterCriticalSection(&monitor_handles_cs);
815 if (name) {
816 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
818 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
819 pm = cursor;
820 break;
825 if (pm == NULL) {
826 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
827 if (pm == NULL) goto cleanup;
828 list_add_tail(&monitor_handles, &pm->entry);
830 pm->refcount++;
832 if (pm->name == NULL) {
833 /* Load the monitor */
834 LPMONITOREX pmonitorEx;
835 DWORD len;
837 if (name) {
838 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
839 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
842 if (regroot) {
843 lstrcpyW(regroot, MonitorsW);
844 lstrcatW(regroot, name);
845 /* Get the Driver from the Registry */
846 if (driver == NULL) {
847 HKEY hroot;
848 DWORD namesize;
849 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
850 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
851 &namesize) == ERROR_SUCCESS) {
852 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
853 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
855 RegCloseKey(hroot);
860 pm->name = strdupW(name);
861 pm->dllname = strdupW(driver);
863 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
864 monitor_unload(pm);
865 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
866 pm = NULL;
867 goto cleanup;
870 pm->hdll = LoadLibraryW(driver);
871 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
873 if (pm->hdll == NULL) {
874 monitor_unload(pm);
875 SetLastError(ERROR_MOD_NOT_FOUND);
876 pm = NULL;
877 goto cleanup;
880 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
881 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
882 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
883 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
884 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
887 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
888 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
889 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
890 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
891 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
893 if (pInitializePrintMonitorUI != NULL) {
894 pm->monitorUI = pInitializePrintMonitorUI();
895 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
896 if (pm->monitorUI) {
897 TRACE( "0x%08x: dwMonitorSize (%d)\n",
898 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
903 if (pInitializePrintMonitor && regroot) {
904 pmonitorEx = pInitializePrintMonitor(regroot);
905 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
906 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
908 if (pmonitorEx) {
909 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
910 pm->monitor = &(pmonitorEx->Monitor);
914 if (pm->monitor) {
915 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
919 if (!pm->monitor && regroot) {
920 if (pInitializePrintMonitor2 != NULL) {
921 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
923 if (pInitializeMonitorEx != NULL) {
924 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
926 if (pInitializeMonitor != NULL) {
927 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
930 if (!pm->monitor && !pm->monitorUI) {
931 monitor_unload(pm);
932 SetLastError(ERROR_PROC_NOT_FOUND);
933 pm = NULL;
936 cleanup:
937 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
938 pm->refcount++;
939 pm_localport = pm;
941 LeaveCriticalSection(&monitor_handles_cs);
942 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
943 HeapFree(GetProcessHeap(), 0, regroot);
944 TRACE("=> %p\n", pm);
945 return pm;
948 /******************************************************************
949 * monitor_loadui [internal]
951 * load the userinterface-dll for a given portmonitor
953 * On failure, NULL is returned
956 static monitor_t * monitor_loadui(monitor_t * pm)
958 monitor_t * pui = NULL;
959 LPWSTR buffer[MAX_PATH];
960 HANDLE hXcv;
961 DWORD len;
962 DWORD res;
964 if (pm == NULL) return NULL;
965 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
967 /* Try the Portmonitor first; works for many monitors */
968 if (pm->monitorUI) {
969 EnterCriticalSection(&monitor_handles_cs);
970 pm->refcount++;
971 LeaveCriticalSection(&monitor_handles_cs);
972 return pm;
975 /* query the userinterface-dllname from the Portmonitor */
976 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
977 /* building (",XcvMonitor %s",pm->name) not needed yet */
978 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
979 TRACE("got %u with %p\n", res, hXcv);
980 if (res) {
981 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
982 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
983 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
984 pm->monitor->pfnXcvClosePort(hXcv);
987 return pui;
991 /******************************************************************
992 * monitor_load_by_port [internal]
994 * load a printmonitor for a given port
996 * On failure, NULL is returned
999 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1001 HKEY hroot;
1002 HKEY hport;
1003 LPWSTR buffer;
1004 monitor_t * pm = NULL;
1005 DWORD registered = 0;
1006 DWORD id = 0;
1007 DWORD len;
1009 TRACE("(%s)\n", debugstr_w(portname));
1011 /* Try the Local Monitor first */
1012 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1013 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1014 /* found the portname */
1015 RegCloseKey(hroot);
1016 return monitor_load(LocalPortW, NULL);
1018 RegCloseKey(hroot);
1021 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1022 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1023 if (buffer == NULL) return NULL;
1025 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1026 EnterCriticalSection(&monitor_handles_cs);
1027 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1029 while ((pm == NULL) && (id < registered)) {
1030 buffer[0] = '\0';
1031 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1032 TRACE("testing %s\n", debugstr_w(buffer));
1033 len = lstrlenW(buffer);
1034 lstrcatW(buffer, bs_Ports_bsW);
1035 lstrcatW(buffer, portname);
1036 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1037 RegCloseKey(hport);
1038 buffer[len] = '\0'; /* use only the Monitor-Name */
1039 pm = monitor_load(buffer, NULL);
1041 id++;
1043 LeaveCriticalSection(&monitor_handles_cs);
1044 RegCloseKey(hroot);
1046 HeapFree(GetProcessHeap(), 0, buffer);
1047 return pm;
1050 /******************************************************************
1051 * get_servername_from_name (internal)
1053 * for an external server, a copy of the serverpart from the full name is returned
1056 static LPWSTR get_servername_from_name(LPCWSTR name)
1058 LPWSTR server;
1059 LPWSTR ptr;
1060 WCHAR buffer[MAX_PATH];
1061 DWORD len;
1063 if (name == NULL) return NULL;
1064 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1066 server = strdupW(&name[2]); /* skip over both backslash */
1067 if (server == NULL) return NULL;
1069 /* strip '\' and the printername */
1070 ptr = strchrW(server, '\\');
1071 if (ptr) ptr[0] = '\0';
1073 TRACE("found %s\n", debugstr_w(server));
1075 len = sizeof(buffer)/sizeof(buffer[0]);
1076 if (GetComputerNameW(buffer, &len)) {
1077 if (lstrcmpW(buffer, server) == 0) {
1078 /* The requested Servername is our computername */
1079 HeapFree(GetProcessHeap(), 0, server);
1080 return NULL;
1083 return server;
1086 /******************************************************************
1087 * get_basename_from_name (internal)
1089 * skip over the serverpart from the full name
1092 static LPCWSTR get_basename_from_name(LPCWSTR name)
1094 if (name == NULL) return NULL;
1095 if ((name[0] == '\\') && (name[1] == '\\')) {
1096 /* skip over the servername and search for the following '\' */
1097 name = strchrW(&name[2], '\\');
1098 if ((name) && (name[1])) {
1099 /* found a separator ('\') followed by a name:
1100 skip over the separator and return the rest */
1101 name++;
1103 else
1105 /* no basename present (we found only a servername) */
1106 return NULL;
1109 return name;
1112 /******************************************************************
1113 * get_opened_printer_entry
1114 * Get the first place empty in the opened printer table
1116 * ToDo:
1117 * - pDefault is ignored
1119 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
1121 UINT_PTR handle = nb_printer_handles, i;
1122 jobqueue_t *queue = NULL;
1123 opened_printer_t *printer = NULL;
1124 LPWSTR servername;
1125 LPCWSTR printername;
1127 if ((backend == NULL) && !load_backend()) return NULL;
1129 servername = get_servername_from_name(name);
1130 if (servername) {
1131 FIXME("server %s not supported\n", debugstr_w(servername));
1132 HeapFree(GetProcessHeap(), 0, servername);
1133 SetLastError(ERROR_INVALID_PRINTER_NAME);
1134 return NULL;
1137 printername = get_basename_from_name(name);
1138 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1140 /* an empty printername is invalid */
1141 if (printername && (!printername[0])) {
1142 SetLastError(ERROR_INVALID_PARAMETER);
1143 return NULL;
1146 EnterCriticalSection(&printer_handles_cs);
1148 for (i = 0; i < nb_printer_handles; i++)
1150 if (!printer_handles[i])
1152 if(handle == nb_printer_handles)
1153 handle = i;
1155 else
1157 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1158 queue = printer_handles[i]->queue;
1162 if (handle >= nb_printer_handles)
1164 opened_printer_t **new_array;
1165 if (printer_handles)
1166 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1167 (nb_printer_handles + 16) * sizeof(*new_array) );
1168 else
1169 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1170 (nb_printer_handles + 16) * sizeof(*new_array) );
1172 if (!new_array)
1174 handle = 0;
1175 goto end;
1177 printer_handles = new_array;
1178 nb_printer_handles += 16;
1181 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1183 handle = 0;
1184 goto end;
1187 /* get a printer handle from the backend */
1188 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
1189 handle = 0;
1190 goto end;
1193 /* clone the base name. This is NULL for the printserver */
1194 printer->printername = strdupW(printername);
1196 /* clone the full name */
1197 printer->name = strdupW(name);
1198 if (name && (!printer->name)) {
1199 handle = 0;
1200 goto end;
1203 if(queue)
1204 printer->queue = queue;
1205 else
1207 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1208 if (!printer->queue) {
1209 handle = 0;
1210 goto end;
1212 list_init(&printer->queue->jobs);
1213 printer->queue->ref = 0;
1215 InterlockedIncrement(&printer->queue->ref);
1217 printer_handles[handle] = printer;
1218 handle++;
1219 end:
1220 LeaveCriticalSection(&printer_handles_cs);
1221 if (!handle && printer) {
1222 /* Something failed: Free all resources */
1223 HeapFree(GetProcessHeap(), 0, printer->printername);
1224 HeapFree(GetProcessHeap(), 0, printer->name);
1225 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1226 HeapFree(GetProcessHeap(), 0, printer);
1229 return (HANDLE)handle;
1232 /******************************************************************
1233 * get_opened_printer
1234 * Get the pointer to the opened printer referred by the handle
1236 static opened_printer_t *get_opened_printer(HANDLE hprn)
1238 UINT_PTR idx = (UINT_PTR)hprn;
1239 opened_printer_t *ret = NULL;
1241 EnterCriticalSection(&printer_handles_cs);
1243 if ((idx > 0) && (idx <= nb_printer_handles)) {
1244 ret = printer_handles[idx - 1];
1246 LeaveCriticalSection(&printer_handles_cs);
1247 return ret;
1250 /******************************************************************
1251 * get_opened_printer_name
1252 * Get the pointer to the opened printer name referred by the handle
1254 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1256 opened_printer_t *printer = get_opened_printer(hprn);
1257 if(!printer) return NULL;
1258 return printer->name;
1261 /******************************************************************
1262 * WINSPOOL_GetOpenedPrinterRegKey
1265 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1267 LPCWSTR name = get_opened_printer_name(hPrinter);
1268 DWORD ret;
1269 HKEY hkeyPrinters;
1271 if(!name) return ERROR_INVALID_HANDLE;
1273 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1274 ERROR_SUCCESS)
1275 return ret;
1277 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1279 ERR("Can't find opened printer %s in registry\n",
1280 debugstr_w(name));
1281 RegCloseKey(hkeyPrinters);
1282 return ERROR_INVALID_PRINTER_NAME; /* ? */
1284 RegCloseKey(hkeyPrinters);
1285 return ERROR_SUCCESS;
1288 void WINSPOOL_LoadSystemPrinters(void)
1290 HKEY hkey, hkeyPrinters;
1291 HANDLE hprn;
1292 DWORD needed, num, i;
1293 WCHAR PrinterName[256];
1294 BOOL done = FALSE;
1296 /* This ensures that all printer entries have a valid Name value. If causes
1297 problems later if they don't. If one is found to be missed we create one
1298 and set it equal to the name of the key */
1299 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1300 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1301 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1302 for(i = 0; i < num; i++) {
1303 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1304 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1305 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1306 set_reg_szW(hkey, NameW, PrinterName);
1308 RegCloseKey(hkey);
1313 RegCloseKey(hkeyPrinters);
1316 /* We want to avoid calling AddPrinter on printers as much as
1317 possible, because on cups printers this will (eventually) lead
1318 to a call to cupsGetPPD which takes forever, even with non-cups
1319 printers AddPrinter takes a while. So we'll tag all printers that
1320 were automatically added last time around, if they still exist
1321 we'll leave them be otherwise we'll delete them. */
1322 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1323 if(needed) {
1324 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1325 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1326 for(i = 0; i < num; i++) {
1327 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1328 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1329 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1330 DWORD dw = 1;
1331 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1332 RegCloseKey(hkey);
1334 ClosePrinter(hprn);
1339 HeapFree(GetProcessHeap(), 0, pi);
1343 #ifdef SONAME_LIBCUPS
1344 done = CUPS_LoadPrinters();
1345 #endif
1347 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1348 PRINTCAP_LoadPrinters();
1350 /* Now enumerate the list again and delete any printers that are still tagged */
1351 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1352 if(needed) {
1353 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1354 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1355 for(i = 0; i < num; i++) {
1356 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1357 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1358 BOOL delete_driver = FALSE;
1359 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1360 DWORD dw, type, size = sizeof(dw);
1361 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1362 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1363 DeletePrinter(hprn);
1364 delete_driver = TRUE;
1366 RegCloseKey(hkey);
1368 ClosePrinter(hprn);
1369 if(delete_driver)
1370 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1375 HeapFree(GetProcessHeap(), 0, pi);
1378 return;
1382 /******************************************************************
1383 * get_job
1385 * Get the pointer to the specified job.
1386 * Should hold the printer_handles_cs before calling.
1388 static job_t *get_job(HANDLE hprn, DWORD JobId)
1390 opened_printer_t *printer = get_opened_printer(hprn);
1391 job_t *job;
1393 if(!printer) return NULL;
1394 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1396 if(job->job_id == JobId)
1397 return job;
1399 return NULL;
1402 /***********************************************************
1403 * DEVMODEcpyAtoW
1405 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1407 BOOL Formname;
1408 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1409 DWORD size;
1411 Formname = (dmA->dmSize > off_formname);
1412 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1413 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1414 dmW->dmDeviceName, CCHDEVICENAME);
1415 if(!Formname) {
1416 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1417 dmA->dmSize - CCHDEVICENAME);
1418 } else {
1419 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1420 off_formname - CCHDEVICENAME);
1421 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1422 dmW->dmFormName, CCHFORMNAME);
1423 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1424 (off_formname + CCHFORMNAME));
1426 dmW->dmSize = size;
1427 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1428 dmA->dmDriverExtra);
1429 return dmW;
1432 /***********************************************************
1433 * DEVMODEdupWtoA
1434 * Creates an ansi copy of supplied devmode
1436 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1438 LPDEVMODEA dmA;
1439 DWORD size;
1441 if (!dmW) return NULL;
1442 size = dmW->dmSize - CCHDEVICENAME -
1443 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1445 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1446 if (!dmA) return NULL;
1448 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1449 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1451 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1452 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1453 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1455 else
1457 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1458 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1459 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1460 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1462 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1465 dmA->dmSize = size;
1466 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1467 return dmA;
1470 /******************************************************************
1471 * convert_printerinfo_W_to_A [internal]
1474 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1475 DWORD level, DWORD outlen, DWORD numentries)
1477 DWORD id = 0;
1478 LPSTR ptr;
1479 INT len;
1481 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1483 len = pi_sizeof[level] * numentries;
1484 ptr = (LPSTR) out + len;
1485 outlen -= len;
1487 /* copy the numbers of all PRINTER_INFO_* first */
1488 memcpy(out, pPrintersW, len);
1490 while (id < numentries) {
1491 switch (level) {
1492 case 1:
1494 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1495 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1497 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1498 if (piW->pDescription) {
1499 piA->pDescription = ptr;
1500 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1501 ptr, outlen, NULL, NULL);
1502 ptr += len;
1503 outlen -= len;
1505 if (piW->pName) {
1506 piA->pName = ptr;
1507 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1508 ptr, outlen, NULL, NULL);
1509 ptr += len;
1510 outlen -= len;
1512 if (piW->pComment) {
1513 piA->pComment = ptr;
1514 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1515 ptr, outlen, NULL, NULL);
1516 ptr += len;
1517 outlen -= len;
1519 break;
1522 case 2:
1524 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1525 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1526 LPDEVMODEA dmA;
1528 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1529 if (piW->pServerName) {
1530 piA->pServerName = ptr;
1531 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1532 ptr, outlen, NULL, NULL);
1533 ptr += len;
1534 outlen -= len;
1536 if (piW->pPrinterName) {
1537 piA->pPrinterName = ptr;
1538 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1539 ptr, outlen, NULL, NULL);
1540 ptr += len;
1541 outlen -= len;
1543 if (piW->pShareName) {
1544 piA->pShareName = ptr;
1545 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1546 ptr, outlen, NULL, NULL);
1547 ptr += len;
1548 outlen -= len;
1550 if (piW->pPortName) {
1551 piA->pPortName = ptr;
1552 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1553 ptr, outlen, NULL, NULL);
1554 ptr += len;
1555 outlen -= len;
1557 if (piW->pDriverName) {
1558 piA->pDriverName = ptr;
1559 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1560 ptr, outlen, NULL, NULL);
1561 ptr += len;
1562 outlen -= len;
1564 if (piW->pComment) {
1565 piA->pComment = ptr;
1566 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1567 ptr, outlen, NULL, NULL);
1568 ptr += len;
1569 outlen -= len;
1571 if (piW->pLocation) {
1572 piA->pLocation = ptr;
1573 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1574 ptr, outlen, NULL, NULL);
1575 ptr += len;
1576 outlen -= len;
1579 dmA = DEVMODEdupWtoA(piW->pDevMode);
1580 if (dmA) {
1581 /* align DEVMODEA to a DWORD boundary */
1582 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1583 ptr += len;
1584 outlen -= len;
1586 piA->pDevMode = (LPDEVMODEA) ptr;
1587 len = dmA->dmSize + dmA->dmDriverExtra;
1588 memcpy(ptr, dmA, len);
1589 HeapFree(GetProcessHeap(), 0, dmA);
1591 ptr += len;
1592 outlen -= len;
1595 if (piW->pSepFile) {
1596 piA->pSepFile = ptr;
1597 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1598 ptr, outlen, NULL, NULL);
1599 ptr += len;
1600 outlen -= len;
1602 if (piW->pPrintProcessor) {
1603 piA->pPrintProcessor = ptr;
1604 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1605 ptr, outlen, NULL, NULL);
1606 ptr += len;
1607 outlen -= len;
1609 if (piW->pDatatype) {
1610 piA->pDatatype = ptr;
1611 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1612 ptr, outlen, NULL, NULL);
1613 ptr += len;
1614 outlen -= len;
1616 if (piW->pParameters) {
1617 piA->pParameters = ptr;
1618 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1619 ptr, outlen, NULL, NULL);
1620 ptr += len;
1621 outlen -= len;
1623 if (piW->pSecurityDescriptor) {
1624 piA->pSecurityDescriptor = NULL;
1625 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1627 break;
1630 case 4:
1632 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1633 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1635 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1637 if (piW->pPrinterName) {
1638 piA->pPrinterName = ptr;
1639 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1640 ptr, outlen, NULL, NULL);
1641 ptr += len;
1642 outlen -= len;
1644 if (piW->pServerName) {
1645 piA->pServerName = ptr;
1646 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1647 ptr, outlen, NULL, NULL);
1648 ptr += len;
1649 outlen -= len;
1651 break;
1654 case 5:
1656 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1657 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1659 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1661 if (piW->pPrinterName) {
1662 piA->pPrinterName = ptr;
1663 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1664 ptr, outlen, NULL, NULL);
1665 ptr += len;
1666 outlen -= len;
1668 if (piW->pPortName) {
1669 piA->pPortName = ptr;
1670 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1671 ptr, outlen, NULL, NULL);
1672 ptr += len;
1673 outlen -= len;
1675 break;
1678 default:
1679 FIXME("for level %u\n", level);
1681 pPrintersW += pi_sizeof[level];
1682 out += pi_sizeof[level];
1683 id++;
1687 /***********************************************************
1688 * PRINTER_INFO_2AtoW
1689 * Creates a unicode copy of PRINTER_INFO_2A on heap
1691 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1693 LPPRINTER_INFO_2W piW;
1694 UNICODE_STRING usBuffer;
1696 if(!piA) return NULL;
1697 piW = HeapAlloc(heap, 0, sizeof(*piW));
1698 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1700 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1701 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1702 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1703 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1704 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1705 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1706 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1707 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1708 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1709 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1710 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1711 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1712 return piW;
1715 /***********************************************************
1716 * FREE_PRINTER_INFO_2W
1717 * Free PRINTER_INFO_2W and all strings
1719 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1721 if(!piW) return;
1723 HeapFree(heap,0,piW->pServerName);
1724 HeapFree(heap,0,piW->pPrinterName);
1725 HeapFree(heap,0,piW->pShareName);
1726 HeapFree(heap,0,piW->pPortName);
1727 HeapFree(heap,0,piW->pDriverName);
1728 HeapFree(heap,0,piW->pComment);
1729 HeapFree(heap,0,piW->pLocation);
1730 HeapFree(heap,0,piW->pDevMode);
1731 HeapFree(heap,0,piW->pSepFile);
1732 HeapFree(heap,0,piW->pPrintProcessor);
1733 HeapFree(heap,0,piW->pDatatype);
1734 HeapFree(heap,0,piW->pParameters);
1735 HeapFree(heap,0,piW);
1736 return;
1739 /******************************************************************
1740 * DeviceCapabilities [WINSPOOL.@]
1741 * DeviceCapabilitiesA [WINSPOOL.@]
1744 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1745 LPSTR pOutput, LPDEVMODEA lpdm)
1747 INT ret;
1749 if (!GDI_CallDeviceCapabilities16)
1751 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1752 (LPCSTR)104 );
1753 if (!GDI_CallDeviceCapabilities16) return -1;
1755 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1757 /* If DC_PAPERSIZE map POINT16s to POINTs */
1758 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1759 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1760 POINT *pt = (POINT *)pOutput;
1761 INT i;
1762 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1763 for(i = 0; i < ret; i++, pt++)
1765 pt->x = tmp[i].x;
1766 pt->y = tmp[i].y;
1768 HeapFree( GetProcessHeap(), 0, tmp );
1770 return ret;
1774 /*****************************************************************************
1775 * DeviceCapabilitiesW [WINSPOOL.@]
1777 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1780 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1781 WORD fwCapability, LPWSTR pOutput,
1782 const DEVMODEW *pDevMode)
1784 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1785 LPSTR pDeviceA = strdupWtoA(pDevice);
1786 LPSTR pPortA = strdupWtoA(pPort);
1787 INT ret;
1789 if(pOutput && (fwCapability == DC_BINNAMES ||
1790 fwCapability == DC_FILEDEPENDENCIES ||
1791 fwCapability == DC_PAPERNAMES)) {
1792 /* These need A -> W translation */
1793 INT size = 0, i;
1794 LPSTR pOutputA;
1795 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1796 dmA);
1797 if(ret == -1)
1798 return ret;
1799 switch(fwCapability) {
1800 case DC_BINNAMES:
1801 size = 24;
1802 break;
1803 case DC_PAPERNAMES:
1804 case DC_FILEDEPENDENCIES:
1805 size = 64;
1806 break;
1808 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1809 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1810 dmA);
1811 for(i = 0; i < ret; i++)
1812 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1813 pOutput + (i * size), size);
1814 HeapFree(GetProcessHeap(), 0, pOutputA);
1815 } else {
1816 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1817 (LPSTR)pOutput, dmA);
1819 HeapFree(GetProcessHeap(),0,pPortA);
1820 HeapFree(GetProcessHeap(),0,pDeviceA);
1821 HeapFree(GetProcessHeap(),0,dmA);
1822 return ret;
1825 /******************************************************************
1826 * DocumentPropertiesA [WINSPOOL.@]
1828 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1830 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1831 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1832 LPDEVMODEA pDevModeInput,DWORD fMode )
1834 LPSTR lpName = pDeviceName;
1835 static CHAR port[] = "LPT1:";
1836 LONG ret;
1838 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1839 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1842 if(!pDeviceName) {
1843 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1844 if(!lpNameW) {
1845 ERR("no name from hPrinter?\n");
1846 SetLastError(ERROR_INVALID_HANDLE);
1847 return -1;
1849 lpName = strdupWtoA(lpNameW);
1852 if (!GDI_CallExtDeviceMode16)
1854 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1855 (LPCSTR)102 );
1856 if (!GDI_CallExtDeviceMode16) {
1857 ERR("No CallExtDeviceMode16?\n");
1858 return -1;
1861 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1862 pDevModeInput, NULL, fMode);
1864 if(!pDeviceName)
1865 HeapFree(GetProcessHeap(),0,lpName);
1866 return ret;
1870 /*****************************************************************************
1871 * DocumentPropertiesW (WINSPOOL.@)
1873 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1875 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1876 LPWSTR pDeviceName,
1877 LPDEVMODEW pDevModeOutput,
1878 LPDEVMODEW pDevModeInput, DWORD fMode)
1881 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1882 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1883 LPDEVMODEA pDevModeOutputA = NULL;
1884 LONG ret;
1886 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1887 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1888 fMode);
1889 if(pDevModeOutput) {
1890 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1891 if(ret < 0) return ret;
1892 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1894 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1895 pDevModeInputA, fMode);
1896 if(pDevModeOutput) {
1897 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1898 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1900 if(fMode == 0 && ret > 0)
1901 ret += (CCHDEVICENAME + CCHFORMNAME);
1902 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1903 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1904 return ret;
1907 /******************************************************************
1908 * OpenPrinterA [WINSPOOL.@]
1910 * See OpenPrinterW.
1913 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1914 LPPRINTER_DEFAULTSA pDefault)
1916 UNICODE_STRING lpPrinterNameW;
1917 UNICODE_STRING usBuffer;
1918 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1919 PWSTR pwstrPrinterNameW;
1920 BOOL ret;
1922 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1924 if(pDefault) {
1925 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1926 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1927 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1928 pDefaultW = &DefaultW;
1930 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1931 if(pDefault) {
1932 RtlFreeUnicodeString(&usBuffer);
1933 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1935 RtlFreeUnicodeString(&lpPrinterNameW);
1936 return ret;
1939 /******************************************************************
1940 * OpenPrinterW [WINSPOOL.@]
1942 * Open a Printer / Printserver or a Printer-Object
1944 * PARAMS
1945 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1946 * phPrinter [O] The resulting Handle is stored here
1947 * pDefault [I] PTR to Default Printer Settings or NULL
1949 * RETURNS
1950 * Success: TRUE
1951 * Failure: FALSE
1953 * NOTES
1954 * lpPrinterName is one of:
1955 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1956 *| Printer: "PrinterName"
1957 *| Printer-Object: "PrinterName,Job xxx"
1958 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1959 *| XcvPort: "Servername,XcvPort PortName"
1961 * BUGS
1962 *| Printer-Object not supported
1963 *| pDefaults is ignored
1966 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1969 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1970 if (pDefault) {
1971 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1972 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1975 if(!phPrinter) {
1976 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1977 SetLastError(ERROR_INVALID_PARAMETER);
1978 return FALSE;
1981 /* Get the unique handle of the printer or Printserver */
1982 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1983 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1984 return (*phPrinter != 0);
1987 /******************************************************************
1988 * AddMonitorA [WINSPOOL.@]
1990 * See AddMonitorW.
1993 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1995 LPWSTR nameW = NULL;
1996 INT len;
1997 BOOL res;
1998 LPMONITOR_INFO_2A mi2a;
1999 MONITOR_INFO_2W mi2w;
2001 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2002 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2003 debugstr_a(mi2a ? mi2a->pName : NULL),
2004 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2005 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2007 if (Level != 2) {
2008 SetLastError(ERROR_INVALID_LEVEL);
2009 return FALSE;
2012 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2013 if (mi2a == NULL) {
2014 return FALSE;
2017 if (pName) {
2018 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2019 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2020 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2023 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2024 if (mi2a->pName) {
2025 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2026 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2027 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2029 if (mi2a->pEnvironment) {
2030 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2031 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2032 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2034 if (mi2a->pDLLName) {
2035 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2036 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2037 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2040 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2042 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2043 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2044 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2046 HeapFree(GetProcessHeap(), 0, nameW);
2047 return (res);
2050 /******************************************************************************
2051 * AddMonitorW [WINSPOOL.@]
2053 * Install a Printmonitor
2055 * PARAMS
2056 * pName [I] Servername or NULL (local Computer)
2057 * Level [I] Structure-Level (Must be 2)
2058 * pMonitors [I] PTR to MONITOR_INFO_2
2060 * RETURNS
2061 * Success: TRUE
2062 * Failure: FALSE
2064 * NOTES
2065 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2068 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2070 LPMONITOR_INFO_2W mi2w;
2072 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2073 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2074 debugstr_w(mi2w ? mi2w->pName : NULL),
2075 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2076 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2078 if ((backend == NULL) && !load_backend()) return FALSE;
2080 if (Level != 2) {
2081 SetLastError(ERROR_INVALID_LEVEL);
2082 return FALSE;
2085 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2086 if (mi2w == NULL) {
2087 return FALSE;
2090 return backend->fpAddMonitor(pName, Level, pMonitors);
2093 /******************************************************************
2094 * DeletePrinterDriverA [WINSPOOL.@]
2097 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2099 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2102 /******************************************************************
2103 * DeletePrinterDriverW [WINSPOOL.@]
2106 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2108 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2111 /******************************************************************
2112 * DeleteMonitorA [WINSPOOL.@]
2114 * See DeleteMonitorW.
2117 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2119 LPWSTR nameW = NULL;
2120 LPWSTR EnvironmentW = NULL;
2121 LPWSTR MonitorNameW = NULL;
2122 BOOL res;
2123 INT len;
2125 if (pName) {
2126 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2127 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2128 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2131 if (pEnvironment) {
2132 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2133 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2134 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2136 if (pMonitorName) {
2137 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2138 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2139 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2142 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2144 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2145 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2146 HeapFree(GetProcessHeap(), 0, nameW);
2147 return (res);
2150 /******************************************************************
2151 * DeleteMonitorW [WINSPOOL.@]
2153 * Delete a specific Printmonitor from a Printing-Environment
2155 * PARAMS
2156 * pName [I] Servername or NULL (local Computer)
2157 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2158 * pMonitorName [I] Name of the Monitor, that should be deleted
2160 * RETURNS
2161 * Success: TRUE
2162 * Failure: FALSE
2164 * NOTES
2165 * pEnvironment is ignored in Windows for the local Computer.
2168 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2171 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2172 debugstr_w(pMonitorName));
2174 if ((backend == NULL) && !load_backend()) return FALSE;
2176 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2180 /******************************************************************
2181 * DeletePortA [WINSPOOL.@]
2183 * See DeletePortW.
2186 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2188 LPWSTR nameW = NULL;
2189 LPWSTR portW = NULL;
2190 INT len;
2191 DWORD res;
2193 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2195 /* convert servername to unicode */
2196 if (pName) {
2197 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2198 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2199 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2202 /* convert portname to unicode */
2203 if (pPortName) {
2204 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2205 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2209 res = DeletePortW(nameW, hWnd, portW);
2210 HeapFree(GetProcessHeap(), 0, nameW);
2211 HeapFree(GetProcessHeap(), 0, portW);
2212 return res;
2215 /******************************************************************
2216 * DeletePortW [WINSPOOL.@]
2218 * Delete a specific Port
2220 * PARAMS
2221 * pName [I] Servername or NULL (local Computer)
2222 * hWnd [I] Handle to parent Window for the Dialog-Box
2223 * pPortName [I] Name of the Port, that should be deleted
2225 * RETURNS
2226 * Success: TRUE
2227 * Failure: FALSE
2230 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2232 monitor_t * pm;
2233 monitor_t * pui;
2234 DWORD res;
2236 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2238 if (pName && pName[0]) {
2239 SetLastError(ERROR_INVALID_PARAMETER);
2240 return FALSE;
2243 if (!pPortName) {
2244 SetLastError(RPC_X_NULL_REF_POINTER);
2245 return FALSE;
2248 /* an empty Portname is Invalid */
2249 if (!pPortName[0]) {
2250 SetLastError(ERROR_NOT_SUPPORTED);
2251 return FALSE;
2254 pm = monitor_load_by_port(pPortName);
2255 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2256 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2257 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2258 TRACE("got %d with %u\n", res, GetLastError());
2260 else
2262 pui = monitor_loadui(pm);
2263 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2264 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2265 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2266 TRACE("got %d with %u\n", res, GetLastError());
2268 else
2270 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2271 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
2273 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2274 SetLastError(ERROR_NOT_SUPPORTED);
2275 res = FALSE;
2277 monitor_unload(pui);
2279 monitor_unload(pm);
2281 TRACE("returning %d with %u\n", res, GetLastError());
2282 return res;
2285 /******************************************************************************
2286 * SetPrinterW [WINSPOOL.@]
2288 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2290 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2291 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2292 return FALSE;
2295 /******************************************************************************
2296 * WritePrinter [WINSPOOL.@]
2298 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2300 opened_printer_t *printer;
2301 BOOL ret = FALSE;
2303 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2305 EnterCriticalSection(&printer_handles_cs);
2306 printer = get_opened_printer(hPrinter);
2307 if(!printer)
2309 SetLastError(ERROR_INVALID_HANDLE);
2310 goto end;
2313 if(!printer->doc)
2315 SetLastError(ERROR_SPL_NO_STARTDOC);
2316 goto end;
2319 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2320 end:
2321 LeaveCriticalSection(&printer_handles_cs);
2322 return ret;
2325 /*****************************************************************************
2326 * AddFormA [WINSPOOL.@]
2328 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2330 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2331 return 1;
2334 /*****************************************************************************
2335 * AddFormW [WINSPOOL.@]
2337 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2339 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2340 return 1;
2343 /*****************************************************************************
2344 * AddJobA [WINSPOOL.@]
2346 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2348 BOOL ret;
2349 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2350 DWORD needed;
2352 if(Level != 1) {
2353 SetLastError(ERROR_INVALID_LEVEL);
2354 return FALSE;
2357 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2359 if(ret) {
2360 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2361 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2362 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2363 if(*pcbNeeded > cbBuf) {
2364 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2365 ret = FALSE;
2366 } else {
2367 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2368 addjobA->JobId = addjobW->JobId;
2369 addjobA->Path = (char *)(addjobA + 1);
2370 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2373 return ret;
2376 /*****************************************************************************
2377 * AddJobW [WINSPOOL.@]
2379 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2381 opened_printer_t *printer;
2382 job_t *job;
2383 BOOL ret = FALSE;
2384 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2385 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2386 WCHAR path[MAX_PATH], filename[MAX_PATH];
2387 DWORD len;
2388 ADDJOB_INFO_1W *addjob;
2390 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2392 EnterCriticalSection(&printer_handles_cs);
2394 printer = get_opened_printer(hPrinter);
2396 if(!printer) {
2397 SetLastError(ERROR_INVALID_HANDLE);
2398 goto end;
2401 if(Level != 1) {
2402 SetLastError(ERROR_INVALID_LEVEL);
2403 goto end;
2406 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2407 if(!job)
2408 goto end;
2410 job->job_id = InterlockedIncrement(&next_job_id);
2412 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2413 if(path[len - 1] != '\\')
2414 path[len++] = '\\';
2415 memcpy(path + len, spool_path, sizeof(spool_path));
2416 sprintfW(filename, fmtW, path, job->job_id);
2418 len = strlenW(filename);
2419 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2420 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2421 job->document_title = strdupW(default_doc_title);
2422 list_add_tail(&printer->queue->jobs, &job->entry);
2424 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2425 if(*pcbNeeded <= cbBuf) {
2426 addjob = (ADDJOB_INFO_1W*)pData;
2427 addjob->JobId = job->job_id;
2428 addjob->Path = (WCHAR *)(addjob + 1);
2429 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2430 ret = TRUE;
2431 } else
2432 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2434 end:
2435 LeaveCriticalSection(&printer_handles_cs);
2436 return ret;
2439 /*****************************************************************************
2440 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2442 * Return the PATH for the Print-Processors
2444 * See GetPrintProcessorDirectoryW.
2448 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2449 DWORD level, LPBYTE Info,
2450 DWORD cbBuf, LPDWORD pcbNeeded)
2452 LPWSTR serverW = NULL;
2453 LPWSTR envW = NULL;
2454 BOOL ret;
2455 INT len;
2457 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2458 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2461 if (server) {
2462 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2463 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2464 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2467 if (env) {
2468 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2469 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2470 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2473 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2474 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2476 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2477 cbBuf, pcbNeeded);
2479 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2480 cbBuf, NULL, NULL) > 0;
2483 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2484 HeapFree(GetProcessHeap(), 0, envW);
2485 HeapFree(GetProcessHeap(), 0, serverW);
2486 return ret;
2489 /*****************************************************************************
2490 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2492 * Return the PATH for the Print-Processors
2494 * PARAMS
2495 * server [I] Servername (NT only) or NULL (local Computer)
2496 * env [I] Printing-Environment (see below) or NULL (Default)
2497 * level [I] Structure-Level (must be 1)
2498 * Info [O] PTR to Buffer that receives the Result
2499 * cbBuf [I] Size of Buffer at "Info"
2500 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2501 * required for the Buffer at "Info"
2503 * RETURNS
2504 * Success: TRUE and in pcbNeeded the Bytes used in Info
2505 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2506 * if cbBuf is too small
2508 * Native Values returned in Info on Success:
2509 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2510 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2511 *| win9x(Windows 4.0): "%winsysdir%"
2513 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2515 * BUGS
2516 * Only NULL or "" is supported for server
2519 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2520 DWORD level, LPBYTE Info,
2521 DWORD cbBuf, LPDWORD pcbNeeded)
2523 DWORD needed;
2524 const printenv_t * env_t;
2526 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2527 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2529 if(server != NULL && server[0]) {
2530 FIXME("server not supported: %s\n", debugstr_w(server));
2531 SetLastError(ERROR_INVALID_PARAMETER);
2532 return FALSE;
2535 env_t = validate_envW(env);
2536 if(!env_t) return FALSE; /* environment invalid or unsupported */
2538 if(level != 1) {
2539 WARN("(Level: %d) is ignored in win9x\n", level);
2540 SetLastError(ERROR_INVALID_LEVEL);
2541 return FALSE;
2544 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2545 needed = GetSystemDirectoryW(NULL, 0);
2546 /* add the Size for the Subdirectories */
2547 needed += lstrlenW(spoolprtprocsW);
2548 needed += lstrlenW(env_t->subdir);
2549 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2551 if(pcbNeeded) *pcbNeeded = needed;
2552 TRACE ("required: 0x%x/%d\n", needed, needed);
2553 if (needed > cbBuf) {
2554 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2555 return FALSE;
2557 if(pcbNeeded == NULL) {
2558 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2559 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2560 SetLastError(RPC_X_NULL_REF_POINTER);
2561 return FALSE;
2563 if(Info == NULL) {
2564 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2565 SetLastError(RPC_X_NULL_REF_POINTER);
2566 return FALSE;
2569 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2570 /* add the Subdirectories */
2571 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2572 lstrcatW((LPWSTR) Info, env_t->subdir);
2573 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2574 return TRUE;
2577 /*****************************************************************************
2578 * WINSPOOL_OpenDriverReg [internal]
2580 * opens the registry for the printer drivers depending on the given input
2581 * variable pEnvironment
2583 * RETURNS:
2584 * the opened hkey on success
2585 * NULL on error
2587 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2589 HKEY retval = NULL;
2590 LPWSTR buffer;
2591 const printenv_t * env;
2593 TRACE("(%s, %d)\n",
2594 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2596 if (!pEnvironment || unicode) {
2597 /* pEnvironment was NULL or a Unicode-String: use it direct */
2598 env = validate_envW(pEnvironment);
2600 else
2602 /* pEnvironment was an ANSI-String: convert to unicode first */
2603 LPWSTR buffer;
2604 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2605 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2606 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2607 env = validate_envW(buffer);
2608 HeapFree(GetProcessHeap(), 0, buffer);
2610 if (!env) return NULL;
2612 buffer = HeapAlloc( GetProcessHeap(), 0,
2613 (strlenW(DriversW) + strlenW(env->envname) +
2614 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2615 if(buffer) {
2616 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2617 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2618 HeapFree(GetProcessHeap(), 0, buffer);
2620 return retval;
2623 /*****************************************************************************
2624 * AddPrinterW [WINSPOOL.@]
2626 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2628 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2629 LPDEVMODEA dmA;
2630 LPDEVMODEW dmW;
2631 HANDLE retval;
2632 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2633 LONG size;
2634 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2635 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2636 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2637 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2638 statusW[] = {'S','t','a','t','u','s',0},
2639 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2641 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2643 if(pName != NULL) {
2644 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2645 SetLastError(ERROR_INVALID_PARAMETER);
2646 return 0;
2648 if(Level != 2) {
2649 ERR("Level = %d, unsupported!\n", Level);
2650 SetLastError(ERROR_INVALID_LEVEL);
2651 return 0;
2653 if(!pPrinter) {
2654 SetLastError(ERROR_INVALID_PARAMETER);
2655 return 0;
2657 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2658 ERROR_SUCCESS) {
2659 ERR("Can't create Printers key\n");
2660 return 0;
2662 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2663 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2664 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2665 RegCloseKey(hkeyPrinter);
2666 RegCloseKey(hkeyPrinters);
2667 return 0;
2669 RegCloseKey(hkeyPrinter);
2671 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2672 if(!hkeyDrivers) {
2673 ERR("Can't create Drivers key\n");
2674 RegCloseKey(hkeyPrinters);
2675 return 0;
2677 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2678 ERROR_SUCCESS) {
2679 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2680 RegCloseKey(hkeyPrinters);
2681 RegCloseKey(hkeyDrivers);
2682 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2683 return 0;
2685 RegCloseKey(hkeyDriver);
2686 RegCloseKey(hkeyDrivers);
2688 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2689 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2690 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2691 RegCloseKey(hkeyPrinters);
2692 return 0;
2695 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2696 ERROR_SUCCESS) {
2697 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2698 SetLastError(ERROR_INVALID_PRINTER_NAME);
2699 RegCloseKey(hkeyPrinters);
2700 return 0;
2702 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2703 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2704 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2706 /* See if we can load the driver. We may need the devmode structure anyway
2708 * FIXME:
2709 * Note that DocumentPropertiesW will briefly try to open the printer we
2710 * just create to find a DEVMODEA struct (it will use the WINEPS default
2711 * one in case it is not there, so we are ok).
2713 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2715 if(size < 0) {
2716 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2717 size = sizeof(DEVMODEW);
2719 if(pi->pDevMode)
2720 dmW = pi->pDevMode;
2721 else
2723 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2724 dmW->dmSize = size;
2725 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2727 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2728 HeapFree(GetProcessHeap(),0,dmW);
2729 dmW=NULL;
2731 else
2733 /* set devmode to printer name */
2734 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2738 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2739 and we support these drivers. NT writes DEVMODEW so somehow
2740 we'll need to distinguish between these when we support NT
2741 drivers */
2742 if (dmW)
2744 dmA = DEVMODEdupWtoA(dmW);
2745 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2746 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2747 HeapFree(GetProcessHeap(), 0, dmA);
2748 if(!pi->pDevMode)
2749 HeapFree(GetProcessHeap(), 0, dmW);
2751 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2752 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2753 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2754 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2756 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2757 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2758 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2759 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2760 (LPBYTE)&pi->Priority, sizeof(DWORD));
2761 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2762 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2763 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2764 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2765 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2766 (LPBYTE)&pi->Status, sizeof(DWORD));
2767 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2768 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2770 RegCloseKey(hkeyPrinter);
2771 RegCloseKey(hkeyPrinters);
2772 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2773 ERR("OpenPrinter failing\n");
2774 return 0;
2776 return retval;
2779 /*****************************************************************************
2780 * AddPrinterA [WINSPOOL.@]
2782 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2784 UNICODE_STRING pNameW;
2785 PWSTR pwstrNameW;
2786 PRINTER_INFO_2W *piW;
2787 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2788 HANDLE ret;
2790 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2791 if(Level != 2) {
2792 ERR("Level = %d, unsupported!\n", Level);
2793 SetLastError(ERROR_INVALID_LEVEL);
2794 return 0;
2796 pwstrNameW = asciitounicode(&pNameW,pName);
2797 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2799 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2801 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2802 RtlFreeUnicodeString(&pNameW);
2803 return ret;
2807 /*****************************************************************************
2808 * ClosePrinter [WINSPOOL.@]
2810 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2812 UINT_PTR i = (UINT_PTR)hPrinter;
2813 opened_printer_t *printer = NULL;
2814 BOOL ret = FALSE;
2816 TRACE("(%p)\n", hPrinter);
2818 EnterCriticalSection(&printer_handles_cs);
2820 if ((i > 0) && (i <= nb_printer_handles))
2821 printer = printer_handles[i - 1];
2824 if(printer)
2826 struct list *cursor, *cursor2;
2828 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2830 if (printer->backend_printer) {
2831 backend->fpClosePrinter(printer->backend_printer);
2834 if(printer->doc)
2835 EndDocPrinter(hPrinter);
2837 if(InterlockedDecrement(&printer->queue->ref) == 0)
2839 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2841 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2842 ScheduleJob(hPrinter, job->job_id);
2844 HeapFree(GetProcessHeap(), 0, printer->queue);
2847 HeapFree(GetProcessHeap(), 0, printer->printername);
2848 HeapFree(GetProcessHeap(), 0, printer->name);
2849 HeapFree(GetProcessHeap(), 0, printer);
2850 printer_handles[i - 1] = NULL;
2851 ret = TRUE;
2853 LeaveCriticalSection(&printer_handles_cs);
2854 return ret;
2857 /*****************************************************************************
2858 * DeleteFormA [WINSPOOL.@]
2860 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2862 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2863 return 1;
2866 /*****************************************************************************
2867 * DeleteFormW [WINSPOOL.@]
2869 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2871 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2872 return 1;
2875 /*****************************************************************************
2876 * DeletePrinter [WINSPOOL.@]
2878 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2880 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2881 HKEY hkeyPrinters, hkey;
2883 if(!lpNameW) {
2884 SetLastError(ERROR_INVALID_HANDLE);
2885 return FALSE;
2887 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2888 RegDeleteTreeW(hkeyPrinters, lpNameW);
2889 RegCloseKey(hkeyPrinters);
2891 WriteProfileStringW(devicesW, lpNameW, NULL);
2892 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2894 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2895 RegDeleteValueW(hkey, lpNameW);
2896 RegCloseKey(hkey);
2899 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2900 RegDeleteValueW(hkey, lpNameW);
2901 RegCloseKey(hkey);
2903 return TRUE;
2906 /*****************************************************************************
2907 * SetPrinterA [WINSPOOL.@]
2909 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2910 DWORD Command)
2912 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2913 return FALSE;
2916 /*****************************************************************************
2917 * SetJobA [WINSPOOL.@]
2919 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2920 LPBYTE pJob, DWORD Command)
2922 BOOL ret;
2923 LPBYTE JobW;
2924 UNICODE_STRING usBuffer;
2926 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2928 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2929 are all ignored by SetJob, so we don't bother copying them */
2930 switch(Level)
2932 case 0:
2933 JobW = NULL;
2934 break;
2935 case 1:
2937 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2938 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2940 JobW = (LPBYTE)info1W;
2941 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2942 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2943 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2944 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2945 info1W->Status = info1A->Status;
2946 info1W->Priority = info1A->Priority;
2947 info1W->Position = info1A->Position;
2948 info1W->PagesPrinted = info1A->PagesPrinted;
2949 break;
2951 case 2:
2953 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2954 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2956 JobW = (LPBYTE)info2W;
2957 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2958 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2959 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2960 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2961 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2962 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2963 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2964 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2965 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2966 info2W->Status = info2A->Status;
2967 info2W->Priority = info2A->Priority;
2968 info2W->Position = info2A->Position;
2969 info2W->StartTime = info2A->StartTime;
2970 info2W->UntilTime = info2A->UntilTime;
2971 info2W->PagesPrinted = info2A->PagesPrinted;
2972 break;
2974 case 3:
2975 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2976 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2977 break;
2978 default:
2979 SetLastError(ERROR_INVALID_LEVEL);
2980 return FALSE;
2983 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2985 switch(Level)
2987 case 1:
2989 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2990 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2991 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2992 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2993 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2994 break;
2996 case 2:
2998 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2999 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3000 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3001 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3002 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3003 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3004 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3005 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3006 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3007 break;
3010 HeapFree(GetProcessHeap(), 0, JobW);
3012 return ret;
3015 /*****************************************************************************
3016 * SetJobW [WINSPOOL.@]
3018 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3019 LPBYTE pJob, DWORD Command)
3021 BOOL ret = FALSE;
3022 job_t *job;
3024 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3025 FIXME("Ignoring everything other than document title\n");
3027 EnterCriticalSection(&printer_handles_cs);
3028 job = get_job(hPrinter, JobId);
3029 if(!job)
3030 goto end;
3032 switch(Level)
3034 case 0:
3035 break;
3036 case 1:
3038 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3039 HeapFree(GetProcessHeap(), 0, job->document_title);
3040 job->document_title = strdupW(info1->pDocument);
3041 break;
3043 case 2:
3045 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3046 HeapFree(GetProcessHeap(), 0, job->document_title);
3047 job->document_title = strdupW(info2->pDocument);
3048 break;
3050 case 3:
3051 break;
3052 default:
3053 SetLastError(ERROR_INVALID_LEVEL);
3054 goto end;
3056 ret = TRUE;
3057 end:
3058 LeaveCriticalSection(&printer_handles_cs);
3059 return ret;
3062 /*****************************************************************************
3063 * EndDocPrinter [WINSPOOL.@]
3065 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3067 opened_printer_t *printer;
3068 BOOL ret = FALSE;
3069 TRACE("(%p)\n", hPrinter);
3071 EnterCriticalSection(&printer_handles_cs);
3073 printer = get_opened_printer(hPrinter);
3074 if(!printer)
3076 SetLastError(ERROR_INVALID_HANDLE);
3077 goto end;
3080 if(!printer->doc)
3082 SetLastError(ERROR_SPL_NO_STARTDOC);
3083 goto end;
3086 CloseHandle(printer->doc->hf);
3087 ScheduleJob(hPrinter, printer->doc->job_id);
3088 HeapFree(GetProcessHeap(), 0, printer->doc);
3089 printer->doc = NULL;
3090 ret = TRUE;
3091 end:
3092 LeaveCriticalSection(&printer_handles_cs);
3093 return ret;
3096 /*****************************************************************************
3097 * EndPagePrinter [WINSPOOL.@]
3099 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3101 FIXME("(%p): stub\n", hPrinter);
3102 return TRUE;
3105 /*****************************************************************************
3106 * StartDocPrinterA [WINSPOOL.@]
3108 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3110 UNICODE_STRING usBuffer;
3111 DOC_INFO_2W doc2W;
3112 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3113 DWORD ret;
3115 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3116 or one (DOC_INFO_3) extra DWORDs */
3118 switch(Level) {
3119 case 2:
3120 doc2W.JobId = doc2->JobId;
3121 /* fall through */
3122 case 3:
3123 doc2W.dwMode = doc2->dwMode;
3124 /* fall through */
3125 case 1:
3126 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3127 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3128 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3129 break;
3131 default:
3132 SetLastError(ERROR_INVALID_LEVEL);
3133 return FALSE;
3136 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3138 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3139 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3140 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3142 return ret;
3145 /*****************************************************************************
3146 * StartDocPrinterW [WINSPOOL.@]
3148 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3150 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3151 opened_printer_t *printer;
3152 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3153 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3154 JOB_INFO_1W job_info;
3155 DWORD needed, ret = 0;
3156 HANDLE hf;
3157 WCHAR *filename;
3159 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3160 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3161 debugstr_w(doc->pDatatype));
3163 if(Level < 1 || Level > 3)
3165 SetLastError(ERROR_INVALID_LEVEL);
3166 return 0;
3169 EnterCriticalSection(&printer_handles_cs);
3170 printer = get_opened_printer(hPrinter);
3171 if(!printer)
3173 SetLastError(ERROR_INVALID_HANDLE);
3174 goto end;
3177 if(printer->doc)
3179 SetLastError(ERROR_INVALID_PRINTER_STATE);
3180 goto end;
3183 /* Even if we're printing to a file we still add a print job, we'll
3184 just ignore the spool file name */
3186 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3188 ERR("AddJob failed gle %u\n", GetLastError());
3189 goto end;
3192 if(doc->pOutputFile)
3193 filename = doc->pOutputFile;
3194 else
3195 filename = addjob->Path;
3197 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3198 if(hf == INVALID_HANDLE_VALUE)
3199 goto end;
3201 memset(&job_info, 0, sizeof(job_info));
3202 job_info.pDocument = doc->pDocName;
3203 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3205 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3206 printer->doc->hf = hf;
3207 ret = printer->doc->job_id = addjob->JobId;
3208 end:
3209 LeaveCriticalSection(&printer_handles_cs);
3211 return ret;
3214 /*****************************************************************************
3215 * StartPagePrinter [WINSPOOL.@]
3217 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3219 FIXME("(%p): stub\n", hPrinter);
3220 return TRUE;
3223 /*****************************************************************************
3224 * GetFormA [WINSPOOL.@]
3226 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3227 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3229 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3230 Level,pForm,cbBuf,pcbNeeded);
3231 return FALSE;
3234 /*****************************************************************************
3235 * GetFormW [WINSPOOL.@]
3237 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3238 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3240 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3241 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3242 return FALSE;
3245 /*****************************************************************************
3246 * SetFormA [WINSPOOL.@]
3248 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3249 LPBYTE pForm)
3251 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3252 return FALSE;
3255 /*****************************************************************************
3256 * SetFormW [WINSPOOL.@]
3258 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3259 LPBYTE pForm)
3261 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3262 return FALSE;
3265 /*****************************************************************************
3266 * ReadPrinter [WINSPOOL.@]
3268 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3269 LPDWORD pNoBytesRead)
3271 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3272 return FALSE;
3275 /*****************************************************************************
3276 * ResetPrinterA [WINSPOOL.@]
3278 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3280 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3281 return FALSE;
3284 /*****************************************************************************
3285 * ResetPrinterW [WINSPOOL.@]
3287 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3289 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3290 return FALSE;
3293 /*****************************************************************************
3294 * WINSPOOL_GetDWORDFromReg
3296 * Return DWORD associated with ValueName from hkey.
3298 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3300 DWORD sz = sizeof(DWORD), type, value = 0;
3301 LONG ret;
3303 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3305 if(ret != ERROR_SUCCESS) {
3306 WARN("Got ret = %d on name %s\n", ret, ValueName);
3307 return 0;
3309 if(type != REG_DWORD) {
3310 ERR("Got type %d\n", type);
3311 return 0;
3313 return value;
3317 /*****************************************************************************
3318 * get_filename_from_reg [internal]
3320 * Get ValueName from hkey storing result in out
3321 * when the Value in the registry has only a filename, use driverdir as prefix
3322 * outlen is space left in out
3323 * String is stored either as unicode or ascii
3327 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3328 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3330 WCHAR filename[MAX_PATH];
3331 DWORD size;
3332 DWORD type;
3333 LONG ret;
3334 LPWSTR buffer = filename;
3335 LPWSTR ptr;
3337 *needed = 0;
3338 size = sizeof(filename);
3339 buffer[0] = '\0';
3340 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3341 if (ret == ERROR_MORE_DATA) {
3342 TRACE("need dynamic buffer: %u\n", size);
3343 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3344 if (!buffer) {
3345 /* No Memory is bad */
3346 return FALSE;
3348 buffer[0] = '\0';
3349 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3352 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3353 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3354 return FALSE;
3357 ptr = buffer;
3358 while (ptr) {
3359 /* do we have a full path ? */
3360 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3361 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3363 if (!ret) {
3364 /* we must build the full Path */
3365 *needed += dirlen;
3366 if ((out) && (outlen > dirlen)) {
3367 if (unicode) {
3368 lstrcpyW((LPWSTR)out, driverdir);
3370 else
3372 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3374 out += dirlen;
3375 outlen -= dirlen;
3377 else
3378 out = NULL;
3381 /* write the filename */
3382 if (unicode) {
3383 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3384 if ((out) && (outlen >= size)) {
3385 lstrcpyW((LPWSTR)out, ptr);
3386 out += size;
3387 outlen -= size;
3389 else
3390 out = NULL;
3392 else
3394 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3395 if ((out) && (outlen >= size)) {
3396 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3397 out += size;
3398 outlen -= size;
3400 else
3401 out = NULL;
3403 *needed += size;
3404 ptr += lstrlenW(ptr)+1;
3405 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3408 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3410 /* write the multisz-termination */
3411 if (type == REG_MULTI_SZ) {
3412 size = (unicode) ? sizeof(WCHAR) : 1;
3414 *needed += size;
3415 if (out && (outlen >= size)) {
3416 memset (out, 0, size);
3419 return TRUE;
3422 /*****************************************************************************
3423 * WINSPOOL_GetStringFromReg
3425 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3426 * String is stored either as unicode or ascii.
3427 * Bit of a hack here to get the ValueName if we want ascii.
3429 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3430 DWORD buflen, DWORD *needed,
3431 BOOL unicode)
3433 DWORD sz = buflen, type;
3434 LONG ret;
3436 if(unicode)
3437 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3438 else {
3439 LPSTR ValueNameA = strdupWtoA(ValueName);
3440 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3441 HeapFree(GetProcessHeap(),0,ValueNameA);
3443 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3444 WARN("Got ret = %d\n", ret);
3445 *needed = 0;
3446 return FALSE;
3448 /* add space for terminating '\0' */
3449 sz += unicode ? sizeof(WCHAR) : 1;
3450 *needed = sz;
3452 if (ptr)
3453 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3455 return TRUE;
3458 /*****************************************************************************
3459 * WINSPOOL_GetDefaultDevMode
3461 * Get a default DevMode values for wineps.
3462 * FIXME - use ppd.
3465 static void WINSPOOL_GetDefaultDevMode(
3466 LPBYTE ptr,
3467 DWORD buflen, DWORD *needed,
3468 BOOL unicode)
3470 DEVMODEA dm;
3471 static const char szwps[] = "wineps.drv";
3473 /* fill default DEVMODE - should be read from ppd... */
3474 ZeroMemory( &dm, sizeof(dm) );
3475 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3476 dm.dmSpecVersion = DM_SPECVERSION;
3477 dm.dmDriverVersion = 1;
3478 dm.dmSize = sizeof(DEVMODEA);
3479 dm.dmDriverExtra = 0;
3480 dm.dmFields =
3481 DM_ORIENTATION | DM_PAPERSIZE |
3482 DM_PAPERLENGTH | DM_PAPERWIDTH |
3483 DM_SCALE |
3484 DM_COPIES |
3485 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3486 DM_YRESOLUTION | DM_TTOPTION;
3488 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3489 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3490 dm.u1.s1.dmPaperLength = 2970;
3491 dm.u1.s1.dmPaperWidth = 2100;
3493 dm.u1.s1.dmScale = 100;
3494 dm.u1.s1.dmCopies = 1;
3495 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3496 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3497 /* dm.dmColor */
3498 /* dm.dmDuplex */
3499 dm.dmYResolution = 300; /* 300dpi */
3500 dm.dmTTOption = DMTT_BITMAP;
3501 /* dm.dmCollate */
3502 /* dm.dmFormName */
3503 /* dm.dmLogPixels */
3504 /* dm.dmBitsPerPel */
3505 /* dm.dmPelsWidth */
3506 /* dm.dmPelsHeight */
3507 /* dm.u2.dmDisplayFlags */
3508 /* dm.dmDisplayFrequency */
3509 /* dm.dmICMMethod */
3510 /* dm.dmICMIntent */
3511 /* dm.dmMediaType */
3512 /* dm.dmDitherType */
3513 /* dm.dmReserved1 */
3514 /* dm.dmReserved2 */
3515 /* dm.dmPanningWidth */
3516 /* dm.dmPanningHeight */
3518 if(unicode) {
3519 if(buflen >= sizeof(DEVMODEW)) {
3520 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3521 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3522 HeapFree(GetProcessHeap(),0,pdmW);
3524 *needed = sizeof(DEVMODEW);
3526 else
3528 if(buflen >= sizeof(DEVMODEA)) {
3529 memcpy(ptr, &dm, sizeof(DEVMODEA));
3531 *needed = sizeof(DEVMODEA);
3535 /*****************************************************************************
3536 * WINSPOOL_GetDevModeFromReg
3538 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3539 * DevMode is stored either as unicode or ascii.
3541 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3542 LPBYTE ptr,
3543 DWORD buflen, DWORD *needed,
3544 BOOL unicode)
3546 DWORD sz = buflen, type;
3547 LONG ret;
3549 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3550 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3551 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3552 if (sz < sizeof(DEVMODEA))
3554 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3555 return FALSE;
3557 /* ensures that dmSize is not erratically bogus if registry is invalid */
3558 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3559 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3560 if(unicode) {
3561 sz += (CCHDEVICENAME + CCHFORMNAME);
3562 if(buflen >= sz) {
3563 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3564 memcpy(ptr, dmW, sz);
3565 HeapFree(GetProcessHeap(),0,dmW);
3568 *needed = sz;
3569 return TRUE;
3572 /*********************************************************************
3573 * WINSPOOL_GetPrinter_1
3575 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3576 * The strings are either stored as unicode or ascii.
3578 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3579 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3580 BOOL unicode)
3582 DWORD size, left = cbBuf;
3583 BOOL space = (cbBuf > 0);
3584 LPBYTE ptr = buf;
3586 *pcbNeeded = 0;
3588 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3589 unicode)) {
3590 if(space && size <= left) {
3591 pi1->pName = (LPWSTR)ptr;
3592 ptr += size;
3593 left -= size;
3594 } else
3595 space = FALSE;
3596 *pcbNeeded += size;
3599 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3600 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3601 unicode)) {
3602 if(space && size <= left) {
3603 pi1->pDescription = (LPWSTR)ptr;
3604 ptr += size;
3605 left -= size;
3606 } else
3607 space = FALSE;
3608 *pcbNeeded += size;
3611 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3612 unicode)) {
3613 if(space && size <= left) {
3614 pi1->pComment = (LPWSTR)ptr;
3615 ptr += size;
3616 left -= size;
3617 } else
3618 space = FALSE;
3619 *pcbNeeded += size;
3622 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3624 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3625 memset(pi1, 0, sizeof(*pi1));
3627 return space;
3629 /*********************************************************************
3630 * WINSPOOL_GetPrinter_2
3632 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3633 * The strings are either stored as unicode or ascii.
3635 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3636 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3637 BOOL unicode)
3639 DWORD size, left = cbBuf;
3640 BOOL space = (cbBuf > 0);
3641 LPBYTE ptr = buf;
3643 *pcbNeeded = 0;
3645 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3646 unicode)) {
3647 if(space && size <= left) {
3648 pi2->pPrinterName = (LPWSTR)ptr;
3649 ptr += size;
3650 left -= size;
3651 } else
3652 space = FALSE;
3653 *pcbNeeded += size;
3655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3656 unicode)) {
3657 if(space && size <= left) {
3658 pi2->pShareName = (LPWSTR)ptr;
3659 ptr += size;
3660 left -= size;
3661 } else
3662 space = FALSE;
3663 *pcbNeeded += size;
3665 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3666 unicode)) {
3667 if(space && size <= left) {
3668 pi2->pPortName = (LPWSTR)ptr;
3669 ptr += size;
3670 left -= size;
3671 } else
3672 space = FALSE;
3673 *pcbNeeded += size;
3675 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3676 &size, unicode)) {
3677 if(space && size <= left) {
3678 pi2->pDriverName = (LPWSTR)ptr;
3679 ptr += size;
3680 left -= size;
3681 } else
3682 space = FALSE;
3683 *pcbNeeded += size;
3685 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3686 unicode)) {
3687 if(space && size <= left) {
3688 pi2->pComment = (LPWSTR)ptr;
3689 ptr += size;
3690 left -= size;
3691 } else
3692 space = FALSE;
3693 *pcbNeeded += size;
3695 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3696 unicode)) {
3697 if(space && size <= left) {
3698 pi2->pLocation = (LPWSTR)ptr;
3699 ptr += size;
3700 left -= size;
3701 } else
3702 space = FALSE;
3703 *pcbNeeded += size;
3705 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3706 &size, unicode)) {
3707 if(space && size <= left) {
3708 pi2->pDevMode = (LPDEVMODEW)ptr;
3709 ptr += size;
3710 left -= size;
3711 } else
3712 space = FALSE;
3713 *pcbNeeded += size;
3715 else
3717 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3718 if(space && size <= left) {
3719 pi2->pDevMode = (LPDEVMODEW)ptr;
3720 ptr += size;
3721 left -= size;
3722 } else
3723 space = FALSE;
3724 *pcbNeeded += size;
3726 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3727 &size, unicode)) {
3728 if(space && size <= left) {
3729 pi2->pSepFile = (LPWSTR)ptr;
3730 ptr += size;
3731 left -= size;
3732 } else
3733 space = FALSE;
3734 *pcbNeeded += size;
3736 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3737 &size, unicode)) {
3738 if(space && size <= left) {
3739 pi2->pPrintProcessor = (LPWSTR)ptr;
3740 ptr += size;
3741 left -= size;
3742 } else
3743 space = FALSE;
3744 *pcbNeeded += size;
3746 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3747 &size, unicode)) {
3748 if(space && size <= left) {
3749 pi2->pDatatype = (LPWSTR)ptr;
3750 ptr += size;
3751 left -= size;
3752 } else
3753 space = FALSE;
3754 *pcbNeeded += size;
3756 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3757 &size, unicode)) {
3758 if(space && size <= left) {
3759 pi2->pParameters = (LPWSTR)ptr;
3760 ptr += size;
3761 left -= size;
3762 } else
3763 space = FALSE;
3764 *pcbNeeded += size;
3766 if(pi2) {
3767 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3768 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3769 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3770 "Default Priority");
3771 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3772 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3775 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3776 memset(pi2, 0, sizeof(*pi2));
3778 return space;
3781 /*********************************************************************
3782 * WINSPOOL_GetPrinter_4
3784 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3786 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3787 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3788 BOOL unicode)
3790 DWORD size, left = cbBuf;
3791 BOOL space = (cbBuf > 0);
3792 LPBYTE ptr = buf;
3794 *pcbNeeded = 0;
3796 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3797 unicode)) {
3798 if(space && size <= left) {
3799 pi4->pPrinterName = (LPWSTR)ptr;
3800 ptr += size;
3801 left -= size;
3802 } else
3803 space = FALSE;
3804 *pcbNeeded += size;
3806 if(pi4) {
3807 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3810 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3811 memset(pi4, 0, sizeof(*pi4));
3813 return space;
3816 /*********************************************************************
3817 * WINSPOOL_GetPrinter_5
3819 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3821 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3822 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3823 BOOL unicode)
3825 DWORD size, left = cbBuf;
3826 BOOL space = (cbBuf > 0);
3827 LPBYTE ptr = buf;
3829 *pcbNeeded = 0;
3831 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3832 unicode)) {
3833 if(space && size <= left) {
3834 pi5->pPrinterName = (LPWSTR)ptr;
3835 ptr += size;
3836 left -= size;
3837 } else
3838 space = FALSE;
3839 *pcbNeeded += size;
3841 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3842 unicode)) {
3843 if(space && size <= left) {
3844 pi5->pPortName = (LPWSTR)ptr;
3845 ptr += size;
3846 left -= size;
3847 } else
3848 space = FALSE;
3849 *pcbNeeded += size;
3851 if(pi5) {
3852 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3853 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3854 "dnsTimeout");
3855 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3856 "txTimeout");
3859 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3860 memset(pi5, 0, sizeof(*pi5));
3862 return space;
3865 /*********************************************************************
3866 * WINSPOOL_GetPrinter_7
3868 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3870 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3871 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3873 DWORD size, left = cbBuf;
3874 BOOL space = (cbBuf > 0);
3875 LPBYTE ptr = buf;
3877 *pcbNeeded = 0;
3879 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3881 if (space && size <= left) {
3882 pi7->pszObjectGUID = (LPWSTR)ptr;
3883 ptr += size;
3884 left -= size;
3885 } else
3886 space = FALSE;
3887 *pcbNeeded += size;
3889 if (pi7) {
3890 /* We do not have a Directory Service */
3891 pi7->dwAction = DSPRINT_UNPUBLISH;
3894 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3895 memset(pi7, 0, sizeof(*pi7));
3897 return space;
3900 /*********************************************************************
3901 * WINSPOOL_GetPrinter_9
3903 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3904 * The strings are either stored as unicode or ascii.
3906 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3907 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3909 DWORD size;
3910 BOOL space = (cbBuf > 0);
3912 *pcbNeeded = 0;
3914 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3915 if(space && size <= cbBuf) {
3916 pi9->pDevMode = (LPDEVMODEW)buf;
3917 } else
3918 space = FALSE;
3919 *pcbNeeded += size;
3921 else
3923 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3924 if(space && size <= cbBuf) {
3925 pi9->pDevMode = (LPDEVMODEW)buf;
3926 } else
3927 space = FALSE;
3928 *pcbNeeded += size;
3931 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3932 memset(pi9, 0, sizeof(*pi9));
3934 return space;
3937 /*****************************************************************************
3938 * WINSPOOL_GetPrinter
3940 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3941 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3942 * just a collection of pointers to strings.
3944 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3945 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3947 LPCWSTR name;
3948 DWORD size, needed = 0;
3949 LPBYTE ptr = NULL;
3950 HKEY hkeyPrinter, hkeyPrinters;
3951 BOOL ret;
3953 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3955 if (!(name = get_opened_printer_name(hPrinter))) {
3956 SetLastError(ERROR_INVALID_HANDLE);
3957 return FALSE;
3960 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3961 ERROR_SUCCESS) {
3962 ERR("Can't create Printers key\n");
3963 return FALSE;
3965 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3967 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3968 RegCloseKey(hkeyPrinters);
3969 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3970 return FALSE;
3973 switch(Level) {
3974 case 2:
3976 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3978 size = sizeof(PRINTER_INFO_2W);
3979 if(size <= cbBuf) {
3980 ptr = pPrinter + size;
3981 cbBuf -= size;
3982 memset(pPrinter, 0, size);
3983 } else {
3984 pi2 = NULL;
3985 cbBuf = 0;
3987 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3988 unicode);
3989 needed += size;
3990 break;
3993 case 4:
3995 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3997 size = sizeof(PRINTER_INFO_4W);
3998 if(size <= cbBuf) {
3999 ptr = pPrinter + size;
4000 cbBuf -= size;
4001 memset(pPrinter, 0, size);
4002 } else {
4003 pi4 = NULL;
4004 cbBuf = 0;
4006 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4007 unicode);
4008 needed += size;
4009 break;
4013 case 5:
4015 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4017 size = sizeof(PRINTER_INFO_5W);
4018 if(size <= cbBuf) {
4019 ptr = pPrinter + size;
4020 cbBuf -= size;
4021 memset(pPrinter, 0, size);
4022 } else {
4023 pi5 = NULL;
4024 cbBuf = 0;
4027 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4028 unicode);
4029 needed += size;
4030 break;
4034 case 6:
4036 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4038 size = sizeof(PRINTER_INFO_6);
4039 if (size <= cbBuf) {
4040 /* FIXME: We do not update the status yet */
4041 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4042 ret = TRUE;
4043 } else {
4044 ret = FALSE;
4047 needed += size;
4048 break;
4051 case 7:
4053 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4055 size = sizeof(PRINTER_INFO_7W);
4056 if (size <= cbBuf) {
4057 ptr = pPrinter + size;
4058 cbBuf -= size;
4059 memset(pPrinter, 0, size);
4060 } else {
4061 pi7 = NULL;
4062 cbBuf = 0;
4065 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4066 needed += size;
4067 break;
4071 case 9:
4073 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4075 size = sizeof(PRINTER_INFO_9W);
4076 if(size <= cbBuf) {
4077 ptr = pPrinter + size;
4078 cbBuf -= size;
4079 memset(pPrinter, 0, size);
4080 } else {
4081 pi9 = NULL;
4082 cbBuf = 0;
4085 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4086 needed += size;
4087 break;
4091 default:
4092 FIXME("Unimplemented level %d\n", Level);
4093 SetLastError(ERROR_INVALID_LEVEL);
4094 RegCloseKey(hkeyPrinters);
4095 RegCloseKey(hkeyPrinter);
4096 return FALSE;
4099 RegCloseKey(hkeyPrinter);
4100 RegCloseKey(hkeyPrinters);
4102 TRACE("returning %d needed = %d\n", ret, needed);
4103 if(pcbNeeded) *pcbNeeded = needed;
4104 if(!ret)
4105 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4106 return ret;
4109 /*****************************************************************************
4110 * GetPrinterW [WINSPOOL.@]
4112 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4113 DWORD cbBuf, LPDWORD pcbNeeded)
4115 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4116 TRUE);
4119 /*****************************************************************************
4120 * GetPrinterA [WINSPOOL.@]
4122 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4123 DWORD cbBuf, LPDWORD pcbNeeded)
4125 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4126 FALSE);
4129 /*****************************************************************************
4130 * WINSPOOL_EnumPrinters
4132 * Implementation of EnumPrintersA|W
4134 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4135 DWORD dwLevel, LPBYTE lpbPrinters,
4136 DWORD cbBuf, LPDWORD lpdwNeeded,
4137 LPDWORD lpdwReturned, BOOL unicode)
4140 HKEY hkeyPrinters, hkeyPrinter;
4141 WCHAR PrinterName[255];
4142 DWORD needed = 0, number = 0;
4143 DWORD used, i, left;
4144 PBYTE pi, buf;
4146 if(lpbPrinters)
4147 memset(lpbPrinters, 0, cbBuf);
4148 if(lpdwReturned)
4149 *lpdwReturned = 0;
4150 if(lpdwNeeded)
4151 *lpdwNeeded = 0;
4153 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4154 if(dwType == PRINTER_ENUM_DEFAULT)
4155 return TRUE;
4157 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4158 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4159 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4160 if (!dwType) {
4161 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4162 *lpdwNeeded = 0;
4163 *lpdwReturned = 0;
4164 return TRUE;
4169 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4170 FIXME("dwType = %08x\n", dwType);
4171 SetLastError(ERROR_INVALID_FLAGS);
4172 return FALSE;
4175 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4176 ERROR_SUCCESS) {
4177 ERR("Can't create Printers key\n");
4178 return FALSE;
4181 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4182 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4183 RegCloseKey(hkeyPrinters);
4184 ERR("Can't query Printers key\n");
4185 return FALSE;
4187 TRACE("Found %d printers\n", number);
4189 switch(dwLevel) {
4190 case 1:
4191 used = number * sizeof(PRINTER_INFO_1W);
4192 break;
4193 case 2:
4194 used = number * sizeof(PRINTER_INFO_2W);
4195 break;
4196 case 4:
4197 used = number * sizeof(PRINTER_INFO_4W);
4198 break;
4199 case 5:
4200 used = number * sizeof(PRINTER_INFO_5W);
4201 break;
4203 default:
4204 SetLastError(ERROR_INVALID_LEVEL);
4205 RegCloseKey(hkeyPrinters);
4206 return FALSE;
4208 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4210 for(i = 0; i < number; i++) {
4211 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4212 ERROR_SUCCESS) {
4213 ERR("Can't enum key number %d\n", i);
4214 RegCloseKey(hkeyPrinters);
4215 return FALSE;
4217 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4218 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4219 ERROR_SUCCESS) {
4220 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4221 RegCloseKey(hkeyPrinters);
4222 return FALSE;
4225 if(cbBuf > used) {
4226 buf = lpbPrinters + used;
4227 left = cbBuf - used;
4228 } else {
4229 buf = NULL;
4230 left = 0;
4233 switch(dwLevel) {
4234 case 1:
4235 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4236 left, &needed, unicode);
4237 used += needed;
4238 if(pi) pi += sizeof(PRINTER_INFO_1W);
4239 break;
4240 case 2:
4241 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4242 left, &needed, unicode);
4243 used += needed;
4244 if(pi) pi += sizeof(PRINTER_INFO_2W);
4245 break;
4246 case 4:
4247 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4248 left, &needed, unicode);
4249 used += needed;
4250 if(pi) pi += sizeof(PRINTER_INFO_4W);
4251 break;
4252 case 5:
4253 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4254 left, &needed, unicode);
4255 used += needed;
4256 if(pi) pi += sizeof(PRINTER_INFO_5W);
4257 break;
4258 default:
4259 ERR("Shouldn't be here!\n");
4260 RegCloseKey(hkeyPrinter);
4261 RegCloseKey(hkeyPrinters);
4262 return FALSE;
4264 RegCloseKey(hkeyPrinter);
4266 RegCloseKey(hkeyPrinters);
4268 if(lpdwNeeded)
4269 *lpdwNeeded = used;
4271 if(used > cbBuf) {
4272 if(lpbPrinters)
4273 memset(lpbPrinters, 0, cbBuf);
4274 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4275 return FALSE;
4277 if(lpdwReturned)
4278 *lpdwReturned = number;
4279 SetLastError(ERROR_SUCCESS);
4280 return TRUE;
4284 /******************************************************************
4285 * EnumPrintersW [WINSPOOL.@]
4287 * Enumerates the available printers, print servers and print
4288 * providers, depending on the specified flags, name and level.
4290 * RETURNS:
4292 * If level is set to 1:
4293 * Returns an array of PRINTER_INFO_1 data structures in the
4294 * lpbPrinters buffer.
4296 * If level is set to 2:
4297 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4298 * Returns an array of PRINTER_INFO_2 data structures in the
4299 * lpbPrinters buffer. Note that according to MSDN also an
4300 * OpenPrinter should be performed on every remote printer.
4302 * If level is set to 4 (officially WinNT only):
4303 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4304 * Fast: Only the registry is queried to retrieve printer names,
4305 * no connection to the driver is made.
4306 * Returns an array of PRINTER_INFO_4 data structures in the
4307 * lpbPrinters buffer.
4309 * If level is set to 5 (officially WinNT4/Win9x only):
4310 * Fast: Only the registry is queried to retrieve printer names,
4311 * no connection to the driver is made.
4312 * Returns an array of PRINTER_INFO_5 data structures in the
4313 * lpbPrinters buffer.
4315 * If level set to 3 or 6+:
4316 * returns zero (failure!)
4318 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4319 * for information.
4321 * BUGS:
4322 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4323 * - Only levels 2, 4 and 5 are implemented at the moment.
4324 * - 16-bit printer drivers are not enumerated.
4325 * - Returned amount of bytes used/needed does not match the real Windoze
4326 * implementation (as in this implementation, all strings are part
4327 * of the buffer, whereas Win32 keeps them somewhere else)
4328 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4330 * NOTE:
4331 * - In a regular Wine installation, no registry settings for printers
4332 * exist, which makes this function return an empty list.
4334 BOOL WINAPI EnumPrintersW(
4335 DWORD dwType, /* [in] Types of print objects to enumerate */
4336 LPWSTR lpszName, /* [in] name of objects to enumerate */
4337 DWORD dwLevel, /* [in] type of printer info structure */
4338 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4339 DWORD cbBuf, /* [in] max size of buffer in bytes */
4340 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4341 LPDWORD lpdwReturned /* [out] number of entries returned */
4344 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4345 lpdwNeeded, lpdwReturned, TRUE);
4348 /******************************************************************
4349 * EnumPrintersA [WINSPOOL.@]
4351 * See EnumPrintersW
4354 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4355 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4357 BOOL ret;
4358 UNICODE_STRING pNameU;
4359 LPWSTR pNameW;
4360 LPBYTE pPrintersW;
4362 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4363 pPrinters, cbBuf, pcbNeeded, pcReturned);
4365 pNameW = asciitounicode(&pNameU, pName);
4367 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4368 MS Office need this */
4369 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4371 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4373 RtlFreeUnicodeString(&pNameU);
4374 if (ret) {
4375 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4377 HeapFree(GetProcessHeap(), 0, pPrintersW);
4378 return ret;
4381 /*****************************************************************************
4382 * WINSPOOL_GetDriverInfoFromReg [internal]
4384 * Enters the information from the registry into the DRIVER_INFO struct
4386 * RETURNS
4387 * zero if the printer driver does not exist in the registry
4388 * (only if Level > 1) otherwise nonzero
4390 static BOOL WINSPOOL_GetDriverInfoFromReg(
4391 HKEY hkeyDrivers,
4392 LPWSTR DriverName,
4393 const printenv_t * env,
4394 DWORD Level,
4395 LPBYTE ptr, /* DRIVER_INFO */
4396 LPBYTE pDriverStrings, /* strings buffer */
4397 DWORD cbBuf, /* size of string buffer */
4398 LPDWORD pcbNeeded, /* space needed for str. */
4399 BOOL unicode) /* type of strings */
4401 DWORD size, tmp;
4402 HKEY hkeyDriver;
4403 WCHAR driverdir[MAX_PATH];
4404 DWORD dirlen;
4405 LPBYTE strPtr = pDriverStrings;
4406 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4408 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4409 debugstr_w(DriverName), env,
4410 Level, di, pDriverStrings, cbBuf, unicode);
4412 if (di) ZeroMemory(di, di_sizeof[Level]);
4414 if (unicode) {
4415 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4416 if (*pcbNeeded <= cbBuf)
4417 strcpyW((LPWSTR)strPtr, DriverName);
4419 else
4421 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4422 if (*pcbNeeded <= cbBuf)
4423 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4426 /* pName for level 1 has a different offset! */
4427 if (Level == 1) {
4428 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4429 return TRUE;
4432 /* .cVersion and .pName for level > 1 */
4433 if (di) {
4434 di->cVersion = env->driverversion;
4435 di->pName = (LPWSTR) strPtr;
4436 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4439 /* Reserve Space for the largest subdir and a Backslash*/
4440 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4441 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4442 /* Should never Fail */
4443 return FALSE;
4445 lstrcatW(driverdir, env->versionsubdir);
4446 lstrcatW(driverdir, backslashW);
4448 /* dirlen must not include the terminating zero */
4449 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4450 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4452 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4453 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4454 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4455 return FALSE;
4458 /* pEnvironment */
4459 if (unicode)
4460 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4461 else
4462 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4464 *pcbNeeded += size;
4465 if (*pcbNeeded <= cbBuf) {
4466 if (unicode) {
4467 lstrcpyW((LPWSTR)strPtr, env->envname);
4469 else
4471 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4473 if (di) di->pEnvironment = (LPWSTR)strPtr;
4474 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4477 /* .pDriverPath is the Graphics rendering engine.
4478 The full Path is required to avoid a crash in some apps */
4479 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4480 *pcbNeeded += size;
4481 if (*pcbNeeded <= cbBuf)
4482 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4484 if (di) di->pDriverPath = (LPWSTR)strPtr;
4485 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4488 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4489 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4490 *pcbNeeded += size;
4491 if (*pcbNeeded <= cbBuf)
4492 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4494 if (di) di->pDataFile = (LPWSTR)strPtr;
4495 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4498 /* .pConfigFile is the Driver user Interface */
4499 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4500 *pcbNeeded += size;
4501 if (*pcbNeeded <= cbBuf)
4502 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4504 if (di) di->pConfigFile = (LPWSTR)strPtr;
4505 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4508 if (Level == 2 ) {
4509 RegCloseKey(hkeyDriver);
4510 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4511 return TRUE;
4514 if (Level == 5 ) {
4515 RegCloseKey(hkeyDriver);
4516 FIXME("level 5: incomplete\n");
4517 return TRUE;
4520 /* .pHelpFile */
4521 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4522 *pcbNeeded += size;
4523 if (*pcbNeeded <= cbBuf)
4524 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4526 if (di) di->pHelpFile = (LPWSTR)strPtr;
4527 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4530 /* .pDependentFiles */
4531 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4532 *pcbNeeded += size;
4533 if (*pcbNeeded <= cbBuf)
4534 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4536 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4537 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4539 else if (GetVersion() & 0x80000000) {
4540 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4541 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4542 *pcbNeeded += size;
4543 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4545 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4546 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4549 /* .pMonitorName is the optional Language Monitor */
4550 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4551 *pcbNeeded += size;
4552 if (*pcbNeeded <= cbBuf)
4553 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4555 if (di) di->pMonitorName = (LPWSTR)strPtr;
4556 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4559 /* .pDefaultDataType */
4560 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4561 *pcbNeeded += size;
4562 if(*pcbNeeded <= cbBuf)
4563 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4565 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4566 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4569 if (Level == 3 ) {
4570 RegCloseKey(hkeyDriver);
4571 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4572 return TRUE;
4575 /* .pszzPreviousNames */
4576 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4577 *pcbNeeded += size;
4578 if(*pcbNeeded <= cbBuf)
4579 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4581 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4582 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4585 if (Level == 4 ) {
4586 RegCloseKey(hkeyDriver);
4587 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4588 return TRUE;
4591 /* support is missing, but not important enough for a FIXME */
4592 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4594 /* .pszMfgName */
4595 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4596 *pcbNeeded += size;
4597 if(*pcbNeeded <= cbBuf)
4598 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4600 if (di) di->pszMfgName = (LPWSTR)strPtr;
4601 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4604 /* .pszOEMUrl */
4605 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4606 *pcbNeeded += size;
4607 if(*pcbNeeded <= cbBuf)
4608 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4610 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4611 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4614 /* .pszHardwareID */
4615 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4616 *pcbNeeded += size;
4617 if(*pcbNeeded <= cbBuf)
4618 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4620 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4621 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4624 /* .pszProvider */
4625 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4626 *pcbNeeded += size;
4627 if(*pcbNeeded <= cbBuf)
4628 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4630 if (di) di->pszProvider = (LPWSTR)strPtr;
4631 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4634 if (Level == 6 ) {
4635 RegCloseKey(hkeyDriver);
4636 return TRUE;
4639 /* support is missing, but not important enough for a FIXME */
4640 TRACE("level 8: incomplete\n");
4642 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4643 RegCloseKey(hkeyDriver);
4644 return TRUE;
4647 /*****************************************************************************
4648 * WINSPOOL_GetPrinterDriver
4650 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4651 DWORD Level, LPBYTE pDriverInfo,
4652 DWORD cbBuf, LPDWORD pcbNeeded,
4653 BOOL unicode)
4655 LPCWSTR name;
4656 WCHAR DriverName[100];
4657 DWORD ret, type, size, needed = 0;
4658 LPBYTE ptr = NULL;
4659 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4660 const printenv_t * env;
4662 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4663 Level,pDriverInfo,cbBuf, pcbNeeded);
4666 if (!(name = get_opened_printer_name(hPrinter))) {
4667 SetLastError(ERROR_INVALID_HANDLE);
4668 return FALSE;
4671 if (Level < 1 || Level == 7 || Level > 8) {
4672 SetLastError(ERROR_INVALID_LEVEL);
4673 return FALSE;
4676 env = validate_envW(pEnvironment);
4677 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4679 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4680 ERROR_SUCCESS) {
4681 ERR("Can't create Printers key\n");
4682 return FALSE;
4684 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4685 != ERROR_SUCCESS) {
4686 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4687 RegCloseKey(hkeyPrinters);
4688 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4689 return FALSE;
4691 size = sizeof(DriverName);
4692 DriverName[0] = 0;
4693 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4694 (LPBYTE)DriverName, &size);
4695 RegCloseKey(hkeyPrinter);
4696 RegCloseKey(hkeyPrinters);
4697 if(ret != ERROR_SUCCESS) {
4698 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4699 return FALSE;
4702 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4703 if(!hkeyDrivers) {
4704 ERR("Can't create Drivers key\n");
4705 return FALSE;
4708 size = di_sizeof[Level];
4709 if ((size <= cbBuf) && pDriverInfo)
4710 ptr = pDriverInfo + size;
4712 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4713 env, Level, pDriverInfo, ptr,
4714 (cbBuf < size) ? 0 : cbBuf - size,
4715 &needed, unicode)) {
4716 RegCloseKey(hkeyDrivers);
4717 return FALSE;
4720 RegCloseKey(hkeyDrivers);
4722 if(pcbNeeded) *pcbNeeded = size + needed;
4723 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4724 if(cbBuf >= needed) return TRUE;
4725 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4726 return FALSE;
4729 /*****************************************************************************
4730 * GetPrinterDriverA [WINSPOOL.@]
4732 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4733 DWORD Level, LPBYTE pDriverInfo,
4734 DWORD cbBuf, LPDWORD pcbNeeded)
4736 BOOL ret;
4737 UNICODE_STRING pEnvW;
4738 PWSTR pwstrEnvW;
4740 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4741 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4742 cbBuf, pcbNeeded, FALSE);
4743 RtlFreeUnicodeString(&pEnvW);
4744 return ret;
4746 /*****************************************************************************
4747 * GetPrinterDriverW [WINSPOOL.@]
4749 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4750 DWORD Level, LPBYTE pDriverInfo,
4751 DWORD cbBuf, LPDWORD pcbNeeded)
4753 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4754 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4757 /*****************************************************************************
4758 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4760 * Return the PATH for the Printer-Drivers (UNICODE)
4762 * PARAMS
4763 * pName [I] Servername (NT only) or NULL (local Computer)
4764 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4765 * Level [I] Structure-Level (must be 1)
4766 * pDriverDirectory [O] PTR to Buffer that receives the Result
4767 * cbBuf [I] Size of Buffer at pDriverDirectory
4768 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4769 * required for pDriverDirectory
4771 * RETURNS
4772 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4773 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4774 * if cbBuf is too small
4776 * Native Values returned in pDriverDirectory on Success:
4777 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4778 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4779 *| win9x(Windows 4.0): "%winsysdir%"
4781 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4783 * FIXME
4784 *- Only NULL or "" is supported for pName
4787 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4788 DWORD Level, LPBYTE pDriverDirectory,
4789 DWORD cbBuf, LPDWORD pcbNeeded)
4791 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4792 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4794 if ((backend == NULL) && !load_backend()) return FALSE;
4796 if (Level != 1) {
4797 /* (Level != 1) is ignored in win9x */
4798 SetLastError(ERROR_INVALID_LEVEL);
4799 return FALSE;
4801 if (pcbNeeded == NULL) {
4802 /* (pcbNeeded == NULL) is ignored in win9x */
4803 SetLastError(RPC_X_NULL_REF_POINTER);
4804 return FALSE;
4807 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4808 pDriverDirectory, cbBuf, pcbNeeded);
4813 /*****************************************************************************
4814 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4816 * Return the PATH for the Printer-Drivers (ANSI)
4818 * See GetPrinterDriverDirectoryW.
4820 * NOTES
4821 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4824 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4825 DWORD Level, LPBYTE pDriverDirectory,
4826 DWORD cbBuf, LPDWORD pcbNeeded)
4828 UNICODE_STRING nameW, environmentW;
4829 BOOL ret;
4830 DWORD pcbNeededW;
4831 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4832 WCHAR *driverDirectoryW = NULL;
4834 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4835 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4837 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4839 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4840 else nameW.Buffer = NULL;
4841 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4842 else environmentW.Buffer = NULL;
4844 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4845 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4846 if (ret) {
4847 DWORD needed;
4848 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4849 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4850 if(pcbNeeded)
4851 *pcbNeeded = needed;
4852 ret = (needed <= cbBuf) ? TRUE : FALSE;
4853 } else
4854 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4856 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4858 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4859 RtlFreeUnicodeString(&environmentW);
4860 RtlFreeUnicodeString(&nameW);
4862 return ret;
4865 /*****************************************************************************
4866 * AddPrinterDriverA [WINSPOOL.@]
4868 * See AddPrinterDriverW.
4871 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4873 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4874 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4877 /******************************************************************************
4878 * AddPrinterDriverW (WINSPOOL.@)
4880 * Install a Printer Driver
4882 * PARAMS
4883 * pName [I] Servername or NULL (local Computer)
4884 * level [I] Level for the supplied DRIVER_INFO_*W struct
4885 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4887 * RESULTS
4888 * Success: TRUE
4889 * Failure: FALSE
4892 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4894 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4895 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4898 /*****************************************************************************
4899 * AddPrintProcessorA [WINSPOOL.@]
4901 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4902 LPSTR pPrintProcessorName)
4904 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4905 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4906 return FALSE;
4909 /*****************************************************************************
4910 * AddPrintProcessorW [WINSPOOL.@]
4912 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4913 LPWSTR pPrintProcessorName)
4915 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4916 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4917 return FALSE;
4920 /*****************************************************************************
4921 * AddPrintProvidorA [WINSPOOL.@]
4923 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4925 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4926 return FALSE;
4929 /*****************************************************************************
4930 * AddPrintProvidorW [WINSPOOL.@]
4932 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4934 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4935 return FALSE;
4938 /*****************************************************************************
4939 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4941 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4942 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4944 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4945 pDevModeOutput, pDevModeInput);
4946 return 0;
4949 /*****************************************************************************
4950 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4952 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4953 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4955 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4956 pDevModeOutput, pDevModeInput);
4957 return 0;
4960 /*****************************************************************************
4961 * PrinterProperties [WINSPOOL.@]
4963 * Displays a dialog to set the properties of the printer.
4965 * RETURNS
4966 * nonzero on success or zero on failure
4968 * BUGS
4969 * implemented as stub only
4971 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4972 HANDLE hPrinter /* [in] handle to printer object */
4974 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4975 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4976 return FALSE;
4979 /*****************************************************************************
4980 * EnumJobsA [WINSPOOL.@]
4983 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4984 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4985 LPDWORD pcReturned)
4987 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4988 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4990 if(pcbNeeded) *pcbNeeded = 0;
4991 if(pcReturned) *pcReturned = 0;
4992 return FALSE;
4996 /*****************************************************************************
4997 * EnumJobsW [WINSPOOL.@]
5000 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5001 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5002 LPDWORD pcReturned)
5004 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5005 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5007 if(pcbNeeded) *pcbNeeded = 0;
5008 if(pcReturned) *pcReturned = 0;
5009 return FALSE;
5012 /*****************************************************************************
5013 * WINSPOOL_EnumPrinterDrivers [internal]
5015 * Delivers information about all printer drivers installed on the
5016 * localhost or a given server
5018 * RETURNS
5019 * nonzero on success or zero on failure. If the buffer for the returned
5020 * information is too small the function will return an error
5022 * BUGS
5023 * - only implemented for localhost, foreign hosts will return an error
5025 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5026 DWORD Level, LPBYTE pDriverInfo,
5027 DWORD cbBuf, LPDWORD pcbNeeded,
5028 LPDWORD pcReturned, BOOL unicode)
5030 { HKEY hkeyDrivers;
5031 DWORD i, needed, number = 0, size = 0;
5032 WCHAR DriverNameW[255];
5033 PBYTE ptr;
5034 const printenv_t * env;
5036 TRACE("%s,%s,%d,%p,%d,%d\n",
5037 debugstr_w(pName), debugstr_w(pEnvironment),
5038 Level, pDriverInfo, cbBuf, unicode);
5040 /* check for local drivers */
5041 if((pName) && (pName[0])) {
5042 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5043 SetLastError(ERROR_ACCESS_DENIED);
5044 return FALSE;
5047 env = validate_envW(pEnvironment);
5048 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5050 /* check input parameter */
5051 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5052 SetLastError(ERROR_INVALID_LEVEL);
5053 return FALSE;
5056 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5057 SetLastError(RPC_X_NULL_REF_POINTER);
5058 return FALSE;
5061 /* initialize return values */
5062 if(pDriverInfo)
5063 memset( pDriverInfo, 0, cbBuf);
5064 *pcbNeeded = 0;
5065 *pcReturned = 0;
5067 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5068 if(!hkeyDrivers) {
5069 ERR("Can't open Drivers key\n");
5070 return FALSE;
5073 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5074 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5075 RegCloseKey(hkeyDrivers);
5076 ERR("Can't query Drivers key\n");
5077 return FALSE;
5079 TRACE("Found %d Drivers\n", number);
5081 /* get size of single struct
5082 * unicode and ascii structure have the same size
5084 size = di_sizeof[Level];
5086 /* calculate required buffer size */
5087 *pcbNeeded = size * number;
5089 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5090 i < number;
5091 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5092 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5093 != ERROR_SUCCESS) {
5094 ERR("Can't enum key number %d\n", i);
5095 RegCloseKey(hkeyDrivers);
5096 return FALSE;
5098 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5099 env, Level, ptr,
5100 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5101 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5102 &needed, unicode)) {
5103 RegCloseKey(hkeyDrivers);
5104 return FALSE;
5106 *pcbNeeded += needed;
5109 RegCloseKey(hkeyDrivers);
5111 if(cbBuf < *pcbNeeded){
5112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5113 return FALSE;
5116 *pcReturned = number;
5117 return TRUE;
5120 /*****************************************************************************
5121 * EnumPrinterDriversW [WINSPOOL.@]
5123 * see function EnumPrinterDrivers for RETURNS, BUGS
5125 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5126 LPBYTE pDriverInfo, DWORD cbBuf,
5127 LPDWORD pcbNeeded, LPDWORD pcReturned)
5129 static const WCHAR allW[] = {'a','l','l',0};
5131 if (pEnvironment && !strcmpW(pEnvironment, allW))
5133 BOOL ret;
5134 DWORD i, needed, returned, bufsize = cbBuf;
5136 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5138 needed = returned = 0;
5139 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5140 pDriverInfo, bufsize, &needed, &returned, TRUE);
5141 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5142 else if (ret)
5144 bufsize -= needed;
5145 if (pDriverInfo) pDriverInfo += needed;
5146 if (pcReturned) *pcReturned += returned;
5148 if (pcbNeeded) *pcbNeeded += needed;
5150 return ret;
5152 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5153 cbBuf, pcbNeeded, pcReturned, TRUE);
5156 /*****************************************************************************
5157 * EnumPrinterDriversA [WINSPOOL.@]
5159 * see function EnumPrinterDrivers for RETURNS, BUGS
5161 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5162 LPBYTE pDriverInfo, DWORD cbBuf,
5163 LPDWORD pcbNeeded, LPDWORD pcReturned)
5165 BOOL ret;
5166 UNICODE_STRING pNameW, pEnvironmentW;
5167 PWSTR pwstrNameW, pwstrEnvironmentW;
5169 pwstrNameW = asciitounicode(&pNameW, pName);
5170 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5172 if (pEnvironment && !strcmp(pEnvironment, "all"))
5174 DWORD i, needed, returned, bufsize = cbBuf;
5176 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5178 needed = returned = 0;
5179 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
5180 pDriverInfo, bufsize, &needed, &returned, FALSE);
5181 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
5182 else if (ret)
5184 bufsize -= needed;
5185 if (pDriverInfo) pDriverInfo += needed;
5186 if (pcReturned) *pcReturned += returned;
5188 if (pcbNeeded) *pcbNeeded += needed;
5191 else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5192 Level, pDriverInfo, cbBuf, pcbNeeded,
5193 pcReturned, FALSE);
5194 RtlFreeUnicodeString(&pNameW);
5195 RtlFreeUnicodeString(&pEnvironmentW);
5197 return ret;
5200 /******************************************************************************
5201 * EnumPortsA (WINSPOOL.@)
5203 * See EnumPortsW.
5206 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5207 LPDWORD pcbNeeded, LPDWORD pcReturned)
5209 BOOL res;
5210 LPBYTE bufferW = NULL;
5211 LPWSTR nameW = NULL;
5212 DWORD needed = 0;
5213 DWORD numentries = 0;
5214 INT len;
5216 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5217 cbBuf, pcbNeeded, pcReturned);
5219 /* convert servername to unicode */
5220 if (pName) {
5221 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5222 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5223 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5225 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5226 needed = cbBuf * sizeof(WCHAR);
5227 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5228 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5230 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5231 if (pcbNeeded) needed = *pcbNeeded;
5232 /* HeapReAlloc return NULL, when bufferW was NULL */
5233 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5234 HeapAlloc(GetProcessHeap(), 0, needed);
5236 /* Try again with the large Buffer */
5237 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5239 needed = pcbNeeded ? *pcbNeeded : 0;
5240 numentries = pcReturned ? *pcReturned : 0;
5243 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5244 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5246 if (res) {
5247 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5248 DWORD entrysize = 0;
5249 DWORD index;
5250 LPSTR ptr;
5251 LPPORT_INFO_2W pi2w;
5252 LPPORT_INFO_2A pi2a;
5254 needed = 0;
5255 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5257 /* First pass: calculate the size for all Entries */
5258 pi2w = (LPPORT_INFO_2W) bufferW;
5259 pi2a = (LPPORT_INFO_2A) pPorts;
5260 index = 0;
5261 while (index < numentries) {
5262 index++;
5263 needed += entrysize; /* PORT_INFO_?A */
5264 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5266 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5267 NULL, 0, NULL, NULL);
5268 if (Level > 1) {
5269 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5270 NULL, 0, NULL, NULL);
5271 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5272 NULL, 0, NULL, NULL);
5274 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5275 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5276 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5279 /* check for errors and quit on failure */
5280 if (cbBuf < needed) {
5281 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5282 res = FALSE;
5283 goto cleanup;
5285 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5286 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5287 cbBuf -= len ; /* free Bytes in the user-Buffer */
5288 pi2w = (LPPORT_INFO_2W) bufferW;
5289 pi2a = (LPPORT_INFO_2A) pPorts;
5290 index = 0;
5291 /* Second Pass: Fill the User Buffer (if we have one) */
5292 while ((index < numentries) && pPorts) {
5293 index++;
5294 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5295 pi2a->pPortName = ptr;
5296 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5297 ptr, cbBuf , NULL, NULL);
5298 ptr += len;
5299 cbBuf -= len;
5300 if (Level > 1) {
5301 pi2a->pMonitorName = ptr;
5302 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5303 ptr, cbBuf, NULL, NULL);
5304 ptr += len;
5305 cbBuf -= len;
5307 pi2a->pDescription = ptr;
5308 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5309 ptr, cbBuf, NULL, NULL);
5310 ptr += len;
5311 cbBuf -= len;
5313 pi2a->fPortType = pi2w->fPortType;
5314 pi2a->Reserved = 0; /* documented: "must be zero" */
5317 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5318 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5319 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5323 cleanup:
5324 if (pcbNeeded) *pcbNeeded = needed;
5325 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5327 HeapFree(GetProcessHeap(), 0, nameW);
5328 HeapFree(GetProcessHeap(), 0, bufferW);
5330 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5331 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5333 return (res);
5337 /******************************************************************************
5338 * EnumPortsW (WINSPOOL.@)
5340 * Enumerate available Ports
5342 * PARAMS
5343 * pName [I] Servername or NULL (local Computer)
5344 * Level [I] Structure-Level (1 or 2)
5345 * pPorts [O] PTR to Buffer that receives the Result
5346 * cbBuf [I] Size of Buffer at pPorts
5347 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5348 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5350 * RETURNS
5351 * Success: TRUE
5352 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5355 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5358 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5359 cbBuf, pcbNeeded, pcReturned);
5361 if ((backend == NULL) && !load_backend()) return FALSE;
5363 /* Level is not checked in win9x */
5364 if (!Level || (Level > 2)) {
5365 WARN("level (%d) is ignored in win9x\n", Level);
5366 SetLastError(ERROR_INVALID_LEVEL);
5367 return FALSE;
5369 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5370 SetLastError(RPC_X_NULL_REF_POINTER);
5371 return FALSE;
5374 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5377 /******************************************************************************
5378 * GetDefaultPrinterW (WINSPOOL.@)
5380 * FIXME
5381 * This function must read the value from data 'device' of key
5382 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5384 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5386 BOOL retval = TRUE;
5387 DWORD insize, len;
5388 WCHAR *buffer, *ptr;
5390 if (!namesize)
5392 SetLastError(ERROR_INVALID_PARAMETER);
5393 return FALSE;
5396 /* make the buffer big enough for the stuff from the profile/registry,
5397 * the content must fit into the local buffer to compute the correct
5398 * size even if the extern buffer is too small or not given.
5399 * (20 for ,driver,port) */
5400 insize = *namesize;
5401 len = max(100, (insize + 20));
5402 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5404 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5406 SetLastError (ERROR_FILE_NOT_FOUND);
5407 retval = FALSE;
5408 goto end;
5410 TRACE("%s\n", debugstr_w(buffer));
5412 if ((ptr = strchrW(buffer, ',')) == NULL)
5414 SetLastError(ERROR_INVALID_NAME);
5415 retval = FALSE;
5416 goto end;
5419 *ptr = 0;
5420 *namesize = strlenW(buffer) + 1;
5421 if(!name || (*namesize > insize))
5423 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5424 retval = FALSE;
5425 goto end;
5427 strcpyW(name, buffer);
5429 end:
5430 HeapFree( GetProcessHeap(), 0, buffer);
5431 return retval;
5435 /******************************************************************************
5436 * GetDefaultPrinterA (WINSPOOL.@)
5438 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5440 BOOL retval = TRUE;
5441 DWORD insize = 0;
5442 WCHAR *bufferW = NULL;
5444 if (!namesize)
5446 SetLastError(ERROR_INVALID_PARAMETER);
5447 return FALSE;
5450 if(name && *namesize) {
5451 insize = *namesize;
5452 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5455 if(!GetDefaultPrinterW( bufferW, namesize)) {
5456 retval = FALSE;
5457 goto end;
5460 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5461 NULL, NULL);
5462 if (!*namesize)
5464 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5465 retval = FALSE;
5467 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5469 end:
5470 HeapFree( GetProcessHeap(), 0, bufferW);
5471 return retval;
5475 /******************************************************************************
5476 * SetDefaultPrinterW (WINSPOOL.204)
5478 * Set the Name of the Default Printer
5480 * PARAMS
5481 * pszPrinter [I] Name of the Printer or NULL
5483 * RETURNS
5484 * Success: True
5485 * Failure: FALSE
5487 * NOTES
5488 * When the Parameter is NULL or points to an Empty String and
5489 * a Default Printer was already present, then this Function changes nothing.
5490 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5491 * the First enumerated local Printer is used.
5494 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5497 TRACE("(%s)\n", debugstr_w(pszPrinter));
5499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5500 return FALSE;
5503 /******************************************************************************
5504 * SetDefaultPrinterA (WINSPOOL.202)
5506 * See SetDefaultPrinterW.
5509 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5512 TRACE("(%s)\n", debugstr_a(pszPrinter));
5514 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5515 return FALSE;
5519 /******************************************************************************
5520 * SetPrinterDataExA (WINSPOOL.@)
5522 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5523 LPCSTR pValueName, DWORD Type,
5524 LPBYTE pData, DWORD cbData)
5526 HKEY hkeyPrinter, hkeySubkey;
5527 DWORD ret;
5529 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5530 debugstr_a(pValueName), Type, pData, cbData);
5532 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5533 != ERROR_SUCCESS)
5534 return ret;
5536 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5537 != ERROR_SUCCESS) {
5538 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5539 RegCloseKey(hkeyPrinter);
5540 return ret;
5542 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5543 RegCloseKey(hkeySubkey);
5544 RegCloseKey(hkeyPrinter);
5545 return ret;
5548 /******************************************************************************
5549 * SetPrinterDataExW (WINSPOOL.@)
5551 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5552 LPCWSTR pValueName, DWORD Type,
5553 LPBYTE pData, DWORD cbData)
5555 HKEY hkeyPrinter, hkeySubkey;
5556 DWORD ret;
5558 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5559 debugstr_w(pValueName), Type, pData, cbData);
5561 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5562 != ERROR_SUCCESS)
5563 return ret;
5565 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5566 != ERROR_SUCCESS) {
5567 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5568 RegCloseKey(hkeyPrinter);
5569 return ret;
5571 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5572 RegCloseKey(hkeySubkey);
5573 RegCloseKey(hkeyPrinter);
5574 return ret;
5577 /******************************************************************************
5578 * SetPrinterDataA (WINSPOOL.@)
5580 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5581 LPBYTE pData, DWORD cbData)
5583 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5584 pData, cbData);
5587 /******************************************************************************
5588 * SetPrinterDataW (WINSPOOL.@)
5590 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5591 LPBYTE pData, DWORD cbData)
5593 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5594 pData, cbData);
5597 /******************************************************************************
5598 * GetPrinterDataExA (WINSPOOL.@)
5600 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5601 LPCSTR pValueName, LPDWORD pType,
5602 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5604 HKEY hkeyPrinter, hkeySubkey;
5605 DWORD ret;
5607 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5608 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5609 pcbNeeded);
5611 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5612 != ERROR_SUCCESS)
5613 return ret;
5615 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5616 != ERROR_SUCCESS) {
5617 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5618 RegCloseKey(hkeyPrinter);
5619 return ret;
5621 *pcbNeeded = nSize;
5622 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5623 RegCloseKey(hkeySubkey);
5624 RegCloseKey(hkeyPrinter);
5625 return ret;
5628 /******************************************************************************
5629 * GetPrinterDataExW (WINSPOOL.@)
5631 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5632 LPCWSTR pValueName, LPDWORD pType,
5633 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5635 HKEY hkeyPrinter, hkeySubkey;
5636 DWORD ret;
5638 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5639 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5640 pcbNeeded);
5642 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5643 != ERROR_SUCCESS)
5644 return ret;
5646 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5647 != ERROR_SUCCESS) {
5648 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5649 RegCloseKey(hkeyPrinter);
5650 return ret;
5652 *pcbNeeded = nSize;
5653 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5654 RegCloseKey(hkeySubkey);
5655 RegCloseKey(hkeyPrinter);
5656 return ret;
5659 /******************************************************************************
5660 * GetPrinterDataA (WINSPOOL.@)
5662 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5663 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5665 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5666 pData, nSize, pcbNeeded);
5669 /******************************************************************************
5670 * GetPrinterDataW (WINSPOOL.@)
5672 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5673 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5675 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5676 pData, nSize, pcbNeeded);
5679 /*******************************************************************************
5680 * EnumPrinterDataExW [WINSPOOL.@]
5682 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5683 LPBYTE pEnumValues, DWORD cbEnumValues,
5684 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5686 HKEY hkPrinter, hkSubKey;
5687 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5688 cbValueNameLen, cbMaxValueLen, cbValueLen,
5689 cbBufSize, dwType;
5690 LPWSTR lpValueName;
5691 HANDLE hHeap;
5692 PBYTE lpValue;
5693 PPRINTER_ENUM_VALUESW ppev;
5695 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5697 if (pKeyName == NULL || *pKeyName == 0)
5698 return ERROR_INVALID_PARAMETER;
5700 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5701 if (ret != ERROR_SUCCESS)
5703 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5704 hPrinter, ret);
5705 return ret;
5708 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5709 if (ret != ERROR_SUCCESS)
5711 r = RegCloseKey (hkPrinter);
5712 if (r != ERROR_SUCCESS)
5713 WARN ("RegCloseKey returned %i\n", r);
5714 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5715 debugstr_w (pKeyName), ret);
5716 return ret;
5719 ret = RegCloseKey (hkPrinter);
5720 if (ret != ERROR_SUCCESS)
5722 ERR ("RegCloseKey returned %i\n", ret);
5723 r = RegCloseKey (hkSubKey);
5724 if (r != ERROR_SUCCESS)
5725 WARN ("RegCloseKey returned %i\n", r);
5726 return ret;
5729 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5730 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5731 if (ret != ERROR_SUCCESS)
5733 r = RegCloseKey (hkSubKey);
5734 if (r != ERROR_SUCCESS)
5735 WARN ("RegCloseKey returned %i\n", r);
5736 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5737 return ret;
5740 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5741 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5743 if (cValues == 0) /* empty key */
5745 r = RegCloseKey (hkSubKey);
5746 if (r != ERROR_SUCCESS)
5747 WARN ("RegCloseKey returned %i\n", r);
5748 *pcbEnumValues = *pnEnumValues = 0;
5749 return ERROR_SUCCESS;
5752 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5754 hHeap = GetProcessHeap ();
5755 if (hHeap == NULL)
5757 ERR ("GetProcessHeap failed\n");
5758 r = RegCloseKey (hkSubKey);
5759 if (r != ERROR_SUCCESS)
5760 WARN ("RegCloseKey returned %i\n", r);
5761 return ERROR_OUTOFMEMORY;
5764 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5765 if (lpValueName == NULL)
5767 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5768 r = RegCloseKey (hkSubKey);
5769 if (r != ERROR_SUCCESS)
5770 WARN ("RegCloseKey returned %i\n", r);
5771 return ERROR_OUTOFMEMORY;
5774 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5775 if (lpValue == NULL)
5777 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5778 if (HeapFree (hHeap, 0, lpValueName) == 0)
5779 WARN ("HeapFree failed with code %i\n", GetLastError ());
5780 r = RegCloseKey (hkSubKey);
5781 if (r != ERROR_SUCCESS)
5782 WARN ("RegCloseKey returned %i\n", r);
5783 return ERROR_OUTOFMEMORY;
5786 TRACE ("pass 1: calculating buffer required for all names and values\n");
5788 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5790 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5792 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5794 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5795 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5796 NULL, NULL, lpValue, &cbValueLen);
5797 if (ret != ERROR_SUCCESS)
5799 if (HeapFree (hHeap, 0, lpValue) == 0)
5800 WARN ("HeapFree failed with code %i\n", GetLastError ());
5801 if (HeapFree (hHeap, 0, lpValueName) == 0)
5802 WARN ("HeapFree failed with code %i\n", GetLastError ());
5803 r = RegCloseKey (hkSubKey);
5804 if (r != ERROR_SUCCESS)
5805 WARN ("RegCloseKey returned %i\n", r);
5806 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5807 return ret;
5810 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5811 debugstr_w (lpValueName), dwIndex,
5812 cbValueNameLen + 1, cbValueLen);
5814 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5815 cbBufSize += cbValueLen;
5818 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5820 *pcbEnumValues = cbBufSize;
5821 *pnEnumValues = cValues;
5823 if (cbEnumValues < cbBufSize) /* buffer too small */
5825 if (HeapFree (hHeap, 0, lpValue) == 0)
5826 WARN ("HeapFree failed with code %i\n", GetLastError ());
5827 if (HeapFree (hHeap, 0, lpValueName) == 0)
5828 WARN ("HeapFree failed with code %i\n", GetLastError ());
5829 r = RegCloseKey (hkSubKey);
5830 if (r != ERROR_SUCCESS)
5831 WARN ("RegCloseKey returned %i\n", r);
5832 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5833 return ERROR_MORE_DATA;
5836 TRACE ("pass 2: copying all names and values to buffer\n");
5838 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5839 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5841 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5843 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5844 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5845 NULL, &dwType, lpValue, &cbValueLen);
5846 if (ret != ERROR_SUCCESS)
5848 if (HeapFree (hHeap, 0, lpValue) == 0)
5849 WARN ("HeapFree failed with code %i\n", GetLastError ());
5850 if (HeapFree (hHeap, 0, lpValueName) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5852 r = RegCloseKey (hkSubKey);
5853 if (r != ERROR_SUCCESS)
5854 WARN ("RegCloseKey returned %i\n", r);
5855 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5856 return ret;
5859 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5860 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5861 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5862 pEnumValues += cbValueNameLen;
5864 /* return # of *bytes* (including trailing \0), not # of chars */
5865 ppev[dwIndex].cbValueName = cbValueNameLen;
5867 ppev[dwIndex].dwType = dwType;
5869 memcpy (pEnumValues, lpValue, cbValueLen);
5870 ppev[dwIndex].pData = pEnumValues;
5871 pEnumValues += cbValueLen;
5873 ppev[dwIndex].cbData = cbValueLen;
5875 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5876 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5879 if (HeapFree (hHeap, 0, lpValue) == 0)
5881 ret = GetLastError ();
5882 ERR ("HeapFree failed with code %i\n", ret);
5883 if (HeapFree (hHeap, 0, lpValueName) == 0)
5884 WARN ("HeapFree failed with code %i\n", GetLastError ());
5885 r = RegCloseKey (hkSubKey);
5886 if (r != ERROR_SUCCESS)
5887 WARN ("RegCloseKey returned %i\n", r);
5888 return ret;
5891 if (HeapFree (hHeap, 0, lpValueName) == 0)
5893 ret = GetLastError ();
5894 ERR ("HeapFree failed with code %i\n", ret);
5895 r = RegCloseKey (hkSubKey);
5896 if (r != ERROR_SUCCESS)
5897 WARN ("RegCloseKey returned %i\n", r);
5898 return ret;
5901 ret = RegCloseKey (hkSubKey);
5902 if (ret != ERROR_SUCCESS)
5904 ERR ("RegCloseKey returned %i\n", ret);
5905 return ret;
5908 return ERROR_SUCCESS;
5911 /*******************************************************************************
5912 * EnumPrinterDataExA [WINSPOOL.@]
5914 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5915 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5916 * what Windows 2000 SP1 does.
5919 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5920 LPBYTE pEnumValues, DWORD cbEnumValues,
5921 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5923 INT len;
5924 LPWSTR pKeyNameW;
5925 DWORD ret, dwIndex, dwBufSize;
5926 HANDLE hHeap;
5927 LPSTR pBuffer;
5929 TRACE ("%p %s\n", hPrinter, pKeyName);
5931 if (pKeyName == NULL || *pKeyName == 0)
5932 return ERROR_INVALID_PARAMETER;
5934 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5935 if (len == 0)
5937 ret = GetLastError ();
5938 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5939 return ret;
5942 hHeap = GetProcessHeap ();
5943 if (hHeap == NULL)
5945 ERR ("GetProcessHeap failed\n");
5946 return ERROR_OUTOFMEMORY;
5949 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5950 if (pKeyNameW == NULL)
5952 ERR ("Failed to allocate %i bytes from process heap\n",
5953 (LONG)(len * sizeof (WCHAR)));
5954 return ERROR_OUTOFMEMORY;
5957 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5959 ret = GetLastError ();
5960 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5961 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5962 WARN ("HeapFree failed with code %i\n", GetLastError ());
5963 return ret;
5966 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5967 pcbEnumValues, pnEnumValues);
5968 if (ret != ERROR_SUCCESS)
5970 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5971 WARN ("HeapFree failed with code %i\n", GetLastError ());
5972 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5973 return ret;
5976 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5978 ret = GetLastError ();
5979 ERR ("HeapFree failed with code %i\n", ret);
5980 return ret;
5983 if (*pnEnumValues == 0) /* empty key */
5984 return ERROR_SUCCESS;
5986 dwBufSize = 0;
5987 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5989 PPRINTER_ENUM_VALUESW ppev =
5990 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5992 if (dwBufSize < ppev->cbValueName)
5993 dwBufSize = ppev->cbValueName;
5995 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5996 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5997 dwBufSize = ppev->cbData;
6000 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6002 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6003 if (pBuffer == NULL)
6005 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6006 return ERROR_OUTOFMEMORY;
6009 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6011 PPRINTER_ENUM_VALUESW ppev =
6012 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6014 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6015 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6016 NULL);
6017 if (len == 0)
6019 ret = GetLastError ();
6020 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6021 if (HeapFree (hHeap, 0, pBuffer) == 0)
6022 WARN ("HeapFree failed with code %i\n", GetLastError ());
6023 return ret;
6026 memcpy (ppev->pValueName, pBuffer, len);
6028 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6030 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6031 ppev->dwType != REG_MULTI_SZ)
6032 continue;
6034 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6035 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6036 if (len == 0)
6038 ret = GetLastError ();
6039 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6040 if (HeapFree (hHeap, 0, pBuffer) == 0)
6041 WARN ("HeapFree failed with code %i\n", GetLastError ());
6042 return ret;
6045 memcpy (ppev->pData, pBuffer, len);
6047 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6048 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6051 if (HeapFree (hHeap, 0, pBuffer) == 0)
6053 ret = GetLastError ();
6054 ERR ("HeapFree failed with code %i\n", ret);
6055 return ret;
6058 return ERROR_SUCCESS;
6061 /******************************************************************************
6062 * AbortPrinter (WINSPOOL.@)
6064 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6066 FIXME("(%p), stub!\n", hPrinter);
6067 return TRUE;
6070 /******************************************************************************
6071 * AddPortA (WINSPOOL.@)
6073 * See AddPortW.
6076 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6078 LPWSTR nameW = NULL;
6079 LPWSTR monitorW = NULL;
6080 DWORD len;
6081 BOOL res;
6083 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6085 if (pName) {
6086 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6087 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6088 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6091 if (pMonitorName) {
6092 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6093 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6094 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6096 res = AddPortW(nameW, hWnd, monitorW);
6097 HeapFree(GetProcessHeap(), 0, nameW);
6098 HeapFree(GetProcessHeap(), 0, monitorW);
6099 return res;
6102 /******************************************************************************
6103 * AddPortW (WINSPOOL.@)
6105 * Add a Port for a specific Monitor
6107 * PARAMS
6108 * pName [I] Servername or NULL (local Computer)
6109 * hWnd [I] Handle to parent Window for the Dialog-Box
6110 * pMonitorName [I] Name of the Monitor that manage the Port
6112 * RETURNS
6113 * Success: TRUE
6114 * Failure: FALSE
6117 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6119 monitor_t * pm;
6120 monitor_t * pui;
6121 DWORD res;
6123 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6125 if (pName && pName[0]) {
6126 SetLastError(ERROR_INVALID_PARAMETER);
6127 return FALSE;
6130 if (!pMonitorName) {
6131 SetLastError(RPC_X_NULL_REF_POINTER);
6132 return FALSE;
6135 /* an empty Monitorname is Invalid */
6136 if (!pMonitorName[0]) {
6137 SetLastError(ERROR_NOT_SUPPORTED);
6138 return FALSE;
6141 pm = monitor_load(pMonitorName, NULL);
6142 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6143 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6144 TRACE("got %d with %u\n", res, GetLastError());
6145 res = TRUE;
6147 else
6149 pui = monitor_loadui(pm);
6150 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6151 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6152 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6153 TRACE("got %d with %u\n", res, GetLastError());
6154 res = TRUE;
6156 else
6158 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6159 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6161 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6162 SetLastError(ERROR_NOT_SUPPORTED);
6163 res = FALSE;
6165 monitor_unload(pui);
6167 monitor_unload(pm);
6168 TRACE("returning %d with %u\n", res, GetLastError());
6169 return res;
6172 /******************************************************************************
6173 * AddPortExA (WINSPOOL.@)
6175 * See AddPortExW.
6178 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6180 PORT_INFO_2W pi2W;
6181 PORT_INFO_2A * pi2A;
6182 LPWSTR nameW = NULL;
6183 LPWSTR monitorW = NULL;
6184 DWORD len;
6185 BOOL res;
6187 pi2A = (PORT_INFO_2A *) pBuffer;
6189 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6190 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6192 if ((level < 1) || (level > 2)) {
6193 SetLastError(ERROR_INVALID_LEVEL);
6194 return FALSE;
6197 if (!pi2A) {
6198 SetLastError(ERROR_INVALID_PARAMETER);
6199 return FALSE;
6202 if (pName) {
6203 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6204 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6205 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6208 if (pMonitorName) {
6209 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6210 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6211 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6214 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6216 if (pi2A->pPortName) {
6217 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6218 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6219 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6222 if (level > 1) {
6223 if (pi2A->pMonitorName) {
6224 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6225 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6226 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6229 if (pi2A->pDescription) {
6230 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6231 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6232 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6234 pi2W.fPortType = pi2A->fPortType;
6235 pi2W.Reserved = pi2A->Reserved;
6238 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6240 HeapFree(GetProcessHeap(), 0, nameW);
6241 HeapFree(GetProcessHeap(), 0, monitorW);
6242 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6243 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6244 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6245 return res;
6249 /******************************************************************************
6250 * AddPortExW (WINSPOOL.@)
6252 * Add a Port for a specific Monitor, without presenting a user interface
6254 * PARAMS
6255 * pName [I] Servername or NULL (local Computer)
6256 * level [I] Structure-Level (1 or 2) for pBuffer
6257 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6258 * pMonitorName [I] Name of the Monitor that manage the Port
6260 * RETURNS
6261 * Success: TRUE
6262 * Failure: FALSE
6265 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6267 PORT_INFO_2W * pi2;
6268 monitor_t * pm;
6269 DWORD res = FALSE;
6271 pi2 = (PORT_INFO_2W *) pBuffer;
6273 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6274 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6275 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6276 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6279 if ((level < 1) || (level > 2)) {
6280 SetLastError(ERROR_INVALID_LEVEL);
6281 return FALSE;
6284 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6285 SetLastError(ERROR_INVALID_PARAMETER);
6286 return FALSE;
6289 /* load the Monitor */
6290 pm = monitor_load(pMonitorName, NULL);
6291 if (!pm) {
6292 SetLastError(ERROR_INVALID_PARAMETER);
6293 return FALSE;
6296 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6297 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6298 TRACE("got %u with %u\n", res, GetLastError());
6300 else
6302 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6304 monitor_unload(pm);
6305 return res;
6308 /******************************************************************************
6309 * AddPrinterConnectionA (WINSPOOL.@)
6311 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6313 FIXME("%s\n", debugstr_a(pName));
6314 return FALSE;
6317 /******************************************************************************
6318 * AddPrinterConnectionW (WINSPOOL.@)
6320 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6322 FIXME("%s\n", debugstr_w(pName));
6323 return FALSE;
6326 /******************************************************************************
6327 * AddPrinterDriverExW (WINSPOOL.@)
6329 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6331 * PARAMS
6332 * pName [I] Servername or NULL (local Computer)
6333 * level [I] Level for the supplied DRIVER_INFO_*W struct
6334 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6335 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6337 * RESULTS
6338 * Success: TRUE
6339 * Failure: FALSE
6342 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6344 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6346 if ((backend == NULL) && !load_backend()) return FALSE;
6348 if (level < 2 || level == 5 || level == 7 || level > 8) {
6349 SetLastError(ERROR_INVALID_LEVEL);
6350 return FALSE;
6353 if (!pDriverInfo) {
6354 SetLastError(ERROR_INVALID_PARAMETER);
6355 return FALSE;
6358 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6361 /******************************************************************************
6362 * AddPrinterDriverExA (WINSPOOL.@)
6364 * See AddPrinterDriverExW.
6367 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6369 DRIVER_INFO_8A *diA;
6370 DRIVER_INFO_8W diW;
6371 LPWSTR nameW = NULL;
6372 DWORD lenA;
6373 DWORD len;
6374 DWORD res = FALSE;
6376 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6378 diA = (DRIVER_INFO_8A *) pDriverInfo;
6379 ZeroMemory(&diW, sizeof(diW));
6381 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6382 SetLastError(ERROR_INVALID_LEVEL);
6383 return FALSE;
6386 if (diA == NULL) {
6387 SetLastError(ERROR_INVALID_PARAMETER);
6388 return FALSE;
6391 /* convert servername to unicode */
6392 if (pName) {
6393 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6394 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6395 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6398 /* common fields */
6399 diW.cVersion = diA->cVersion;
6401 if (diA->pName) {
6402 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6403 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6404 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6407 if (diA->pEnvironment) {
6408 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6409 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6410 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6413 if (diA->pDriverPath) {
6414 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6415 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6416 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6419 if (diA->pDataFile) {
6420 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6421 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6422 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6425 if (diA->pConfigFile) {
6426 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6427 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6428 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6431 if ((Level > 2) && diA->pDependentFiles) {
6432 lenA = multi_sz_lenA(diA->pDependentFiles);
6433 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6434 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6435 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6438 if ((Level > 2) && diA->pMonitorName) {
6439 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6440 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6441 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6444 if ((Level > 3) && diA->pDefaultDataType) {
6445 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6446 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6447 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6450 if ((Level > 3) && diA->pszzPreviousNames) {
6451 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6452 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6453 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6454 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6457 if ((Level > 5) && diA->pszMfgName) {
6458 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6459 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6460 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6463 if ((Level > 5) && diA->pszOEMUrl) {
6464 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6465 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6466 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6469 if ((Level > 5) && diA->pszHardwareID) {
6470 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6471 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6472 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6475 if ((Level > 5) && diA->pszProvider) {
6476 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6477 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6478 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6481 if (Level > 7) {
6482 FIXME("level %u is incomplete\n", Level);
6485 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6486 TRACE("got %u with %u\n", res, GetLastError());
6487 HeapFree(GetProcessHeap(), 0, nameW);
6488 HeapFree(GetProcessHeap(), 0, diW.pName);
6489 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6490 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6491 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6492 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6493 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6494 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6495 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6496 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6497 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6498 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6499 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6500 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6502 TRACE("=> %u with %u\n", res, GetLastError());
6503 return res;
6506 /******************************************************************************
6507 * ConfigurePortA (WINSPOOL.@)
6509 * See ConfigurePortW.
6512 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6514 LPWSTR nameW = NULL;
6515 LPWSTR portW = NULL;
6516 INT len;
6517 DWORD res;
6519 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6521 /* convert servername to unicode */
6522 if (pName) {
6523 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6524 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6525 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6528 /* convert portname to unicode */
6529 if (pPortName) {
6530 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6531 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6532 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6535 res = ConfigurePortW(nameW, hWnd, portW);
6536 HeapFree(GetProcessHeap(), 0, nameW);
6537 HeapFree(GetProcessHeap(), 0, portW);
6538 return res;
6541 /******************************************************************************
6542 * ConfigurePortW (WINSPOOL.@)
6544 * Display the Configuration-Dialog for a specific Port
6546 * PARAMS
6547 * pName [I] Servername or NULL (local Computer)
6548 * hWnd [I] Handle to parent Window for the Dialog-Box
6549 * pPortName [I] Name of the Port, that should be configured
6551 * RETURNS
6552 * Success: TRUE
6553 * Failure: FALSE
6556 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6558 monitor_t * pm;
6559 monitor_t * pui;
6560 DWORD res;
6562 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6564 if (pName && pName[0]) {
6565 SetLastError(ERROR_INVALID_PARAMETER);
6566 return FALSE;
6569 if (!pPortName) {
6570 SetLastError(RPC_X_NULL_REF_POINTER);
6571 return FALSE;
6574 /* an empty Portname is Invalid, but can popup a Dialog */
6575 if (!pPortName[0]) {
6576 SetLastError(ERROR_NOT_SUPPORTED);
6577 return FALSE;
6580 pm = monitor_load_by_port(pPortName);
6581 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6582 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6583 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6584 TRACE("got %d with %u\n", res, GetLastError());
6586 else
6588 pui = monitor_loadui(pm);
6589 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6590 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6591 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6592 TRACE("got %d with %u\n", res, GetLastError());
6594 else
6596 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6597 pm, debugstr_w(pm ? pm->dllname : NULL), pui, debugstr_w(pui ? pui->dllname : NULL));
6599 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6600 SetLastError(ERROR_NOT_SUPPORTED);
6601 res = FALSE;
6603 monitor_unload(pui);
6605 monitor_unload(pm);
6607 TRACE("returning %d with %u\n", res, GetLastError());
6608 return res;
6611 /******************************************************************************
6612 * ConnectToPrinterDlg (WINSPOOL.@)
6614 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6616 FIXME("%p %x\n", hWnd, Flags);
6617 return NULL;
6620 /******************************************************************************
6621 * DeletePrinterConnectionA (WINSPOOL.@)
6623 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6625 FIXME("%s\n", debugstr_a(pName));
6626 return TRUE;
6629 /******************************************************************************
6630 * DeletePrinterConnectionW (WINSPOOL.@)
6632 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6634 FIXME("%s\n", debugstr_w(pName));
6635 return TRUE;
6638 /******************************************************************************
6639 * DeletePrinterDriverExW (WINSPOOL.@)
6641 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6642 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6644 HKEY hkey_drivers;
6645 BOOL ret = FALSE;
6647 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6648 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6650 if(pName && pName[0])
6652 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6653 SetLastError(ERROR_INVALID_PARAMETER);
6654 return FALSE;
6657 if(dwDeleteFlag)
6659 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6660 SetLastError(ERROR_INVALID_PARAMETER);
6661 return FALSE;
6664 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6666 if(!hkey_drivers)
6668 ERR("Can't open drivers key\n");
6669 return FALSE;
6672 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6673 ret = TRUE;
6675 RegCloseKey(hkey_drivers);
6677 return ret;
6680 /******************************************************************************
6681 * DeletePrinterDriverExA (WINSPOOL.@)
6683 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6684 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6686 UNICODE_STRING NameW, EnvW, DriverW;
6687 BOOL ret;
6689 asciitounicode(&NameW, pName);
6690 asciitounicode(&EnvW, pEnvironment);
6691 asciitounicode(&DriverW, pDriverName);
6693 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6695 RtlFreeUnicodeString(&DriverW);
6696 RtlFreeUnicodeString(&EnvW);
6697 RtlFreeUnicodeString(&NameW);
6699 return ret;
6702 /******************************************************************************
6703 * DeletePrinterDataExW (WINSPOOL.@)
6705 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6706 LPCWSTR pValueName)
6708 FIXME("%p %s %s\n", hPrinter,
6709 debugstr_w(pKeyName), debugstr_w(pValueName));
6710 return ERROR_INVALID_PARAMETER;
6713 /******************************************************************************
6714 * DeletePrinterDataExA (WINSPOOL.@)
6716 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6717 LPCSTR pValueName)
6719 FIXME("%p %s %s\n", hPrinter,
6720 debugstr_a(pKeyName), debugstr_a(pValueName));
6721 return ERROR_INVALID_PARAMETER;
6724 /******************************************************************************
6725 * DeletePrintProcessorA (WINSPOOL.@)
6727 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6729 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6730 debugstr_a(pPrintProcessorName));
6731 return TRUE;
6734 /******************************************************************************
6735 * DeletePrintProcessorW (WINSPOOL.@)
6737 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6739 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6740 debugstr_w(pPrintProcessorName));
6741 return TRUE;
6744 /******************************************************************************
6745 * DeletePrintProvidorA (WINSPOOL.@)
6747 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6749 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6750 debugstr_a(pPrintProviderName));
6751 return TRUE;
6754 /******************************************************************************
6755 * DeletePrintProvidorW (WINSPOOL.@)
6757 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6759 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6760 debugstr_w(pPrintProviderName));
6761 return TRUE;
6764 /******************************************************************************
6765 * EnumFormsA (WINSPOOL.@)
6767 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6768 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6770 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6771 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6772 return FALSE;
6775 /******************************************************************************
6776 * EnumFormsW (WINSPOOL.@)
6778 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6779 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6781 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6782 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6783 return FALSE;
6786 /*****************************************************************************
6787 * EnumMonitorsA [WINSPOOL.@]
6789 * See EnumMonitorsW.
6792 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6793 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6795 BOOL res;
6796 LPBYTE bufferW = NULL;
6797 LPWSTR nameW = NULL;
6798 DWORD needed = 0;
6799 DWORD numentries = 0;
6800 INT len;
6802 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6803 cbBuf, pcbNeeded, pcReturned);
6805 /* convert servername to unicode */
6806 if (pName) {
6807 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6808 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6809 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6811 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6812 needed = cbBuf * sizeof(WCHAR);
6813 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6814 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6816 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6817 if (pcbNeeded) needed = *pcbNeeded;
6818 /* HeapReAlloc return NULL, when bufferW was NULL */
6819 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6820 HeapAlloc(GetProcessHeap(), 0, needed);
6822 /* Try again with the large Buffer */
6823 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6825 numentries = pcReturned ? *pcReturned : 0;
6826 needed = 0;
6828 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6829 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6831 if (res) {
6832 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6833 DWORD entrysize = 0;
6834 DWORD index;
6835 LPSTR ptr;
6836 LPMONITOR_INFO_2W mi2w;
6837 LPMONITOR_INFO_2A mi2a;
6839 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6840 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6842 /* First pass: calculate the size for all Entries */
6843 mi2w = (LPMONITOR_INFO_2W) bufferW;
6844 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6845 index = 0;
6846 while (index < numentries) {
6847 index++;
6848 needed += entrysize; /* MONITOR_INFO_?A */
6849 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6851 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6852 NULL, 0, NULL, NULL);
6853 if (Level > 1) {
6854 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6855 NULL, 0, NULL, NULL);
6856 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6857 NULL, 0, NULL, NULL);
6859 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6860 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6861 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6864 /* check for errors and quit on failure */
6865 if (cbBuf < needed) {
6866 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6867 res = FALSE;
6868 goto emA_cleanup;
6870 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6871 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6872 cbBuf -= len ; /* free Bytes in the user-Buffer */
6873 mi2w = (LPMONITOR_INFO_2W) bufferW;
6874 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6875 index = 0;
6876 /* Second Pass: Fill the User Buffer (if we have one) */
6877 while ((index < numentries) && pMonitors) {
6878 index++;
6879 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6880 mi2a->pName = ptr;
6881 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6882 ptr, cbBuf , NULL, NULL);
6883 ptr += len;
6884 cbBuf -= len;
6885 if (Level > 1) {
6886 mi2a->pEnvironment = ptr;
6887 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6888 ptr, cbBuf, NULL, NULL);
6889 ptr += len;
6890 cbBuf -= len;
6892 mi2a->pDLLName = ptr;
6893 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6894 ptr, cbBuf, NULL, NULL);
6895 ptr += len;
6896 cbBuf -= len;
6898 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6899 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6900 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6903 emA_cleanup:
6904 if (pcbNeeded) *pcbNeeded = needed;
6905 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6907 HeapFree(GetProcessHeap(), 0, nameW);
6908 HeapFree(GetProcessHeap(), 0, bufferW);
6910 TRACE("returning %d with %d (%d byte for %d entries)\n",
6911 (res), GetLastError(), needed, numentries);
6913 return (res);
6917 /*****************************************************************************
6918 * EnumMonitorsW [WINSPOOL.@]
6920 * Enumerate available Port-Monitors
6922 * PARAMS
6923 * pName [I] Servername or NULL (local Computer)
6924 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6925 * pMonitors [O] PTR to Buffer that receives the Result
6926 * cbBuf [I] Size of Buffer at pMonitors
6927 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6928 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6930 * RETURNS
6931 * Success: TRUE
6932 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6935 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6936 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6939 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6940 cbBuf, pcbNeeded, pcReturned);
6942 if ((backend == NULL) && !load_backend()) return FALSE;
6944 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6945 SetLastError(RPC_X_NULL_REF_POINTER);
6946 return FALSE;
6949 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6952 /******************************************************************************
6953 * SpoolerInit (WINSPOOL.@)
6955 * Initialize the Spooler
6957 * RETURNS
6958 * Success: TRUE
6959 * Failure: FALSE
6961 * NOTES
6962 * The function fails on windows, when the spooler service is not running
6965 BOOL WINAPI SpoolerInit(void)
6968 if ((backend == NULL) && !load_backend()) return FALSE;
6969 return TRUE;
6972 /******************************************************************************
6973 * XcvDataW (WINSPOOL.@)
6975 * Execute commands in the Printmonitor DLL
6977 * PARAMS
6978 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6979 * pszDataName [i] Name of the command to execute
6980 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6981 * cbInputData [i] Size in Bytes of Buffer at pInputData
6982 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6983 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6984 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6985 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6987 * RETURNS
6988 * Success: TRUE
6989 * Failure: FALSE
6991 * NOTES
6992 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6993 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6995 * Minimal List of commands, that a Printmonitor DLL should support:
6997 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6998 *| "AddPort" : Add a Port
6999 *| "DeletePort": Delete a Port
7001 * Many Printmonitors support additional commands. Examples for localspl.dll:
7002 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7003 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7006 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7007 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7008 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7010 opened_printer_t *printer;
7012 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7013 pInputData, cbInputData, pOutputData,
7014 cbOutputData, pcbOutputNeeded, pdwStatus);
7016 if ((backend == NULL) && !load_backend()) return FALSE;
7018 printer = get_opened_printer(hXcv);
7019 if (!printer || (!printer->backend_printer)) {
7020 SetLastError(ERROR_INVALID_HANDLE);
7021 return FALSE;
7024 if (!pcbOutputNeeded) {
7025 SetLastError(ERROR_INVALID_PARAMETER);
7026 return FALSE;
7029 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7030 SetLastError(RPC_X_NULL_REF_POINTER);
7031 return FALSE;
7034 *pcbOutputNeeded = 0;
7036 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
7037 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
7041 /*****************************************************************************
7042 * EnumPrinterDataA [WINSPOOL.@]
7045 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7046 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7047 DWORD cbData, LPDWORD pcbData )
7049 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7050 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7051 return ERROR_NO_MORE_ITEMS;
7054 /*****************************************************************************
7055 * EnumPrinterDataW [WINSPOOL.@]
7058 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7059 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7060 DWORD cbData, LPDWORD pcbData )
7062 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7063 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7064 return ERROR_NO_MORE_ITEMS;
7067 /*****************************************************************************
7068 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7071 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7072 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7073 LPDWORD pcbNeeded, LPDWORD pcReturned)
7075 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7076 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7077 pcbNeeded, pcReturned);
7078 return FALSE;
7081 /*****************************************************************************
7082 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7085 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7086 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7087 LPDWORD pcbNeeded, LPDWORD pcReturned)
7089 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7090 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7091 pcbNeeded, pcReturned);
7092 return FALSE;
7095 /*****************************************************************************
7096 * EnumPrintProcessorsA [WINSPOOL.@]
7099 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7100 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7102 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7103 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7104 return FALSE;
7107 /*****************************************************************************
7108 * EnumPrintProcessorsW [WINSPOOL.@]
7111 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7112 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7114 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7115 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7116 cbBuf, pcbNeeded, pcbReturned);
7117 return FALSE;
7120 /*****************************************************************************
7121 * ExtDeviceMode [WINSPOOL.@]
7124 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7125 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7126 DWORD fMode)
7128 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7129 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7130 debugstr_a(pProfile), fMode);
7131 return -1;
7134 /*****************************************************************************
7135 * FindClosePrinterChangeNotification [WINSPOOL.@]
7138 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7140 FIXME("Stub: %p\n", hChange);
7141 return TRUE;
7144 /*****************************************************************************
7145 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7148 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7149 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7151 FIXME("Stub: %p %x %x %p\n",
7152 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7153 return INVALID_HANDLE_VALUE;
7156 /*****************************************************************************
7157 * FindNextPrinterChangeNotification [WINSPOOL.@]
7160 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7161 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7163 FIXME("Stub: %p %p %p %p\n",
7164 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7165 return FALSE;
7168 /*****************************************************************************
7169 * FreePrinterNotifyInfo [WINSPOOL.@]
7172 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7174 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7175 return TRUE;
7178 /*****************************************************************************
7179 * string_to_buf
7181 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7182 * ansi depending on the unicode parameter.
7184 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7186 if(!str)
7188 *size = 0;
7189 return TRUE;
7192 if(unicode)
7194 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7195 if(*size <= cb)
7197 memcpy(ptr, str, *size);
7198 return TRUE;
7200 return FALSE;
7202 else
7204 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7205 if(*size <= cb)
7207 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7208 return TRUE;
7210 return FALSE;
7214 /*****************************************************************************
7215 * get_job_info_1
7217 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7218 LPDWORD pcbNeeded, BOOL unicode)
7220 DWORD size, left = cbBuf;
7221 BOOL space = (cbBuf > 0);
7222 LPBYTE ptr = buf;
7224 *pcbNeeded = 0;
7226 if(space)
7228 ji1->JobId = job->job_id;
7231 string_to_buf(job->document_title, ptr, left, &size, unicode);
7232 if(space && size <= left)
7234 ji1->pDocument = (LPWSTR)ptr;
7235 ptr += size;
7236 left -= size;
7238 else
7239 space = FALSE;
7240 *pcbNeeded += size;
7242 return space;
7245 /*****************************************************************************
7246 * get_job_info_2
7248 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7249 LPDWORD pcbNeeded, BOOL unicode)
7251 DWORD size, left = cbBuf;
7252 BOOL space = (cbBuf > 0);
7253 LPBYTE ptr = buf;
7255 *pcbNeeded = 0;
7257 if(space)
7259 ji2->JobId = job->job_id;
7262 string_to_buf(job->document_title, ptr, left, &size, unicode);
7263 if(space && size <= left)
7265 ji2->pDocument = (LPWSTR)ptr;
7266 ptr += size;
7267 left -= size;
7269 else
7270 space = FALSE;
7271 *pcbNeeded += size;
7273 return space;
7276 /*****************************************************************************
7277 * get_job_info
7279 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7280 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7282 BOOL ret = FALSE;
7283 DWORD needed = 0, size;
7284 job_t *job;
7285 LPBYTE ptr = pJob;
7287 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7289 EnterCriticalSection(&printer_handles_cs);
7290 job = get_job(hPrinter, JobId);
7291 if(!job)
7292 goto end;
7294 switch(Level)
7296 case 1:
7297 size = sizeof(JOB_INFO_1W);
7298 if(cbBuf >= size)
7300 cbBuf -= size;
7301 ptr += size;
7302 memset(pJob, 0, size);
7304 else
7305 cbBuf = 0;
7306 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7307 needed += size;
7308 break;
7310 case 2:
7311 size = sizeof(JOB_INFO_2W);
7312 if(cbBuf >= size)
7314 cbBuf -= size;
7315 ptr += size;
7316 memset(pJob, 0, size);
7318 else
7319 cbBuf = 0;
7320 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7321 needed += size;
7322 break;
7324 case 3:
7325 size = sizeof(JOB_INFO_3);
7326 if(cbBuf >= size)
7328 cbBuf -= size;
7329 memset(pJob, 0, size);
7330 ret = TRUE;
7332 else
7333 cbBuf = 0;
7334 needed = size;
7335 break;
7337 default:
7338 SetLastError(ERROR_INVALID_LEVEL);
7339 goto end;
7341 if(pcbNeeded)
7342 *pcbNeeded = needed;
7343 end:
7344 LeaveCriticalSection(&printer_handles_cs);
7345 return ret;
7348 /*****************************************************************************
7349 * GetJobA [WINSPOOL.@]
7352 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7353 DWORD cbBuf, LPDWORD pcbNeeded)
7355 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7358 /*****************************************************************************
7359 * GetJobW [WINSPOOL.@]
7362 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7363 DWORD cbBuf, LPDWORD pcbNeeded)
7365 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7368 /*****************************************************************************
7369 * schedule_lpr
7371 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7373 char *unixname, *queue, *cmd;
7374 char fmt[] = "lpr -P%s %s";
7375 DWORD len;
7376 int r;
7378 if(!(unixname = wine_get_unix_file_name(filename)))
7379 return FALSE;
7381 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7382 queue = HeapAlloc(GetProcessHeap(), 0, len);
7383 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7385 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7386 sprintf(cmd, fmt, queue, unixname);
7388 TRACE("printing with: %s\n", cmd);
7389 r = system(cmd);
7391 HeapFree(GetProcessHeap(), 0, cmd);
7392 HeapFree(GetProcessHeap(), 0, queue);
7393 HeapFree(GetProcessHeap(), 0, unixname);
7394 return (r == 0);
7397 /*****************************************************************************
7398 * schedule_cups
7400 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7402 #ifdef SONAME_LIBCUPS
7403 if(pcupsPrintFile)
7405 char *unixname, *queue, *unix_doc_title;
7406 DWORD len;
7407 BOOL ret;
7409 if(!(unixname = wine_get_unix_file_name(filename)))
7410 return FALSE;
7412 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7413 queue = HeapAlloc(GetProcessHeap(), 0, len);
7414 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7416 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7417 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7418 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7420 TRACE("printing via cups\n");
7421 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7422 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7423 HeapFree(GetProcessHeap(), 0, queue);
7424 HeapFree(GetProcessHeap(), 0, unixname);
7425 return ret;
7427 else
7428 #endif
7430 return schedule_lpr(printer_name, filename);
7434 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7436 LPWSTR filename;
7438 switch(msg)
7440 case WM_INITDIALOG:
7441 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7442 return TRUE;
7444 case WM_COMMAND:
7445 if(HIWORD(wparam) == BN_CLICKED)
7447 if(LOWORD(wparam) == IDOK)
7449 HANDLE hf;
7450 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7451 LPWSTR *output;
7453 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7454 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7456 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7458 WCHAR caption[200], message[200];
7459 int mb_ret;
7461 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7462 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7463 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7464 if(mb_ret == IDCANCEL)
7466 HeapFree(GetProcessHeap(), 0, filename);
7467 return TRUE;
7470 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7471 if(hf == INVALID_HANDLE_VALUE)
7473 WCHAR caption[200], message[200];
7475 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7476 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7477 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7478 HeapFree(GetProcessHeap(), 0, filename);
7479 return TRUE;
7481 CloseHandle(hf);
7482 DeleteFileW(filename);
7483 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7484 *output = filename;
7485 EndDialog(hwnd, IDOK);
7486 return TRUE;
7488 if(LOWORD(wparam) == IDCANCEL)
7490 EndDialog(hwnd, IDCANCEL);
7491 return TRUE;
7494 return FALSE;
7496 return FALSE;
7499 /*****************************************************************************
7500 * get_filename
7502 static BOOL get_filename(LPWSTR *filename)
7504 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7505 file_dlg_proc, (LPARAM)filename) == IDOK;
7508 /*****************************************************************************
7509 * schedule_file
7511 static BOOL schedule_file(LPCWSTR filename)
7513 LPWSTR output = NULL;
7515 if(get_filename(&output))
7517 BOOL r;
7518 TRACE("copy to %s\n", debugstr_w(output));
7519 r = CopyFileW(filename, output, FALSE);
7520 HeapFree(GetProcessHeap(), 0, output);
7521 return r;
7523 return FALSE;
7526 /*****************************************************************************
7527 * schedule_pipe
7529 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7531 #ifdef HAVE_FORK
7532 char *unixname, *cmdA;
7533 DWORD len;
7534 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7535 BOOL ret = FALSE;
7536 char buf[1024];
7538 if(!(unixname = wine_get_unix_file_name(filename)))
7539 return FALSE;
7541 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7542 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7543 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7545 TRACE("printing with: %s\n", cmdA);
7547 if((file_fd = open(unixname, O_RDONLY)) == -1)
7548 goto end;
7550 if (pipe(fds))
7552 ERR("pipe() failed!\n");
7553 goto end;
7556 if (fork() == 0)
7558 close(0);
7559 dup2(fds[0], 0);
7560 close(fds[1]);
7562 /* reset signals that we previously set to SIG_IGN */
7563 signal(SIGPIPE, SIG_DFL);
7564 signal(SIGCHLD, SIG_DFL);
7566 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7567 _exit(1);
7570 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7571 write(fds[1], buf, no_read);
7573 ret = TRUE;
7575 end:
7576 if(file_fd != -1) close(file_fd);
7577 if(fds[0] != -1) close(fds[0]);
7578 if(fds[1] != -1) close(fds[1]);
7580 HeapFree(GetProcessHeap(), 0, cmdA);
7581 HeapFree(GetProcessHeap(), 0, unixname);
7582 return ret;
7583 #else
7584 return FALSE;
7585 #endif
7588 /*****************************************************************************
7589 * schedule_unixfile
7591 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7593 int in_fd, out_fd, no_read;
7594 char buf[1024];
7595 BOOL ret = FALSE;
7596 char *unixname, *outputA;
7597 DWORD len;
7599 if(!(unixname = wine_get_unix_file_name(filename)))
7600 return FALSE;
7602 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7603 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7604 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7606 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7607 in_fd = open(unixname, O_RDONLY);
7608 if(out_fd == -1 || in_fd == -1)
7609 goto end;
7611 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7612 write(out_fd, buf, no_read);
7614 ret = TRUE;
7615 end:
7616 if(in_fd != -1) close(in_fd);
7617 if(out_fd != -1) close(out_fd);
7618 HeapFree(GetProcessHeap(), 0, outputA);
7619 HeapFree(GetProcessHeap(), 0, unixname);
7620 return ret;
7623 /*****************************************************************************
7624 * ScheduleJob [WINSPOOL.@]
7627 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7629 opened_printer_t *printer;
7630 BOOL ret = FALSE;
7631 struct list *cursor, *cursor2;
7633 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7634 EnterCriticalSection(&printer_handles_cs);
7635 printer = get_opened_printer(hPrinter);
7636 if(!printer)
7637 goto end;
7639 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7641 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7642 HANDLE hf;
7644 if(job->job_id != dwJobID) continue;
7646 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7647 if(hf != INVALID_HANDLE_VALUE)
7649 PRINTER_INFO_5W *pi5;
7650 DWORD needed;
7651 HKEY hkey;
7652 WCHAR output[1024];
7653 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7654 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7656 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7657 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7658 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7659 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7660 debugstr_w(pi5->pPortName));
7662 output[0] = 0;
7664 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7665 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7667 DWORD type, count = sizeof(output);
7668 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7669 RegCloseKey(hkey);
7671 if(output[0] == '|')
7673 ret = schedule_pipe(output + 1, job->filename);
7675 else if(output[0])
7677 ret = schedule_unixfile(output, job->filename);
7679 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7681 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7683 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7685 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7687 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7689 ret = schedule_file(job->filename);
7691 else
7693 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7695 HeapFree(GetProcessHeap(), 0, pi5);
7696 CloseHandle(hf);
7697 DeleteFileW(job->filename);
7699 list_remove(cursor);
7700 HeapFree(GetProcessHeap(), 0, job->document_title);
7701 HeapFree(GetProcessHeap(), 0, job->filename);
7702 HeapFree(GetProcessHeap(), 0, job);
7703 break;
7705 end:
7706 LeaveCriticalSection(&printer_handles_cs);
7707 return ret;
7710 /*****************************************************************************
7711 * StartDocDlgA [WINSPOOL.@]
7713 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7715 UNICODE_STRING usBuffer;
7716 DOCINFOW docW;
7717 LPWSTR retW;
7718 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7719 LPSTR ret = NULL;
7721 docW.cbSize = sizeof(docW);
7722 if (doc->lpszDocName)
7724 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7725 if (!(docW.lpszDocName = docnameW)) return NULL;
7727 if (doc->lpszOutput)
7729 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7730 if (!(docW.lpszOutput = outputW)) return NULL;
7732 if (doc->lpszDatatype)
7734 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7735 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7737 docW.fwType = doc->fwType;
7739 retW = StartDocDlgW(hPrinter, &docW);
7741 if(retW)
7743 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7744 ret = HeapAlloc(GetProcessHeap(), 0, len);
7745 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7746 HeapFree(GetProcessHeap(), 0, retW);
7749 HeapFree(GetProcessHeap(), 0, datatypeW);
7750 HeapFree(GetProcessHeap(), 0, outputW);
7751 HeapFree(GetProcessHeap(), 0, docnameW);
7753 return ret;
7756 /*****************************************************************************
7757 * StartDocDlgW [WINSPOOL.@]
7759 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7760 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7761 * port is "FILE:". Also returns the full path if passed a relative path.
7763 * The caller should free the returned string from the process heap.
7765 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7767 LPWSTR ret = NULL;
7768 DWORD len, attr;
7770 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7772 PRINTER_INFO_5W *pi5;
7773 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7774 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7775 return NULL;
7776 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7777 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7778 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7780 HeapFree(GetProcessHeap(), 0, pi5);
7781 return NULL;
7783 HeapFree(GetProcessHeap(), 0, pi5);
7786 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7788 LPWSTR name;
7790 if (get_filename(&name))
7792 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7794 HeapFree(GetProcessHeap(), 0, name);
7795 return NULL;
7797 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7798 GetFullPathNameW(name, len, ret, NULL);
7799 HeapFree(GetProcessHeap(), 0, name);
7801 return ret;
7804 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7805 return NULL;
7807 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7808 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7810 attr = GetFileAttributesW(ret);
7811 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7813 HeapFree(GetProcessHeap(), 0, ret);
7814 ret = NULL;
7816 return ret;