push 014043c4937c940c54cd1214c96e33a3b3c8cf7d
[wine/hacks.git] / dlls / winspool.drv / info.c
blob76225826381603fa2631437fd2a774133dd9946d
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-2008 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 monitor_t *pm;
113 HANDLE hXcv;
114 jobqueue_t *queue;
115 started_doc_t *doc;
116 } opened_printer_t;
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
191 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
192 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
193 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
194 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
195 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
196 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
197 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
198 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
200 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
201 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
203 static const WCHAR backslashW[] = {'\\',0};
204 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
209 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
210 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
211 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
212 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
213 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
214 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
215 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
216 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW[] = {'N','a','m','e',0};
219 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
220 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
221 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
222 static const WCHAR PortW[] = {'P','o','r','t',0};
223 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
224 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
225 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
226 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
227 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
228 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
229 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
230 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
232 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
233 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
234 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
235 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
236 static const WCHAR emptyStringW[] = {0};
237 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
238 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
240 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
242 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
243 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
244 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
246 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
247 'D','o','c','u','m','e','n','t',0};
249 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
250 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
251 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
252 0, sizeof(DRIVER_INFO_8W)};
254 /******************************************************************
255 * validate the user-supplied printing-environment [internal]
257 * PARAMS
258 * env [I] PTR to Environment-String or NULL
260 * RETURNS
261 * Failure: NULL
262 * Success: PTR to printenv_t
264 * NOTES
265 * An empty string is handled the same way as NULL.
266 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
270 static const printenv_t * validate_envW(LPCWSTR env)
272 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
273 3, Version3_RegPathW, Version3_SubdirW};
274 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
275 0, Version0_RegPathW, Version0_SubdirW};
277 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
279 const printenv_t *result = NULL;
280 unsigned int i;
282 TRACE("testing %s\n", debugstr_w(env));
283 if (env && env[0])
285 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
287 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
289 result = all_printenv[i];
290 break;
294 if (result == NULL) {
295 FIXME("unsupported Environment: %s\n", debugstr_w(env));
296 SetLastError(ERROR_INVALID_ENVIRONMENT);
298 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
300 else
302 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
304 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
306 return result;
310 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
311 if passed a NULL string. This returns NULLs to the result.
313 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
315 if ( (src) )
317 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
318 return usBufferPtr->Buffer;
320 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
321 return NULL;
324 static LPWSTR strdupW(LPCWSTR p)
326 LPWSTR ret;
327 DWORD len;
329 if(!p) return NULL;
330 len = (strlenW(p) + 1) * sizeof(WCHAR);
331 ret = HeapAlloc(GetProcessHeap(), 0, len);
332 memcpy(ret, p, len);
333 return ret;
336 static LPSTR strdupWtoA( LPCWSTR str )
338 LPSTR ret;
339 INT len;
341 if (!str) return NULL;
342 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
343 ret = HeapAlloc( GetProcessHeap(), 0, len );
344 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
345 return ret;
348 /******************************************************************
349 * Return the number of bytes for an multi_sz string.
350 * The result includes all \0s
351 * (specifically the extra \0, that is needed as multi_sz terminator).
353 #if 0
354 static int multi_sz_lenW(const WCHAR *str)
356 const WCHAR *ptr = str;
357 if(!str) return 0;
360 ptr += lstrlenW(ptr) + 1;
361 } while(*ptr);
363 return (ptr - str + 1) * sizeof(WCHAR);
365 #endif
366 /* ################################ */
368 static int multi_sz_lenA(const char *str)
370 const char *ptr = str;
371 if(!str) return 0;
374 ptr += lstrlenA(ptr) + 1;
375 } while(*ptr);
377 return ptr - str + 1;
380 static void
381 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
382 char qbuf[200];
384 /* If forcing, or no profile string entry for device yet, set the entry
386 * The always change entry if not WINEPS yet is discussable.
388 if (force ||
389 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
390 !strcmp(qbuf,"*") ||
391 !strstr(qbuf,"WINEPS.DRV")
393 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
394 HKEY hkey;
396 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
397 WriteProfileStringA("windows","device",buf);
398 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
399 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
400 RegCloseKey(hkey);
402 HeapFree(GetProcessHeap(),0,buf);
406 static BOOL add_printer_driver(const char *name)
408 DRIVER_INFO_3A di3a;
410 static char driver_9x[] = "wineps16.drv",
411 driver_nt[] = "wineps.drv",
412 env_9x[] = "Windows 4.0",
413 env_nt[] = "Windows NT x86",
414 data_file[] = "generic.ppd",
415 default_data_type[] = "RAW";
417 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
418 di3a.cVersion = 3;
419 di3a.pName = (char *)name;
420 di3a.pEnvironment = env_nt;
421 di3a.pDriverPath = driver_nt;
422 di3a.pDataFile = data_file;
423 di3a.pConfigFile = driver_nt;
424 di3a.pDefaultDataType = default_data_type;
426 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
427 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
429 di3a.cVersion = 0;
430 di3a.pEnvironment = env_9x;
431 di3a.pDriverPath = driver_9x;
432 di3a.pConfigFile = driver_9x;
433 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
434 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
436 return TRUE;
439 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
440 debugstr_a(di3a.pEnvironment), GetLastError());
441 return FALSE;
444 #ifdef SONAME_LIBCUPS
445 static typeof(cupsGetDests) *pcupsGetDests;
446 static typeof(cupsGetPPD) *pcupsGetPPD;
447 static typeof(cupsPrintFile) *pcupsPrintFile;
448 static void *cupshandle;
450 static BOOL CUPS_LoadPrinters(void)
452 int i, nrofdests;
453 BOOL hadprinter = FALSE, haddefault = FALSE;
454 cups_dest_t *dests;
455 PRINTER_INFO_2A pinfo2a;
456 char *port,*devline;
457 HKEY hkeyPrinter, hkeyPrinters, hkey;
458 char loaderror[256];
460 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
461 if (!cupshandle) {
462 TRACE("%s\n", loaderror);
463 return FALSE;
465 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
467 #define DYNCUPS(x) \
468 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
469 if (!p##x) return FALSE;
471 DYNCUPS(cupsGetPPD);
472 DYNCUPS(cupsGetDests);
473 DYNCUPS(cupsPrintFile);
474 #undef DYNCUPS
476 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
477 ERROR_SUCCESS) {
478 ERR("Can't create Printers key\n");
479 return FALSE;
482 nrofdests = pcupsGetDests(&dests);
483 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
484 for (i=0;i<nrofdests;i++) {
485 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
486 sprintf(port,"LPR:%s",dests[i].name);
487 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
488 sprintf(devline,"WINEPS.DRV,%s",port);
489 WriteProfileStringA("devices",dests[i].name,devline);
490 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
491 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
492 RegCloseKey(hkey);
494 HeapFree(GetProcessHeap(),0,devline);
496 TRACE("Printer %d: %s\n", i, dests[i].name);
497 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
498 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
499 and continue */
500 TRACE("Printer already exists\n");
501 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
502 RegCloseKey(hkeyPrinter);
503 } else {
504 static CHAR data_type[] = "RAW",
505 print_proc[] = "WinPrint",
506 comment[] = "WINEPS Printer using CUPS",
507 location[] = "<physical location of printer>",
508 params[] = "<parameters?>",
509 share_name[] = "<share name?>",
510 sep_file[] = "<sep file?>";
512 add_printer_driver(dests[i].name);
514 memset(&pinfo2a,0,sizeof(pinfo2a));
515 pinfo2a.pPrinterName = dests[i].name;
516 pinfo2a.pDatatype = data_type;
517 pinfo2a.pPrintProcessor = print_proc;
518 pinfo2a.pDriverName = dests[i].name;
519 pinfo2a.pComment = comment;
520 pinfo2a.pLocation = location;
521 pinfo2a.pPortName = port;
522 pinfo2a.pParameters = params;
523 pinfo2a.pShareName = share_name;
524 pinfo2a.pSepFile = sep_file;
526 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
527 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
528 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
531 HeapFree(GetProcessHeap(),0,port);
533 hadprinter = TRUE;
534 if (dests[i].is_default) {
535 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
536 haddefault = TRUE;
539 if (hadprinter & !haddefault)
540 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
541 RegCloseKey(hkeyPrinters);
542 return hadprinter;
544 #endif
546 static BOOL
547 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
548 PRINTER_INFO_2A pinfo2a;
549 char *e,*s,*name,*prettyname,*devname;
550 BOOL ret = FALSE, set_default = FALSE;
551 char *port = NULL, *devline,*env_default;
552 HKEY hkeyPrinter, hkeyPrinters, hkey;
554 while (isspace(*pent)) pent++;
555 s = strchr(pent,':');
556 if(s) *s='\0';
557 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
558 strcpy(name,pent);
559 if(s) {
560 *s=':';
561 pent = s;
562 } else
563 pent = "";
565 TRACE("name=%s entry=%s\n",name, pent);
567 if(ispunct(*name)) { /* a tc entry, not a real printer */
568 TRACE("skipping tc entry\n");
569 goto end;
572 if(strstr(pent,":server")) { /* server only version so skip */
573 TRACE("skipping server entry\n");
574 goto end;
577 /* Determine whether this is a postscript printer. */
579 ret = TRUE;
580 env_default = getenv("PRINTER");
581 prettyname = name;
582 /* Get longest name, usually the one at the right for later display. */
583 while((s=strchr(prettyname,'|'))) {
584 *s = '\0';
585 e = s;
586 while(isspace(*--e)) *e = '\0';
587 TRACE("\t%s\n", debugstr_a(prettyname));
588 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
589 for(prettyname = s+1; isspace(*prettyname); prettyname++)
592 e = prettyname + strlen(prettyname);
593 while(isspace(*--e)) *e = '\0';
594 TRACE("\t%s\n", debugstr_a(prettyname));
595 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
597 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
598 * if it is too long, we use it as comment below. */
599 devname = prettyname;
600 if (strlen(devname)>=CCHDEVICENAME-1)
601 devname = name;
602 if (strlen(devname)>=CCHDEVICENAME-1) {
603 ret = FALSE;
604 goto end;
607 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
608 sprintf(port,"LPR:%s",name);
610 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
611 sprintf(devline,"WINEPS.DRV,%s",port);
612 WriteProfileStringA("devices",devname,devline);
613 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
614 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
615 RegCloseKey(hkey);
617 HeapFree(GetProcessHeap(),0,devline);
619 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
620 ERROR_SUCCESS) {
621 ERR("Can't create Printers key\n");
622 ret = FALSE;
623 goto end;
625 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
626 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
627 and continue */
628 TRACE("Printer already exists\n");
629 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
630 RegCloseKey(hkeyPrinter);
631 } else {
632 static CHAR data_type[] = "RAW",
633 print_proc[] = "WinPrint",
634 comment[] = "WINEPS Printer using LPR",
635 params[] = "<parameters?>",
636 share_name[] = "<share name?>",
637 sep_file[] = "<sep file?>";
639 add_printer_driver(devname);
641 memset(&pinfo2a,0,sizeof(pinfo2a));
642 pinfo2a.pPrinterName = devname;
643 pinfo2a.pDatatype = data_type;
644 pinfo2a.pPrintProcessor = print_proc;
645 pinfo2a.pDriverName = devname;
646 pinfo2a.pComment = comment;
647 pinfo2a.pLocation = prettyname;
648 pinfo2a.pPortName = port;
649 pinfo2a.pParameters = params;
650 pinfo2a.pShareName = share_name;
651 pinfo2a.pSepFile = sep_file;
653 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
654 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
655 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
658 RegCloseKey(hkeyPrinters);
660 if (isfirst || set_default)
661 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
663 end:
664 HeapFree(GetProcessHeap(), 0, port);
665 HeapFree(GetProcessHeap(), 0, name);
666 return ret;
669 static BOOL
670 PRINTCAP_LoadPrinters(void) {
671 BOOL hadprinter = FALSE;
672 char buf[200];
673 FILE *f;
674 char *pent = NULL;
675 BOOL had_bash = FALSE;
677 f = fopen("/etc/printcap","r");
678 if (!f)
679 return FALSE;
681 while(fgets(buf,sizeof(buf),f)) {
682 char *start, *end;
684 end=strchr(buf,'\n');
685 if (end) *end='\0';
687 start = buf;
688 while(isspace(*start)) start++;
689 if(*start == '#' || *start == '\0')
690 continue;
692 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
693 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
694 HeapFree(GetProcessHeap(),0,pent);
695 pent = NULL;
698 if (end && *--end == '\\') {
699 *end = '\0';
700 had_bash = TRUE;
701 } else
702 had_bash = FALSE;
704 if (pent) {
705 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
706 strcat(pent,start);
707 } else {
708 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
709 strcpy(pent,start);
713 if(pent) {
714 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
715 HeapFree(GetProcessHeap(),0,pent);
717 fclose(f);
718 return hadprinter;
721 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
723 if (value)
724 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
725 (lstrlenW(value) + 1) * sizeof(WCHAR));
726 else
727 return ERROR_FILE_NOT_FOUND;
730 /*****************************************************************************
731 * enumerate the local monitors (INTERNAL)
733 * returns the needed size (in bytes) for pMonitors
734 * and *lpreturned is set to number of entries returned in pMonitors
737 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
739 HKEY hroot = NULL;
740 HKEY hentry = NULL;
741 LPWSTR ptr;
742 LPMONITOR_INFO_2W mi;
743 WCHAR buffer[MAX_PATH];
744 WCHAR dllname[MAX_PATH];
745 DWORD dllsize;
746 DWORD len;
747 DWORD index = 0;
748 DWORD needed = 0;
749 DWORD numentries;
750 DWORD entrysize;
752 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
754 numentries = *lpreturned; /* this is 0, when we scan the registry */
755 len = entrysize * numentries;
756 ptr = (LPWSTR) &pMonitors[len];
758 numentries = 0;
759 len = sizeof(buffer)/sizeof(buffer[0]);
760 buffer[0] = '\0';
762 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
763 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
764 /* Scan all Monitor-Registry-Keys */
765 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
766 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
767 dllsize = sizeof(dllname);
768 dllname[0] = '\0';
770 /* The Monitor must have a Driver-DLL */
771 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
772 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
773 /* We found a valid DLL for this Monitor. */
774 TRACE("using Driver: %s\n", debugstr_w(dllname));
776 RegCloseKey(hentry);
779 /* Windows returns only Port-Monitors here, but to simplify our code,
780 we do no filtering for Language-Monitors */
781 if (dllname[0]) {
782 numentries++;
783 needed += entrysize;
784 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
785 if (level > 1) {
786 /* we install and return only monitors for "Windows NT x86" */
787 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
788 needed += dllsize;
791 /* required size is calculated. Now fill the user-buffer */
792 if (pMonitors && (cbBuf >= needed)){
793 mi = (LPMONITOR_INFO_2W) pMonitors;
794 pMonitors += entrysize;
796 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
797 mi->pName = ptr;
798 lstrcpyW(ptr, buffer); /* Name of the Monitor */
799 ptr += (len+1); /* len is lstrlenW(monitorname) */
800 if (level > 1) {
801 mi->pEnvironment = ptr;
802 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
803 ptr += (lstrlenW(envname_x86W)+1);
805 mi->pDLLName = ptr;
806 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
807 ptr += (dllsize / sizeof(WCHAR));
811 index++;
812 len = sizeof(buffer)/sizeof(buffer[0]);
813 buffer[0] = '\0';
815 RegCloseKey(hroot);
817 *lpreturned = numentries;
818 TRACE("need %d byte for %d entries\n", needed, numentries);
819 return needed;
822 /******************************************************************
823 * monitor_unload [internal]
825 * release a printmonitor and unload it from memory, when needed
828 static void monitor_unload(monitor_t * pm)
830 if (pm == NULL) return;
831 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
833 EnterCriticalSection(&monitor_handles_cs);
835 if (pm->refcount) pm->refcount--;
837 if (pm->refcount == 0) {
838 list_remove(&pm->entry);
839 FreeLibrary(pm->hdll);
840 HeapFree(GetProcessHeap(), 0, pm->name);
841 HeapFree(GetProcessHeap(), 0, pm->dllname);
842 HeapFree(GetProcessHeap(), 0, pm);
844 LeaveCriticalSection(&monitor_handles_cs);
847 /******************************************************************
848 * monitor_unloadall [internal]
850 * release all printmonitors and unload them from memory, when needed
853 static void monitor_unloadall(void)
855 monitor_t * pm;
856 monitor_t * next;
858 EnterCriticalSection(&monitor_handles_cs);
859 /* iterate through the list, with safety against removal */
860 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
862 monitor_unload(pm);
864 LeaveCriticalSection(&monitor_handles_cs);
867 /******************************************************************
868 * monitor_load [internal]
870 * load a printmonitor, get the dllname from the registry, when needed
871 * initialize the monitor and dump found function-pointers
873 * On failure, SetLastError() is called and NULL is returned
876 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
878 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
879 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
880 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
881 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
882 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
884 monitor_t * pm = NULL;
885 monitor_t * cursor;
886 LPWSTR regroot = NULL;
887 LPWSTR driver = dllname;
889 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
890 /* Is the Monitor already loaded? */
891 EnterCriticalSection(&monitor_handles_cs);
893 if (name) {
894 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
896 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
897 pm = cursor;
898 break;
903 if (pm == NULL) {
904 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
905 if (pm == NULL) goto cleanup;
906 list_add_tail(&monitor_handles, &pm->entry);
908 pm->refcount++;
910 if (pm->name == NULL) {
911 /* Load the monitor */
912 LPMONITOREX pmonitorEx;
913 DWORD len;
915 if (name) {
916 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
917 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
920 if (regroot) {
921 lstrcpyW(regroot, MonitorsW);
922 lstrcatW(regroot, name);
923 /* Get the Driver from the Registry */
924 if (driver == NULL) {
925 HKEY hroot;
926 DWORD namesize;
927 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
928 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
929 &namesize) == ERROR_SUCCESS) {
930 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
931 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
933 RegCloseKey(hroot);
938 pm->name = strdupW(name);
939 pm->dllname = strdupW(driver);
941 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
942 monitor_unload(pm);
943 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
944 pm = NULL;
945 goto cleanup;
948 pm->hdll = LoadLibraryW(driver);
949 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
951 if (pm->hdll == NULL) {
952 monitor_unload(pm);
953 SetLastError(ERROR_MOD_NOT_FOUND);
954 pm = NULL;
955 goto cleanup;
958 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
959 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
960 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
961 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
962 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
965 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
966 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
967 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
968 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
969 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
971 if (pInitializePrintMonitorUI != NULL) {
972 pm->monitorUI = pInitializePrintMonitorUI();
973 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
974 if (pm->monitorUI) {
975 TRACE( "0x%08x: dwMonitorSize (%d)\n",
976 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
981 if (pInitializePrintMonitor && regroot) {
982 pmonitorEx = pInitializePrintMonitor(regroot);
983 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
984 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
986 if (pmonitorEx) {
987 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
988 pm->monitor = &(pmonitorEx->Monitor);
992 if (pm->monitor) {
993 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
997 if (!pm->monitor && regroot) {
998 if (pInitializePrintMonitor2 != NULL) {
999 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1001 if (pInitializeMonitorEx != NULL) {
1002 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1004 if (pInitializeMonitor != NULL) {
1005 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1008 if (!pm->monitor && !pm->monitorUI) {
1009 monitor_unload(pm);
1010 SetLastError(ERROR_PROC_NOT_FOUND);
1011 pm = NULL;
1014 cleanup:
1015 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1016 pm->refcount++;
1017 pm_localport = pm;
1019 LeaveCriticalSection(&monitor_handles_cs);
1020 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1021 HeapFree(GetProcessHeap(), 0, regroot);
1022 TRACE("=> %p\n", pm);
1023 return pm;
1026 /******************************************************************
1027 * monitor_loadall [internal]
1029 * Load all registered monitors
1032 static DWORD monitor_loadall(void)
1034 monitor_t * pm;
1035 DWORD registered = 0;
1036 DWORD loaded = 0;
1037 HKEY hmonitors;
1038 WCHAR buffer[MAX_PATH];
1039 DWORD id = 0;
1041 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1042 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1043 NULL, NULL, NULL, NULL, NULL);
1045 TRACE("%d monitors registered\n", registered);
1047 EnterCriticalSection(&monitor_handles_cs);
1048 while (id < registered) {
1049 buffer[0] = '\0';
1050 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1051 pm = monitor_load(buffer, NULL);
1052 if (pm) loaded++;
1053 id++;
1055 LeaveCriticalSection(&monitor_handles_cs);
1056 RegCloseKey(hmonitors);
1058 TRACE("%d monitors loaded\n", loaded);
1059 return loaded;
1062 /******************************************************************
1063 * monitor_loadui [internal]
1065 * load the userinterface-dll for a given portmonitor
1067 * On failure, NULL is returned
1070 static monitor_t * monitor_loadui(monitor_t * pm)
1072 monitor_t * pui = NULL;
1073 LPWSTR buffer[MAX_PATH];
1074 HANDLE hXcv;
1075 DWORD len;
1076 DWORD res;
1078 if (pm == NULL) return NULL;
1079 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1081 /* Try the Portmonitor first; works for many monitors */
1082 if (pm->monitorUI) {
1083 EnterCriticalSection(&monitor_handles_cs);
1084 pm->refcount++;
1085 LeaveCriticalSection(&monitor_handles_cs);
1086 return pm;
1089 /* query the userinterface-dllname from the Portmonitor */
1090 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1091 /* building (",XcvMonitor %s",pm->name) not needed yet */
1092 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1093 TRACE("got %u with %p\n", res, hXcv);
1094 if (res) {
1095 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1096 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1097 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1098 pm->monitor->pfnXcvClosePort(hXcv);
1101 return pui;
1105 /******************************************************************
1106 * monitor_load_by_port [internal]
1108 * load a printmonitor for a given port
1110 * On failure, NULL is returned
1113 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1115 HKEY hroot;
1116 HKEY hport;
1117 LPWSTR buffer;
1118 monitor_t * pm = NULL;
1119 DWORD registered = 0;
1120 DWORD id = 0;
1121 DWORD len;
1123 TRACE("(%s)\n", debugstr_w(portname));
1125 /* Try the Local Monitor first */
1126 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1127 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1128 /* found the portname */
1129 RegCloseKey(hroot);
1130 return monitor_load(LocalPortW, NULL);
1132 RegCloseKey(hroot);
1135 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1136 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1137 if (buffer == NULL) return NULL;
1139 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1140 EnterCriticalSection(&monitor_handles_cs);
1141 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1143 while ((pm == NULL) && (id < registered)) {
1144 buffer[0] = '\0';
1145 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1146 TRACE("testing %s\n", debugstr_w(buffer));
1147 len = lstrlenW(buffer);
1148 lstrcatW(buffer, bs_Ports_bsW);
1149 lstrcatW(buffer, portname);
1150 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1151 RegCloseKey(hport);
1152 buffer[len] = '\0'; /* use only the Monitor-Name */
1153 pm = monitor_load(buffer, NULL);
1155 id++;
1157 LeaveCriticalSection(&monitor_handles_cs);
1158 RegCloseKey(hroot);
1160 HeapFree(GetProcessHeap(), 0, buffer);
1161 return pm;
1164 /******************************************************************
1165 * enumerate the local Ports from all loaded monitors (internal)
1167 * returns the needed size (in bytes) for pPorts
1168 * and *lpreturned is set to number of entries returned in pPorts
1171 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1173 monitor_t * pm;
1174 LPWSTR ptr;
1175 LPPORT_INFO_2W cache;
1176 LPPORT_INFO_2W out;
1177 LPBYTE pi_buffer = NULL;
1178 DWORD pi_allocated = 0;
1179 DWORD pi_needed;
1180 DWORD pi_index;
1181 DWORD pi_returned;
1182 DWORD res;
1183 DWORD outindex = 0;
1184 DWORD needed;
1185 DWORD numentries;
1186 DWORD entrysize;
1189 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1190 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1192 numentries = *lpreturned; /* this is 0, when we scan the registry */
1193 needed = entrysize * numentries;
1194 ptr = (LPWSTR) &pPorts[needed];
1196 numentries = 0;
1197 needed = 0;
1199 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1201 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1202 pi_needed = 0;
1203 pi_returned = 0;
1204 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1205 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1206 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1207 HeapFree(GetProcessHeap(), 0, pi_buffer);
1208 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1209 pi_allocated = (pi_buffer) ? pi_needed : 0;
1210 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1212 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1213 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1215 numentries += pi_returned;
1216 needed += pi_needed;
1218 /* fill the output-buffer (pPorts), if we have one */
1219 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1220 pi_index = 0;
1221 while (pi_returned > pi_index) {
1222 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1223 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1224 out->pPortName = ptr;
1225 lstrcpyW(ptr, cache->pPortName);
1226 ptr += (lstrlenW(ptr)+1);
1227 if (level > 1) {
1228 out->pMonitorName = ptr;
1229 lstrcpyW(ptr, cache->pMonitorName);
1230 ptr += (lstrlenW(ptr)+1);
1232 out->pDescription = ptr;
1233 lstrcpyW(ptr, cache->pDescription);
1234 ptr += (lstrlenW(ptr)+1);
1235 out->fPortType = cache->fPortType;
1236 out->Reserved = cache->Reserved;
1238 pi_index++;
1239 outindex++;
1244 /* the temporary portinfo-buffer is no longer needed */
1245 HeapFree(GetProcessHeap(), 0, pi_buffer);
1247 *lpreturned = numentries;
1248 TRACE("need %d byte for %d entries\n", needed, numentries);
1249 return needed;
1252 /******************************************************************
1253 * get_servername_from_name (internal)
1255 * for an external server, a copy of the serverpart from the full name is returned
1258 static LPWSTR get_servername_from_name(LPCWSTR name)
1260 LPWSTR server;
1261 LPWSTR ptr;
1262 WCHAR buffer[MAX_PATH];
1263 DWORD len;
1265 if (name == NULL) return NULL;
1266 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1268 server = strdupW(&name[2]); /* skip over both backslash */
1269 if (server == NULL) return NULL;
1271 /* strip '\' and the printername */
1272 ptr = strchrW(server, '\\');
1273 if (ptr) ptr[0] = '\0';
1275 TRACE("found %s\n", debugstr_w(server));
1277 len = sizeof(buffer)/sizeof(buffer[0]);
1278 if (GetComputerNameW(buffer, &len)) {
1279 if (lstrcmpW(buffer, server) == 0) {
1280 /* The requested Servername is our computername */
1281 HeapFree(GetProcessHeap(), 0, server);
1282 return NULL;
1285 return server;
1288 /******************************************************************
1289 * get_basename_from_name (internal)
1291 * skip over the serverpart from the full name
1294 static LPCWSTR get_basename_from_name(LPCWSTR name)
1296 if (name == NULL) return NULL;
1297 if ((name[0] == '\\') && (name[1] == '\\')) {
1298 /* skip over the servername and search for the following '\' */
1299 name = strchrW(&name[2], '\\');
1300 if ((name) && (name[1])) {
1301 /* found a separator ('\') followed by a name:
1302 skip over the separator and return the rest */
1303 name++;
1305 else
1307 /* no basename present (we found only a servername) */
1308 return NULL;
1311 return name;
1314 /******************************************************************
1315 * get_opened_printer_entry
1316 * Get the first place empty in the opened printer table
1318 * ToDo:
1319 * - pDefault is ignored
1321 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1323 UINT_PTR handle = nb_printer_handles, i;
1324 jobqueue_t *queue = NULL;
1325 opened_printer_t *printer = NULL;
1326 LPWSTR servername;
1327 LPCWSTR printername;
1328 HKEY hkeyPrinters;
1329 HKEY hkeyPrinter;
1330 DWORD len;
1332 servername = get_servername_from_name(name);
1333 if (servername) {
1334 FIXME("server %s not supported\n", debugstr_w(servername));
1335 HeapFree(GetProcessHeap(), 0, servername);
1336 SetLastError(ERROR_INVALID_PRINTER_NAME);
1337 return NULL;
1340 printername = get_basename_from_name(name);
1341 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1343 /* an empty printername is invalid */
1344 if (printername && (!printername[0])) {
1345 SetLastError(ERROR_INVALID_PARAMETER);
1346 return NULL;
1349 EnterCriticalSection(&printer_handles_cs);
1351 for (i = 0; i < nb_printer_handles; i++)
1353 if (!printer_handles[i])
1355 if(handle == nb_printer_handles)
1356 handle = i;
1358 else
1360 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1361 queue = printer_handles[i]->queue;
1365 if (handle >= nb_printer_handles)
1367 opened_printer_t **new_array;
1368 if (printer_handles)
1369 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1370 (nb_printer_handles + 16) * sizeof(*new_array) );
1371 else
1372 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1373 (nb_printer_handles + 16) * sizeof(*new_array) );
1375 if (!new_array)
1377 handle = 0;
1378 goto end;
1380 printer_handles = new_array;
1381 nb_printer_handles += 16;
1384 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1386 handle = 0;
1387 goto end;
1391 /* clone the base name. This is NULL for the printserver */
1392 printer->printername = strdupW(printername);
1394 /* clone the full name */
1395 printer->name = strdupW(name);
1396 if (name && (!printer->name)) {
1397 handle = 0;
1398 goto end;
1401 if (printername) {
1402 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1403 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1404 /* OpenPrinter(",XcvMonitor " detected */
1405 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1406 printer->pm = monitor_load(&printername[len], NULL);
1407 if (printer->pm == NULL) {
1408 SetLastError(ERROR_UNKNOWN_PORT);
1409 handle = 0;
1410 goto end;
1413 else
1415 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1416 if (strncmpW( printername, XcvPortW, len) == 0) {
1417 /* OpenPrinter(",XcvPort " detected */
1418 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1419 printer->pm = monitor_load_by_port(&printername[len]);
1420 if (printer->pm == NULL) {
1421 SetLastError(ERROR_UNKNOWN_PORT);
1422 handle = 0;
1423 goto end;
1428 if (printer->pm) {
1429 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1430 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1431 pDefault ? pDefault->DesiredAccess : 0,
1432 &printer->hXcv);
1434 if (printer->hXcv == NULL) {
1435 SetLastError(ERROR_INVALID_PARAMETER);
1436 handle = 0;
1437 goto end;
1440 else
1442 /* Does the Printer exist? */
1443 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1444 ERR("Can't create Printers key\n");
1445 handle = 0;
1446 goto end;
1448 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1449 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1450 RegCloseKey(hkeyPrinters);
1451 SetLastError(ERROR_INVALID_PRINTER_NAME);
1452 handle = 0;
1453 goto end;
1455 RegCloseKey(hkeyPrinter);
1456 RegCloseKey(hkeyPrinters);
1459 else
1461 TRACE("using the local printserver\n");
1464 if(queue)
1465 printer->queue = queue;
1466 else
1468 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1469 if (!printer->queue) {
1470 handle = 0;
1471 goto end;
1473 list_init(&printer->queue->jobs);
1474 printer->queue->ref = 0;
1476 InterlockedIncrement(&printer->queue->ref);
1478 printer_handles[handle] = printer;
1479 handle++;
1480 end:
1481 LeaveCriticalSection(&printer_handles_cs);
1482 if (!handle && printer) {
1483 /* Something failed: Free all resources */
1484 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1485 monitor_unload(printer->pm);
1486 HeapFree(GetProcessHeap(), 0, printer->printername);
1487 HeapFree(GetProcessHeap(), 0, printer->name);
1488 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1489 HeapFree(GetProcessHeap(), 0, printer);
1492 return (HANDLE)handle;
1495 /******************************************************************
1496 * get_opened_printer
1497 * Get the pointer to the opened printer referred by the handle
1499 static opened_printer_t *get_opened_printer(HANDLE hprn)
1501 UINT_PTR idx = (UINT_PTR)hprn;
1502 opened_printer_t *ret = NULL;
1504 EnterCriticalSection(&printer_handles_cs);
1506 if ((idx > 0) && (idx <= nb_printer_handles)) {
1507 ret = printer_handles[idx - 1];
1509 LeaveCriticalSection(&printer_handles_cs);
1510 return ret;
1513 /******************************************************************
1514 * get_opened_printer_name
1515 * Get the pointer to the opened printer name referred by the handle
1517 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1519 opened_printer_t *printer = get_opened_printer(hprn);
1520 if(!printer) return NULL;
1521 return printer->name;
1524 /******************************************************************
1525 * WINSPOOL_GetOpenedPrinterRegKey
1528 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1530 LPCWSTR name = get_opened_printer_name(hPrinter);
1531 DWORD ret;
1532 HKEY hkeyPrinters;
1534 if(!name) return ERROR_INVALID_HANDLE;
1536 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1537 ERROR_SUCCESS)
1538 return ret;
1540 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1542 ERR("Can't find opened printer %s in registry\n",
1543 debugstr_w(name));
1544 RegCloseKey(hkeyPrinters);
1545 return ERROR_INVALID_PRINTER_NAME; /* ? */
1547 RegCloseKey(hkeyPrinters);
1548 return ERROR_SUCCESS;
1551 void WINSPOOL_LoadSystemPrinters(void)
1553 HKEY hkey, hkeyPrinters;
1554 HANDLE hprn;
1555 DWORD needed, num, i;
1556 WCHAR PrinterName[256];
1557 BOOL done = FALSE;
1559 /* This ensures that all printer entries have a valid Name value. If causes
1560 problems later if they don't. If one is found to be missed we create one
1561 and set it equal to the name of the key */
1562 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1563 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1564 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1565 for(i = 0; i < num; i++) {
1566 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1567 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1568 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1569 set_reg_szW(hkey, NameW, PrinterName);
1571 RegCloseKey(hkey);
1576 RegCloseKey(hkeyPrinters);
1579 /* We want to avoid calling AddPrinter on printers as much as
1580 possible, because on cups printers this will (eventually) lead
1581 to a call to cupsGetPPD which takes forever, even with non-cups
1582 printers AddPrinter takes a while. So we'll tag all printers that
1583 were automatically added last time around, if they still exist
1584 we'll leave them be otherwise we'll delete them. */
1585 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1586 if(needed) {
1587 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1588 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1589 for(i = 0; i < num; i++) {
1590 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1591 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1592 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1593 DWORD dw = 1;
1594 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1595 RegCloseKey(hkey);
1597 ClosePrinter(hprn);
1602 HeapFree(GetProcessHeap(), 0, pi);
1606 #ifdef SONAME_LIBCUPS
1607 done = CUPS_LoadPrinters();
1608 #endif
1610 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1611 PRINTCAP_LoadPrinters();
1613 /* Now enumerate the list again and delete any printers that are still tagged */
1614 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1615 if(needed) {
1616 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1617 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1618 for(i = 0; i < num; i++) {
1619 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1620 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1621 BOOL delete_driver = FALSE;
1622 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1623 DWORD dw, type, size = sizeof(dw);
1624 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1625 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1626 DeletePrinter(hprn);
1627 delete_driver = TRUE;
1629 RegCloseKey(hkey);
1631 ClosePrinter(hprn);
1632 if(delete_driver)
1633 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1638 HeapFree(GetProcessHeap(), 0, pi);
1641 return;
1645 /******************************************************************
1646 * get_job
1648 * Get the pointer to the specified job.
1649 * Should hold the printer_handles_cs before calling.
1651 static job_t *get_job(HANDLE hprn, DWORD JobId)
1653 opened_printer_t *printer = get_opened_printer(hprn);
1654 job_t *job;
1656 if(!printer) return NULL;
1657 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1659 if(job->job_id == JobId)
1660 return job;
1662 return NULL;
1665 /***********************************************************
1666 * DEVMODEcpyAtoW
1668 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1670 BOOL Formname;
1671 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1672 DWORD size;
1674 Formname = (dmA->dmSize > off_formname);
1675 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1676 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1677 dmW->dmDeviceName, CCHDEVICENAME);
1678 if(!Formname) {
1679 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1680 dmA->dmSize - CCHDEVICENAME);
1681 } else {
1682 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1683 off_formname - CCHDEVICENAME);
1684 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1685 dmW->dmFormName, CCHFORMNAME);
1686 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1687 (off_formname + CCHFORMNAME));
1689 dmW->dmSize = size;
1690 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1691 dmA->dmDriverExtra);
1692 return dmW;
1695 /***********************************************************
1696 * DEVMODEdupWtoA
1697 * Creates an ascii copy of supplied devmode on heap
1699 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1701 LPDEVMODEA dmA;
1702 DWORD size;
1703 BOOL Formname;
1704 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1706 if(!dmW) return NULL;
1707 Formname = (dmW->dmSize > off_formname);
1708 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1709 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1710 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1711 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1712 if(!Formname) {
1713 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1714 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1715 } else {
1716 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1717 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1718 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1719 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1720 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1721 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1723 dmA->dmSize = size;
1724 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1725 dmW->dmDriverExtra);
1726 return dmA;
1729 /***********************************************************
1730 * PRINTER_INFO_2AtoW
1731 * Creates a unicode copy of PRINTER_INFO_2A on heap
1733 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1735 LPPRINTER_INFO_2W piW;
1736 UNICODE_STRING usBuffer;
1738 if(!piA) return NULL;
1739 piW = HeapAlloc(heap, 0, sizeof(*piW));
1740 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1742 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1743 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1744 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1745 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1746 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1747 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1748 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1749 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1750 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1751 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1752 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1753 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1754 return piW;
1757 /***********************************************************
1758 * FREE_PRINTER_INFO_2W
1759 * Free PRINTER_INFO_2W and all strings
1761 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1763 if(!piW) return;
1765 HeapFree(heap,0,piW->pServerName);
1766 HeapFree(heap,0,piW->pPrinterName);
1767 HeapFree(heap,0,piW->pShareName);
1768 HeapFree(heap,0,piW->pPortName);
1769 HeapFree(heap,0,piW->pDriverName);
1770 HeapFree(heap,0,piW->pComment);
1771 HeapFree(heap,0,piW->pLocation);
1772 HeapFree(heap,0,piW->pDevMode);
1773 HeapFree(heap,0,piW->pSepFile);
1774 HeapFree(heap,0,piW->pPrintProcessor);
1775 HeapFree(heap,0,piW->pDatatype);
1776 HeapFree(heap,0,piW->pParameters);
1777 HeapFree(heap,0,piW);
1778 return;
1781 /******************************************************************
1782 * DeviceCapabilities [WINSPOOL.@]
1783 * DeviceCapabilitiesA [WINSPOOL.@]
1786 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1787 LPSTR pOutput, LPDEVMODEA lpdm)
1789 INT ret;
1791 if (!GDI_CallDeviceCapabilities16)
1793 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1794 (LPCSTR)104 );
1795 if (!GDI_CallDeviceCapabilities16) return -1;
1797 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1799 /* If DC_PAPERSIZE map POINT16s to POINTs */
1800 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1801 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1802 POINT *pt = (POINT *)pOutput;
1803 INT i;
1804 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1805 for(i = 0; i < ret; i++, pt++)
1807 pt->x = tmp[i].x;
1808 pt->y = tmp[i].y;
1810 HeapFree( GetProcessHeap(), 0, tmp );
1812 return ret;
1816 /*****************************************************************************
1817 * DeviceCapabilitiesW [WINSPOOL.@]
1819 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1822 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1823 WORD fwCapability, LPWSTR pOutput,
1824 const DEVMODEW *pDevMode)
1826 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1827 LPSTR pDeviceA = strdupWtoA(pDevice);
1828 LPSTR pPortA = strdupWtoA(pPort);
1829 INT ret;
1831 if(pOutput && (fwCapability == DC_BINNAMES ||
1832 fwCapability == DC_FILEDEPENDENCIES ||
1833 fwCapability == DC_PAPERNAMES)) {
1834 /* These need A -> W translation */
1835 INT size = 0, i;
1836 LPSTR pOutputA;
1837 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1838 dmA);
1839 if(ret == -1)
1840 return ret;
1841 switch(fwCapability) {
1842 case DC_BINNAMES:
1843 size = 24;
1844 break;
1845 case DC_PAPERNAMES:
1846 case DC_FILEDEPENDENCIES:
1847 size = 64;
1848 break;
1850 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1851 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1852 dmA);
1853 for(i = 0; i < ret; i++)
1854 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1855 pOutput + (i * size), size);
1856 HeapFree(GetProcessHeap(), 0, pOutputA);
1857 } else {
1858 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1859 (LPSTR)pOutput, dmA);
1861 HeapFree(GetProcessHeap(),0,pPortA);
1862 HeapFree(GetProcessHeap(),0,pDeviceA);
1863 HeapFree(GetProcessHeap(),0,dmA);
1864 return ret;
1867 /******************************************************************
1868 * DocumentPropertiesA [WINSPOOL.@]
1870 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1872 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1873 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1874 LPDEVMODEA pDevModeInput,DWORD fMode )
1876 LPSTR lpName = pDeviceName;
1877 static CHAR port[] = "LPT1:";
1878 LONG ret;
1880 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1881 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1884 if(!pDeviceName) {
1885 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1886 if(!lpNameW) {
1887 ERR("no name from hPrinter?\n");
1888 SetLastError(ERROR_INVALID_HANDLE);
1889 return -1;
1891 lpName = strdupWtoA(lpNameW);
1894 if (!GDI_CallExtDeviceMode16)
1896 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1897 (LPCSTR)102 );
1898 if (!GDI_CallExtDeviceMode16) {
1899 ERR("No CallExtDeviceMode16?\n");
1900 return -1;
1903 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1904 pDevModeInput, NULL, fMode);
1906 if(!pDeviceName)
1907 HeapFree(GetProcessHeap(),0,lpName);
1908 return ret;
1912 /*****************************************************************************
1913 * DocumentPropertiesW (WINSPOOL.@)
1915 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1917 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1918 LPWSTR pDeviceName,
1919 LPDEVMODEW pDevModeOutput,
1920 LPDEVMODEW pDevModeInput, DWORD fMode)
1923 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1924 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1925 LPDEVMODEA pDevModeOutputA = NULL;
1926 LONG ret;
1928 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1929 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1930 fMode);
1931 if(pDevModeOutput) {
1932 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1933 if(ret < 0) return ret;
1934 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1936 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1937 pDevModeInputA, fMode);
1938 if(pDevModeOutput) {
1939 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1940 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1942 if(fMode == 0 && ret > 0)
1943 ret += (CCHDEVICENAME + CCHFORMNAME);
1944 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1945 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1946 return ret;
1949 /******************************************************************
1950 * OpenPrinterA [WINSPOOL.@]
1952 * See OpenPrinterW.
1955 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1956 LPPRINTER_DEFAULTSA pDefault)
1958 UNICODE_STRING lpPrinterNameW;
1959 UNICODE_STRING usBuffer;
1960 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1961 PWSTR pwstrPrinterNameW;
1962 BOOL ret;
1964 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1966 if(pDefault) {
1967 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1968 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1969 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1970 pDefaultW = &DefaultW;
1972 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1973 if(pDefault) {
1974 RtlFreeUnicodeString(&usBuffer);
1975 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1977 RtlFreeUnicodeString(&lpPrinterNameW);
1978 return ret;
1981 /******************************************************************
1982 * OpenPrinterW [WINSPOOL.@]
1984 * Open a Printer / Printserver or a Printer-Object
1986 * PARAMS
1987 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1988 * phPrinter [O] The resulting Handle is stored here
1989 * pDefault [I] PTR to Default Printer Settings or NULL
1991 * RETURNS
1992 * Success: TRUE
1993 * Failure: FALSE
1995 * NOTES
1996 * lpPrinterName is one of:
1997 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1998 *| Printer: "PrinterName"
1999 *| Printer-Object: "PrinterName,Job xxx"
2000 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2001 *| XcvPort: "Servername,XcvPort PortName"
2003 * BUGS
2004 *| Printer-Object not supported
2005 *| pDefaults is ignored
2008 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2011 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2012 if (pDefault) {
2013 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2014 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2017 if(!phPrinter) {
2018 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2019 SetLastError(ERROR_INVALID_PARAMETER);
2020 return FALSE;
2023 /* Get the unique handle of the printer or Printserver */
2024 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2025 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2026 return (*phPrinter != 0);
2029 /******************************************************************
2030 * AddMonitorA [WINSPOOL.@]
2032 * See AddMonitorW.
2035 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2037 LPWSTR nameW = NULL;
2038 INT len;
2039 BOOL res;
2040 LPMONITOR_INFO_2A mi2a;
2041 MONITOR_INFO_2W mi2w;
2043 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2044 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2045 mi2a ? debugstr_a(mi2a->pName) : NULL,
2046 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2047 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2049 if (Level != 2) {
2050 SetLastError(ERROR_INVALID_LEVEL);
2051 return FALSE;
2054 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2055 if (mi2a == NULL) {
2056 return FALSE;
2059 if (pName) {
2060 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2061 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2062 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2065 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2066 if (mi2a->pName) {
2067 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2068 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2069 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2071 if (mi2a->pEnvironment) {
2072 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2073 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2074 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2076 if (mi2a->pDLLName) {
2077 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2078 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2079 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2082 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2084 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2085 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2086 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2088 HeapFree(GetProcessHeap(), 0, nameW);
2089 return (res);
2092 /******************************************************************************
2093 * AddMonitorW [WINSPOOL.@]
2095 * Install a Printmonitor
2097 * PARAMS
2098 * pName [I] Servername or NULL (local Computer)
2099 * Level [I] Structure-Level (Must be 2)
2100 * pMonitors [I] PTR to MONITOR_INFO_2
2102 * RETURNS
2103 * Success: TRUE
2104 * Failure: FALSE
2106 * NOTES
2107 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2110 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2112 monitor_t * pm = NULL;
2113 LPMONITOR_INFO_2W mi2w;
2114 HKEY hroot = NULL;
2115 HKEY hentry = NULL;
2116 DWORD disposition;
2117 BOOL res = FALSE;
2119 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2120 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2121 mi2w ? debugstr_w(mi2w->pName) : NULL,
2122 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2123 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2125 if (Level != 2) {
2126 SetLastError(ERROR_INVALID_LEVEL);
2127 return FALSE;
2130 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2131 if (mi2w == NULL) {
2132 return FALSE;
2135 if (pName && (pName[0])) {
2136 FIXME("for server %s not implemented\n", debugstr_w(pName));
2137 SetLastError(ERROR_ACCESS_DENIED);
2138 return FALSE;
2142 if (!mi2w->pName || (! mi2w->pName[0])) {
2143 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2144 SetLastError(ERROR_INVALID_PARAMETER);
2145 return FALSE;
2147 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2148 WARN("Environment %s requested (we support only %s)\n",
2149 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2150 SetLastError(ERROR_INVALID_ENVIRONMENT);
2151 return FALSE;
2154 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2155 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2156 SetLastError(ERROR_INVALID_PARAMETER);
2157 return FALSE;
2160 /* Load and initialize the monitor. SetLastError() is called on failure */
2161 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2162 return FALSE;
2164 monitor_unload(pm);
2166 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2167 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2168 return FALSE;
2171 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2172 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2173 &disposition) == ERROR_SUCCESS) {
2175 /* Some installers set options for the port before calling AddMonitor.
2176 We query the "Driver" entry to verify that the monitor is installed,
2177 before we return an error.
2178 When a user installs two print monitors at the same time with the
2179 same name but with a different driver DLL and a task switch comes
2180 between RegQueryValueExW and RegSetValueExW, a race condition
2181 is possible but silently ignored. */
2183 DWORD namesize = 0;
2185 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2186 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2187 &namesize) == ERROR_SUCCESS)) {
2188 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2189 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2190 9x: ERROR_ALREADY_EXISTS (183) */
2191 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2193 else
2195 INT len;
2196 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2197 res = (RegSetValueExW(hentry, DriverW, 0,
2198 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2200 RegCloseKey(hentry);
2203 RegCloseKey(hroot);
2204 return (res);
2207 /******************************************************************
2208 * DeletePrinterDriverA [WINSPOOL.@]
2211 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2213 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2216 /******************************************************************
2217 * DeletePrinterDriverW [WINSPOOL.@]
2220 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2222 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2225 /******************************************************************
2226 * DeleteMonitorA [WINSPOOL.@]
2228 * See DeleteMonitorW.
2231 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2233 LPWSTR nameW = NULL;
2234 LPWSTR EnvironmentW = NULL;
2235 LPWSTR MonitorNameW = NULL;
2236 BOOL res;
2237 INT len;
2239 if (pName) {
2240 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2241 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2242 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2245 if (pEnvironment) {
2246 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2247 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2248 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2250 if (pMonitorName) {
2251 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2252 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2253 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2256 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2258 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2259 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2260 HeapFree(GetProcessHeap(), 0, nameW);
2261 return (res);
2264 /******************************************************************
2265 * DeleteMonitorW [WINSPOOL.@]
2267 * Delete a specific Printmonitor from a Printing-Environment
2269 * PARAMS
2270 * pName [I] Servername or NULL (local Computer)
2271 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2272 * pMonitorName [I] Name of the Monitor, that should be deleted
2274 * RETURNS
2275 * Success: TRUE
2276 * Failure: FALSE
2278 * NOTES
2279 * pEnvironment is ignored in Windows for the local Computer.
2283 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2285 HKEY hroot = NULL;
2287 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2288 debugstr_w(pMonitorName));
2290 if (pName && (pName[0])) {
2291 FIXME("for server %s not implemented\n", debugstr_w(pName));
2292 SetLastError(ERROR_ACCESS_DENIED);
2293 return FALSE;
2296 /* pEnvironment is ignored in Windows for the local Computer */
2298 if (!pMonitorName || !pMonitorName[0]) {
2299 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2300 SetLastError(ERROR_INVALID_PARAMETER);
2301 return FALSE;
2304 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2305 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2306 return FALSE;
2309 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2310 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2311 RegCloseKey(hroot);
2312 return TRUE;
2315 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2316 RegCloseKey(hroot);
2318 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2319 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2320 return (FALSE);
2323 /******************************************************************
2324 * DeletePortA [WINSPOOL.@]
2326 * See DeletePortW.
2329 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2331 LPWSTR nameW = NULL;
2332 LPWSTR portW = NULL;
2333 INT len;
2334 DWORD res;
2336 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2338 /* convert servername to unicode */
2339 if (pName) {
2340 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2341 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2342 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2345 /* convert portname to unicode */
2346 if (pPortName) {
2347 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2348 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2349 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2352 res = DeletePortW(nameW, hWnd, portW);
2353 HeapFree(GetProcessHeap(), 0, nameW);
2354 HeapFree(GetProcessHeap(), 0, portW);
2355 return res;
2358 /******************************************************************
2359 * DeletePortW [WINSPOOL.@]
2361 * Delete a specific Port
2363 * PARAMS
2364 * pName [I] Servername or NULL (local Computer)
2365 * hWnd [I] Handle to parent Window for the Dialog-Box
2366 * pPortName [I] Name of the Port, that should be deleted
2368 * RETURNS
2369 * Success: TRUE
2370 * Failure: FALSE
2373 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2375 monitor_t * pm;
2376 monitor_t * pui;
2377 DWORD res;
2379 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2381 if (pName && pName[0]) {
2382 SetLastError(ERROR_INVALID_PARAMETER);
2383 return FALSE;
2386 if (!pPortName) {
2387 SetLastError(RPC_X_NULL_REF_POINTER);
2388 return FALSE;
2391 /* an empty Portname is Invalid */
2392 if (!pPortName[0]) {
2393 SetLastError(ERROR_NOT_SUPPORTED);
2394 return FALSE;
2397 pm = monitor_load_by_port(pPortName);
2398 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2399 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2400 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2401 TRACE("got %d with %u\n", res, GetLastError());
2403 else
2405 pui = monitor_loadui(pm);
2406 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2407 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2408 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2409 TRACE("got %d with %u\n", res, GetLastError());
2411 else
2413 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2414 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2416 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2417 SetLastError(ERROR_NOT_SUPPORTED);
2418 res = FALSE;
2420 monitor_unload(pui);
2422 monitor_unload(pm);
2424 TRACE("returning %d with %u\n", res, GetLastError());
2425 return res;
2428 /******************************************************************************
2429 * SetPrinterW [WINSPOOL.@]
2431 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2433 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2434 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2435 return FALSE;
2438 /******************************************************************************
2439 * WritePrinter [WINSPOOL.@]
2441 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2443 opened_printer_t *printer;
2444 BOOL ret = FALSE;
2446 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2448 EnterCriticalSection(&printer_handles_cs);
2449 printer = get_opened_printer(hPrinter);
2450 if(!printer)
2452 SetLastError(ERROR_INVALID_HANDLE);
2453 goto end;
2456 if(!printer->doc)
2458 SetLastError(ERROR_SPL_NO_STARTDOC);
2459 goto end;
2462 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2463 end:
2464 LeaveCriticalSection(&printer_handles_cs);
2465 return ret;
2468 /*****************************************************************************
2469 * AddFormA [WINSPOOL.@]
2471 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2473 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2474 return 1;
2477 /*****************************************************************************
2478 * AddFormW [WINSPOOL.@]
2480 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2482 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2483 return 1;
2486 /*****************************************************************************
2487 * AddJobA [WINSPOOL.@]
2489 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2491 BOOL ret;
2492 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2493 DWORD needed;
2495 if(Level != 1) {
2496 SetLastError(ERROR_INVALID_LEVEL);
2497 return FALSE;
2500 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2502 if(ret) {
2503 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2504 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2505 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2506 if(*pcbNeeded > cbBuf) {
2507 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2508 ret = FALSE;
2509 } else {
2510 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2511 addjobA->JobId = addjobW->JobId;
2512 addjobA->Path = (char *)(addjobA + 1);
2513 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2516 return ret;
2519 /*****************************************************************************
2520 * AddJobW [WINSPOOL.@]
2522 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2524 opened_printer_t *printer;
2525 job_t *job;
2526 BOOL ret = FALSE;
2527 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2528 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2529 WCHAR path[MAX_PATH], filename[MAX_PATH];
2530 DWORD len;
2531 ADDJOB_INFO_1W *addjob;
2533 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2535 EnterCriticalSection(&printer_handles_cs);
2537 printer = get_opened_printer(hPrinter);
2539 if(!printer) {
2540 SetLastError(ERROR_INVALID_HANDLE);
2541 goto end;
2544 if(Level != 1) {
2545 SetLastError(ERROR_INVALID_LEVEL);
2546 goto end;
2549 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2550 if(!job)
2551 goto end;
2553 job->job_id = InterlockedIncrement(&next_job_id);
2555 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2556 if(path[len - 1] != '\\')
2557 path[len++] = '\\';
2558 memcpy(path + len, spool_path, sizeof(spool_path));
2559 sprintfW(filename, fmtW, path, job->job_id);
2561 len = strlenW(filename);
2562 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2563 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2564 job->document_title = strdupW(default_doc_title);
2565 list_add_tail(&printer->queue->jobs, &job->entry);
2567 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2568 if(*pcbNeeded <= cbBuf) {
2569 addjob = (ADDJOB_INFO_1W*)pData;
2570 addjob->JobId = job->job_id;
2571 addjob->Path = (WCHAR *)(addjob + 1);
2572 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2573 ret = TRUE;
2574 } else
2575 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2577 end:
2578 LeaveCriticalSection(&printer_handles_cs);
2579 return ret;
2582 /*****************************************************************************
2583 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2585 * Return the PATH for the Print-Processors
2587 * See GetPrintProcessorDirectoryW.
2591 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2592 DWORD level, LPBYTE Info,
2593 DWORD cbBuf, LPDWORD pcbNeeded)
2595 LPWSTR serverW = NULL;
2596 LPWSTR envW = NULL;
2597 BOOL ret;
2598 INT len;
2600 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2601 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2604 if (server) {
2605 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2606 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2607 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2610 if (env) {
2611 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2612 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2613 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2616 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2617 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2619 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2620 cbBuf, pcbNeeded);
2622 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2623 cbBuf, NULL, NULL) > 0;
2626 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2627 HeapFree(GetProcessHeap(), 0, envW);
2628 HeapFree(GetProcessHeap(), 0, serverW);
2629 return ret;
2632 /*****************************************************************************
2633 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2635 * Return the PATH for the Print-Processors
2637 * PARAMS
2638 * server [I] Servername (NT only) or NULL (local Computer)
2639 * env [I] Printing-Environment (see below) or NULL (Default)
2640 * level [I] Structure-Level (must be 1)
2641 * Info [O] PTR to Buffer that receives the Result
2642 * cbBuf [I] Size of Buffer at "Info"
2643 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2644 * required for the Buffer at "Info"
2646 * RETURNS
2647 * Success: TRUE and in pcbNeeded the Bytes used in Info
2648 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2649 * if cbBuf is too small
2651 * Native Values returned in Info on Success:
2652 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2653 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2654 *| win9x(Windows 4.0): "%winsysdir%"
2656 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2658 * BUGS
2659 * Only NULL or "" is supported for server
2662 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2663 DWORD level, LPBYTE Info,
2664 DWORD cbBuf, LPDWORD pcbNeeded)
2666 DWORD needed;
2667 const printenv_t * env_t;
2669 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2670 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2672 if(server != NULL && server[0]) {
2673 FIXME("server not supported: %s\n", debugstr_w(server));
2674 SetLastError(ERROR_INVALID_PARAMETER);
2675 return FALSE;
2678 env_t = validate_envW(env);
2679 if(!env_t) return FALSE; /* environment invalid or unsupported */
2681 if(level != 1) {
2682 WARN("(Level: %d) is ignored in win9x\n", level);
2683 SetLastError(ERROR_INVALID_LEVEL);
2684 return FALSE;
2687 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2688 needed = GetSystemDirectoryW(NULL, 0);
2689 /* add the Size for the Subdirectories */
2690 needed += lstrlenW(spoolprtprocsW);
2691 needed += lstrlenW(env_t->subdir);
2692 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2694 if(pcbNeeded) *pcbNeeded = needed;
2695 TRACE ("required: 0x%x/%d\n", needed, needed);
2696 if (needed > cbBuf) {
2697 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2698 return FALSE;
2700 if(pcbNeeded == NULL) {
2701 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2702 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2703 SetLastError(RPC_X_NULL_REF_POINTER);
2704 return FALSE;
2706 if(Info == NULL) {
2707 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2708 SetLastError(RPC_X_NULL_REF_POINTER);
2709 return FALSE;
2712 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2713 /* add the Subdirectories */
2714 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2715 lstrcatW((LPWSTR) Info, env_t->subdir);
2716 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2717 return TRUE;
2720 /*****************************************************************************
2721 * WINSPOOL_OpenDriverReg [internal]
2723 * opens the registry for the printer drivers depending on the given input
2724 * variable pEnvironment
2726 * RETURNS:
2727 * the opened hkey on success
2728 * NULL on error
2730 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2732 HKEY retval = NULL;
2733 LPWSTR buffer;
2734 const printenv_t * env;
2736 TRACE("(%s, %d)\n",
2737 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2739 if (!pEnvironment || unicode) {
2740 /* pEnvironment was NULL or an Unicode-String: use it direct */
2741 env = validate_envW(pEnvironment);
2743 else
2745 /* pEnvironment was an ANSI-String: convert to unicode first */
2746 LPWSTR buffer;
2747 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2748 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2749 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2750 env = validate_envW(buffer);
2751 HeapFree(GetProcessHeap(), 0, buffer);
2753 if (!env) return NULL;
2755 buffer = HeapAlloc( GetProcessHeap(), 0,
2756 (strlenW(DriversW) + strlenW(env->envname) +
2757 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2758 if(buffer) {
2759 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2760 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2761 HeapFree(GetProcessHeap(), 0, buffer);
2763 return retval;
2766 /*****************************************************************************
2767 * AddPrinterW [WINSPOOL.@]
2769 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2771 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2772 LPDEVMODEA dmA;
2773 LPDEVMODEW dmW;
2774 HANDLE retval;
2775 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2776 LONG size;
2777 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2778 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2779 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2780 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2781 statusW[] = {'S','t','a','t','u','s',0},
2782 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2784 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2786 if(pName != NULL) {
2787 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2788 SetLastError(ERROR_INVALID_PARAMETER);
2789 return 0;
2791 if(Level != 2) {
2792 ERR("Level = %d, unsupported!\n", Level);
2793 SetLastError(ERROR_INVALID_LEVEL);
2794 return 0;
2796 if(!pPrinter) {
2797 SetLastError(ERROR_INVALID_PARAMETER);
2798 return 0;
2800 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2801 ERROR_SUCCESS) {
2802 ERR("Can't create Printers key\n");
2803 return 0;
2805 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2806 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2807 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2808 RegCloseKey(hkeyPrinter);
2809 RegCloseKey(hkeyPrinters);
2810 return 0;
2812 RegCloseKey(hkeyPrinter);
2814 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2815 if(!hkeyDrivers) {
2816 ERR("Can't create Drivers key\n");
2817 RegCloseKey(hkeyPrinters);
2818 return 0;
2820 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2821 ERROR_SUCCESS) {
2822 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2823 RegCloseKey(hkeyPrinters);
2824 RegCloseKey(hkeyDrivers);
2825 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2826 return 0;
2828 RegCloseKey(hkeyDriver);
2829 RegCloseKey(hkeyDrivers);
2831 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2832 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2833 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2834 RegCloseKey(hkeyPrinters);
2835 return 0;
2838 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2839 ERROR_SUCCESS) {
2840 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2841 SetLastError(ERROR_INVALID_PRINTER_NAME);
2842 RegCloseKey(hkeyPrinters);
2843 return 0;
2845 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2846 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2847 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2849 /* See if we can load the driver. We may need the devmode structure anyway
2851 * FIXME:
2852 * Note that DocumentPropertiesW will briefly try to open the printer we
2853 * just create to find a DEVMODEA struct (it will use the WINEPS default
2854 * one in case it is not there, so we are ok).
2856 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2858 if(size < 0) {
2859 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2860 size = sizeof(DEVMODEW);
2862 if(pi->pDevMode)
2863 dmW = pi->pDevMode;
2864 else
2866 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2867 dmW->dmSize = size;
2868 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2870 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2871 HeapFree(GetProcessHeap(),0,dmW);
2872 dmW=NULL;
2874 else
2876 /* set devmode to printer name */
2877 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2881 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2882 and we support these drivers. NT writes DEVMODEW so somehow
2883 we'll need to distinguish between these when we support NT
2884 drivers */
2885 if (dmW)
2887 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2888 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2889 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2890 HeapFree(GetProcessHeap(), 0, dmA);
2891 if(!pi->pDevMode)
2892 HeapFree(GetProcessHeap(), 0, dmW);
2894 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2895 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2896 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2897 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2899 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2900 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2901 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2902 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2903 (LPBYTE)&pi->Priority, sizeof(DWORD));
2904 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2905 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2906 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2907 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2908 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2909 (LPBYTE)&pi->Status, sizeof(DWORD));
2910 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2911 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2913 RegCloseKey(hkeyPrinter);
2914 RegCloseKey(hkeyPrinters);
2915 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2916 ERR("OpenPrinter failing\n");
2917 return 0;
2919 return retval;
2922 /*****************************************************************************
2923 * AddPrinterA [WINSPOOL.@]
2925 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2927 UNICODE_STRING pNameW;
2928 PWSTR pwstrNameW;
2929 PRINTER_INFO_2W *piW;
2930 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2931 HANDLE ret;
2933 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2934 if(Level != 2) {
2935 ERR("Level = %d, unsupported!\n", Level);
2936 SetLastError(ERROR_INVALID_LEVEL);
2937 return 0;
2939 pwstrNameW = asciitounicode(&pNameW,pName);
2940 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2942 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2944 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2945 RtlFreeUnicodeString(&pNameW);
2946 return ret;
2950 /*****************************************************************************
2951 * ClosePrinter [WINSPOOL.@]
2953 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2955 UINT_PTR i = (UINT_PTR)hPrinter;
2956 opened_printer_t *printer = NULL;
2957 BOOL ret = FALSE;
2959 TRACE("(%p)\n", hPrinter);
2961 EnterCriticalSection(&printer_handles_cs);
2963 if ((i > 0) && (i <= nb_printer_handles))
2964 printer = printer_handles[i - 1];
2967 if(printer)
2969 struct list *cursor, *cursor2;
2971 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2972 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2973 printer->hXcv, debugstr_w(printer->name), printer->doc );
2975 if(printer->doc)
2976 EndDocPrinter(hPrinter);
2978 if(InterlockedDecrement(&printer->queue->ref) == 0)
2980 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2982 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2983 ScheduleJob(hPrinter, job->job_id);
2985 HeapFree(GetProcessHeap(), 0, printer->queue);
2987 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2988 monitor_unload(printer->pm);
2989 HeapFree(GetProcessHeap(), 0, printer->printername);
2990 HeapFree(GetProcessHeap(), 0, printer->name);
2991 HeapFree(GetProcessHeap(), 0, printer);
2992 printer_handles[i - 1] = NULL;
2993 ret = TRUE;
2995 LeaveCriticalSection(&printer_handles_cs);
2996 return ret;
2999 /*****************************************************************************
3000 * DeleteFormA [WINSPOOL.@]
3002 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3004 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3005 return 1;
3008 /*****************************************************************************
3009 * DeleteFormW [WINSPOOL.@]
3011 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3013 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3014 return 1;
3017 /*****************************************************************************
3018 * DeletePrinter [WINSPOOL.@]
3020 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3022 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3023 HKEY hkeyPrinters, hkey;
3025 if(!lpNameW) {
3026 SetLastError(ERROR_INVALID_HANDLE);
3027 return FALSE;
3029 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3030 RegDeleteTreeW(hkeyPrinters, lpNameW);
3031 RegCloseKey(hkeyPrinters);
3033 WriteProfileStringW(devicesW, lpNameW, NULL);
3034 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3035 RegDeleteValueW(hkey, lpNameW);
3036 RegCloseKey(hkey);
3038 return TRUE;
3041 /*****************************************************************************
3042 * SetPrinterA [WINSPOOL.@]
3044 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3045 DWORD Command)
3047 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3048 return FALSE;
3051 /*****************************************************************************
3052 * SetJobA [WINSPOOL.@]
3054 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3055 LPBYTE pJob, DWORD Command)
3057 BOOL ret;
3058 LPBYTE JobW;
3059 UNICODE_STRING usBuffer;
3061 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3063 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3064 are all ignored by SetJob, so we don't bother copying them */
3065 switch(Level)
3067 case 0:
3068 JobW = NULL;
3069 break;
3070 case 1:
3072 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3073 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3075 JobW = (LPBYTE)info1W;
3076 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3077 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3078 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3079 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3080 info1W->Status = info1A->Status;
3081 info1W->Priority = info1A->Priority;
3082 info1W->Position = info1A->Position;
3083 info1W->PagesPrinted = info1A->PagesPrinted;
3084 break;
3086 case 2:
3088 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3089 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3091 JobW = (LPBYTE)info2W;
3092 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3093 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3094 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3095 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3096 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3097 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3098 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3099 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3100 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3101 info2W->Status = info2A->Status;
3102 info2W->Priority = info2A->Priority;
3103 info2W->Position = info2A->Position;
3104 info2W->StartTime = info2A->StartTime;
3105 info2W->UntilTime = info2A->UntilTime;
3106 info2W->PagesPrinted = info2A->PagesPrinted;
3107 break;
3109 case 3:
3110 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3111 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3112 break;
3113 default:
3114 SetLastError(ERROR_INVALID_LEVEL);
3115 return FALSE;
3118 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3120 switch(Level)
3122 case 1:
3124 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3125 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3126 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3127 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3128 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3129 break;
3131 case 2:
3133 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3134 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3135 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3136 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3137 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3138 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3139 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3140 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3141 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3142 break;
3145 HeapFree(GetProcessHeap(), 0, JobW);
3147 return ret;
3150 /*****************************************************************************
3151 * SetJobW [WINSPOOL.@]
3153 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3154 LPBYTE pJob, DWORD Command)
3156 BOOL ret = FALSE;
3157 job_t *job;
3159 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3160 FIXME("Ignoring everything other than document title\n");
3162 EnterCriticalSection(&printer_handles_cs);
3163 job = get_job(hPrinter, JobId);
3164 if(!job)
3165 goto end;
3167 switch(Level)
3169 case 0:
3170 break;
3171 case 1:
3173 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3174 HeapFree(GetProcessHeap(), 0, job->document_title);
3175 job->document_title = strdupW(info1->pDocument);
3176 break;
3178 case 2:
3180 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3181 HeapFree(GetProcessHeap(), 0, job->document_title);
3182 job->document_title = strdupW(info2->pDocument);
3183 break;
3185 case 3:
3186 break;
3187 default:
3188 SetLastError(ERROR_INVALID_LEVEL);
3189 goto end;
3191 ret = TRUE;
3192 end:
3193 LeaveCriticalSection(&printer_handles_cs);
3194 return ret;
3197 /*****************************************************************************
3198 * EndDocPrinter [WINSPOOL.@]
3200 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3202 opened_printer_t *printer;
3203 BOOL ret = FALSE;
3204 TRACE("(%p)\n", hPrinter);
3206 EnterCriticalSection(&printer_handles_cs);
3208 printer = get_opened_printer(hPrinter);
3209 if(!printer)
3211 SetLastError(ERROR_INVALID_HANDLE);
3212 goto end;
3215 if(!printer->doc)
3217 SetLastError(ERROR_SPL_NO_STARTDOC);
3218 goto end;
3221 CloseHandle(printer->doc->hf);
3222 ScheduleJob(hPrinter, printer->doc->job_id);
3223 HeapFree(GetProcessHeap(), 0, printer->doc);
3224 printer->doc = NULL;
3225 ret = TRUE;
3226 end:
3227 LeaveCriticalSection(&printer_handles_cs);
3228 return ret;
3231 /*****************************************************************************
3232 * EndPagePrinter [WINSPOOL.@]
3234 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3236 FIXME("(%p): stub\n", hPrinter);
3237 return TRUE;
3240 /*****************************************************************************
3241 * StartDocPrinterA [WINSPOOL.@]
3243 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3245 UNICODE_STRING usBuffer;
3246 DOC_INFO_2W doc2W;
3247 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3248 DWORD ret;
3250 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3251 or one (DOC_INFO_3) extra DWORDs */
3253 switch(Level) {
3254 case 2:
3255 doc2W.JobId = doc2->JobId;
3256 /* fall through */
3257 case 3:
3258 doc2W.dwMode = doc2->dwMode;
3259 /* fall through */
3260 case 1:
3261 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3262 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3263 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3264 break;
3266 default:
3267 SetLastError(ERROR_INVALID_LEVEL);
3268 return FALSE;
3271 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3273 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3274 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3275 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3277 return ret;
3280 /*****************************************************************************
3281 * StartDocPrinterW [WINSPOOL.@]
3283 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3285 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3286 opened_printer_t *printer;
3287 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3288 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3289 JOB_INFO_1W job_info;
3290 DWORD needed, ret = 0;
3291 HANDLE hf;
3292 WCHAR *filename;
3294 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3295 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3296 debugstr_w(doc->pDatatype));
3298 if(Level < 1 || Level > 3)
3300 SetLastError(ERROR_INVALID_LEVEL);
3301 return 0;
3304 EnterCriticalSection(&printer_handles_cs);
3305 printer = get_opened_printer(hPrinter);
3306 if(!printer)
3308 SetLastError(ERROR_INVALID_HANDLE);
3309 goto end;
3312 if(printer->doc)
3314 SetLastError(ERROR_INVALID_PRINTER_STATE);
3315 goto end;
3318 /* Even if we're printing to a file we still add a print job, we'll
3319 just ignore the spool file name */
3321 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3323 ERR("AddJob failed gle %u\n", GetLastError());
3324 goto end;
3327 if(doc->pOutputFile)
3328 filename = doc->pOutputFile;
3329 else
3330 filename = addjob->Path;
3332 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3333 if(hf == INVALID_HANDLE_VALUE)
3334 goto end;
3336 memset(&job_info, 0, sizeof(job_info));
3337 job_info.pDocument = doc->pDocName;
3338 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3340 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3341 printer->doc->hf = hf;
3342 ret = printer->doc->job_id = addjob->JobId;
3343 end:
3344 LeaveCriticalSection(&printer_handles_cs);
3346 return ret;
3349 /*****************************************************************************
3350 * StartPagePrinter [WINSPOOL.@]
3352 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3354 FIXME("(%p): stub\n", hPrinter);
3355 return TRUE;
3358 /*****************************************************************************
3359 * GetFormA [WINSPOOL.@]
3361 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3362 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3364 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3365 Level,pForm,cbBuf,pcbNeeded);
3366 return FALSE;
3369 /*****************************************************************************
3370 * GetFormW [WINSPOOL.@]
3372 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3373 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3375 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3376 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3377 return FALSE;
3380 /*****************************************************************************
3381 * SetFormA [WINSPOOL.@]
3383 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3384 LPBYTE pForm)
3386 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3387 return FALSE;
3390 /*****************************************************************************
3391 * SetFormW [WINSPOOL.@]
3393 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3394 LPBYTE pForm)
3396 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3397 return FALSE;
3400 /*****************************************************************************
3401 * ReadPrinter [WINSPOOL.@]
3403 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3404 LPDWORD pNoBytesRead)
3406 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3407 return FALSE;
3410 /*****************************************************************************
3411 * ResetPrinterA [WINSPOOL.@]
3413 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3415 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3416 return FALSE;
3419 /*****************************************************************************
3420 * ResetPrinterW [WINSPOOL.@]
3422 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3424 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3425 return FALSE;
3428 /*****************************************************************************
3429 * WINSPOOL_GetDWORDFromReg
3431 * Return DWORD associated with ValueName from hkey.
3433 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3435 DWORD sz = sizeof(DWORD), type, value = 0;
3436 LONG ret;
3438 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3440 if(ret != ERROR_SUCCESS) {
3441 WARN("Got ret = %d on name %s\n", ret, ValueName);
3442 return 0;
3444 if(type != REG_DWORD) {
3445 ERR("Got type %d\n", type);
3446 return 0;
3448 return value;
3452 /*****************************************************************************
3453 * get_filename_from_reg [internal]
3455 * Get ValueName from hkey storing result in out
3456 * when the Value in the registry has only a filename, use driverdir as prefix
3457 * outlen is space left in out
3458 * String is stored either as unicode or ascii
3462 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3463 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3465 WCHAR filename[MAX_PATH];
3466 DWORD size;
3467 DWORD type;
3468 LONG ret;
3469 LPWSTR buffer = filename;
3470 LPWSTR ptr;
3472 *needed = 0;
3473 size = sizeof(filename);
3474 buffer[0] = '\0';
3475 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3476 if (ret == ERROR_MORE_DATA) {
3477 TRACE("need dynamic buffer: %u\n", size);
3478 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3479 if (!buffer) {
3480 /* No Memory is bad */
3481 return FALSE;
3483 buffer[0] = '\0';
3484 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3487 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3488 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3489 return FALSE;
3492 ptr = buffer;
3493 while (ptr) {
3494 /* do we have a full path ? */
3495 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3496 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3498 if (!ret) {
3499 /* we must build the full Path */
3500 *needed += dirlen;
3501 if ((out) && (outlen > dirlen)) {
3502 if (unicode) {
3503 lstrcpyW((LPWSTR)out, driverdir);
3505 else
3507 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3509 out += dirlen;
3510 outlen -= dirlen;
3512 else
3513 out = NULL;
3516 /* write the filename */
3517 if (unicode) {
3518 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3519 if ((out) && (outlen >= size)) {
3520 lstrcpyW((LPWSTR)out, ptr);
3521 out += size;
3522 outlen -= size;
3524 else
3525 out = NULL;
3527 else
3529 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3530 if ((out) && (outlen >= size)) {
3531 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3532 out += size;
3533 outlen -= size;
3535 else
3536 out = NULL;
3538 *needed += size;
3539 ptr += lstrlenW(ptr)+1;
3540 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3543 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3545 /* write the multisz-termination */
3546 if (type == REG_MULTI_SZ) {
3547 size = (unicode) ? sizeof(WCHAR) : 1;
3549 *needed += size;
3550 if (out && (outlen >= size)) {
3551 memset (out, 0, size);
3554 return TRUE;
3557 /*****************************************************************************
3558 * WINSPOOL_GetStringFromReg
3560 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3561 * String is stored either as unicode or ascii.
3562 * Bit of a hack here to get the ValueName if we want ascii.
3564 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3565 DWORD buflen, DWORD *needed,
3566 BOOL unicode)
3568 DWORD sz = buflen, type;
3569 LONG ret;
3571 if(unicode)
3572 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3573 else {
3574 LPSTR ValueNameA = strdupWtoA(ValueName);
3575 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3576 HeapFree(GetProcessHeap(),0,ValueNameA);
3578 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3579 WARN("Got ret = %d\n", ret);
3580 *needed = 0;
3581 return FALSE;
3583 /* add space for terminating '\0' */
3584 sz += unicode ? sizeof(WCHAR) : 1;
3585 *needed = sz;
3587 if (ptr)
3588 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3590 return TRUE;
3593 /*****************************************************************************
3594 * WINSPOOL_GetDefaultDevMode
3596 * Get a default DevMode values for wineps.
3597 * FIXME - use ppd.
3600 static void WINSPOOL_GetDefaultDevMode(
3601 LPBYTE ptr,
3602 DWORD buflen, DWORD *needed,
3603 BOOL unicode)
3605 DEVMODEA dm;
3606 static const char szwps[] = "wineps.drv";
3608 /* fill default DEVMODE - should be read from ppd... */
3609 ZeroMemory( &dm, sizeof(dm) );
3610 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3611 dm.dmSpecVersion = DM_SPECVERSION;
3612 dm.dmDriverVersion = 1;
3613 dm.dmSize = sizeof(DEVMODEA);
3614 dm.dmDriverExtra = 0;
3615 dm.dmFields =
3616 DM_ORIENTATION | DM_PAPERSIZE |
3617 DM_PAPERLENGTH | DM_PAPERWIDTH |
3618 DM_SCALE |
3619 DM_COPIES |
3620 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3621 DM_YRESOLUTION | DM_TTOPTION;
3623 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3624 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3625 dm.u1.s1.dmPaperLength = 2970;
3626 dm.u1.s1.dmPaperWidth = 2100;
3628 dm.u1.s1.dmScale = 100;
3629 dm.u1.s1.dmCopies = 1;
3630 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3631 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3632 /* dm.dmColor */
3633 /* dm.dmDuplex */
3634 dm.dmYResolution = 300; /* 300dpi */
3635 dm.dmTTOption = DMTT_BITMAP;
3636 /* dm.dmCollate */
3637 /* dm.dmFormName */
3638 /* dm.dmLogPixels */
3639 /* dm.dmBitsPerPel */
3640 /* dm.dmPelsWidth */
3641 /* dm.dmPelsHeight */
3642 /* dm.u2.dmDisplayFlags */
3643 /* dm.dmDisplayFrequency */
3644 /* dm.dmICMMethod */
3645 /* dm.dmICMIntent */
3646 /* dm.dmMediaType */
3647 /* dm.dmDitherType */
3648 /* dm.dmReserved1 */
3649 /* dm.dmReserved2 */
3650 /* dm.dmPanningWidth */
3651 /* dm.dmPanningHeight */
3653 if(unicode) {
3654 if(buflen >= sizeof(DEVMODEW)) {
3655 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3656 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3657 HeapFree(GetProcessHeap(),0,pdmW);
3659 *needed = sizeof(DEVMODEW);
3661 else
3663 if(buflen >= sizeof(DEVMODEA)) {
3664 memcpy(ptr, &dm, sizeof(DEVMODEA));
3666 *needed = sizeof(DEVMODEA);
3670 /*****************************************************************************
3671 * WINSPOOL_GetDevModeFromReg
3673 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3674 * DevMode is stored either as unicode or ascii.
3676 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3677 LPBYTE ptr,
3678 DWORD buflen, DWORD *needed,
3679 BOOL unicode)
3681 DWORD sz = buflen, type;
3682 LONG ret;
3684 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3685 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3686 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3687 if (sz < sizeof(DEVMODEA))
3689 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3690 return FALSE;
3692 /* ensures that dmSize is not erratically bogus if registry is invalid */
3693 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3694 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3695 if(unicode) {
3696 sz += (CCHDEVICENAME + CCHFORMNAME);
3697 if(buflen >= sz) {
3698 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3699 memcpy(ptr, dmW, sz);
3700 HeapFree(GetProcessHeap(),0,dmW);
3703 *needed = sz;
3704 return TRUE;
3707 /*********************************************************************
3708 * WINSPOOL_GetPrinter_1
3710 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3711 * The strings are either stored as unicode or ascii.
3713 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3714 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3715 BOOL unicode)
3717 DWORD size, left = cbBuf;
3718 BOOL space = (cbBuf > 0);
3719 LPBYTE ptr = buf;
3721 *pcbNeeded = 0;
3723 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3724 unicode)) {
3725 if(space && size <= left) {
3726 pi1->pName = (LPWSTR)ptr;
3727 ptr += size;
3728 left -= size;
3729 } else
3730 space = FALSE;
3731 *pcbNeeded += size;
3734 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3735 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3736 unicode)) {
3737 if(space && size <= left) {
3738 pi1->pDescription = (LPWSTR)ptr;
3739 ptr += size;
3740 left -= size;
3741 } else
3742 space = FALSE;
3743 *pcbNeeded += size;
3746 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3747 unicode)) {
3748 if(space && size <= left) {
3749 pi1->pComment = (LPWSTR)ptr;
3750 ptr += size;
3751 left -= size;
3752 } else
3753 space = FALSE;
3754 *pcbNeeded += size;
3757 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3759 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3760 memset(pi1, 0, sizeof(*pi1));
3762 return space;
3764 /*********************************************************************
3765 * WINSPOOL_GetPrinter_2
3767 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3768 * The strings are either stored as unicode or ascii.
3770 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3771 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3772 BOOL unicode)
3774 DWORD size, left = cbBuf;
3775 BOOL space = (cbBuf > 0);
3776 LPBYTE ptr = buf;
3778 *pcbNeeded = 0;
3780 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3781 unicode)) {
3782 if(space && size <= left) {
3783 pi2->pPrinterName = (LPWSTR)ptr;
3784 ptr += size;
3785 left -= size;
3786 } else
3787 space = FALSE;
3788 *pcbNeeded += size;
3790 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3791 unicode)) {
3792 if(space && size <= left) {
3793 pi2->pShareName = (LPWSTR)ptr;
3794 ptr += size;
3795 left -= size;
3796 } else
3797 space = FALSE;
3798 *pcbNeeded += size;
3800 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3801 unicode)) {
3802 if(space && size <= left) {
3803 pi2->pPortName = (LPWSTR)ptr;
3804 ptr += size;
3805 left -= size;
3806 } else
3807 space = FALSE;
3808 *pcbNeeded += size;
3810 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3811 &size, unicode)) {
3812 if(space && size <= left) {
3813 pi2->pDriverName = (LPWSTR)ptr;
3814 ptr += size;
3815 left -= size;
3816 } else
3817 space = FALSE;
3818 *pcbNeeded += size;
3820 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3821 unicode)) {
3822 if(space && size <= left) {
3823 pi2->pComment = (LPWSTR)ptr;
3824 ptr += size;
3825 left -= size;
3826 } else
3827 space = FALSE;
3828 *pcbNeeded += size;
3830 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3831 unicode)) {
3832 if(space && size <= left) {
3833 pi2->pLocation = (LPWSTR)ptr;
3834 ptr += size;
3835 left -= size;
3836 } else
3837 space = FALSE;
3838 *pcbNeeded += size;
3840 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3841 &size, unicode)) {
3842 if(space && size <= left) {
3843 pi2->pDevMode = (LPDEVMODEW)ptr;
3844 ptr += size;
3845 left -= size;
3846 } else
3847 space = FALSE;
3848 *pcbNeeded += size;
3850 else
3852 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3853 if(space && size <= left) {
3854 pi2->pDevMode = (LPDEVMODEW)ptr;
3855 ptr += size;
3856 left -= size;
3857 } else
3858 space = FALSE;
3859 *pcbNeeded += size;
3861 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3862 &size, unicode)) {
3863 if(space && size <= left) {
3864 pi2->pSepFile = (LPWSTR)ptr;
3865 ptr += size;
3866 left -= size;
3867 } else
3868 space = FALSE;
3869 *pcbNeeded += size;
3871 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3872 &size, unicode)) {
3873 if(space && size <= left) {
3874 pi2->pPrintProcessor = (LPWSTR)ptr;
3875 ptr += size;
3876 left -= size;
3877 } else
3878 space = FALSE;
3879 *pcbNeeded += size;
3881 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3882 &size, unicode)) {
3883 if(space && size <= left) {
3884 pi2->pDatatype = (LPWSTR)ptr;
3885 ptr += size;
3886 left -= size;
3887 } else
3888 space = FALSE;
3889 *pcbNeeded += size;
3891 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3892 &size, unicode)) {
3893 if(space && size <= left) {
3894 pi2->pParameters = (LPWSTR)ptr;
3895 ptr += size;
3896 left -= size;
3897 } else
3898 space = FALSE;
3899 *pcbNeeded += size;
3901 if(pi2) {
3902 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3903 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3904 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3905 "Default Priority");
3906 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3907 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3910 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3911 memset(pi2, 0, sizeof(*pi2));
3913 return space;
3916 /*********************************************************************
3917 * WINSPOOL_GetPrinter_4
3919 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3921 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3922 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3923 BOOL unicode)
3925 DWORD size, left = cbBuf;
3926 BOOL space = (cbBuf > 0);
3927 LPBYTE ptr = buf;
3929 *pcbNeeded = 0;
3931 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3932 unicode)) {
3933 if(space && size <= left) {
3934 pi4->pPrinterName = (LPWSTR)ptr;
3935 ptr += size;
3936 left -= size;
3937 } else
3938 space = FALSE;
3939 *pcbNeeded += size;
3941 if(pi4) {
3942 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3945 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3946 memset(pi4, 0, sizeof(*pi4));
3948 return space;
3951 /*********************************************************************
3952 * WINSPOOL_GetPrinter_5
3954 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3956 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3957 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3958 BOOL unicode)
3960 DWORD size, left = cbBuf;
3961 BOOL space = (cbBuf > 0);
3962 LPBYTE ptr = buf;
3964 *pcbNeeded = 0;
3966 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3967 unicode)) {
3968 if(space && size <= left) {
3969 pi5->pPrinterName = (LPWSTR)ptr;
3970 ptr += size;
3971 left -= size;
3972 } else
3973 space = FALSE;
3974 *pcbNeeded += size;
3976 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3977 unicode)) {
3978 if(space && size <= left) {
3979 pi5->pPortName = (LPWSTR)ptr;
3980 ptr += size;
3981 left -= size;
3982 } else
3983 space = FALSE;
3984 *pcbNeeded += size;
3986 if(pi5) {
3987 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3988 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3989 "dnsTimeout");
3990 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3991 "txTimeout");
3994 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3995 memset(pi5, 0, sizeof(*pi5));
3997 return space;
4000 /*********************************************************************
4001 * WINSPOOL_GetPrinter_7
4003 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4005 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4006 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4008 DWORD size, left = cbBuf;
4009 BOOL space = (cbBuf > 0);
4010 LPBYTE ptr = buf;
4012 *pcbNeeded = 0;
4014 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4016 if (space && size <= left) {
4017 pi7->pszObjectGUID = (LPWSTR)ptr;
4018 ptr += size;
4019 left -= size;
4020 } else
4021 space = FALSE;
4022 *pcbNeeded += size;
4024 if (pi7) {
4025 /* We do not have a Directory Service */
4026 pi7->dwAction = DSPRINT_UNPUBLISH;
4029 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4030 memset(pi7, 0, sizeof(*pi7));
4032 return space;
4035 /*********************************************************************
4036 * WINSPOOL_GetPrinter_9
4038 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4039 * The strings are either stored as unicode or ascii.
4041 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4042 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4044 DWORD size;
4045 BOOL space = (cbBuf > 0);
4047 *pcbNeeded = 0;
4049 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4050 if(space && size <= cbBuf) {
4051 pi9->pDevMode = (LPDEVMODEW)buf;
4052 } else
4053 space = FALSE;
4054 *pcbNeeded += size;
4056 else
4058 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4059 if(space && size <= cbBuf) {
4060 pi9->pDevMode = (LPDEVMODEW)buf;
4061 } else
4062 space = FALSE;
4063 *pcbNeeded += size;
4066 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4067 memset(pi9, 0, sizeof(*pi9));
4069 return space;
4072 /*****************************************************************************
4073 * WINSPOOL_GetPrinter
4075 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4076 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4077 * just a collection of pointers to strings.
4079 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4080 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4082 LPCWSTR name;
4083 DWORD size, needed = 0;
4084 LPBYTE ptr = NULL;
4085 HKEY hkeyPrinter, hkeyPrinters;
4086 BOOL ret;
4088 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4090 if (!(name = get_opened_printer_name(hPrinter))) {
4091 SetLastError(ERROR_INVALID_HANDLE);
4092 return FALSE;
4095 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4096 ERROR_SUCCESS) {
4097 ERR("Can't create Printers key\n");
4098 return FALSE;
4100 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4102 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4103 RegCloseKey(hkeyPrinters);
4104 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4105 return FALSE;
4108 switch(Level) {
4109 case 2:
4111 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4113 size = sizeof(PRINTER_INFO_2W);
4114 if(size <= cbBuf) {
4115 ptr = pPrinter + size;
4116 cbBuf -= size;
4117 memset(pPrinter, 0, size);
4118 } else {
4119 pi2 = NULL;
4120 cbBuf = 0;
4122 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4123 unicode);
4124 needed += size;
4125 break;
4128 case 4:
4130 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4132 size = sizeof(PRINTER_INFO_4W);
4133 if(size <= cbBuf) {
4134 ptr = pPrinter + size;
4135 cbBuf -= size;
4136 memset(pPrinter, 0, size);
4137 } else {
4138 pi4 = NULL;
4139 cbBuf = 0;
4141 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4142 unicode);
4143 needed += size;
4144 break;
4148 case 5:
4150 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4152 size = sizeof(PRINTER_INFO_5W);
4153 if(size <= cbBuf) {
4154 ptr = pPrinter + size;
4155 cbBuf -= size;
4156 memset(pPrinter, 0, size);
4157 } else {
4158 pi5 = NULL;
4159 cbBuf = 0;
4162 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4163 unicode);
4164 needed += size;
4165 break;
4169 case 6:
4171 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4173 size = sizeof(PRINTER_INFO_6);
4174 if (size <= cbBuf) {
4175 /* FIXME: We do not update the status yet */
4176 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4177 ret = TRUE;
4178 } else {
4179 ret = FALSE;
4182 needed += size;
4183 break;
4186 case 7:
4188 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4190 size = sizeof(PRINTER_INFO_7W);
4191 if (size <= cbBuf) {
4192 ptr = pPrinter + size;
4193 cbBuf -= size;
4194 memset(pPrinter, 0, size);
4195 } else {
4196 pi7 = NULL;
4197 cbBuf = 0;
4200 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4201 needed += size;
4202 break;
4206 case 9:
4208 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4210 size = sizeof(PRINTER_INFO_9W);
4211 if(size <= cbBuf) {
4212 ptr = pPrinter + size;
4213 cbBuf -= size;
4214 memset(pPrinter, 0, size);
4215 } else {
4216 pi9 = NULL;
4217 cbBuf = 0;
4220 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4221 needed += size;
4222 break;
4226 default:
4227 FIXME("Unimplemented level %d\n", Level);
4228 SetLastError(ERROR_INVALID_LEVEL);
4229 RegCloseKey(hkeyPrinters);
4230 RegCloseKey(hkeyPrinter);
4231 return FALSE;
4234 RegCloseKey(hkeyPrinter);
4235 RegCloseKey(hkeyPrinters);
4237 TRACE("returning %d needed = %d\n", ret, needed);
4238 if(pcbNeeded) *pcbNeeded = needed;
4239 if(!ret)
4240 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4241 return ret;
4244 /*****************************************************************************
4245 * GetPrinterW [WINSPOOL.@]
4247 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4248 DWORD cbBuf, LPDWORD pcbNeeded)
4250 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4251 TRUE);
4254 /*****************************************************************************
4255 * GetPrinterA [WINSPOOL.@]
4257 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4258 DWORD cbBuf, LPDWORD pcbNeeded)
4260 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4261 FALSE);
4264 /*****************************************************************************
4265 * WINSPOOL_EnumPrinters
4267 * Implementation of EnumPrintersA|W
4269 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4270 DWORD dwLevel, LPBYTE lpbPrinters,
4271 DWORD cbBuf, LPDWORD lpdwNeeded,
4272 LPDWORD lpdwReturned, BOOL unicode)
4275 HKEY hkeyPrinters, hkeyPrinter;
4276 WCHAR PrinterName[255];
4277 DWORD needed = 0, number = 0;
4278 DWORD used, i, left;
4279 PBYTE pi, buf;
4281 if(lpbPrinters)
4282 memset(lpbPrinters, 0, cbBuf);
4283 if(lpdwReturned)
4284 *lpdwReturned = 0;
4285 if(lpdwNeeded)
4286 *lpdwNeeded = 0;
4288 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4289 if(dwType == PRINTER_ENUM_DEFAULT)
4290 return TRUE;
4292 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4293 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4294 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4295 if (!dwType) {
4296 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4297 *lpdwNeeded = 0;
4298 *lpdwReturned = 0;
4299 return TRUE;
4304 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4305 FIXME("dwType = %08x\n", dwType);
4306 SetLastError(ERROR_INVALID_FLAGS);
4307 return FALSE;
4310 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4311 ERROR_SUCCESS) {
4312 ERR("Can't create Printers key\n");
4313 return FALSE;
4316 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4317 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4318 RegCloseKey(hkeyPrinters);
4319 ERR("Can't query Printers key\n");
4320 return FALSE;
4322 TRACE("Found %d printers\n", number);
4324 switch(dwLevel) {
4325 case 1:
4326 used = number * sizeof(PRINTER_INFO_1W);
4327 break;
4328 case 2:
4329 used = number * sizeof(PRINTER_INFO_2W);
4330 break;
4331 case 4:
4332 used = number * sizeof(PRINTER_INFO_4W);
4333 break;
4334 case 5:
4335 used = number * sizeof(PRINTER_INFO_5W);
4336 break;
4338 default:
4339 SetLastError(ERROR_INVALID_LEVEL);
4340 RegCloseKey(hkeyPrinters);
4341 return FALSE;
4343 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4345 for(i = 0; i < number; i++) {
4346 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4347 ERROR_SUCCESS) {
4348 ERR("Can't enum key number %d\n", i);
4349 RegCloseKey(hkeyPrinters);
4350 return FALSE;
4352 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4353 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4354 ERROR_SUCCESS) {
4355 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4356 RegCloseKey(hkeyPrinters);
4357 return FALSE;
4360 if(cbBuf > used) {
4361 buf = lpbPrinters + used;
4362 left = cbBuf - used;
4363 } else {
4364 buf = NULL;
4365 left = 0;
4368 switch(dwLevel) {
4369 case 1:
4370 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4371 left, &needed, unicode);
4372 used += needed;
4373 if(pi) pi += sizeof(PRINTER_INFO_1W);
4374 break;
4375 case 2:
4376 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4377 left, &needed, unicode);
4378 used += needed;
4379 if(pi) pi += sizeof(PRINTER_INFO_2W);
4380 break;
4381 case 4:
4382 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4383 left, &needed, unicode);
4384 used += needed;
4385 if(pi) pi += sizeof(PRINTER_INFO_4W);
4386 break;
4387 case 5:
4388 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4389 left, &needed, unicode);
4390 used += needed;
4391 if(pi) pi += sizeof(PRINTER_INFO_5W);
4392 break;
4393 default:
4394 ERR("Shouldn't be here!\n");
4395 RegCloseKey(hkeyPrinter);
4396 RegCloseKey(hkeyPrinters);
4397 return FALSE;
4399 RegCloseKey(hkeyPrinter);
4401 RegCloseKey(hkeyPrinters);
4403 if(lpdwNeeded)
4404 *lpdwNeeded = used;
4406 if(used > cbBuf) {
4407 if(lpbPrinters)
4408 memset(lpbPrinters, 0, cbBuf);
4409 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4410 return FALSE;
4412 if(lpdwReturned)
4413 *lpdwReturned = number;
4414 SetLastError(ERROR_SUCCESS);
4415 return TRUE;
4419 /******************************************************************
4420 * EnumPrintersW [WINSPOOL.@]
4422 * Enumerates the available printers, print servers and print
4423 * providers, depending on the specified flags, name and level.
4425 * RETURNS:
4427 * If level is set to 1:
4428 * Returns an array of PRINTER_INFO_1 data structures in the
4429 * lpbPrinters buffer.
4431 * If level is set to 2:
4432 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4433 * Returns an array of PRINTER_INFO_2 data structures in the
4434 * lpbPrinters buffer. Note that according to MSDN also an
4435 * OpenPrinter should be performed on every remote printer.
4437 * If level is set to 4 (officially WinNT only):
4438 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4439 * Fast: Only the registry is queried to retrieve printer names,
4440 * no connection to the driver is made.
4441 * Returns an array of PRINTER_INFO_4 data structures in the
4442 * lpbPrinters buffer.
4444 * If level is set to 5 (officially WinNT4/Win9x only):
4445 * Fast: Only the registry is queried to retrieve printer names,
4446 * no connection to the driver is made.
4447 * Returns an array of PRINTER_INFO_5 data structures in the
4448 * lpbPrinters buffer.
4450 * If level set to 3 or 6+:
4451 * returns zero (failure!)
4453 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4454 * for information.
4456 * BUGS:
4457 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4458 * - Only levels 2, 4 and 5 are implemented at the moment.
4459 * - 16-bit printer drivers are not enumerated.
4460 * - Returned amount of bytes used/needed does not match the real Windoze
4461 * implementation (as in this implementation, all strings are part
4462 * of the buffer, whereas Win32 keeps them somewhere else)
4463 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4465 * NOTE:
4466 * - In a regular Wine installation, no registry settings for printers
4467 * exist, which makes this function return an empty list.
4469 BOOL WINAPI EnumPrintersW(
4470 DWORD dwType, /* [in] Types of print objects to enumerate */
4471 LPWSTR lpszName, /* [in] name of objects to enumerate */
4472 DWORD dwLevel, /* [in] type of printer info structure */
4473 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4474 DWORD cbBuf, /* [in] max size of buffer in bytes */
4475 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4476 LPDWORD lpdwReturned /* [out] number of entries returned */
4479 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4480 lpdwNeeded, lpdwReturned, TRUE);
4483 /******************************************************************
4484 * EnumPrintersA [WINSPOOL.@]
4487 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4488 DWORD dwLevel, LPBYTE lpbPrinters,
4489 DWORD cbBuf, LPDWORD lpdwNeeded,
4490 LPDWORD lpdwReturned)
4492 BOOL ret, unicode = FALSE;
4493 UNICODE_STRING lpszNameW;
4494 PWSTR pwstrNameW;
4496 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4497 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4498 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4499 lpdwNeeded, lpdwReturned, unicode);
4500 RtlFreeUnicodeString(&lpszNameW);
4501 return ret;
4504 /*****************************************************************************
4505 * WINSPOOL_GetDriverInfoFromReg [internal]
4507 * Enters the information from the registry into the DRIVER_INFO struct
4509 * RETURNS
4510 * zero if the printer driver does not exist in the registry
4511 * (only if Level > 1) otherwise nonzero
4513 static BOOL WINSPOOL_GetDriverInfoFromReg(
4514 HKEY hkeyDrivers,
4515 LPWSTR DriverName,
4516 const printenv_t * env,
4517 DWORD Level,
4518 LPBYTE ptr, /* DRIVER_INFO */
4519 LPBYTE pDriverStrings, /* strings buffer */
4520 DWORD cbBuf, /* size of string buffer */
4521 LPDWORD pcbNeeded, /* space needed for str. */
4522 BOOL unicode) /* type of strings */
4524 DWORD size, tmp;
4525 HKEY hkeyDriver;
4526 WCHAR driverdir[MAX_PATH];
4527 DWORD dirlen;
4528 LPBYTE strPtr = pDriverStrings;
4529 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4531 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4532 debugstr_w(DriverName), env,
4533 Level, di, pDriverStrings, cbBuf, unicode);
4535 if (di) ZeroMemory(di, di_sizeof[Level]);
4537 if (unicode) {
4538 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4539 if (*pcbNeeded <= cbBuf)
4540 strcpyW((LPWSTR)strPtr, DriverName);
4542 else
4544 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4545 if (*pcbNeeded <= cbBuf)
4546 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4549 /* pName for level 1 has a different offset! */
4550 if (Level == 1) {
4551 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4552 return TRUE;
4555 /* .cVersion and .pName for level > 1 */
4556 if (di) {
4557 di->cVersion = env->driverversion;
4558 di->pName = (LPWSTR) strPtr;
4559 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4562 /* Reserve Space for the largest subdir and a Backslash*/
4563 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4564 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4565 /* Should never Fail */
4566 return FALSE;
4568 lstrcatW(driverdir, env->versionsubdir);
4569 lstrcatW(driverdir, backslashW);
4571 /* dirlen must not include the terminating zero */
4572 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4573 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4575 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4576 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4577 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4578 return FALSE;
4581 /* pEnvironment */
4582 if (unicode)
4583 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4584 else
4585 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4587 *pcbNeeded += size;
4588 if (*pcbNeeded <= cbBuf) {
4589 if (unicode) {
4590 lstrcpyW((LPWSTR)strPtr, env->envname);
4592 else
4594 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4596 if (di) di->pEnvironment = (LPWSTR)strPtr;
4597 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4600 /* .pDriverPath is the Graphics rendering engine.
4601 The full Path is required to avoid a crash in some apps */
4602 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4603 *pcbNeeded += size;
4604 if (*pcbNeeded <= cbBuf)
4605 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4607 if (di) di->pDriverPath = (LPWSTR)strPtr;
4608 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4611 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4612 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4613 *pcbNeeded += size;
4614 if (*pcbNeeded <= cbBuf)
4615 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4617 if (di) di->pDataFile = (LPWSTR)strPtr;
4618 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4621 /* .pConfigFile is the Driver user Interface */
4622 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4623 *pcbNeeded += size;
4624 if (*pcbNeeded <= cbBuf)
4625 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4627 if (di) di->pConfigFile = (LPWSTR)strPtr;
4628 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4631 if (Level == 2 ) {
4632 RegCloseKey(hkeyDriver);
4633 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4634 return TRUE;
4637 if (Level == 5 ) {
4638 RegCloseKey(hkeyDriver);
4639 FIXME("level 5: incomplete\n");
4640 return TRUE;
4643 /* .pHelpFile */
4644 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4645 *pcbNeeded += size;
4646 if (*pcbNeeded <= cbBuf)
4647 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4649 if (di) di->pHelpFile = (LPWSTR)strPtr;
4650 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4653 /* .pDependentFiles */
4654 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4655 *pcbNeeded += size;
4656 if (*pcbNeeded <= cbBuf)
4657 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4659 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4660 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4662 else if (GetVersion() & 0x80000000) {
4663 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4664 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4665 *pcbNeeded += size;
4666 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4668 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4669 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4672 /* .pMonitorName is the optional Language Monitor */
4673 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4674 *pcbNeeded += size;
4675 if (*pcbNeeded <= cbBuf)
4676 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4678 if (di) di->pMonitorName = (LPWSTR)strPtr;
4679 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4682 /* .pDefaultDataType */
4683 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4684 *pcbNeeded += size;
4685 if(*pcbNeeded <= cbBuf)
4686 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4688 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4689 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4692 if (Level == 3 ) {
4693 RegCloseKey(hkeyDriver);
4694 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4695 return TRUE;
4698 /* .pszzPreviousNames */
4699 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4700 *pcbNeeded += size;
4701 if(*pcbNeeded <= cbBuf)
4702 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4704 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4705 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4708 if (Level == 4 ) {
4709 RegCloseKey(hkeyDriver);
4710 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4711 return TRUE;
4714 /* support is missing, but not important enough for a FIXME */
4715 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4717 /* .pszMfgName */
4718 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4719 *pcbNeeded += size;
4720 if(*pcbNeeded <= cbBuf)
4721 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4723 if (di) di->pszMfgName = (LPWSTR)strPtr;
4724 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4727 /* .pszOEMUrl */
4728 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4729 *pcbNeeded += size;
4730 if(*pcbNeeded <= cbBuf)
4731 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4733 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4734 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4737 /* .pszHardwareID */
4738 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4739 *pcbNeeded += size;
4740 if(*pcbNeeded <= cbBuf)
4741 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4743 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4744 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4747 /* .pszProvider */
4748 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4749 *pcbNeeded += size;
4750 if(*pcbNeeded <= cbBuf)
4751 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4753 if (di) di->pszProvider = (LPWSTR)strPtr;
4754 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4757 if (Level == 6 ) {
4758 RegCloseKey(hkeyDriver);
4759 return TRUE;
4762 /* support is missing, but not important enough for a FIXME */
4763 TRACE("level 8: incomplete\n");
4765 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4766 RegCloseKey(hkeyDriver);
4767 return TRUE;
4770 /*****************************************************************************
4771 * WINSPOOL_GetPrinterDriver
4773 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4774 DWORD Level, LPBYTE pDriverInfo,
4775 DWORD cbBuf, LPDWORD pcbNeeded,
4776 BOOL unicode)
4778 LPCWSTR name;
4779 WCHAR DriverName[100];
4780 DWORD ret, type, size, needed = 0;
4781 LPBYTE ptr = NULL;
4782 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4783 const printenv_t * env;
4785 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4786 Level,pDriverInfo,cbBuf, pcbNeeded);
4789 if (!(name = get_opened_printer_name(hPrinter))) {
4790 SetLastError(ERROR_INVALID_HANDLE);
4791 return FALSE;
4794 if (Level < 1 || Level == 7 || Level > 8) {
4795 SetLastError(ERROR_INVALID_LEVEL);
4796 return FALSE;
4799 env = validate_envW(pEnvironment);
4800 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4802 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4803 ERROR_SUCCESS) {
4804 ERR("Can't create Printers key\n");
4805 return FALSE;
4807 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4808 != ERROR_SUCCESS) {
4809 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4810 RegCloseKey(hkeyPrinters);
4811 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4812 return FALSE;
4814 size = sizeof(DriverName);
4815 DriverName[0] = 0;
4816 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4817 (LPBYTE)DriverName, &size);
4818 RegCloseKey(hkeyPrinter);
4819 RegCloseKey(hkeyPrinters);
4820 if(ret != ERROR_SUCCESS) {
4821 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4822 return FALSE;
4825 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4826 if(!hkeyDrivers) {
4827 ERR("Can't create Drivers key\n");
4828 return FALSE;
4831 size = di_sizeof[Level];
4832 if ((size <= cbBuf) && pDriverInfo)
4833 ptr = pDriverInfo + size;
4835 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4836 env, Level, pDriverInfo, ptr,
4837 (cbBuf < size) ? 0 : cbBuf - size,
4838 &needed, unicode)) {
4839 RegCloseKey(hkeyDrivers);
4840 return FALSE;
4843 RegCloseKey(hkeyDrivers);
4845 if(pcbNeeded) *pcbNeeded = size + needed;
4846 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4847 if(cbBuf >= needed) return TRUE;
4848 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4849 return FALSE;
4852 /*****************************************************************************
4853 * GetPrinterDriverA [WINSPOOL.@]
4855 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4856 DWORD Level, LPBYTE pDriverInfo,
4857 DWORD cbBuf, LPDWORD pcbNeeded)
4859 BOOL ret;
4860 UNICODE_STRING pEnvW;
4861 PWSTR pwstrEnvW;
4863 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4864 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4865 cbBuf, pcbNeeded, FALSE);
4866 RtlFreeUnicodeString(&pEnvW);
4867 return ret;
4869 /*****************************************************************************
4870 * GetPrinterDriverW [WINSPOOL.@]
4872 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4873 DWORD Level, LPBYTE pDriverInfo,
4874 DWORD cbBuf, LPDWORD pcbNeeded)
4876 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4877 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4880 /*****************************************************************************
4881 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4883 * Return the PATH for the Printer-Drivers (UNICODE)
4885 * PARAMS
4886 * pName [I] Servername (NT only) or NULL (local Computer)
4887 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4888 * Level [I] Structure-Level (must be 1)
4889 * pDriverDirectory [O] PTR to Buffer that receives the Result
4890 * cbBuf [I] Size of Buffer at pDriverDirectory
4891 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4892 * required for pDriverDirectory
4894 * RETURNS
4895 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4896 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4897 * if cbBuf is too small
4899 * Native Values returned in pDriverDirectory on Success:
4900 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4901 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4902 *| win9x(Windows 4.0): "%winsysdir%"
4904 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4906 * FIXME
4907 *- Only NULL or "" is supported for pName
4910 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4911 DWORD Level, LPBYTE pDriverDirectory,
4912 DWORD cbBuf, LPDWORD pcbNeeded)
4914 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4915 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4917 if ((backend == NULL) && !load_backend()) return FALSE;
4919 if (Level != 1) {
4920 /* (Level != 1) is ignored in win9x */
4921 SetLastError(ERROR_INVALID_LEVEL);
4922 return FALSE;
4924 if (pcbNeeded == NULL) {
4925 /* (pcbNeeded == NULL) is ignored in win9x */
4926 SetLastError(RPC_X_NULL_REF_POINTER);
4927 return FALSE;
4930 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4931 pDriverDirectory, cbBuf, pcbNeeded);
4936 /*****************************************************************************
4937 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4939 * Return the PATH for the Printer-Drivers (ANSI)
4941 * See GetPrinterDriverDirectoryW.
4943 * NOTES
4944 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4947 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4948 DWORD Level, LPBYTE pDriverDirectory,
4949 DWORD cbBuf, LPDWORD pcbNeeded)
4951 UNICODE_STRING nameW, environmentW;
4952 BOOL ret;
4953 DWORD pcbNeededW;
4954 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4955 WCHAR *driverDirectoryW = NULL;
4957 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4958 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4960 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4962 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4963 else nameW.Buffer = NULL;
4964 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4965 else environmentW.Buffer = NULL;
4967 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4968 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4969 if (ret) {
4970 DWORD needed;
4971 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4972 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4973 if(pcbNeeded)
4974 *pcbNeeded = needed;
4975 ret = (needed <= cbBuf) ? TRUE : FALSE;
4976 } else
4977 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4979 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4981 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4982 RtlFreeUnicodeString(&environmentW);
4983 RtlFreeUnicodeString(&nameW);
4985 return ret;
4988 /*****************************************************************************
4989 * AddPrinterDriverA [WINSPOOL.@]
4991 * See AddPrinterDriverW.
4994 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4996 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4997 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5000 /******************************************************************************
5001 * AddPrinterDriverW (WINSPOOL.@)
5003 * Install a Printer Driver
5005 * PARAMS
5006 * pName [I] Servername or NULL (local Computer)
5007 * level [I] Level for the supplied DRIVER_INFO_*W struct
5008 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5010 * RESULTS
5011 * Success: TRUE
5012 * Failure: FALSE
5015 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5017 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5018 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5021 /*****************************************************************************
5022 * AddPrintProcessorA [WINSPOOL.@]
5024 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5025 LPSTR pPrintProcessorName)
5027 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5028 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5029 return FALSE;
5032 /*****************************************************************************
5033 * AddPrintProcessorW [WINSPOOL.@]
5035 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5036 LPWSTR pPrintProcessorName)
5038 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5039 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5040 return FALSE;
5043 /*****************************************************************************
5044 * AddPrintProvidorA [WINSPOOL.@]
5046 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5048 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5049 return FALSE;
5052 /*****************************************************************************
5053 * AddPrintProvidorW [WINSPOOL.@]
5055 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5057 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5058 return FALSE;
5061 /*****************************************************************************
5062 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5064 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5065 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5067 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5068 pDevModeOutput, pDevModeInput);
5069 return 0;
5072 /*****************************************************************************
5073 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5075 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5076 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5078 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5079 pDevModeOutput, pDevModeInput);
5080 return 0;
5083 /*****************************************************************************
5084 * PrinterProperties [WINSPOOL.@]
5086 * Displays a dialog to set the properties of the printer.
5088 * RETURNS
5089 * nonzero on success or zero on failure
5091 * BUGS
5092 * implemented as stub only
5094 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5095 HANDLE hPrinter /* [in] handle to printer object */
5097 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5098 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5099 return FALSE;
5102 /*****************************************************************************
5103 * EnumJobsA [WINSPOOL.@]
5106 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5107 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5108 LPDWORD pcReturned)
5110 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5111 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5113 if(pcbNeeded) *pcbNeeded = 0;
5114 if(pcReturned) *pcReturned = 0;
5115 return FALSE;
5119 /*****************************************************************************
5120 * EnumJobsW [WINSPOOL.@]
5123 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5124 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5125 LPDWORD pcReturned)
5127 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5128 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5130 if(pcbNeeded) *pcbNeeded = 0;
5131 if(pcReturned) *pcReturned = 0;
5132 return FALSE;
5135 /*****************************************************************************
5136 * WINSPOOL_EnumPrinterDrivers [internal]
5138 * Delivers information about all printer drivers installed on the
5139 * localhost or a given server
5141 * RETURNS
5142 * nonzero on success or zero on failure. If the buffer for the returned
5143 * information is too small the function will return an error
5145 * BUGS
5146 * - only implemented for localhost, foreign hosts will return an error
5148 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5149 DWORD Level, LPBYTE pDriverInfo,
5150 DWORD cbBuf, LPDWORD pcbNeeded,
5151 LPDWORD pcReturned, BOOL unicode)
5153 { HKEY hkeyDrivers;
5154 DWORD i, needed, number = 0, size = 0;
5155 WCHAR DriverNameW[255];
5156 PBYTE ptr;
5157 const printenv_t * env;
5159 TRACE("%s,%s,%d,%p,%d,%d\n",
5160 debugstr_w(pName), debugstr_w(pEnvironment),
5161 Level, pDriverInfo, cbBuf, unicode);
5163 /* check for local drivers */
5164 if((pName) && (pName[0])) {
5165 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5166 SetLastError(ERROR_ACCESS_DENIED);
5167 return FALSE;
5170 env = validate_envW(pEnvironment);
5171 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5173 /* check input parameter */
5174 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5175 SetLastError(ERROR_INVALID_LEVEL);
5176 return FALSE;
5179 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5180 SetLastError(RPC_X_NULL_REF_POINTER);
5181 return FALSE;
5184 /* initialize return values */
5185 if(pDriverInfo)
5186 memset( pDriverInfo, 0, cbBuf);
5187 *pcbNeeded = 0;
5188 *pcReturned = 0;
5190 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5191 if(!hkeyDrivers) {
5192 ERR("Can't open Drivers key\n");
5193 return FALSE;
5196 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5197 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5198 RegCloseKey(hkeyDrivers);
5199 ERR("Can't query Drivers key\n");
5200 return FALSE;
5202 TRACE("Found %d Drivers\n", number);
5204 /* get size of single struct
5205 * unicode and ascii structure have the same size
5207 size = di_sizeof[Level];
5209 /* calculate required buffer size */
5210 *pcbNeeded = size * number;
5212 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5213 i < number;
5214 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5215 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5216 != ERROR_SUCCESS) {
5217 ERR("Can't enum key number %d\n", i);
5218 RegCloseKey(hkeyDrivers);
5219 return FALSE;
5221 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5222 env, Level, ptr,
5223 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5224 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5225 &needed, unicode)) {
5226 RegCloseKey(hkeyDrivers);
5227 return FALSE;
5229 (*pcbNeeded) += needed;
5232 RegCloseKey(hkeyDrivers);
5234 if(cbBuf < *pcbNeeded){
5235 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5236 return FALSE;
5239 *pcReturned = number;
5240 return TRUE;
5243 /*****************************************************************************
5244 * EnumPrinterDriversW [WINSPOOL.@]
5246 * see function EnumPrinterDrivers for RETURNS, BUGS
5248 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5249 LPBYTE pDriverInfo, DWORD cbBuf,
5250 LPDWORD pcbNeeded, LPDWORD pcReturned)
5252 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5253 cbBuf, pcbNeeded, pcReturned, TRUE);
5256 /*****************************************************************************
5257 * EnumPrinterDriversA [WINSPOOL.@]
5259 * see function EnumPrinterDrivers for RETURNS, BUGS
5261 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5262 LPBYTE pDriverInfo, DWORD cbBuf,
5263 LPDWORD pcbNeeded, LPDWORD pcReturned)
5264 { BOOL ret;
5265 UNICODE_STRING pNameW, pEnvironmentW;
5266 PWSTR pwstrNameW, pwstrEnvironmentW;
5268 pwstrNameW = asciitounicode(&pNameW, pName);
5269 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5271 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5272 Level, pDriverInfo, cbBuf, pcbNeeded,
5273 pcReturned, FALSE);
5274 RtlFreeUnicodeString(&pNameW);
5275 RtlFreeUnicodeString(&pEnvironmentW);
5277 return ret;
5280 /******************************************************************************
5281 * EnumPortsA (WINSPOOL.@)
5283 * See EnumPortsW.
5286 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5287 LPDWORD pcbNeeded, LPDWORD pcReturned)
5289 BOOL res;
5290 LPBYTE bufferW = NULL;
5291 LPWSTR nameW = NULL;
5292 DWORD needed = 0;
5293 DWORD numentries = 0;
5294 INT len;
5296 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5297 cbBuf, pcbNeeded, pcReturned);
5299 /* convert servername to unicode */
5300 if (pName) {
5301 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5302 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5303 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5305 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5306 needed = cbBuf * sizeof(WCHAR);
5307 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5308 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5310 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5311 if (pcbNeeded) needed = *pcbNeeded;
5312 /* HeapReAlloc return NULL, when bufferW was NULL */
5313 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5314 HeapAlloc(GetProcessHeap(), 0, needed);
5316 /* Try again with the large Buffer */
5317 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5319 needed = pcbNeeded ? *pcbNeeded : 0;
5320 numentries = pcReturned ? *pcReturned : 0;
5323 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5324 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5326 if (res) {
5327 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5328 DWORD entrysize = 0;
5329 DWORD index;
5330 LPSTR ptr;
5331 LPPORT_INFO_2W pi2w;
5332 LPPORT_INFO_2A pi2a;
5334 needed = 0;
5335 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5337 /* First pass: calculate the size for all Entries */
5338 pi2w = (LPPORT_INFO_2W) bufferW;
5339 pi2a = (LPPORT_INFO_2A) pPorts;
5340 index = 0;
5341 while (index < numentries) {
5342 index++;
5343 needed += entrysize; /* PORT_INFO_?A */
5344 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5346 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5347 NULL, 0, NULL, NULL);
5348 if (Level > 1) {
5349 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5350 NULL, 0, NULL, NULL);
5351 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5352 NULL, 0, NULL, NULL);
5354 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5355 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5356 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5359 /* check for errors and quit on failure */
5360 if (cbBuf < needed) {
5361 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5362 res = FALSE;
5363 goto cleanup;
5365 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5366 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5367 cbBuf -= len ; /* free Bytes in the user-Buffer */
5368 pi2w = (LPPORT_INFO_2W) bufferW;
5369 pi2a = (LPPORT_INFO_2A) pPorts;
5370 index = 0;
5371 /* Second Pass: Fill the User Buffer (if we have one) */
5372 while ((index < numentries) && pPorts) {
5373 index++;
5374 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5375 pi2a->pPortName = ptr;
5376 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5377 ptr, cbBuf , NULL, NULL);
5378 ptr += len;
5379 cbBuf -= len;
5380 if (Level > 1) {
5381 pi2a->pMonitorName = ptr;
5382 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5383 ptr, cbBuf, NULL, NULL);
5384 ptr += len;
5385 cbBuf -= len;
5387 pi2a->pDescription = ptr;
5388 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5389 ptr, cbBuf, NULL, NULL);
5390 ptr += len;
5391 cbBuf -= len;
5393 pi2a->fPortType = pi2w->fPortType;
5394 pi2a->Reserved = 0; /* documented: "must be zero" */
5397 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5398 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5399 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5403 cleanup:
5404 if (pcbNeeded) *pcbNeeded = needed;
5405 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5407 HeapFree(GetProcessHeap(), 0, nameW);
5408 HeapFree(GetProcessHeap(), 0, bufferW);
5410 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5411 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5413 return (res);
5417 /******************************************************************************
5418 * EnumPortsW (WINSPOOL.@)
5420 * Enumerate available Ports
5422 * PARAMS
5423 * name [I] Servername or NULL (local Computer)
5424 * level [I] Structure-Level (1 or 2)
5425 * buffer [O] PTR to Buffer that receives the Result
5426 * bufsize [I] Size of Buffer at buffer
5427 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5428 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5430 * RETURNS
5431 * Success: TRUE
5432 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5436 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5438 DWORD needed = 0;
5439 DWORD numentries = 0;
5440 BOOL res = FALSE;
5442 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5443 cbBuf, pcbNeeded, pcReturned);
5445 if (pName && (pName[0])) {
5446 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5447 SetLastError(ERROR_ACCESS_DENIED);
5448 goto emP_cleanup;
5451 /* Level is not checked in win9x */
5452 if (!Level || (Level > 2)) {
5453 WARN("level (%d) is ignored in win9x\n", Level);
5454 SetLastError(ERROR_INVALID_LEVEL);
5455 goto emP_cleanup;
5457 if (!pcbNeeded) {
5458 SetLastError(RPC_X_NULL_REF_POINTER);
5459 goto emP_cleanup;
5462 EnterCriticalSection(&monitor_handles_cs);
5463 monitor_loadall();
5465 /* Scan all local Ports */
5466 numentries = 0;
5467 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5469 /* we calculated the needed buffersize. now do the error-checks */
5470 if (cbBuf < needed) {
5471 monitor_unloadall();
5472 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5473 goto emP_cleanup_cs;
5475 else if (!pPorts || !pcReturned) {
5476 monitor_unloadall();
5477 SetLastError(RPC_X_NULL_REF_POINTER);
5478 goto emP_cleanup_cs;
5481 /* Fill the Buffer */
5482 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5483 res = TRUE;
5484 monitor_unloadall();
5486 emP_cleanup_cs:
5487 LeaveCriticalSection(&monitor_handles_cs);
5489 emP_cleanup:
5490 if (pcbNeeded) *pcbNeeded = needed;
5491 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5493 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5494 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5496 return (res);
5499 /******************************************************************************
5500 * GetDefaultPrinterW (WINSPOOL.@)
5502 * FIXME
5503 * This function must read the value from data 'device' of key
5504 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5506 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5508 BOOL retval = TRUE;
5509 DWORD insize, len;
5510 WCHAR *buffer, *ptr;
5512 if (!namesize)
5514 SetLastError(ERROR_INVALID_PARAMETER);
5515 return FALSE;
5518 /* make the buffer big enough for the stuff from the profile/registry,
5519 * the content must fit into the local buffer to compute the correct
5520 * size even if the extern buffer is too small or not given.
5521 * (20 for ,driver,port) */
5522 insize = *namesize;
5523 len = max(100, (insize + 20));
5524 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5526 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5528 SetLastError (ERROR_FILE_NOT_FOUND);
5529 retval = FALSE;
5530 goto end;
5532 TRACE("%s\n", debugstr_w(buffer));
5534 if ((ptr = strchrW(buffer, ',')) == NULL)
5536 SetLastError(ERROR_INVALID_NAME);
5537 retval = FALSE;
5538 goto end;
5541 *ptr = 0;
5542 *namesize = strlenW(buffer) + 1;
5543 if(!name || (*namesize > insize))
5545 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5546 retval = FALSE;
5547 goto end;
5549 strcpyW(name, buffer);
5551 end:
5552 HeapFree( GetProcessHeap(), 0, buffer);
5553 return retval;
5557 /******************************************************************************
5558 * GetDefaultPrinterA (WINSPOOL.@)
5560 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5562 BOOL retval = TRUE;
5563 DWORD insize = 0;
5564 WCHAR *bufferW = NULL;
5566 if (!namesize)
5568 SetLastError(ERROR_INVALID_PARAMETER);
5569 return FALSE;
5572 if(name && *namesize) {
5573 insize = *namesize;
5574 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5577 if(!GetDefaultPrinterW( bufferW, namesize)) {
5578 retval = FALSE;
5579 goto end;
5582 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5583 NULL, NULL);
5584 if (!*namesize)
5586 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5587 retval = FALSE;
5589 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5591 end:
5592 HeapFree( GetProcessHeap(), 0, bufferW);
5593 return retval;
5597 /******************************************************************************
5598 * SetDefaultPrinterW (WINSPOOL.204)
5600 * Set the Name of the Default Printer
5602 * PARAMS
5603 * pszPrinter [I] Name of the Printer or NULL
5605 * RETURNS
5606 * Success: True
5607 * Failure: FALSE
5609 * NOTES
5610 * When the Parameter is NULL or points to an Empty String and
5611 * a Default Printer was already present, then this Function changes nothing.
5612 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5613 * the First enumerated local Printer is used.
5616 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5619 TRACE("(%s)\n", debugstr_w(pszPrinter));
5621 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5622 return FALSE;
5625 /******************************************************************************
5626 * SetDefaultPrinterA (WINSPOOL.202)
5628 * See SetDefaultPrinterW.
5631 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5634 TRACE("(%s)\n", debugstr_a(pszPrinter));
5636 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5637 return FALSE;
5641 /******************************************************************************
5642 * SetPrinterDataExA (WINSPOOL.@)
5644 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5645 LPCSTR pValueName, DWORD Type,
5646 LPBYTE pData, DWORD cbData)
5648 HKEY hkeyPrinter, hkeySubkey;
5649 DWORD ret;
5651 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5652 debugstr_a(pValueName), Type, pData, cbData);
5654 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5655 != ERROR_SUCCESS)
5656 return ret;
5658 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5659 != ERROR_SUCCESS) {
5660 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5661 RegCloseKey(hkeyPrinter);
5662 return ret;
5664 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5665 RegCloseKey(hkeySubkey);
5666 RegCloseKey(hkeyPrinter);
5667 return ret;
5670 /******************************************************************************
5671 * SetPrinterDataExW (WINSPOOL.@)
5673 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5674 LPCWSTR pValueName, DWORD Type,
5675 LPBYTE pData, DWORD cbData)
5677 HKEY hkeyPrinter, hkeySubkey;
5678 DWORD ret;
5680 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5681 debugstr_w(pValueName), Type, pData, cbData);
5683 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5684 != ERROR_SUCCESS)
5685 return ret;
5687 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5688 != ERROR_SUCCESS) {
5689 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5690 RegCloseKey(hkeyPrinter);
5691 return ret;
5693 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5694 RegCloseKey(hkeySubkey);
5695 RegCloseKey(hkeyPrinter);
5696 return ret;
5699 /******************************************************************************
5700 * SetPrinterDataA (WINSPOOL.@)
5702 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5703 LPBYTE pData, DWORD cbData)
5705 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5706 pData, cbData);
5709 /******************************************************************************
5710 * SetPrinterDataW (WINSPOOL.@)
5712 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5713 LPBYTE pData, DWORD cbData)
5715 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5716 pData, cbData);
5719 /******************************************************************************
5720 * GetPrinterDataExA (WINSPOOL.@)
5722 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5723 LPCSTR pValueName, LPDWORD pType,
5724 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5726 HKEY hkeyPrinter, hkeySubkey;
5727 DWORD ret;
5729 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5730 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5731 pcbNeeded);
5733 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5734 != ERROR_SUCCESS)
5735 return ret;
5737 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5738 != ERROR_SUCCESS) {
5739 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5740 RegCloseKey(hkeyPrinter);
5741 return ret;
5743 *pcbNeeded = nSize;
5744 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5745 RegCloseKey(hkeySubkey);
5746 RegCloseKey(hkeyPrinter);
5747 return ret;
5750 /******************************************************************************
5751 * GetPrinterDataExW (WINSPOOL.@)
5753 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5754 LPCWSTR pValueName, LPDWORD pType,
5755 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5757 HKEY hkeyPrinter, hkeySubkey;
5758 DWORD ret;
5760 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5761 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5762 pcbNeeded);
5764 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5765 != ERROR_SUCCESS)
5766 return ret;
5768 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5769 != ERROR_SUCCESS) {
5770 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5771 RegCloseKey(hkeyPrinter);
5772 return ret;
5774 *pcbNeeded = nSize;
5775 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5776 RegCloseKey(hkeySubkey);
5777 RegCloseKey(hkeyPrinter);
5778 return ret;
5781 /******************************************************************************
5782 * GetPrinterDataA (WINSPOOL.@)
5784 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5785 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5787 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5788 pData, nSize, pcbNeeded);
5791 /******************************************************************************
5792 * GetPrinterDataW (WINSPOOL.@)
5794 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5795 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5797 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5798 pData, nSize, pcbNeeded);
5801 /*******************************************************************************
5802 * EnumPrinterDataExW [WINSPOOL.@]
5804 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5805 LPBYTE pEnumValues, DWORD cbEnumValues,
5806 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5808 HKEY hkPrinter, hkSubKey;
5809 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5810 cbValueNameLen, cbMaxValueLen, cbValueLen,
5811 cbBufSize, dwType;
5812 LPWSTR lpValueName;
5813 HANDLE hHeap;
5814 PBYTE lpValue;
5815 PPRINTER_ENUM_VALUESW ppev;
5817 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5819 if (pKeyName == NULL || *pKeyName == 0)
5820 return ERROR_INVALID_PARAMETER;
5822 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5823 if (ret != ERROR_SUCCESS)
5825 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5826 hPrinter, ret);
5827 return ret;
5830 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5831 if (ret != ERROR_SUCCESS)
5833 r = RegCloseKey (hkPrinter);
5834 if (r != ERROR_SUCCESS)
5835 WARN ("RegCloseKey returned %i\n", r);
5836 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5837 debugstr_w (pKeyName), ret);
5838 return ret;
5841 ret = RegCloseKey (hkPrinter);
5842 if (ret != ERROR_SUCCESS)
5844 ERR ("RegCloseKey returned %i\n", ret);
5845 r = RegCloseKey (hkSubKey);
5846 if (r != ERROR_SUCCESS)
5847 WARN ("RegCloseKey returned %i\n", r);
5848 return ret;
5851 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5852 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5853 if (ret != ERROR_SUCCESS)
5855 r = RegCloseKey (hkSubKey);
5856 if (r != ERROR_SUCCESS)
5857 WARN ("RegCloseKey returned %i\n", r);
5858 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5859 return ret;
5862 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5863 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5865 if (cValues == 0) /* empty key */
5867 r = RegCloseKey (hkSubKey);
5868 if (r != ERROR_SUCCESS)
5869 WARN ("RegCloseKey returned %i\n", r);
5870 *pcbEnumValues = *pnEnumValues = 0;
5871 return ERROR_SUCCESS;
5874 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5876 hHeap = GetProcessHeap ();
5877 if (hHeap == NULL)
5879 ERR ("GetProcessHeap failed\n");
5880 r = RegCloseKey (hkSubKey);
5881 if (r != ERROR_SUCCESS)
5882 WARN ("RegCloseKey returned %i\n", r);
5883 return ERROR_OUTOFMEMORY;
5886 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5887 if (lpValueName == NULL)
5889 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5890 r = RegCloseKey (hkSubKey);
5891 if (r != ERROR_SUCCESS)
5892 WARN ("RegCloseKey returned %i\n", r);
5893 return ERROR_OUTOFMEMORY;
5896 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5897 if (lpValue == NULL)
5899 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5900 if (HeapFree (hHeap, 0, lpValueName) == 0)
5901 WARN ("HeapFree failed with code %i\n", GetLastError ());
5902 r = RegCloseKey (hkSubKey);
5903 if (r != ERROR_SUCCESS)
5904 WARN ("RegCloseKey returned %i\n", r);
5905 return ERROR_OUTOFMEMORY;
5908 TRACE ("pass 1: calculating buffer required for all names and values\n");
5910 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5912 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5914 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5916 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5917 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5918 NULL, NULL, lpValue, &cbValueLen);
5919 if (ret != ERROR_SUCCESS)
5921 if (HeapFree (hHeap, 0, lpValue) == 0)
5922 WARN ("HeapFree failed with code %i\n", GetLastError ());
5923 if (HeapFree (hHeap, 0, lpValueName) == 0)
5924 WARN ("HeapFree failed with code %i\n", GetLastError ());
5925 r = RegCloseKey (hkSubKey);
5926 if (r != ERROR_SUCCESS)
5927 WARN ("RegCloseKey returned %i\n", r);
5928 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5929 return ret;
5932 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5933 debugstr_w (lpValueName), dwIndex,
5934 cbValueNameLen + 1, cbValueLen);
5936 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5937 cbBufSize += cbValueLen;
5940 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5942 *pcbEnumValues = cbBufSize;
5943 *pnEnumValues = cValues;
5945 if (cbEnumValues < cbBufSize) /* buffer too small */
5947 if (HeapFree (hHeap, 0, lpValue) == 0)
5948 WARN ("HeapFree failed with code %i\n", GetLastError ());
5949 if (HeapFree (hHeap, 0, lpValueName) == 0)
5950 WARN ("HeapFree failed with code %i\n", GetLastError ());
5951 r = RegCloseKey (hkSubKey);
5952 if (r != ERROR_SUCCESS)
5953 WARN ("RegCloseKey returned %i\n", r);
5954 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5955 return ERROR_MORE_DATA;
5958 TRACE ("pass 2: copying all names and values to buffer\n");
5960 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5961 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5963 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5965 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5966 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5967 NULL, &dwType, lpValue, &cbValueLen);
5968 if (ret != ERROR_SUCCESS)
5970 if (HeapFree (hHeap, 0, lpValue) == 0)
5971 WARN ("HeapFree failed with code %i\n", GetLastError ());
5972 if (HeapFree (hHeap, 0, lpValueName) == 0)
5973 WARN ("HeapFree failed with code %i\n", GetLastError ());
5974 r = RegCloseKey (hkSubKey);
5975 if (r != ERROR_SUCCESS)
5976 WARN ("RegCloseKey returned %i\n", r);
5977 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5978 return ret;
5981 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5982 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5983 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5984 pEnumValues += cbValueNameLen;
5986 /* return # of *bytes* (including trailing \0), not # of chars */
5987 ppev[dwIndex].cbValueName = cbValueNameLen;
5989 ppev[dwIndex].dwType = dwType;
5991 memcpy (pEnumValues, lpValue, cbValueLen);
5992 ppev[dwIndex].pData = pEnumValues;
5993 pEnumValues += cbValueLen;
5995 ppev[dwIndex].cbData = cbValueLen;
5997 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5998 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6001 if (HeapFree (hHeap, 0, lpValue) == 0)
6003 ret = GetLastError ();
6004 ERR ("HeapFree failed with code %i\n", ret);
6005 if (HeapFree (hHeap, 0, lpValueName) == 0)
6006 WARN ("HeapFree failed with code %i\n", GetLastError ());
6007 r = RegCloseKey (hkSubKey);
6008 if (r != ERROR_SUCCESS)
6009 WARN ("RegCloseKey returned %i\n", r);
6010 return ret;
6013 if (HeapFree (hHeap, 0, lpValueName) == 0)
6015 ret = GetLastError ();
6016 ERR ("HeapFree failed with code %i\n", ret);
6017 r = RegCloseKey (hkSubKey);
6018 if (r != ERROR_SUCCESS)
6019 WARN ("RegCloseKey returned %i\n", r);
6020 return ret;
6023 ret = RegCloseKey (hkSubKey);
6024 if (ret != ERROR_SUCCESS)
6026 ERR ("RegCloseKey returned %i\n", ret);
6027 return ret;
6030 return ERROR_SUCCESS;
6033 /*******************************************************************************
6034 * EnumPrinterDataExA [WINSPOOL.@]
6036 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6037 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6038 * what Windows 2000 SP1 does.
6041 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6042 LPBYTE pEnumValues, DWORD cbEnumValues,
6043 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6045 INT len;
6046 LPWSTR pKeyNameW;
6047 DWORD ret, dwIndex, dwBufSize;
6048 HANDLE hHeap;
6049 LPSTR pBuffer;
6051 TRACE ("%p %s\n", hPrinter, pKeyName);
6053 if (pKeyName == NULL || *pKeyName == 0)
6054 return ERROR_INVALID_PARAMETER;
6056 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6057 if (len == 0)
6059 ret = GetLastError ();
6060 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6061 return ret;
6064 hHeap = GetProcessHeap ();
6065 if (hHeap == NULL)
6067 ERR ("GetProcessHeap failed\n");
6068 return ERROR_OUTOFMEMORY;
6071 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6072 if (pKeyNameW == NULL)
6074 ERR ("Failed to allocate %i bytes from process heap\n",
6075 (LONG)(len * sizeof (WCHAR)));
6076 return ERROR_OUTOFMEMORY;
6079 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6081 ret = GetLastError ();
6082 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6083 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6084 WARN ("HeapFree failed with code %i\n", GetLastError ());
6085 return ret;
6088 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6089 pcbEnumValues, pnEnumValues);
6090 if (ret != ERROR_SUCCESS)
6092 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6093 WARN ("HeapFree failed with code %i\n", GetLastError ());
6094 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6095 return ret;
6098 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6100 ret = GetLastError ();
6101 ERR ("HeapFree failed with code %i\n", ret);
6102 return ret;
6105 if (*pnEnumValues == 0) /* empty key */
6106 return ERROR_SUCCESS;
6108 dwBufSize = 0;
6109 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6111 PPRINTER_ENUM_VALUESW ppev =
6112 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6114 if (dwBufSize < ppev->cbValueName)
6115 dwBufSize = ppev->cbValueName;
6117 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6118 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6119 dwBufSize = ppev->cbData;
6122 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6124 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6125 if (pBuffer == NULL)
6127 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6128 return ERROR_OUTOFMEMORY;
6131 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6133 PPRINTER_ENUM_VALUESW ppev =
6134 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6136 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6137 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6138 NULL);
6139 if (len == 0)
6141 ret = GetLastError ();
6142 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6143 if (HeapFree (hHeap, 0, pBuffer) == 0)
6144 WARN ("HeapFree failed with code %i\n", GetLastError ());
6145 return ret;
6148 memcpy (ppev->pValueName, pBuffer, len);
6150 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6152 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6153 ppev->dwType != REG_MULTI_SZ)
6154 continue;
6156 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6157 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6158 if (len == 0)
6160 ret = GetLastError ();
6161 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6162 if (HeapFree (hHeap, 0, pBuffer) == 0)
6163 WARN ("HeapFree failed with code %i\n", GetLastError ());
6164 return ret;
6167 memcpy (ppev->pData, pBuffer, len);
6169 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6170 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6173 if (HeapFree (hHeap, 0, pBuffer) == 0)
6175 ret = GetLastError ();
6176 ERR ("HeapFree failed with code %i\n", ret);
6177 return ret;
6180 return ERROR_SUCCESS;
6183 /******************************************************************************
6184 * AbortPrinter (WINSPOOL.@)
6186 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6188 FIXME("(%p), stub!\n", hPrinter);
6189 return TRUE;
6192 /******************************************************************************
6193 * AddPortA (WINSPOOL.@)
6195 * See AddPortW.
6198 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6200 LPWSTR nameW = NULL;
6201 LPWSTR monitorW = NULL;
6202 DWORD len;
6203 BOOL res;
6205 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6207 if (pName) {
6208 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6209 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6210 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6213 if (pMonitorName) {
6214 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6215 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6216 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6218 res = AddPortW(nameW, hWnd, monitorW);
6219 HeapFree(GetProcessHeap(), 0, nameW);
6220 HeapFree(GetProcessHeap(), 0, monitorW);
6221 return res;
6224 /******************************************************************************
6225 * AddPortW (WINSPOOL.@)
6227 * Add a Port for a specific Monitor
6229 * PARAMS
6230 * pName [I] Servername or NULL (local Computer)
6231 * hWnd [I] Handle to parent Window for the Dialog-Box
6232 * pMonitorName [I] Name of the Monitor that manage the Port
6234 * RETURNS
6235 * Success: TRUE
6236 * Failure: FALSE
6239 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6241 monitor_t * pm;
6242 monitor_t * pui;
6243 DWORD res;
6245 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6247 if (pName && pName[0]) {
6248 SetLastError(ERROR_INVALID_PARAMETER);
6249 return FALSE;
6252 if (!pMonitorName) {
6253 SetLastError(RPC_X_NULL_REF_POINTER);
6254 return FALSE;
6257 /* an empty Monitorname is Invalid */
6258 if (!pMonitorName[0]) {
6259 SetLastError(ERROR_NOT_SUPPORTED);
6260 return FALSE;
6263 pm = monitor_load(pMonitorName, NULL);
6264 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6265 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6266 TRACE("got %d with %u\n", res, GetLastError());
6267 res = TRUE;
6269 else
6271 pui = monitor_loadui(pm);
6272 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6273 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6274 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6275 TRACE("got %d with %u\n", res, GetLastError());
6276 res = TRUE;
6278 else
6280 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6281 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6283 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6284 SetLastError(ERROR_NOT_SUPPORTED);
6285 res = FALSE;
6287 monitor_unload(pui);
6289 monitor_unload(pm);
6290 TRACE("returning %d with %u\n", res, GetLastError());
6291 return res;
6294 /******************************************************************************
6295 * AddPortExA (WINSPOOL.@)
6297 * See AddPortExW.
6300 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6302 PORT_INFO_2W pi2W;
6303 PORT_INFO_2A * pi2A;
6304 LPWSTR nameW = NULL;
6305 LPWSTR monitorW = NULL;
6306 DWORD len;
6307 BOOL res;
6309 pi2A = (PORT_INFO_2A *) pBuffer;
6311 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6312 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6314 if ((level < 1) || (level > 2)) {
6315 SetLastError(ERROR_INVALID_LEVEL);
6316 return FALSE;
6319 if (!pi2A) {
6320 SetLastError(ERROR_INVALID_PARAMETER);
6321 return FALSE;
6324 if (pName) {
6325 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6326 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6327 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6330 if (pMonitorName) {
6331 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6332 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6333 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6336 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6338 if (pi2A->pPortName) {
6339 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6340 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6341 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6344 if (level > 1) {
6345 if (pi2A->pMonitorName) {
6346 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6347 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6348 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6351 if (pi2A->pDescription) {
6352 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6353 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6354 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6356 pi2W.fPortType = pi2A->fPortType;
6357 pi2W.Reserved = pi2A->Reserved;
6360 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6362 HeapFree(GetProcessHeap(), 0, nameW);
6363 HeapFree(GetProcessHeap(), 0, monitorW);
6364 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6365 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6366 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6367 return res;
6371 /******************************************************************************
6372 * AddPortExW (WINSPOOL.@)
6374 * Add a Port for a specific Monitor, without presenting a user interface
6376 * PARAMS
6377 * pName [I] Servername or NULL (local Computer)
6378 * level [I] Structure-Level (1 or 2) for pBuffer
6379 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6380 * pMonitorName [I] Name of the Monitor that manage the Port
6382 * RETURNS
6383 * Success: TRUE
6384 * Failure: FALSE
6387 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6389 PORT_INFO_2W * pi2;
6390 monitor_t * pm;
6391 DWORD res = FALSE;
6393 pi2 = (PORT_INFO_2W *) pBuffer;
6395 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6396 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6397 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6398 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6401 if ((level < 1) || (level > 2)) {
6402 SetLastError(ERROR_INVALID_LEVEL);
6403 return FALSE;
6406 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6407 SetLastError(ERROR_INVALID_PARAMETER);
6408 return FALSE;
6411 /* load the Monitor */
6412 pm = monitor_load(pMonitorName, NULL);
6413 if (!pm) {
6414 SetLastError(ERROR_INVALID_PARAMETER);
6415 return FALSE;
6418 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6419 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6420 TRACE("got %u with %u\n", res, GetLastError());
6422 else
6424 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6426 monitor_unload(pm);
6427 return res;
6430 /******************************************************************************
6431 * AddPrinterConnectionA (WINSPOOL.@)
6433 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6435 FIXME("%s\n", debugstr_a(pName));
6436 return FALSE;
6439 /******************************************************************************
6440 * AddPrinterConnectionW (WINSPOOL.@)
6442 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6444 FIXME("%s\n", debugstr_w(pName));
6445 return FALSE;
6448 /******************************************************************************
6449 * AddPrinterDriverExW (WINSPOOL.@)
6451 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6453 * PARAMS
6454 * pName [I] Servername or NULL (local Computer)
6455 * level [I] Level for the supplied DRIVER_INFO_*W struct
6456 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6457 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6459 * RESULTS
6460 * Success: TRUE
6461 * Failure: FALSE
6464 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6466 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6468 if ((backend == NULL) && !load_backend()) return FALSE;
6470 if (level < 2 || level == 5 || level == 7 || level > 8) {
6471 SetLastError(ERROR_INVALID_LEVEL);
6472 return FALSE;
6475 if (!pDriverInfo) {
6476 SetLastError(ERROR_INVALID_PARAMETER);
6477 return FALSE;
6480 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6483 /******************************************************************************
6484 * AddPrinterDriverExA (WINSPOOL.@)
6486 * See AddPrinterDriverExW.
6489 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6491 DRIVER_INFO_8A *diA;
6492 DRIVER_INFO_8W diW;
6493 LPWSTR nameW = NULL;
6494 DWORD lenA;
6495 DWORD len;
6496 DWORD res = FALSE;
6498 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6500 diA = (DRIVER_INFO_8A *) pDriverInfo;
6501 ZeroMemory(&diW, sizeof(diW));
6503 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6504 SetLastError(ERROR_INVALID_LEVEL);
6505 return FALSE;
6508 if (diA == NULL) {
6509 SetLastError(ERROR_INVALID_PARAMETER);
6510 return FALSE;
6513 /* convert servername to unicode */
6514 if (pName) {
6515 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6516 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6517 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6520 /* common fields */
6521 diW.cVersion = diA->cVersion;
6523 if (diA->pName) {
6524 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6525 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6526 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6529 if (diA->pEnvironment) {
6530 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6531 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6532 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6535 if (diA->pDriverPath) {
6536 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6537 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6538 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6541 if (diA->pDataFile) {
6542 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6543 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6544 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6547 if (diA->pConfigFile) {
6548 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6549 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6550 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6553 if ((Level > 2) && diA->pDependentFiles) {
6554 lenA = multi_sz_lenA(diA->pDependentFiles);
6555 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6556 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6557 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6560 if ((Level > 2) && diA->pMonitorName) {
6561 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6562 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6563 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6566 if ((Level > 3) && diA->pDefaultDataType) {
6567 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6568 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6569 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6572 if ((Level > 3) && diA->pszzPreviousNames) {
6573 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6574 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6575 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6576 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6579 if ((Level > 5) && diA->pszMfgName) {
6580 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6581 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6582 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6585 if ((Level > 5) && diA->pszOEMUrl) {
6586 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6587 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6588 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6591 if ((Level > 5) && diA->pszHardwareID) {
6592 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6593 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6594 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6597 if ((Level > 5) && diA->pszProvider) {
6598 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6599 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6600 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6603 if (Level > 7) {
6604 FIXME("level %u is incomplete\n", Level);
6607 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6608 TRACE("got %u with %u\n", res, GetLastError());
6609 HeapFree(GetProcessHeap(), 0, nameW);
6610 HeapFree(GetProcessHeap(), 0, diW.pName);
6611 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6612 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6613 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6614 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6615 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6616 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6617 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6618 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6619 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6620 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6621 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6622 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6624 TRACE("=> %u with %u\n", res, GetLastError());
6625 return res;
6628 /******************************************************************************
6629 * ConfigurePortA (WINSPOOL.@)
6631 * See ConfigurePortW.
6634 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6636 LPWSTR nameW = NULL;
6637 LPWSTR portW = NULL;
6638 INT len;
6639 DWORD res;
6641 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6643 /* convert servername to unicode */
6644 if (pName) {
6645 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6646 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6647 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6650 /* convert portname to unicode */
6651 if (pPortName) {
6652 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6653 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6654 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6657 res = ConfigurePortW(nameW, hWnd, portW);
6658 HeapFree(GetProcessHeap(), 0, nameW);
6659 HeapFree(GetProcessHeap(), 0, portW);
6660 return res;
6663 /******************************************************************************
6664 * ConfigurePortW (WINSPOOL.@)
6666 * Display the Configuration-Dialog for a specific Port
6668 * PARAMS
6669 * pName [I] Servername or NULL (local Computer)
6670 * hWnd [I] Handle to parent Window for the Dialog-Box
6671 * pPortName [I] Name of the Port, that should be configured
6673 * RETURNS
6674 * Success: TRUE
6675 * Failure: FALSE
6678 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6680 monitor_t * pm;
6681 monitor_t * pui;
6682 DWORD res;
6684 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6686 if (pName && pName[0]) {
6687 SetLastError(ERROR_INVALID_PARAMETER);
6688 return FALSE;
6691 if (!pPortName) {
6692 SetLastError(RPC_X_NULL_REF_POINTER);
6693 return FALSE;
6696 /* an empty Portname is Invalid, but can popup a Dialog */
6697 if (!pPortName[0]) {
6698 SetLastError(ERROR_NOT_SUPPORTED);
6699 return FALSE;
6702 pm = monitor_load_by_port(pPortName);
6703 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6704 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6705 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6706 TRACE("got %d with %u\n", res, GetLastError());
6708 else
6710 pui = monitor_loadui(pm);
6711 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6712 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6713 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6714 TRACE("got %d with %u\n", res, GetLastError());
6716 else
6718 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6719 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6721 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6722 SetLastError(ERROR_NOT_SUPPORTED);
6723 res = FALSE;
6725 monitor_unload(pui);
6727 monitor_unload(pm);
6729 TRACE("returning %d with %u\n", res, GetLastError());
6730 return res;
6733 /******************************************************************************
6734 * ConnectToPrinterDlg (WINSPOOL.@)
6736 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6738 FIXME("%p %x\n", hWnd, Flags);
6739 return NULL;
6742 /******************************************************************************
6743 * DeletePrinterConnectionA (WINSPOOL.@)
6745 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6747 FIXME("%s\n", debugstr_a(pName));
6748 return TRUE;
6751 /******************************************************************************
6752 * DeletePrinterConnectionW (WINSPOOL.@)
6754 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6756 FIXME("%s\n", debugstr_w(pName));
6757 return TRUE;
6760 /******************************************************************************
6761 * DeletePrinterDriverExW (WINSPOOL.@)
6763 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6764 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6766 HKEY hkey_drivers;
6767 BOOL ret = FALSE;
6769 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6770 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6772 if(pName && pName[0])
6774 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6775 SetLastError(ERROR_INVALID_PARAMETER);
6776 return FALSE;
6779 if(dwDeleteFlag)
6781 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6782 SetLastError(ERROR_INVALID_PARAMETER);
6783 return FALSE;
6786 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6788 if(!hkey_drivers)
6790 ERR("Can't open drivers key\n");
6791 return FALSE;
6794 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6795 ret = TRUE;
6797 RegCloseKey(hkey_drivers);
6799 return ret;
6802 /******************************************************************************
6803 * DeletePrinterDriverExA (WINSPOOL.@)
6805 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6806 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6808 UNICODE_STRING NameW, EnvW, DriverW;
6809 BOOL ret;
6811 asciitounicode(&NameW, pName);
6812 asciitounicode(&EnvW, pEnvironment);
6813 asciitounicode(&DriverW, pDriverName);
6815 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6817 RtlFreeUnicodeString(&DriverW);
6818 RtlFreeUnicodeString(&EnvW);
6819 RtlFreeUnicodeString(&NameW);
6821 return ret;
6824 /******************************************************************************
6825 * DeletePrinterDataExW (WINSPOOL.@)
6827 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6828 LPCWSTR pValueName)
6830 FIXME("%p %s %s\n", hPrinter,
6831 debugstr_w(pKeyName), debugstr_w(pValueName));
6832 return ERROR_INVALID_PARAMETER;
6835 /******************************************************************************
6836 * DeletePrinterDataExA (WINSPOOL.@)
6838 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6839 LPCSTR pValueName)
6841 FIXME("%p %s %s\n", hPrinter,
6842 debugstr_a(pKeyName), debugstr_a(pValueName));
6843 return ERROR_INVALID_PARAMETER;
6846 /******************************************************************************
6847 * DeletePrintProcessorA (WINSPOOL.@)
6849 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6851 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6852 debugstr_a(pPrintProcessorName));
6853 return TRUE;
6856 /******************************************************************************
6857 * DeletePrintProcessorW (WINSPOOL.@)
6859 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6861 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6862 debugstr_w(pPrintProcessorName));
6863 return TRUE;
6866 /******************************************************************************
6867 * DeletePrintProvidorA (WINSPOOL.@)
6869 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6871 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6872 debugstr_a(pPrintProviderName));
6873 return TRUE;
6876 /******************************************************************************
6877 * DeletePrintProvidorW (WINSPOOL.@)
6879 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6881 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6882 debugstr_w(pPrintProviderName));
6883 return TRUE;
6886 /******************************************************************************
6887 * EnumFormsA (WINSPOOL.@)
6889 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6890 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6892 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6893 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6894 return FALSE;
6897 /******************************************************************************
6898 * EnumFormsW (WINSPOOL.@)
6900 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6901 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6903 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6904 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6905 return FALSE;
6908 /*****************************************************************************
6909 * EnumMonitorsA [WINSPOOL.@]
6911 * See EnumMonitorsW.
6914 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6915 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6917 BOOL res;
6918 LPBYTE bufferW = NULL;
6919 LPWSTR nameW = NULL;
6920 DWORD needed = 0;
6921 DWORD numentries = 0;
6922 INT len;
6924 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6925 cbBuf, pcbNeeded, pcReturned);
6927 /* convert servername to unicode */
6928 if (pName) {
6929 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6930 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6931 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6933 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6934 needed = cbBuf * sizeof(WCHAR);
6935 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6936 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6938 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6939 if (pcbNeeded) needed = *pcbNeeded;
6940 /* HeapReAlloc return NULL, when bufferW was NULL */
6941 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6942 HeapAlloc(GetProcessHeap(), 0, needed);
6944 /* Try again with the large Buffer */
6945 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6947 numentries = pcReturned ? *pcReturned : 0;
6948 needed = 0;
6950 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6951 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6953 if (res) {
6954 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6955 DWORD entrysize = 0;
6956 DWORD index;
6957 LPSTR ptr;
6958 LPMONITOR_INFO_2W mi2w;
6959 LPMONITOR_INFO_2A mi2a;
6961 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6962 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6964 /* First pass: calculate the size for all Entries */
6965 mi2w = (LPMONITOR_INFO_2W) bufferW;
6966 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6967 index = 0;
6968 while (index < numentries) {
6969 index++;
6970 needed += entrysize; /* MONITOR_INFO_?A */
6971 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6973 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6974 NULL, 0, NULL, NULL);
6975 if (Level > 1) {
6976 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6977 NULL, 0, NULL, NULL);
6978 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6979 NULL, 0, NULL, NULL);
6981 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6982 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6983 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6986 /* check for errors and quit on failure */
6987 if (cbBuf < needed) {
6988 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6989 res = FALSE;
6990 goto emA_cleanup;
6992 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6993 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6994 cbBuf -= len ; /* free Bytes in the user-Buffer */
6995 mi2w = (LPMONITOR_INFO_2W) bufferW;
6996 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6997 index = 0;
6998 /* Second Pass: Fill the User Buffer (if we have one) */
6999 while ((index < numentries) && pMonitors) {
7000 index++;
7001 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7002 mi2a->pName = ptr;
7003 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7004 ptr, cbBuf , NULL, NULL);
7005 ptr += len;
7006 cbBuf -= len;
7007 if (Level > 1) {
7008 mi2a->pEnvironment = ptr;
7009 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7010 ptr, cbBuf, NULL, NULL);
7011 ptr += len;
7012 cbBuf -= len;
7014 mi2a->pDLLName = ptr;
7015 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7016 ptr, cbBuf, NULL, NULL);
7017 ptr += len;
7018 cbBuf -= len;
7020 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7021 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7022 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7025 emA_cleanup:
7026 if (pcbNeeded) *pcbNeeded = needed;
7027 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7029 HeapFree(GetProcessHeap(), 0, nameW);
7030 HeapFree(GetProcessHeap(), 0, bufferW);
7032 TRACE("returning %d with %d (%d byte for %d entries)\n",
7033 (res), GetLastError(), needed, numentries);
7035 return (res);
7039 /*****************************************************************************
7040 * EnumMonitorsW [WINSPOOL.@]
7042 * Enumerate available Port-Monitors
7044 * PARAMS
7045 * pName [I] Servername or NULL (local Computer)
7046 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7047 * pMonitors [O] PTR to Buffer that receives the Result
7048 * cbBuf [I] Size of Buffer at pMonitors
7049 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7050 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7052 * RETURNS
7053 * Success: TRUE
7054 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7056 * NOTES
7057 * Windows reads the Registry once and cache the Results.
7059 *| Language-Monitors are also installed in the same Registry-Location but
7060 *| they are filtered in Windows (not returned by EnumMonitors).
7061 *| We do no filtering to simplify our Code.
7064 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7065 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7067 DWORD needed = 0;
7068 DWORD numentries = 0;
7069 BOOL res = FALSE;
7071 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7072 cbBuf, pcbNeeded, pcReturned);
7074 if (pName && (lstrlenW(pName))) {
7075 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7076 SetLastError(ERROR_ACCESS_DENIED);
7077 goto emW_cleanup;
7080 /* Level is not checked in win9x */
7081 if (!Level || (Level > 2)) {
7082 WARN("level (%d) is ignored in win9x\n", Level);
7083 SetLastError(ERROR_INVALID_LEVEL);
7084 goto emW_cleanup;
7086 if (!pcbNeeded) {
7087 SetLastError(RPC_X_NULL_REF_POINTER);
7088 goto emW_cleanup;
7091 /* Scan all Monitor-Keys */
7092 numentries = 0;
7093 needed = get_local_monitors(Level, NULL, 0, &numentries);
7095 /* we calculated the needed buffersize. now do the error-checks */
7096 if (cbBuf < needed) {
7097 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7098 goto emW_cleanup;
7100 else if (!pMonitors || !pcReturned) {
7101 SetLastError(RPC_X_NULL_REF_POINTER);
7102 goto emW_cleanup;
7105 /* fill the Buffer with the Monitor-Keys */
7106 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7107 res = TRUE;
7109 emW_cleanup:
7110 if (pcbNeeded) *pcbNeeded = needed;
7111 if (pcReturned) *pcReturned = numentries;
7113 TRACE("returning %d with %d (%d byte for %d entries)\n",
7114 res, GetLastError(), needed, numentries);
7116 return (res);
7119 /******************************************************************************
7120 * XcvDataW (WINSPOOL.@)
7122 * Execute commands in the Printmonitor DLL
7124 * PARAMS
7125 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7126 * pszDataName [i] Name of the command to execute
7127 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7128 * cbInputData [i] Size in Bytes of Buffer at pInputData
7129 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7130 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7131 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7132 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7134 * RETURNS
7135 * Success: TRUE
7136 * Failure: FALSE
7138 * NOTES
7139 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7140 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7142 * Minimal List of commands, that a Printmonitor DLL should support:
7144 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7145 *| "AddPort" : Add a Port
7146 *| "DeletePort": Delete a Port
7148 * Many Printmonitors support additional commands. Examples for localspl.dll:
7149 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7150 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7153 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7154 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7155 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7157 opened_printer_t *printer;
7159 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7160 pInputData, cbInputData, pOutputData,
7161 cbOutputData, pcbOutputNeeded, pdwStatus);
7163 printer = get_opened_printer(hXcv);
7164 if (!printer || (!printer->hXcv)) {
7165 SetLastError(ERROR_INVALID_HANDLE);
7166 return FALSE;
7169 if (!pcbOutputNeeded) {
7170 SetLastError(ERROR_INVALID_PARAMETER);
7171 return FALSE;
7174 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7175 SetLastError(RPC_X_NULL_REF_POINTER);
7176 return FALSE;
7179 *pcbOutputNeeded = 0;
7181 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7182 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7184 return TRUE;
7187 /*****************************************************************************
7188 * EnumPrinterDataA [WINSPOOL.@]
7191 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7192 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7193 DWORD cbData, LPDWORD pcbData )
7195 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7196 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7197 return ERROR_NO_MORE_ITEMS;
7200 /*****************************************************************************
7201 * EnumPrinterDataW [WINSPOOL.@]
7204 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7205 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7206 DWORD cbData, LPDWORD pcbData )
7208 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7209 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7210 return ERROR_NO_MORE_ITEMS;
7213 /*****************************************************************************
7214 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7217 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7218 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7219 LPDWORD pcbNeeded, LPDWORD pcReturned)
7221 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7222 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7223 pcbNeeded, pcReturned);
7224 return FALSE;
7227 /*****************************************************************************
7228 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7231 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7232 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7233 LPDWORD pcbNeeded, LPDWORD pcReturned)
7235 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7236 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7237 pcbNeeded, pcReturned);
7238 return FALSE;
7241 /*****************************************************************************
7242 * EnumPrintProcessorsA [WINSPOOL.@]
7245 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7246 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7248 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7249 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7250 return FALSE;
7253 /*****************************************************************************
7254 * EnumPrintProcessorsW [WINSPOOL.@]
7257 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7258 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7260 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7261 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7262 cbBuf, pcbNeeded, pcbReturned);
7263 return FALSE;
7266 /*****************************************************************************
7267 * ExtDeviceMode [WINSPOOL.@]
7270 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7271 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7272 DWORD fMode)
7274 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7275 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7276 debugstr_a(pProfile), fMode);
7277 return -1;
7280 /*****************************************************************************
7281 * FindClosePrinterChangeNotification [WINSPOOL.@]
7284 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7286 FIXME("Stub: %p\n", hChange);
7287 return TRUE;
7290 /*****************************************************************************
7291 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7294 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7295 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7297 FIXME("Stub: %p %x %x %p\n",
7298 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7299 return INVALID_HANDLE_VALUE;
7302 /*****************************************************************************
7303 * FindNextPrinterChangeNotification [WINSPOOL.@]
7306 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7307 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7309 FIXME("Stub: %p %p %p %p\n",
7310 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7311 return FALSE;
7314 /*****************************************************************************
7315 * FreePrinterNotifyInfo [WINSPOOL.@]
7318 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7320 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7321 return TRUE;
7324 /*****************************************************************************
7325 * string_to_buf
7327 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7328 * ansi depending on the unicode parameter.
7330 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7332 if(!str)
7334 *size = 0;
7335 return TRUE;
7338 if(unicode)
7340 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7341 if(*size <= cb)
7343 memcpy(ptr, str, *size);
7344 return TRUE;
7346 return FALSE;
7348 else
7350 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7351 if(*size <= cb)
7353 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7354 return TRUE;
7356 return FALSE;
7360 /*****************************************************************************
7361 * get_job_info_1
7363 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7364 LPDWORD pcbNeeded, BOOL unicode)
7366 DWORD size, left = cbBuf;
7367 BOOL space = (cbBuf > 0);
7368 LPBYTE ptr = buf;
7370 *pcbNeeded = 0;
7372 if(space)
7374 ji1->JobId = job->job_id;
7377 string_to_buf(job->document_title, ptr, left, &size, unicode);
7378 if(space && size <= left)
7380 ji1->pDocument = (LPWSTR)ptr;
7381 ptr += size;
7382 left -= size;
7384 else
7385 space = FALSE;
7386 *pcbNeeded += size;
7388 return space;
7391 /*****************************************************************************
7392 * get_job_info_2
7394 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7395 LPDWORD pcbNeeded, BOOL unicode)
7397 DWORD size, left = cbBuf;
7398 BOOL space = (cbBuf > 0);
7399 LPBYTE ptr = buf;
7401 *pcbNeeded = 0;
7403 if(space)
7405 ji2->JobId = job->job_id;
7408 string_to_buf(job->document_title, ptr, left, &size, unicode);
7409 if(space && size <= left)
7411 ji2->pDocument = (LPWSTR)ptr;
7412 ptr += size;
7413 left -= size;
7415 else
7416 space = FALSE;
7417 *pcbNeeded += size;
7419 return space;
7422 /*****************************************************************************
7423 * get_job_info
7425 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7426 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7428 BOOL ret = FALSE;
7429 DWORD needed = 0, size;
7430 job_t *job;
7431 LPBYTE ptr = pJob;
7433 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7435 EnterCriticalSection(&printer_handles_cs);
7436 job = get_job(hPrinter, JobId);
7437 if(!job)
7438 goto end;
7440 switch(Level)
7442 case 1:
7443 size = sizeof(JOB_INFO_1W);
7444 if(cbBuf >= size)
7446 cbBuf -= size;
7447 ptr += size;
7448 memset(pJob, 0, size);
7450 else
7451 cbBuf = 0;
7452 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7453 needed += size;
7454 break;
7456 case 2:
7457 size = sizeof(JOB_INFO_2W);
7458 if(cbBuf >= size)
7460 cbBuf -= size;
7461 ptr += size;
7462 memset(pJob, 0, size);
7464 else
7465 cbBuf = 0;
7466 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7467 needed += size;
7468 break;
7470 case 3:
7471 size = sizeof(JOB_INFO_3);
7472 if(cbBuf >= size)
7474 cbBuf -= size;
7475 memset(pJob, 0, size);
7476 ret = TRUE;
7478 else
7479 cbBuf = 0;
7480 needed = size;
7481 break;
7483 default:
7484 SetLastError(ERROR_INVALID_LEVEL);
7485 goto end;
7487 if(pcbNeeded)
7488 *pcbNeeded = needed;
7489 end:
7490 LeaveCriticalSection(&printer_handles_cs);
7491 return ret;
7494 /*****************************************************************************
7495 * GetJobA [WINSPOOL.@]
7498 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7499 DWORD cbBuf, LPDWORD pcbNeeded)
7501 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7504 /*****************************************************************************
7505 * GetJobW [WINSPOOL.@]
7508 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7509 DWORD cbBuf, LPDWORD pcbNeeded)
7511 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7514 /*****************************************************************************
7515 * schedule_lpr
7517 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7519 char *unixname, *queue, *cmd;
7520 char fmt[] = "lpr -P%s %s";
7521 DWORD len;
7523 if(!(unixname = wine_get_unix_file_name(filename)))
7524 return FALSE;
7526 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7527 queue = HeapAlloc(GetProcessHeap(), 0, len);
7528 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7530 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7531 sprintf(cmd, fmt, queue, unixname);
7533 TRACE("printing with: %s\n", cmd);
7534 system(cmd);
7536 HeapFree(GetProcessHeap(), 0, cmd);
7537 HeapFree(GetProcessHeap(), 0, queue);
7538 HeapFree(GetProcessHeap(), 0, unixname);
7539 return TRUE;
7542 /*****************************************************************************
7543 * schedule_cups
7545 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7547 #ifdef SONAME_LIBCUPS
7548 if(pcupsPrintFile)
7550 char *unixname, *queue, *doc_titleA;
7551 DWORD len;
7552 BOOL ret;
7554 if(!(unixname = wine_get_unix_file_name(filename)))
7555 return FALSE;
7557 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7558 queue = HeapAlloc(GetProcessHeap(), 0, len);
7559 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7561 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7562 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7563 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7565 TRACE("printing via cups\n");
7566 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7567 HeapFree(GetProcessHeap(), 0, doc_titleA);
7568 HeapFree(GetProcessHeap(), 0, queue);
7569 HeapFree(GetProcessHeap(), 0, unixname);
7570 return ret;
7572 else
7573 #endif
7575 return schedule_lpr(printer_name, filename);
7579 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7581 LPWSTR filename;
7583 switch(msg)
7585 case WM_INITDIALOG:
7586 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7587 return TRUE;
7589 case WM_COMMAND:
7590 if(HIWORD(wparam) == BN_CLICKED)
7592 if(LOWORD(wparam) == IDOK)
7594 HANDLE hf;
7595 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7596 LPWSTR *output;
7598 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7599 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7601 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7603 WCHAR caption[200], message[200];
7604 int mb_ret;
7606 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7607 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7608 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7609 if(mb_ret == IDCANCEL)
7611 HeapFree(GetProcessHeap(), 0, filename);
7612 return TRUE;
7615 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7616 if(hf == INVALID_HANDLE_VALUE)
7618 WCHAR caption[200], message[200];
7620 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7621 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7622 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7623 HeapFree(GetProcessHeap(), 0, filename);
7624 return TRUE;
7626 CloseHandle(hf);
7627 DeleteFileW(filename);
7628 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7629 *output = filename;
7630 EndDialog(hwnd, IDOK);
7631 return TRUE;
7633 if(LOWORD(wparam) == IDCANCEL)
7635 EndDialog(hwnd, IDCANCEL);
7636 return TRUE;
7639 return FALSE;
7641 return FALSE;
7644 /*****************************************************************************
7645 * get_filename
7647 static BOOL get_filename(LPWSTR *filename)
7649 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7650 file_dlg_proc, (LPARAM)filename) == IDOK;
7653 /*****************************************************************************
7654 * schedule_file
7656 static BOOL schedule_file(LPCWSTR filename)
7658 LPWSTR output = NULL;
7660 if(get_filename(&output))
7662 TRACE("copy to %s\n", debugstr_w(output));
7663 CopyFileW(filename, output, FALSE);
7664 HeapFree(GetProcessHeap(), 0, output);
7665 return TRUE;
7667 return FALSE;
7670 /*****************************************************************************
7671 * schedule_pipe
7673 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7675 #ifdef HAVE_FORK
7676 char *unixname, *cmdA;
7677 DWORD len;
7678 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7679 BOOL ret = FALSE;
7680 char buf[1024];
7682 if(!(unixname = wine_get_unix_file_name(filename)))
7683 return FALSE;
7685 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7686 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7687 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7689 TRACE("printing with: %s\n", cmdA);
7691 if((file_fd = open(unixname, O_RDONLY)) == -1)
7692 goto end;
7694 if (pipe(fds))
7696 ERR("pipe() failed!\n");
7697 goto end;
7700 if (fork() == 0)
7702 close(0);
7703 dup2(fds[0], 0);
7704 close(fds[1]);
7706 /* reset signals that we previously set to SIG_IGN */
7707 signal(SIGPIPE, SIG_DFL);
7708 signal(SIGCHLD, SIG_DFL);
7710 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7711 _exit(1);
7714 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7715 write(fds[1], buf, no_read);
7717 ret = TRUE;
7719 end:
7720 if(file_fd != -1) close(file_fd);
7721 if(fds[0] != -1) close(fds[0]);
7722 if(fds[1] != -1) close(fds[1]);
7724 HeapFree(GetProcessHeap(), 0, cmdA);
7725 HeapFree(GetProcessHeap(), 0, unixname);
7726 return ret;
7727 #else
7728 return FALSE;
7729 #endif
7732 /*****************************************************************************
7733 * schedule_unixfile
7735 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7737 int in_fd, out_fd, no_read;
7738 char buf[1024];
7739 BOOL ret = FALSE;
7740 char *unixname, *outputA;
7741 DWORD len;
7743 if(!(unixname = wine_get_unix_file_name(filename)))
7744 return FALSE;
7746 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7747 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7748 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7750 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7751 in_fd = open(unixname, O_RDONLY);
7752 if(out_fd == -1 || in_fd == -1)
7753 goto end;
7755 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7756 write(out_fd, buf, no_read);
7758 ret = TRUE;
7759 end:
7760 if(in_fd != -1) close(in_fd);
7761 if(out_fd != -1) close(out_fd);
7762 HeapFree(GetProcessHeap(), 0, outputA);
7763 HeapFree(GetProcessHeap(), 0, unixname);
7764 return ret;
7767 /*****************************************************************************
7768 * ScheduleJob [WINSPOOL.@]
7771 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7773 opened_printer_t *printer;
7774 BOOL ret = FALSE;
7775 struct list *cursor, *cursor2;
7777 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7778 EnterCriticalSection(&printer_handles_cs);
7779 printer = get_opened_printer(hPrinter);
7780 if(!printer)
7781 goto end;
7783 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7785 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7786 HANDLE hf;
7788 if(job->job_id != dwJobID) continue;
7790 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7791 if(hf != INVALID_HANDLE_VALUE)
7793 PRINTER_INFO_5W *pi5;
7794 DWORD needed;
7795 HKEY hkey;
7796 WCHAR output[1024];
7797 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7798 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7800 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7801 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7802 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7803 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7804 debugstr_w(pi5->pPortName));
7806 output[0] = 0;
7808 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7809 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7811 DWORD type, count = sizeof(output);
7812 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7813 RegCloseKey(hkey);
7815 if(output[0] == '|')
7817 schedule_pipe(output + 1, job->filename);
7819 else if(output[0])
7821 schedule_unixfile(output, job->filename);
7823 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7825 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7827 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7829 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7831 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7833 schedule_file(job->filename);
7835 else
7837 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7839 HeapFree(GetProcessHeap(), 0, pi5);
7840 CloseHandle(hf);
7841 DeleteFileW(job->filename);
7843 list_remove(cursor);
7844 HeapFree(GetProcessHeap(), 0, job->document_title);
7845 HeapFree(GetProcessHeap(), 0, job->filename);
7846 HeapFree(GetProcessHeap(), 0, job);
7847 ret = TRUE;
7848 break;
7850 end:
7851 LeaveCriticalSection(&printer_handles_cs);
7852 return ret;
7855 /*****************************************************************************
7856 * StartDocDlgA [WINSPOOL.@]
7858 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7860 UNICODE_STRING usBuffer;
7861 DOCINFOW docW;
7862 LPWSTR retW;
7863 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7864 LPSTR ret = NULL;
7866 docW.cbSize = sizeof(docW);
7867 if (doc->lpszDocName)
7869 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7870 if (!(docW.lpszDocName = docnameW)) return NULL;
7872 if (doc->lpszOutput)
7874 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7875 if (!(docW.lpszOutput = outputW)) return NULL;
7877 if (doc->lpszDatatype)
7879 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7880 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7882 docW.fwType = doc->fwType;
7884 retW = StartDocDlgW(hPrinter, &docW);
7886 if(retW)
7888 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7889 ret = HeapAlloc(GetProcessHeap(), 0, len);
7890 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7891 HeapFree(GetProcessHeap(), 0, retW);
7894 HeapFree(GetProcessHeap(), 0, datatypeW);
7895 HeapFree(GetProcessHeap(), 0, outputW);
7896 HeapFree(GetProcessHeap(), 0, docnameW);
7898 return ret;
7901 /*****************************************************************************
7902 * StartDocDlgW [WINSPOOL.@]
7904 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7905 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7906 * port is "FILE:". Also returns the full path if passed a relative path.
7908 * The caller should free the returned string from the process heap.
7910 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7912 LPWSTR ret = NULL;
7913 DWORD len, attr;
7915 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7917 PRINTER_INFO_5W *pi5;
7918 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7919 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7920 return NULL;
7921 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7922 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7923 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7925 HeapFree(GetProcessHeap(), 0, pi5);
7926 return NULL;
7928 HeapFree(GetProcessHeap(), 0, pi5);
7931 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7933 LPWSTR name;
7935 if (get_filename(&name))
7937 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7939 HeapFree(GetProcessHeap(), 0, name);
7940 return NULL;
7942 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7943 GetFullPathNameW(name, len, ret, NULL);
7944 HeapFree(GetProcessHeap(), 0, name);
7946 return ret;
7949 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7950 return NULL;
7952 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7953 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7955 attr = GetFileAttributesW(ret);
7956 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7958 HeapFree(GetProcessHeap(), 0, ret);
7959 ret = NULL;
7961 return ret;