winspool: Cleanup for DEVMODEdupWtoA.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob7d49d2c3e463358c9cc7a02ba83927cdd98e1ed2
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 ansi copy of supplied devmode
1699 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1701 LPDEVMODEA dmA;
1702 DWORD size;
1704 if (!dmW) return NULL;
1705 size = dmW->dmSize - CCHDEVICENAME -
1706 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1708 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1709 if (!dmA) return NULL;
1711 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1712 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1714 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1715 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1716 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1718 else
1720 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1721 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1722 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1723 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1725 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1728 dmA->dmSize = size;
1729 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1730 return dmA;
1733 /***********************************************************
1734 * PRINTER_INFO_2AtoW
1735 * Creates a unicode copy of PRINTER_INFO_2A on heap
1737 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1739 LPPRINTER_INFO_2W piW;
1740 UNICODE_STRING usBuffer;
1742 if(!piA) return NULL;
1743 piW = HeapAlloc(heap, 0, sizeof(*piW));
1744 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1746 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1747 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1748 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1749 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1750 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1751 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1752 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1753 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1754 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1755 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1756 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1757 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1758 return piW;
1761 /***********************************************************
1762 * FREE_PRINTER_INFO_2W
1763 * Free PRINTER_INFO_2W and all strings
1765 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1767 if(!piW) return;
1769 HeapFree(heap,0,piW->pServerName);
1770 HeapFree(heap,0,piW->pPrinterName);
1771 HeapFree(heap,0,piW->pShareName);
1772 HeapFree(heap,0,piW->pPortName);
1773 HeapFree(heap,0,piW->pDriverName);
1774 HeapFree(heap,0,piW->pComment);
1775 HeapFree(heap,0,piW->pLocation);
1776 HeapFree(heap,0,piW->pDevMode);
1777 HeapFree(heap,0,piW->pSepFile);
1778 HeapFree(heap,0,piW->pPrintProcessor);
1779 HeapFree(heap,0,piW->pDatatype);
1780 HeapFree(heap,0,piW->pParameters);
1781 HeapFree(heap,0,piW);
1782 return;
1785 /******************************************************************
1786 * DeviceCapabilities [WINSPOOL.@]
1787 * DeviceCapabilitiesA [WINSPOOL.@]
1790 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1791 LPSTR pOutput, LPDEVMODEA lpdm)
1793 INT ret;
1795 if (!GDI_CallDeviceCapabilities16)
1797 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1798 (LPCSTR)104 );
1799 if (!GDI_CallDeviceCapabilities16) return -1;
1801 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1803 /* If DC_PAPERSIZE map POINT16s to POINTs */
1804 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1805 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1806 POINT *pt = (POINT *)pOutput;
1807 INT i;
1808 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1809 for(i = 0; i < ret; i++, pt++)
1811 pt->x = tmp[i].x;
1812 pt->y = tmp[i].y;
1814 HeapFree( GetProcessHeap(), 0, tmp );
1816 return ret;
1820 /*****************************************************************************
1821 * DeviceCapabilitiesW [WINSPOOL.@]
1823 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1826 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1827 WORD fwCapability, LPWSTR pOutput,
1828 const DEVMODEW *pDevMode)
1830 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1831 LPSTR pDeviceA = strdupWtoA(pDevice);
1832 LPSTR pPortA = strdupWtoA(pPort);
1833 INT ret;
1835 if(pOutput && (fwCapability == DC_BINNAMES ||
1836 fwCapability == DC_FILEDEPENDENCIES ||
1837 fwCapability == DC_PAPERNAMES)) {
1838 /* These need A -> W translation */
1839 INT size = 0, i;
1840 LPSTR pOutputA;
1841 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1842 dmA);
1843 if(ret == -1)
1844 return ret;
1845 switch(fwCapability) {
1846 case DC_BINNAMES:
1847 size = 24;
1848 break;
1849 case DC_PAPERNAMES:
1850 case DC_FILEDEPENDENCIES:
1851 size = 64;
1852 break;
1854 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1855 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1856 dmA);
1857 for(i = 0; i < ret; i++)
1858 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1859 pOutput + (i * size), size);
1860 HeapFree(GetProcessHeap(), 0, pOutputA);
1861 } else {
1862 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1863 (LPSTR)pOutput, dmA);
1865 HeapFree(GetProcessHeap(),0,pPortA);
1866 HeapFree(GetProcessHeap(),0,pDeviceA);
1867 HeapFree(GetProcessHeap(),0,dmA);
1868 return ret;
1871 /******************************************************************
1872 * DocumentPropertiesA [WINSPOOL.@]
1874 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1876 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1877 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1878 LPDEVMODEA pDevModeInput,DWORD fMode )
1880 LPSTR lpName = pDeviceName;
1881 static CHAR port[] = "LPT1:";
1882 LONG ret;
1884 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1885 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1888 if(!pDeviceName) {
1889 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1890 if(!lpNameW) {
1891 ERR("no name from hPrinter?\n");
1892 SetLastError(ERROR_INVALID_HANDLE);
1893 return -1;
1895 lpName = strdupWtoA(lpNameW);
1898 if (!GDI_CallExtDeviceMode16)
1900 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1901 (LPCSTR)102 );
1902 if (!GDI_CallExtDeviceMode16) {
1903 ERR("No CallExtDeviceMode16?\n");
1904 return -1;
1907 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1908 pDevModeInput, NULL, fMode);
1910 if(!pDeviceName)
1911 HeapFree(GetProcessHeap(),0,lpName);
1912 return ret;
1916 /*****************************************************************************
1917 * DocumentPropertiesW (WINSPOOL.@)
1919 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1921 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1922 LPWSTR pDeviceName,
1923 LPDEVMODEW pDevModeOutput,
1924 LPDEVMODEW pDevModeInput, DWORD fMode)
1927 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1928 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1929 LPDEVMODEA pDevModeOutputA = NULL;
1930 LONG ret;
1932 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1933 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1934 fMode);
1935 if(pDevModeOutput) {
1936 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1937 if(ret < 0) return ret;
1938 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1940 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1941 pDevModeInputA, fMode);
1942 if(pDevModeOutput) {
1943 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1944 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1946 if(fMode == 0 && ret > 0)
1947 ret += (CCHDEVICENAME + CCHFORMNAME);
1948 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1949 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1950 return ret;
1953 /******************************************************************
1954 * OpenPrinterA [WINSPOOL.@]
1956 * See OpenPrinterW.
1959 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1960 LPPRINTER_DEFAULTSA pDefault)
1962 UNICODE_STRING lpPrinterNameW;
1963 UNICODE_STRING usBuffer;
1964 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1965 PWSTR pwstrPrinterNameW;
1966 BOOL ret;
1968 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1970 if(pDefault) {
1971 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1972 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1973 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1974 pDefaultW = &DefaultW;
1976 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1977 if(pDefault) {
1978 RtlFreeUnicodeString(&usBuffer);
1979 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1981 RtlFreeUnicodeString(&lpPrinterNameW);
1982 return ret;
1985 /******************************************************************
1986 * OpenPrinterW [WINSPOOL.@]
1988 * Open a Printer / Printserver or a Printer-Object
1990 * PARAMS
1991 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1992 * phPrinter [O] The resulting Handle is stored here
1993 * pDefault [I] PTR to Default Printer Settings or NULL
1995 * RETURNS
1996 * Success: TRUE
1997 * Failure: FALSE
1999 * NOTES
2000 * lpPrinterName is one of:
2001 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2002 *| Printer: "PrinterName"
2003 *| Printer-Object: "PrinterName,Job xxx"
2004 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2005 *| XcvPort: "Servername,XcvPort PortName"
2007 * BUGS
2008 *| Printer-Object not supported
2009 *| pDefaults is ignored
2012 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2015 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2016 if (pDefault) {
2017 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2018 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2021 if(!phPrinter) {
2022 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2023 SetLastError(ERROR_INVALID_PARAMETER);
2024 return FALSE;
2027 /* Get the unique handle of the printer or Printserver */
2028 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2029 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2030 return (*phPrinter != 0);
2033 /******************************************************************
2034 * AddMonitorA [WINSPOOL.@]
2036 * See AddMonitorW.
2039 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2041 LPWSTR nameW = NULL;
2042 INT len;
2043 BOOL res;
2044 LPMONITOR_INFO_2A mi2a;
2045 MONITOR_INFO_2W mi2w;
2047 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2048 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2049 mi2a ? debugstr_a(mi2a->pName) : NULL,
2050 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2051 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2053 if (Level != 2) {
2054 SetLastError(ERROR_INVALID_LEVEL);
2055 return FALSE;
2058 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2059 if (mi2a == NULL) {
2060 return FALSE;
2063 if (pName) {
2064 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2065 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2066 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2069 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2070 if (mi2a->pName) {
2071 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2072 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2073 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2075 if (mi2a->pEnvironment) {
2076 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2077 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2078 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2080 if (mi2a->pDLLName) {
2081 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2082 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2083 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2086 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2088 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2089 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2090 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2092 HeapFree(GetProcessHeap(), 0, nameW);
2093 return (res);
2096 /******************************************************************************
2097 * AddMonitorW [WINSPOOL.@]
2099 * Install a Printmonitor
2101 * PARAMS
2102 * pName [I] Servername or NULL (local Computer)
2103 * Level [I] Structure-Level (Must be 2)
2104 * pMonitors [I] PTR to MONITOR_INFO_2
2106 * RETURNS
2107 * Success: TRUE
2108 * Failure: FALSE
2110 * NOTES
2111 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2114 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2116 monitor_t * pm = NULL;
2117 LPMONITOR_INFO_2W mi2w;
2118 HKEY hroot = NULL;
2119 HKEY hentry = NULL;
2120 DWORD disposition;
2121 BOOL res = FALSE;
2123 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2124 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2125 mi2w ? debugstr_w(mi2w->pName) : NULL,
2126 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2127 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2129 if (Level != 2) {
2130 SetLastError(ERROR_INVALID_LEVEL);
2131 return FALSE;
2134 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2135 if (mi2w == NULL) {
2136 return FALSE;
2139 if (pName && (pName[0])) {
2140 FIXME("for server %s not implemented\n", debugstr_w(pName));
2141 SetLastError(ERROR_ACCESS_DENIED);
2142 return FALSE;
2146 if (!mi2w->pName || (! mi2w->pName[0])) {
2147 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2148 SetLastError(ERROR_INVALID_PARAMETER);
2149 return FALSE;
2151 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2152 WARN("Environment %s requested (we support only %s)\n",
2153 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2154 SetLastError(ERROR_INVALID_ENVIRONMENT);
2155 return FALSE;
2158 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2159 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2160 SetLastError(ERROR_INVALID_PARAMETER);
2161 return FALSE;
2164 /* Load and initialize the monitor. SetLastError() is called on failure */
2165 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2166 return FALSE;
2168 monitor_unload(pm);
2170 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2171 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2172 return FALSE;
2175 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2176 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2177 &disposition) == ERROR_SUCCESS) {
2179 /* Some installers set options for the port before calling AddMonitor.
2180 We query the "Driver" entry to verify that the monitor is installed,
2181 before we return an error.
2182 When a user installs two print monitors at the same time with the
2183 same name but with a different driver DLL and a task switch comes
2184 between RegQueryValueExW and RegSetValueExW, a race condition
2185 is possible but silently ignored. */
2187 DWORD namesize = 0;
2189 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2190 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2191 &namesize) == ERROR_SUCCESS)) {
2192 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2193 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2194 9x: ERROR_ALREADY_EXISTS (183) */
2195 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2197 else
2199 INT len;
2200 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2201 res = (RegSetValueExW(hentry, DriverW, 0,
2202 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2204 RegCloseKey(hentry);
2207 RegCloseKey(hroot);
2208 return (res);
2211 /******************************************************************
2212 * DeletePrinterDriverA [WINSPOOL.@]
2215 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2217 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2220 /******************************************************************
2221 * DeletePrinterDriverW [WINSPOOL.@]
2224 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2226 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2229 /******************************************************************
2230 * DeleteMonitorA [WINSPOOL.@]
2232 * See DeleteMonitorW.
2235 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2237 LPWSTR nameW = NULL;
2238 LPWSTR EnvironmentW = NULL;
2239 LPWSTR MonitorNameW = NULL;
2240 BOOL res;
2241 INT len;
2243 if (pName) {
2244 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2245 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2246 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2249 if (pEnvironment) {
2250 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2251 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2252 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2254 if (pMonitorName) {
2255 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2256 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2257 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2260 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2262 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2263 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2264 HeapFree(GetProcessHeap(), 0, nameW);
2265 return (res);
2268 /******************************************************************
2269 * DeleteMonitorW [WINSPOOL.@]
2271 * Delete a specific Printmonitor from a Printing-Environment
2273 * PARAMS
2274 * pName [I] Servername or NULL (local Computer)
2275 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2276 * pMonitorName [I] Name of the Monitor, that should be deleted
2278 * RETURNS
2279 * Success: TRUE
2280 * Failure: FALSE
2282 * NOTES
2283 * pEnvironment is ignored in Windows for the local Computer.
2287 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2289 HKEY hroot = NULL;
2291 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2292 debugstr_w(pMonitorName));
2294 if (pName && (pName[0])) {
2295 FIXME("for server %s not implemented\n", debugstr_w(pName));
2296 SetLastError(ERROR_ACCESS_DENIED);
2297 return FALSE;
2300 /* pEnvironment is ignored in Windows for the local Computer */
2302 if (!pMonitorName || !pMonitorName[0]) {
2303 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2304 SetLastError(ERROR_INVALID_PARAMETER);
2305 return FALSE;
2308 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2309 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2310 return FALSE;
2313 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2314 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2315 RegCloseKey(hroot);
2316 return TRUE;
2319 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2320 RegCloseKey(hroot);
2322 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2323 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2324 return (FALSE);
2327 /******************************************************************
2328 * DeletePortA [WINSPOOL.@]
2330 * See DeletePortW.
2333 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2335 LPWSTR nameW = NULL;
2336 LPWSTR portW = NULL;
2337 INT len;
2338 DWORD res;
2340 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2342 /* convert servername to unicode */
2343 if (pName) {
2344 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2345 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2346 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2349 /* convert portname to unicode */
2350 if (pPortName) {
2351 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2352 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2353 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2356 res = DeletePortW(nameW, hWnd, portW);
2357 HeapFree(GetProcessHeap(), 0, nameW);
2358 HeapFree(GetProcessHeap(), 0, portW);
2359 return res;
2362 /******************************************************************
2363 * DeletePortW [WINSPOOL.@]
2365 * Delete a specific Port
2367 * PARAMS
2368 * pName [I] Servername or NULL (local Computer)
2369 * hWnd [I] Handle to parent Window for the Dialog-Box
2370 * pPortName [I] Name of the Port, that should be deleted
2372 * RETURNS
2373 * Success: TRUE
2374 * Failure: FALSE
2377 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2379 monitor_t * pm;
2380 monitor_t * pui;
2381 DWORD res;
2383 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2385 if (pName && pName[0]) {
2386 SetLastError(ERROR_INVALID_PARAMETER);
2387 return FALSE;
2390 if (!pPortName) {
2391 SetLastError(RPC_X_NULL_REF_POINTER);
2392 return FALSE;
2395 /* an empty Portname is Invalid */
2396 if (!pPortName[0]) {
2397 SetLastError(ERROR_NOT_SUPPORTED);
2398 return FALSE;
2401 pm = monitor_load_by_port(pPortName);
2402 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2403 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2404 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2405 TRACE("got %d with %u\n", res, GetLastError());
2407 else
2409 pui = monitor_loadui(pm);
2410 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2411 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2412 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2413 TRACE("got %d with %u\n", res, GetLastError());
2415 else
2417 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2418 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2420 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2421 SetLastError(ERROR_NOT_SUPPORTED);
2422 res = FALSE;
2424 monitor_unload(pui);
2426 monitor_unload(pm);
2428 TRACE("returning %d with %u\n", res, GetLastError());
2429 return res;
2432 /******************************************************************************
2433 * SetPrinterW [WINSPOOL.@]
2435 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2437 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2438 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2439 return FALSE;
2442 /******************************************************************************
2443 * WritePrinter [WINSPOOL.@]
2445 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2447 opened_printer_t *printer;
2448 BOOL ret = FALSE;
2450 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2452 EnterCriticalSection(&printer_handles_cs);
2453 printer = get_opened_printer(hPrinter);
2454 if(!printer)
2456 SetLastError(ERROR_INVALID_HANDLE);
2457 goto end;
2460 if(!printer->doc)
2462 SetLastError(ERROR_SPL_NO_STARTDOC);
2463 goto end;
2466 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2467 end:
2468 LeaveCriticalSection(&printer_handles_cs);
2469 return ret;
2472 /*****************************************************************************
2473 * AddFormA [WINSPOOL.@]
2475 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2477 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2478 return 1;
2481 /*****************************************************************************
2482 * AddFormW [WINSPOOL.@]
2484 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2486 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2487 return 1;
2490 /*****************************************************************************
2491 * AddJobA [WINSPOOL.@]
2493 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2495 BOOL ret;
2496 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2497 DWORD needed;
2499 if(Level != 1) {
2500 SetLastError(ERROR_INVALID_LEVEL);
2501 return FALSE;
2504 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2506 if(ret) {
2507 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2508 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2509 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2510 if(*pcbNeeded > cbBuf) {
2511 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2512 ret = FALSE;
2513 } else {
2514 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2515 addjobA->JobId = addjobW->JobId;
2516 addjobA->Path = (char *)(addjobA + 1);
2517 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2520 return ret;
2523 /*****************************************************************************
2524 * AddJobW [WINSPOOL.@]
2526 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2528 opened_printer_t *printer;
2529 job_t *job;
2530 BOOL ret = FALSE;
2531 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2532 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2533 WCHAR path[MAX_PATH], filename[MAX_PATH];
2534 DWORD len;
2535 ADDJOB_INFO_1W *addjob;
2537 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2539 EnterCriticalSection(&printer_handles_cs);
2541 printer = get_opened_printer(hPrinter);
2543 if(!printer) {
2544 SetLastError(ERROR_INVALID_HANDLE);
2545 goto end;
2548 if(Level != 1) {
2549 SetLastError(ERROR_INVALID_LEVEL);
2550 goto end;
2553 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2554 if(!job)
2555 goto end;
2557 job->job_id = InterlockedIncrement(&next_job_id);
2559 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2560 if(path[len - 1] != '\\')
2561 path[len++] = '\\';
2562 memcpy(path + len, spool_path, sizeof(spool_path));
2563 sprintfW(filename, fmtW, path, job->job_id);
2565 len = strlenW(filename);
2566 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2567 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2568 job->document_title = strdupW(default_doc_title);
2569 list_add_tail(&printer->queue->jobs, &job->entry);
2571 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2572 if(*pcbNeeded <= cbBuf) {
2573 addjob = (ADDJOB_INFO_1W*)pData;
2574 addjob->JobId = job->job_id;
2575 addjob->Path = (WCHAR *)(addjob + 1);
2576 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2577 ret = TRUE;
2578 } else
2579 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2581 end:
2582 LeaveCriticalSection(&printer_handles_cs);
2583 return ret;
2586 /*****************************************************************************
2587 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2589 * Return the PATH for the Print-Processors
2591 * See GetPrintProcessorDirectoryW.
2595 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2596 DWORD level, LPBYTE Info,
2597 DWORD cbBuf, LPDWORD pcbNeeded)
2599 LPWSTR serverW = NULL;
2600 LPWSTR envW = NULL;
2601 BOOL ret;
2602 INT len;
2604 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2605 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2608 if (server) {
2609 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2610 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2611 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2614 if (env) {
2615 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2616 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2617 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2620 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2621 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2623 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2624 cbBuf, pcbNeeded);
2626 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2627 cbBuf, NULL, NULL) > 0;
2630 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2631 HeapFree(GetProcessHeap(), 0, envW);
2632 HeapFree(GetProcessHeap(), 0, serverW);
2633 return ret;
2636 /*****************************************************************************
2637 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2639 * Return the PATH for the Print-Processors
2641 * PARAMS
2642 * server [I] Servername (NT only) or NULL (local Computer)
2643 * env [I] Printing-Environment (see below) or NULL (Default)
2644 * level [I] Structure-Level (must be 1)
2645 * Info [O] PTR to Buffer that receives the Result
2646 * cbBuf [I] Size of Buffer at "Info"
2647 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2648 * required for the Buffer at "Info"
2650 * RETURNS
2651 * Success: TRUE and in pcbNeeded the Bytes used in Info
2652 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2653 * if cbBuf is too small
2655 * Native Values returned in Info on Success:
2656 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2657 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2658 *| win9x(Windows 4.0): "%winsysdir%"
2660 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2662 * BUGS
2663 * Only NULL or "" is supported for server
2666 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2667 DWORD level, LPBYTE Info,
2668 DWORD cbBuf, LPDWORD pcbNeeded)
2670 DWORD needed;
2671 const printenv_t * env_t;
2673 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2674 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2676 if(server != NULL && server[0]) {
2677 FIXME("server not supported: %s\n", debugstr_w(server));
2678 SetLastError(ERROR_INVALID_PARAMETER);
2679 return FALSE;
2682 env_t = validate_envW(env);
2683 if(!env_t) return FALSE; /* environment invalid or unsupported */
2685 if(level != 1) {
2686 WARN("(Level: %d) is ignored in win9x\n", level);
2687 SetLastError(ERROR_INVALID_LEVEL);
2688 return FALSE;
2691 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2692 needed = GetSystemDirectoryW(NULL, 0);
2693 /* add the Size for the Subdirectories */
2694 needed += lstrlenW(spoolprtprocsW);
2695 needed += lstrlenW(env_t->subdir);
2696 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2698 if(pcbNeeded) *pcbNeeded = needed;
2699 TRACE ("required: 0x%x/%d\n", needed, needed);
2700 if (needed > cbBuf) {
2701 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2702 return FALSE;
2704 if(pcbNeeded == NULL) {
2705 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2706 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2707 SetLastError(RPC_X_NULL_REF_POINTER);
2708 return FALSE;
2710 if(Info == NULL) {
2711 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2712 SetLastError(RPC_X_NULL_REF_POINTER);
2713 return FALSE;
2716 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2717 /* add the Subdirectories */
2718 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2719 lstrcatW((LPWSTR) Info, env_t->subdir);
2720 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2721 return TRUE;
2724 /*****************************************************************************
2725 * WINSPOOL_OpenDriverReg [internal]
2727 * opens the registry for the printer drivers depending on the given input
2728 * variable pEnvironment
2730 * RETURNS:
2731 * the opened hkey on success
2732 * NULL on error
2734 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2736 HKEY retval = NULL;
2737 LPWSTR buffer;
2738 const printenv_t * env;
2740 TRACE("(%s, %d)\n",
2741 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2743 if (!pEnvironment || unicode) {
2744 /* pEnvironment was NULL or an Unicode-String: use it direct */
2745 env = validate_envW(pEnvironment);
2747 else
2749 /* pEnvironment was an ANSI-String: convert to unicode first */
2750 LPWSTR buffer;
2751 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2752 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2753 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2754 env = validate_envW(buffer);
2755 HeapFree(GetProcessHeap(), 0, buffer);
2757 if (!env) return NULL;
2759 buffer = HeapAlloc( GetProcessHeap(), 0,
2760 (strlenW(DriversW) + strlenW(env->envname) +
2761 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2762 if(buffer) {
2763 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2764 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2765 HeapFree(GetProcessHeap(), 0, buffer);
2767 return retval;
2770 /*****************************************************************************
2771 * AddPrinterW [WINSPOOL.@]
2773 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2775 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2776 LPDEVMODEA dmA;
2777 LPDEVMODEW dmW;
2778 HANDLE retval;
2779 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2780 LONG size;
2781 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2782 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2783 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2784 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2785 statusW[] = {'S','t','a','t','u','s',0},
2786 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2788 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2790 if(pName != NULL) {
2791 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2792 SetLastError(ERROR_INVALID_PARAMETER);
2793 return 0;
2795 if(Level != 2) {
2796 ERR("Level = %d, unsupported!\n", Level);
2797 SetLastError(ERROR_INVALID_LEVEL);
2798 return 0;
2800 if(!pPrinter) {
2801 SetLastError(ERROR_INVALID_PARAMETER);
2802 return 0;
2804 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2805 ERROR_SUCCESS) {
2806 ERR("Can't create Printers key\n");
2807 return 0;
2809 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2810 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2811 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2812 RegCloseKey(hkeyPrinter);
2813 RegCloseKey(hkeyPrinters);
2814 return 0;
2816 RegCloseKey(hkeyPrinter);
2818 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2819 if(!hkeyDrivers) {
2820 ERR("Can't create Drivers key\n");
2821 RegCloseKey(hkeyPrinters);
2822 return 0;
2824 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2825 ERROR_SUCCESS) {
2826 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2827 RegCloseKey(hkeyPrinters);
2828 RegCloseKey(hkeyDrivers);
2829 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2830 return 0;
2832 RegCloseKey(hkeyDriver);
2833 RegCloseKey(hkeyDrivers);
2835 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2836 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2837 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2838 RegCloseKey(hkeyPrinters);
2839 return 0;
2842 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2843 ERROR_SUCCESS) {
2844 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2845 SetLastError(ERROR_INVALID_PRINTER_NAME);
2846 RegCloseKey(hkeyPrinters);
2847 return 0;
2849 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2850 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2851 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2853 /* See if we can load the driver. We may need the devmode structure anyway
2855 * FIXME:
2856 * Note that DocumentPropertiesW will briefly try to open the printer we
2857 * just create to find a DEVMODEA struct (it will use the WINEPS default
2858 * one in case it is not there, so we are ok).
2860 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2862 if(size < 0) {
2863 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2864 size = sizeof(DEVMODEW);
2866 if(pi->pDevMode)
2867 dmW = pi->pDevMode;
2868 else
2870 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2871 dmW->dmSize = size;
2872 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2874 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2875 HeapFree(GetProcessHeap(),0,dmW);
2876 dmW=NULL;
2878 else
2880 /* set devmode to printer name */
2881 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2885 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2886 and we support these drivers. NT writes DEVMODEW so somehow
2887 we'll need to distinguish between these when we support NT
2888 drivers */
2889 if (dmW)
2891 dmA = DEVMODEdupWtoA(dmW);
2892 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2893 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2894 HeapFree(GetProcessHeap(), 0, dmA);
2895 if(!pi->pDevMode)
2896 HeapFree(GetProcessHeap(), 0, dmW);
2898 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2899 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2900 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2901 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2903 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2904 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2905 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2906 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2907 (LPBYTE)&pi->Priority, sizeof(DWORD));
2908 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2909 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2910 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2911 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2912 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2913 (LPBYTE)&pi->Status, sizeof(DWORD));
2914 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2915 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2917 RegCloseKey(hkeyPrinter);
2918 RegCloseKey(hkeyPrinters);
2919 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2920 ERR("OpenPrinter failing\n");
2921 return 0;
2923 return retval;
2926 /*****************************************************************************
2927 * AddPrinterA [WINSPOOL.@]
2929 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2931 UNICODE_STRING pNameW;
2932 PWSTR pwstrNameW;
2933 PRINTER_INFO_2W *piW;
2934 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2935 HANDLE ret;
2937 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2938 if(Level != 2) {
2939 ERR("Level = %d, unsupported!\n", Level);
2940 SetLastError(ERROR_INVALID_LEVEL);
2941 return 0;
2943 pwstrNameW = asciitounicode(&pNameW,pName);
2944 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2946 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2948 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2949 RtlFreeUnicodeString(&pNameW);
2950 return ret;
2954 /*****************************************************************************
2955 * ClosePrinter [WINSPOOL.@]
2957 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2959 UINT_PTR i = (UINT_PTR)hPrinter;
2960 opened_printer_t *printer = NULL;
2961 BOOL ret = FALSE;
2963 TRACE("(%p)\n", hPrinter);
2965 EnterCriticalSection(&printer_handles_cs);
2967 if ((i > 0) && (i <= nb_printer_handles))
2968 printer = printer_handles[i - 1];
2971 if(printer)
2973 struct list *cursor, *cursor2;
2975 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2976 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2977 printer->hXcv, debugstr_w(printer->name), printer->doc );
2979 if(printer->doc)
2980 EndDocPrinter(hPrinter);
2982 if(InterlockedDecrement(&printer->queue->ref) == 0)
2984 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2986 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2987 ScheduleJob(hPrinter, job->job_id);
2989 HeapFree(GetProcessHeap(), 0, printer->queue);
2991 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2992 monitor_unload(printer->pm);
2993 HeapFree(GetProcessHeap(), 0, printer->printername);
2994 HeapFree(GetProcessHeap(), 0, printer->name);
2995 HeapFree(GetProcessHeap(), 0, printer);
2996 printer_handles[i - 1] = NULL;
2997 ret = TRUE;
2999 LeaveCriticalSection(&printer_handles_cs);
3000 return ret;
3003 /*****************************************************************************
3004 * DeleteFormA [WINSPOOL.@]
3006 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3008 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3009 return 1;
3012 /*****************************************************************************
3013 * DeleteFormW [WINSPOOL.@]
3015 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3017 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3018 return 1;
3021 /*****************************************************************************
3022 * DeletePrinter [WINSPOOL.@]
3024 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3026 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3027 HKEY hkeyPrinters, hkey;
3029 if(!lpNameW) {
3030 SetLastError(ERROR_INVALID_HANDLE);
3031 return FALSE;
3033 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3034 RegDeleteTreeW(hkeyPrinters, lpNameW);
3035 RegCloseKey(hkeyPrinters);
3037 WriteProfileStringW(devicesW, lpNameW, NULL);
3038 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3039 RegDeleteValueW(hkey, lpNameW);
3040 RegCloseKey(hkey);
3042 return TRUE;
3045 /*****************************************************************************
3046 * SetPrinterA [WINSPOOL.@]
3048 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3049 DWORD Command)
3051 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3052 return FALSE;
3055 /*****************************************************************************
3056 * SetJobA [WINSPOOL.@]
3058 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3059 LPBYTE pJob, DWORD Command)
3061 BOOL ret;
3062 LPBYTE JobW;
3063 UNICODE_STRING usBuffer;
3065 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3067 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3068 are all ignored by SetJob, so we don't bother copying them */
3069 switch(Level)
3071 case 0:
3072 JobW = NULL;
3073 break;
3074 case 1:
3076 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3077 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3079 JobW = (LPBYTE)info1W;
3080 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3081 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3082 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3083 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3084 info1W->Status = info1A->Status;
3085 info1W->Priority = info1A->Priority;
3086 info1W->Position = info1A->Position;
3087 info1W->PagesPrinted = info1A->PagesPrinted;
3088 break;
3090 case 2:
3092 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3093 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3095 JobW = (LPBYTE)info2W;
3096 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3097 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3098 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3099 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3100 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3101 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3102 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3103 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3104 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3105 info2W->Status = info2A->Status;
3106 info2W->Priority = info2A->Priority;
3107 info2W->Position = info2A->Position;
3108 info2W->StartTime = info2A->StartTime;
3109 info2W->UntilTime = info2A->UntilTime;
3110 info2W->PagesPrinted = info2A->PagesPrinted;
3111 break;
3113 case 3:
3114 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3115 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3116 break;
3117 default:
3118 SetLastError(ERROR_INVALID_LEVEL);
3119 return FALSE;
3122 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3124 switch(Level)
3126 case 1:
3128 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3129 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3130 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3131 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3132 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3133 break;
3135 case 2:
3137 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3138 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3139 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3140 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3141 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3142 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3143 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3144 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3145 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3146 break;
3149 HeapFree(GetProcessHeap(), 0, JobW);
3151 return ret;
3154 /*****************************************************************************
3155 * SetJobW [WINSPOOL.@]
3157 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3158 LPBYTE pJob, DWORD Command)
3160 BOOL ret = FALSE;
3161 job_t *job;
3163 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3164 FIXME("Ignoring everything other than document title\n");
3166 EnterCriticalSection(&printer_handles_cs);
3167 job = get_job(hPrinter, JobId);
3168 if(!job)
3169 goto end;
3171 switch(Level)
3173 case 0:
3174 break;
3175 case 1:
3177 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3178 HeapFree(GetProcessHeap(), 0, job->document_title);
3179 job->document_title = strdupW(info1->pDocument);
3180 break;
3182 case 2:
3184 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3185 HeapFree(GetProcessHeap(), 0, job->document_title);
3186 job->document_title = strdupW(info2->pDocument);
3187 break;
3189 case 3:
3190 break;
3191 default:
3192 SetLastError(ERROR_INVALID_LEVEL);
3193 goto end;
3195 ret = TRUE;
3196 end:
3197 LeaveCriticalSection(&printer_handles_cs);
3198 return ret;
3201 /*****************************************************************************
3202 * EndDocPrinter [WINSPOOL.@]
3204 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3206 opened_printer_t *printer;
3207 BOOL ret = FALSE;
3208 TRACE("(%p)\n", hPrinter);
3210 EnterCriticalSection(&printer_handles_cs);
3212 printer = get_opened_printer(hPrinter);
3213 if(!printer)
3215 SetLastError(ERROR_INVALID_HANDLE);
3216 goto end;
3219 if(!printer->doc)
3221 SetLastError(ERROR_SPL_NO_STARTDOC);
3222 goto end;
3225 CloseHandle(printer->doc->hf);
3226 ScheduleJob(hPrinter, printer->doc->job_id);
3227 HeapFree(GetProcessHeap(), 0, printer->doc);
3228 printer->doc = NULL;
3229 ret = TRUE;
3230 end:
3231 LeaveCriticalSection(&printer_handles_cs);
3232 return ret;
3235 /*****************************************************************************
3236 * EndPagePrinter [WINSPOOL.@]
3238 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3240 FIXME("(%p): stub\n", hPrinter);
3241 return TRUE;
3244 /*****************************************************************************
3245 * StartDocPrinterA [WINSPOOL.@]
3247 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3249 UNICODE_STRING usBuffer;
3250 DOC_INFO_2W doc2W;
3251 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3252 DWORD ret;
3254 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3255 or one (DOC_INFO_3) extra DWORDs */
3257 switch(Level) {
3258 case 2:
3259 doc2W.JobId = doc2->JobId;
3260 /* fall through */
3261 case 3:
3262 doc2W.dwMode = doc2->dwMode;
3263 /* fall through */
3264 case 1:
3265 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3266 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3267 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3268 break;
3270 default:
3271 SetLastError(ERROR_INVALID_LEVEL);
3272 return FALSE;
3275 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3277 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3278 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3279 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3281 return ret;
3284 /*****************************************************************************
3285 * StartDocPrinterW [WINSPOOL.@]
3287 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3289 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3290 opened_printer_t *printer;
3291 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3292 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3293 JOB_INFO_1W job_info;
3294 DWORD needed, ret = 0;
3295 HANDLE hf;
3296 WCHAR *filename;
3298 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3299 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3300 debugstr_w(doc->pDatatype));
3302 if(Level < 1 || Level > 3)
3304 SetLastError(ERROR_INVALID_LEVEL);
3305 return 0;
3308 EnterCriticalSection(&printer_handles_cs);
3309 printer = get_opened_printer(hPrinter);
3310 if(!printer)
3312 SetLastError(ERROR_INVALID_HANDLE);
3313 goto end;
3316 if(printer->doc)
3318 SetLastError(ERROR_INVALID_PRINTER_STATE);
3319 goto end;
3322 /* Even if we're printing to a file we still add a print job, we'll
3323 just ignore the spool file name */
3325 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3327 ERR("AddJob failed gle %u\n", GetLastError());
3328 goto end;
3331 if(doc->pOutputFile)
3332 filename = doc->pOutputFile;
3333 else
3334 filename = addjob->Path;
3336 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3337 if(hf == INVALID_HANDLE_VALUE)
3338 goto end;
3340 memset(&job_info, 0, sizeof(job_info));
3341 job_info.pDocument = doc->pDocName;
3342 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3344 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3345 printer->doc->hf = hf;
3346 ret = printer->doc->job_id = addjob->JobId;
3347 end:
3348 LeaveCriticalSection(&printer_handles_cs);
3350 return ret;
3353 /*****************************************************************************
3354 * StartPagePrinter [WINSPOOL.@]
3356 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3358 FIXME("(%p): stub\n", hPrinter);
3359 return TRUE;
3362 /*****************************************************************************
3363 * GetFormA [WINSPOOL.@]
3365 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3366 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3368 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3369 Level,pForm,cbBuf,pcbNeeded);
3370 return FALSE;
3373 /*****************************************************************************
3374 * GetFormW [WINSPOOL.@]
3376 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3377 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3379 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3380 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3381 return FALSE;
3384 /*****************************************************************************
3385 * SetFormA [WINSPOOL.@]
3387 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3388 LPBYTE pForm)
3390 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3391 return FALSE;
3394 /*****************************************************************************
3395 * SetFormW [WINSPOOL.@]
3397 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3398 LPBYTE pForm)
3400 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3401 return FALSE;
3404 /*****************************************************************************
3405 * ReadPrinter [WINSPOOL.@]
3407 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3408 LPDWORD pNoBytesRead)
3410 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3411 return FALSE;
3414 /*****************************************************************************
3415 * ResetPrinterA [WINSPOOL.@]
3417 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3419 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3420 return FALSE;
3423 /*****************************************************************************
3424 * ResetPrinterW [WINSPOOL.@]
3426 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3428 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3429 return FALSE;
3432 /*****************************************************************************
3433 * WINSPOOL_GetDWORDFromReg
3435 * Return DWORD associated with ValueName from hkey.
3437 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3439 DWORD sz = sizeof(DWORD), type, value = 0;
3440 LONG ret;
3442 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3444 if(ret != ERROR_SUCCESS) {
3445 WARN("Got ret = %d on name %s\n", ret, ValueName);
3446 return 0;
3448 if(type != REG_DWORD) {
3449 ERR("Got type %d\n", type);
3450 return 0;
3452 return value;
3456 /*****************************************************************************
3457 * get_filename_from_reg [internal]
3459 * Get ValueName from hkey storing result in out
3460 * when the Value in the registry has only a filename, use driverdir as prefix
3461 * outlen is space left in out
3462 * String is stored either as unicode or ascii
3466 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3467 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3469 WCHAR filename[MAX_PATH];
3470 DWORD size;
3471 DWORD type;
3472 LONG ret;
3473 LPWSTR buffer = filename;
3474 LPWSTR ptr;
3476 *needed = 0;
3477 size = sizeof(filename);
3478 buffer[0] = '\0';
3479 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3480 if (ret == ERROR_MORE_DATA) {
3481 TRACE("need dynamic buffer: %u\n", size);
3482 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3483 if (!buffer) {
3484 /* No Memory is bad */
3485 return FALSE;
3487 buffer[0] = '\0';
3488 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3491 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3492 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3493 return FALSE;
3496 ptr = buffer;
3497 while (ptr) {
3498 /* do we have a full path ? */
3499 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3500 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3502 if (!ret) {
3503 /* we must build the full Path */
3504 *needed += dirlen;
3505 if ((out) && (outlen > dirlen)) {
3506 if (unicode) {
3507 lstrcpyW((LPWSTR)out, driverdir);
3509 else
3511 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3513 out += dirlen;
3514 outlen -= dirlen;
3516 else
3517 out = NULL;
3520 /* write the filename */
3521 if (unicode) {
3522 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3523 if ((out) && (outlen >= size)) {
3524 lstrcpyW((LPWSTR)out, ptr);
3525 out += size;
3526 outlen -= size;
3528 else
3529 out = NULL;
3531 else
3533 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3534 if ((out) && (outlen >= size)) {
3535 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3536 out += size;
3537 outlen -= size;
3539 else
3540 out = NULL;
3542 *needed += size;
3543 ptr += lstrlenW(ptr)+1;
3544 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3547 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3549 /* write the multisz-termination */
3550 if (type == REG_MULTI_SZ) {
3551 size = (unicode) ? sizeof(WCHAR) : 1;
3553 *needed += size;
3554 if (out && (outlen >= size)) {
3555 memset (out, 0, size);
3558 return TRUE;
3561 /*****************************************************************************
3562 * WINSPOOL_GetStringFromReg
3564 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3565 * String is stored either as unicode or ascii.
3566 * Bit of a hack here to get the ValueName if we want ascii.
3568 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3569 DWORD buflen, DWORD *needed,
3570 BOOL unicode)
3572 DWORD sz = buflen, type;
3573 LONG ret;
3575 if(unicode)
3576 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3577 else {
3578 LPSTR ValueNameA = strdupWtoA(ValueName);
3579 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3580 HeapFree(GetProcessHeap(),0,ValueNameA);
3582 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3583 WARN("Got ret = %d\n", ret);
3584 *needed = 0;
3585 return FALSE;
3587 /* add space for terminating '\0' */
3588 sz += unicode ? sizeof(WCHAR) : 1;
3589 *needed = sz;
3591 if (ptr)
3592 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3594 return TRUE;
3597 /*****************************************************************************
3598 * WINSPOOL_GetDefaultDevMode
3600 * Get a default DevMode values for wineps.
3601 * FIXME - use ppd.
3604 static void WINSPOOL_GetDefaultDevMode(
3605 LPBYTE ptr,
3606 DWORD buflen, DWORD *needed,
3607 BOOL unicode)
3609 DEVMODEA dm;
3610 static const char szwps[] = "wineps.drv";
3612 /* fill default DEVMODE - should be read from ppd... */
3613 ZeroMemory( &dm, sizeof(dm) );
3614 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3615 dm.dmSpecVersion = DM_SPECVERSION;
3616 dm.dmDriverVersion = 1;
3617 dm.dmSize = sizeof(DEVMODEA);
3618 dm.dmDriverExtra = 0;
3619 dm.dmFields =
3620 DM_ORIENTATION | DM_PAPERSIZE |
3621 DM_PAPERLENGTH | DM_PAPERWIDTH |
3622 DM_SCALE |
3623 DM_COPIES |
3624 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3625 DM_YRESOLUTION | DM_TTOPTION;
3627 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3628 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3629 dm.u1.s1.dmPaperLength = 2970;
3630 dm.u1.s1.dmPaperWidth = 2100;
3632 dm.u1.s1.dmScale = 100;
3633 dm.u1.s1.dmCopies = 1;
3634 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3635 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3636 /* dm.dmColor */
3637 /* dm.dmDuplex */
3638 dm.dmYResolution = 300; /* 300dpi */
3639 dm.dmTTOption = DMTT_BITMAP;
3640 /* dm.dmCollate */
3641 /* dm.dmFormName */
3642 /* dm.dmLogPixels */
3643 /* dm.dmBitsPerPel */
3644 /* dm.dmPelsWidth */
3645 /* dm.dmPelsHeight */
3646 /* dm.u2.dmDisplayFlags */
3647 /* dm.dmDisplayFrequency */
3648 /* dm.dmICMMethod */
3649 /* dm.dmICMIntent */
3650 /* dm.dmMediaType */
3651 /* dm.dmDitherType */
3652 /* dm.dmReserved1 */
3653 /* dm.dmReserved2 */
3654 /* dm.dmPanningWidth */
3655 /* dm.dmPanningHeight */
3657 if(unicode) {
3658 if(buflen >= sizeof(DEVMODEW)) {
3659 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3660 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3661 HeapFree(GetProcessHeap(),0,pdmW);
3663 *needed = sizeof(DEVMODEW);
3665 else
3667 if(buflen >= sizeof(DEVMODEA)) {
3668 memcpy(ptr, &dm, sizeof(DEVMODEA));
3670 *needed = sizeof(DEVMODEA);
3674 /*****************************************************************************
3675 * WINSPOOL_GetDevModeFromReg
3677 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3678 * DevMode is stored either as unicode or ascii.
3680 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3681 LPBYTE ptr,
3682 DWORD buflen, DWORD *needed,
3683 BOOL unicode)
3685 DWORD sz = buflen, type;
3686 LONG ret;
3688 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3689 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3690 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3691 if (sz < sizeof(DEVMODEA))
3693 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3694 return FALSE;
3696 /* ensures that dmSize is not erratically bogus if registry is invalid */
3697 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3698 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3699 if(unicode) {
3700 sz += (CCHDEVICENAME + CCHFORMNAME);
3701 if(buflen >= sz) {
3702 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3703 memcpy(ptr, dmW, sz);
3704 HeapFree(GetProcessHeap(),0,dmW);
3707 *needed = sz;
3708 return TRUE;
3711 /*********************************************************************
3712 * WINSPOOL_GetPrinter_1
3714 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3715 * The strings are either stored as unicode or ascii.
3717 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3718 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3719 BOOL unicode)
3721 DWORD size, left = cbBuf;
3722 BOOL space = (cbBuf > 0);
3723 LPBYTE ptr = buf;
3725 *pcbNeeded = 0;
3727 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3728 unicode)) {
3729 if(space && size <= left) {
3730 pi1->pName = (LPWSTR)ptr;
3731 ptr += size;
3732 left -= size;
3733 } else
3734 space = FALSE;
3735 *pcbNeeded += size;
3738 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3739 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3740 unicode)) {
3741 if(space && size <= left) {
3742 pi1->pDescription = (LPWSTR)ptr;
3743 ptr += size;
3744 left -= size;
3745 } else
3746 space = FALSE;
3747 *pcbNeeded += size;
3750 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3751 unicode)) {
3752 if(space && size <= left) {
3753 pi1->pComment = (LPWSTR)ptr;
3754 ptr += size;
3755 left -= size;
3756 } else
3757 space = FALSE;
3758 *pcbNeeded += size;
3761 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3763 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3764 memset(pi1, 0, sizeof(*pi1));
3766 return space;
3768 /*********************************************************************
3769 * WINSPOOL_GetPrinter_2
3771 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3772 * The strings are either stored as unicode or ascii.
3774 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3775 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3776 BOOL unicode)
3778 DWORD size, left = cbBuf;
3779 BOOL space = (cbBuf > 0);
3780 LPBYTE ptr = buf;
3782 *pcbNeeded = 0;
3784 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3785 unicode)) {
3786 if(space && size <= left) {
3787 pi2->pPrinterName = (LPWSTR)ptr;
3788 ptr += size;
3789 left -= size;
3790 } else
3791 space = FALSE;
3792 *pcbNeeded += size;
3794 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3795 unicode)) {
3796 if(space && size <= left) {
3797 pi2->pShareName = (LPWSTR)ptr;
3798 ptr += size;
3799 left -= size;
3800 } else
3801 space = FALSE;
3802 *pcbNeeded += size;
3804 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3805 unicode)) {
3806 if(space && size <= left) {
3807 pi2->pPortName = (LPWSTR)ptr;
3808 ptr += size;
3809 left -= size;
3810 } else
3811 space = FALSE;
3812 *pcbNeeded += size;
3814 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3815 &size, unicode)) {
3816 if(space && size <= left) {
3817 pi2->pDriverName = (LPWSTR)ptr;
3818 ptr += size;
3819 left -= size;
3820 } else
3821 space = FALSE;
3822 *pcbNeeded += size;
3824 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3825 unicode)) {
3826 if(space && size <= left) {
3827 pi2->pComment = (LPWSTR)ptr;
3828 ptr += size;
3829 left -= size;
3830 } else
3831 space = FALSE;
3832 *pcbNeeded += size;
3834 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3835 unicode)) {
3836 if(space && size <= left) {
3837 pi2->pLocation = (LPWSTR)ptr;
3838 ptr += size;
3839 left -= size;
3840 } else
3841 space = FALSE;
3842 *pcbNeeded += size;
3844 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3845 &size, unicode)) {
3846 if(space && size <= left) {
3847 pi2->pDevMode = (LPDEVMODEW)ptr;
3848 ptr += size;
3849 left -= size;
3850 } else
3851 space = FALSE;
3852 *pcbNeeded += size;
3854 else
3856 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3857 if(space && size <= left) {
3858 pi2->pDevMode = (LPDEVMODEW)ptr;
3859 ptr += size;
3860 left -= size;
3861 } else
3862 space = FALSE;
3863 *pcbNeeded += size;
3865 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3866 &size, unicode)) {
3867 if(space && size <= left) {
3868 pi2->pSepFile = (LPWSTR)ptr;
3869 ptr += size;
3870 left -= size;
3871 } else
3872 space = FALSE;
3873 *pcbNeeded += size;
3875 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3876 &size, unicode)) {
3877 if(space && size <= left) {
3878 pi2->pPrintProcessor = (LPWSTR)ptr;
3879 ptr += size;
3880 left -= size;
3881 } else
3882 space = FALSE;
3883 *pcbNeeded += size;
3885 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3886 &size, unicode)) {
3887 if(space && size <= left) {
3888 pi2->pDatatype = (LPWSTR)ptr;
3889 ptr += size;
3890 left -= size;
3891 } else
3892 space = FALSE;
3893 *pcbNeeded += size;
3895 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3896 &size, unicode)) {
3897 if(space && size <= left) {
3898 pi2->pParameters = (LPWSTR)ptr;
3899 ptr += size;
3900 left -= size;
3901 } else
3902 space = FALSE;
3903 *pcbNeeded += size;
3905 if(pi2) {
3906 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3907 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3908 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3909 "Default Priority");
3910 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3911 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3914 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3915 memset(pi2, 0, sizeof(*pi2));
3917 return space;
3920 /*********************************************************************
3921 * WINSPOOL_GetPrinter_4
3923 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3925 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3926 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3927 BOOL unicode)
3929 DWORD size, left = cbBuf;
3930 BOOL space = (cbBuf > 0);
3931 LPBYTE ptr = buf;
3933 *pcbNeeded = 0;
3935 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3936 unicode)) {
3937 if(space && size <= left) {
3938 pi4->pPrinterName = (LPWSTR)ptr;
3939 ptr += size;
3940 left -= size;
3941 } else
3942 space = FALSE;
3943 *pcbNeeded += size;
3945 if(pi4) {
3946 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3949 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3950 memset(pi4, 0, sizeof(*pi4));
3952 return space;
3955 /*********************************************************************
3956 * WINSPOOL_GetPrinter_5
3958 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3960 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3961 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3962 BOOL unicode)
3964 DWORD size, left = cbBuf;
3965 BOOL space = (cbBuf > 0);
3966 LPBYTE ptr = buf;
3968 *pcbNeeded = 0;
3970 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3971 unicode)) {
3972 if(space && size <= left) {
3973 pi5->pPrinterName = (LPWSTR)ptr;
3974 ptr += size;
3975 left -= size;
3976 } else
3977 space = FALSE;
3978 *pcbNeeded += size;
3980 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3981 unicode)) {
3982 if(space && size <= left) {
3983 pi5->pPortName = (LPWSTR)ptr;
3984 ptr += size;
3985 left -= size;
3986 } else
3987 space = FALSE;
3988 *pcbNeeded += size;
3990 if(pi5) {
3991 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3992 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3993 "dnsTimeout");
3994 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3995 "txTimeout");
3998 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3999 memset(pi5, 0, sizeof(*pi5));
4001 return space;
4004 /*********************************************************************
4005 * WINSPOOL_GetPrinter_7
4007 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4009 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4010 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4012 DWORD size, left = cbBuf;
4013 BOOL space = (cbBuf > 0);
4014 LPBYTE ptr = buf;
4016 *pcbNeeded = 0;
4018 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4020 if (space && size <= left) {
4021 pi7->pszObjectGUID = (LPWSTR)ptr;
4022 ptr += size;
4023 left -= size;
4024 } else
4025 space = FALSE;
4026 *pcbNeeded += size;
4028 if (pi7) {
4029 /* We do not have a Directory Service */
4030 pi7->dwAction = DSPRINT_UNPUBLISH;
4033 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4034 memset(pi7, 0, sizeof(*pi7));
4036 return space;
4039 /*********************************************************************
4040 * WINSPOOL_GetPrinter_9
4042 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4043 * The strings are either stored as unicode or ascii.
4045 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4046 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4048 DWORD size;
4049 BOOL space = (cbBuf > 0);
4051 *pcbNeeded = 0;
4053 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4054 if(space && size <= cbBuf) {
4055 pi9->pDevMode = (LPDEVMODEW)buf;
4056 } else
4057 space = FALSE;
4058 *pcbNeeded += size;
4060 else
4062 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4063 if(space && size <= cbBuf) {
4064 pi9->pDevMode = (LPDEVMODEW)buf;
4065 } else
4066 space = FALSE;
4067 *pcbNeeded += size;
4070 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4071 memset(pi9, 0, sizeof(*pi9));
4073 return space;
4076 /*****************************************************************************
4077 * WINSPOOL_GetPrinter
4079 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4080 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4081 * just a collection of pointers to strings.
4083 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4084 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4086 LPCWSTR name;
4087 DWORD size, needed = 0;
4088 LPBYTE ptr = NULL;
4089 HKEY hkeyPrinter, hkeyPrinters;
4090 BOOL ret;
4092 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4094 if (!(name = get_opened_printer_name(hPrinter))) {
4095 SetLastError(ERROR_INVALID_HANDLE);
4096 return FALSE;
4099 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4100 ERROR_SUCCESS) {
4101 ERR("Can't create Printers key\n");
4102 return FALSE;
4104 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4106 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4107 RegCloseKey(hkeyPrinters);
4108 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4109 return FALSE;
4112 switch(Level) {
4113 case 2:
4115 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4117 size = sizeof(PRINTER_INFO_2W);
4118 if(size <= cbBuf) {
4119 ptr = pPrinter + size;
4120 cbBuf -= size;
4121 memset(pPrinter, 0, size);
4122 } else {
4123 pi2 = NULL;
4124 cbBuf = 0;
4126 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4127 unicode);
4128 needed += size;
4129 break;
4132 case 4:
4134 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4136 size = sizeof(PRINTER_INFO_4W);
4137 if(size <= cbBuf) {
4138 ptr = pPrinter + size;
4139 cbBuf -= size;
4140 memset(pPrinter, 0, size);
4141 } else {
4142 pi4 = NULL;
4143 cbBuf = 0;
4145 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4146 unicode);
4147 needed += size;
4148 break;
4152 case 5:
4154 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4156 size = sizeof(PRINTER_INFO_5W);
4157 if(size <= cbBuf) {
4158 ptr = pPrinter + size;
4159 cbBuf -= size;
4160 memset(pPrinter, 0, size);
4161 } else {
4162 pi5 = NULL;
4163 cbBuf = 0;
4166 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4167 unicode);
4168 needed += size;
4169 break;
4173 case 6:
4175 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4177 size = sizeof(PRINTER_INFO_6);
4178 if (size <= cbBuf) {
4179 /* FIXME: We do not update the status yet */
4180 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4181 ret = TRUE;
4182 } else {
4183 ret = FALSE;
4186 needed += size;
4187 break;
4190 case 7:
4192 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4194 size = sizeof(PRINTER_INFO_7W);
4195 if (size <= cbBuf) {
4196 ptr = pPrinter + size;
4197 cbBuf -= size;
4198 memset(pPrinter, 0, size);
4199 } else {
4200 pi7 = NULL;
4201 cbBuf = 0;
4204 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4205 needed += size;
4206 break;
4210 case 9:
4212 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4214 size = sizeof(PRINTER_INFO_9W);
4215 if(size <= cbBuf) {
4216 ptr = pPrinter + size;
4217 cbBuf -= size;
4218 memset(pPrinter, 0, size);
4219 } else {
4220 pi9 = NULL;
4221 cbBuf = 0;
4224 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4225 needed += size;
4226 break;
4230 default:
4231 FIXME("Unimplemented level %d\n", Level);
4232 SetLastError(ERROR_INVALID_LEVEL);
4233 RegCloseKey(hkeyPrinters);
4234 RegCloseKey(hkeyPrinter);
4235 return FALSE;
4238 RegCloseKey(hkeyPrinter);
4239 RegCloseKey(hkeyPrinters);
4241 TRACE("returning %d needed = %d\n", ret, needed);
4242 if(pcbNeeded) *pcbNeeded = needed;
4243 if(!ret)
4244 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4245 return ret;
4248 /*****************************************************************************
4249 * GetPrinterW [WINSPOOL.@]
4251 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4252 DWORD cbBuf, LPDWORD pcbNeeded)
4254 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4255 TRUE);
4258 /*****************************************************************************
4259 * GetPrinterA [WINSPOOL.@]
4261 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4262 DWORD cbBuf, LPDWORD pcbNeeded)
4264 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4265 FALSE);
4268 /*****************************************************************************
4269 * WINSPOOL_EnumPrinters
4271 * Implementation of EnumPrintersA|W
4273 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4274 DWORD dwLevel, LPBYTE lpbPrinters,
4275 DWORD cbBuf, LPDWORD lpdwNeeded,
4276 LPDWORD lpdwReturned, BOOL unicode)
4279 HKEY hkeyPrinters, hkeyPrinter;
4280 WCHAR PrinterName[255];
4281 DWORD needed = 0, number = 0;
4282 DWORD used, i, left;
4283 PBYTE pi, buf;
4285 if(lpbPrinters)
4286 memset(lpbPrinters, 0, cbBuf);
4287 if(lpdwReturned)
4288 *lpdwReturned = 0;
4289 if(lpdwNeeded)
4290 *lpdwNeeded = 0;
4292 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4293 if(dwType == PRINTER_ENUM_DEFAULT)
4294 return TRUE;
4296 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4297 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4298 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4299 if (!dwType) {
4300 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4301 *lpdwNeeded = 0;
4302 *lpdwReturned = 0;
4303 return TRUE;
4308 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4309 FIXME("dwType = %08x\n", dwType);
4310 SetLastError(ERROR_INVALID_FLAGS);
4311 return FALSE;
4314 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4315 ERROR_SUCCESS) {
4316 ERR("Can't create Printers key\n");
4317 return FALSE;
4320 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4321 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4322 RegCloseKey(hkeyPrinters);
4323 ERR("Can't query Printers key\n");
4324 return FALSE;
4326 TRACE("Found %d printers\n", number);
4328 switch(dwLevel) {
4329 case 1:
4330 used = number * sizeof(PRINTER_INFO_1W);
4331 break;
4332 case 2:
4333 used = number * sizeof(PRINTER_INFO_2W);
4334 break;
4335 case 4:
4336 used = number * sizeof(PRINTER_INFO_4W);
4337 break;
4338 case 5:
4339 used = number * sizeof(PRINTER_INFO_5W);
4340 break;
4342 default:
4343 SetLastError(ERROR_INVALID_LEVEL);
4344 RegCloseKey(hkeyPrinters);
4345 return FALSE;
4347 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4349 for(i = 0; i < number; i++) {
4350 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4351 ERROR_SUCCESS) {
4352 ERR("Can't enum key number %d\n", i);
4353 RegCloseKey(hkeyPrinters);
4354 return FALSE;
4356 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4357 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4358 ERROR_SUCCESS) {
4359 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4360 RegCloseKey(hkeyPrinters);
4361 return FALSE;
4364 if(cbBuf > used) {
4365 buf = lpbPrinters + used;
4366 left = cbBuf - used;
4367 } else {
4368 buf = NULL;
4369 left = 0;
4372 switch(dwLevel) {
4373 case 1:
4374 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4375 left, &needed, unicode);
4376 used += needed;
4377 if(pi) pi += sizeof(PRINTER_INFO_1W);
4378 break;
4379 case 2:
4380 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4381 left, &needed, unicode);
4382 used += needed;
4383 if(pi) pi += sizeof(PRINTER_INFO_2W);
4384 break;
4385 case 4:
4386 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4387 left, &needed, unicode);
4388 used += needed;
4389 if(pi) pi += sizeof(PRINTER_INFO_4W);
4390 break;
4391 case 5:
4392 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4393 left, &needed, unicode);
4394 used += needed;
4395 if(pi) pi += sizeof(PRINTER_INFO_5W);
4396 break;
4397 default:
4398 ERR("Shouldn't be here!\n");
4399 RegCloseKey(hkeyPrinter);
4400 RegCloseKey(hkeyPrinters);
4401 return FALSE;
4403 RegCloseKey(hkeyPrinter);
4405 RegCloseKey(hkeyPrinters);
4407 if(lpdwNeeded)
4408 *lpdwNeeded = used;
4410 if(used > cbBuf) {
4411 if(lpbPrinters)
4412 memset(lpbPrinters, 0, cbBuf);
4413 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4414 return FALSE;
4416 if(lpdwReturned)
4417 *lpdwReturned = number;
4418 SetLastError(ERROR_SUCCESS);
4419 return TRUE;
4423 /******************************************************************
4424 * EnumPrintersW [WINSPOOL.@]
4426 * Enumerates the available printers, print servers and print
4427 * providers, depending on the specified flags, name and level.
4429 * RETURNS:
4431 * If level is set to 1:
4432 * Returns an array of PRINTER_INFO_1 data structures in the
4433 * lpbPrinters buffer.
4435 * If level is set to 2:
4436 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4437 * Returns an array of PRINTER_INFO_2 data structures in the
4438 * lpbPrinters buffer. Note that according to MSDN also an
4439 * OpenPrinter should be performed on every remote printer.
4441 * If level is set to 4 (officially WinNT only):
4442 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4443 * Fast: Only the registry is queried to retrieve printer names,
4444 * no connection to the driver is made.
4445 * Returns an array of PRINTER_INFO_4 data structures in the
4446 * lpbPrinters buffer.
4448 * If level is set to 5 (officially WinNT4/Win9x only):
4449 * Fast: Only the registry is queried to retrieve printer names,
4450 * no connection to the driver is made.
4451 * Returns an array of PRINTER_INFO_5 data structures in the
4452 * lpbPrinters buffer.
4454 * If level set to 3 or 6+:
4455 * returns zero (failure!)
4457 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4458 * for information.
4460 * BUGS:
4461 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4462 * - Only levels 2, 4 and 5 are implemented at the moment.
4463 * - 16-bit printer drivers are not enumerated.
4464 * - Returned amount of bytes used/needed does not match the real Windoze
4465 * implementation (as in this implementation, all strings are part
4466 * of the buffer, whereas Win32 keeps them somewhere else)
4467 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4469 * NOTE:
4470 * - In a regular Wine installation, no registry settings for printers
4471 * exist, which makes this function return an empty list.
4473 BOOL WINAPI EnumPrintersW(
4474 DWORD dwType, /* [in] Types of print objects to enumerate */
4475 LPWSTR lpszName, /* [in] name of objects to enumerate */
4476 DWORD dwLevel, /* [in] type of printer info structure */
4477 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4478 DWORD cbBuf, /* [in] max size of buffer in bytes */
4479 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4480 LPDWORD lpdwReturned /* [out] number of entries returned */
4483 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4484 lpdwNeeded, lpdwReturned, TRUE);
4487 /******************************************************************
4488 * EnumPrintersA [WINSPOOL.@]
4491 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4492 DWORD dwLevel, LPBYTE lpbPrinters,
4493 DWORD cbBuf, LPDWORD lpdwNeeded,
4494 LPDWORD lpdwReturned)
4496 BOOL ret, unicode = FALSE;
4497 UNICODE_STRING lpszNameW;
4498 PWSTR pwstrNameW;
4500 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4501 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4502 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4503 lpdwNeeded, lpdwReturned, unicode);
4504 RtlFreeUnicodeString(&lpszNameW);
4505 return ret;
4508 /*****************************************************************************
4509 * WINSPOOL_GetDriverInfoFromReg [internal]
4511 * Enters the information from the registry into the DRIVER_INFO struct
4513 * RETURNS
4514 * zero if the printer driver does not exist in the registry
4515 * (only if Level > 1) otherwise nonzero
4517 static BOOL WINSPOOL_GetDriverInfoFromReg(
4518 HKEY hkeyDrivers,
4519 LPWSTR DriverName,
4520 const printenv_t * env,
4521 DWORD Level,
4522 LPBYTE ptr, /* DRIVER_INFO */
4523 LPBYTE pDriverStrings, /* strings buffer */
4524 DWORD cbBuf, /* size of string buffer */
4525 LPDWORD pcbNeeded, /* space needed for str. */
4526 BOOL unicode) /* type of strings */
4528 DWORD size, tmp;
4529 HKEY hkeyDriver;
4530 WCHAR driverdir[MAX_PATH];
4531 DWORD dirlen;
4532 LPBYTE strPtr = pDriverStrings;
4533 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4535 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4536 debugstr_w(DriverName), env,
4537 Level, di, pDriverStrings, cbBuf, unicode);
4539 if (di) ZeroMemory(di, di_sizeof[Level]);
4541 if (unicode) {
4542 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4543 if (*pcbNeeded <= cbBuf)
4544 strcpyW((LPWSTR)strPtr, DriverName);
4546 else
4548 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4549 if (*pcbNeeded <= cbBuf)
4550 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4553 /* pName for level 1 has a different offset! */
4554 if (Level == 1) {
4555 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4556 return TRUE;
4559 /* .cVersion and .pName for level > 1 */
4560 if (di) {
4561 di->cVersion = env->driverversion;
4562 di->pName = (LPWSTR) strPtr;
4563 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4566 /* Reserve Space for the largest subdir and a Backslash*/
4567 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4568 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4569 /* Should never Fail */
4570 return FALSE;
4572 lstrcatW(driverdir, env->versionsubdir);
4573 lstrcatW(driverdir, backslashW);
4575 /* dirlen must not include the terminating zero */
4576 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4577 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4579 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4580 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4581 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4582 return FALSE;
4585 /* pEnvironment */
4586 if (unicode)
4587 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4588 else
4589 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4591 *pcbNeeded += size;
4592 if (*pcbNeeded <= cbBuf) {
4593 if (unicode) {
4594 lstrcpyW((LPWSTR)strPtr, env->envname);
4596 else
4598 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4600 if (di) di->pEnvironment = (LPWSTR)strPtr;
4601 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4604 /* .pDriverPath is the Graphics rendering engine.
4605 The full Path is required to avoid a crash in some apps */
4606 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4607 *pcbNeeded += size;
4608 if (*pcbNeeded <= cbBuf)
4609 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4611 if (di) di->pDriverPath = (LPWSTR)strPtr;
4612 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4615 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4616 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4617 *pcbNeeded += size;
4618 if (*pcbNeeded <= cbBuf)
4619 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4621 if (di) di->pDataFile = (LPWSTR)strPtr;
4622 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4625 /* .pConfigFile is the Driver user Interface */
4626 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4627 *pcbNeeded += size;
4628 if (*pcbNeeded <= cbBuf)
4629 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4631 if (di) di->pConfigFile = (LPWSTR)strPtr;
4632 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4635 if (Level == 2 ) {
4636 RegCloseKey(hkeyDriver);
4637 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4638 return TRUE;
4641 if (Level == 5 ) {
4642 RegCloseKey(hkeyDriver);
4643 FIXME("level 5: incomplete\n");
4644 return TRUE;
4647 /* .pHelpFile */
4648 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4649 *pcbNeeded += size;
4650 if (*pcbNeeded <= cbBuf)
4651 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4653 if (di) di->pHelpFile = (LPWSTR)strPtr;
4654 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4657 /* .pDependentFiles */
4658 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4659 *pcbNeeded += size;
4660 if (*pcbNeeded <= cbBuf)
4661 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4663 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4664 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4666 else if (GetVersion() & 0x80000000) {
4667 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4668 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4669 *pcbNeeded += size;
4670 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4672 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4673 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4676 /* .pMonitorName is the optional Language Monitor */
4677 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4678 *pcbNeeded += size;
4679 if (*pcbNeeded <= cbBuf)
4680 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4682 if (di) di->pMonitorName = (LPWSTR)strPtr;
4683 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4686 /* .pDefaultDataType */
4687 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4688 *pcbNeeded += size;
4689 if(*pcbNeeded <= cbBuf)
4690 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4692 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4693 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4696 if (Level == 3 ) {
4697 RegCloseKey(hkeyDriver);
4698 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4699 return TRUE;
4702 /* .pszzPreviousNames */
4703 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4704 *pcbNeeded += size;
4705 if(*pcbNeeded <= cbBuf)
4706 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4708 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4709 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4712 if (Level == 4 ) {
4713 RegCloseKey(hkeyDriver);
4714 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4715 return TRUE;
4718 /* support is missing, but not important enough for a FIXME */
4719 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4721 /* .pszMfgName */
4722 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4723 *pcbNeeded += size;
4724 if(*pcbNeeded <= cbBuf)
4725 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4727 if (di) di->pszMfgName = (LPWSTR)strPtr;
4728 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4731 /* .pszOEMUrl */
4732 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4733 *pcbNeeded += size;
4734 if(*pcbNeeded <= cbBuf)
4735 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4737 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4738 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4741 /* .pszHardwareID */
4742 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4743 *pcbNeeded += size;
4744 if(*pcbNeeded <= cbBuf)
4745 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4747 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4748 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4751 /* .pszProvider */
4752 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4753 *pcbNeeded += size;
4754 if(*pcbNeeded <= cbBuf)
4755 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4757 if (di) di->pszProvider = (LPWSTR)strPtr;
4758 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4761 if (Level == 6 ) {
4762 RegCloseKey(hkeyDriver);
4763 return TRUE;
4766 /* support is missing, but not important enough for a FIXME */
4767 TRACE("level 8: incomplete\n");
4769 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4770 RegCloseKey(hkeyDriver);
4771 return TRUE;
4774 /*****************************************************************************
4775 * WINSPOOL_GetPrinterDriver
4777 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4778 DWORD Level, LPBYTE pDriverInfo,
4779 DWORD cbBuf, LPDWORD pcbNeeded,
4780 BOOL unicode)
4782 LPCWSTR name;
4783 WCHAR DriverName[100];
4784 DWORD ret, type, size, needed = 0;
4785 LPBYTE ptr = NULL;
4786 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4787 const printenv_t * env;
4789 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4790 Level,pDriverInfo,cbBuf, pcbNeeded);
4793 if (!(name = get_opened_printer_name(hPrinter))) {
4794 SetLastError(ERROR_INVALID_HANDLE);
4795 return FALSE;
4798 if (Level < 1 || Level == 7 || Level > 8) {
4799 SetLastError(ERROR_INVALID_LEVEL);
4800 return FALSE;
4803 env = validate_envW(pEnvironment);
4804 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4806 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4807 ERROR_SUCCESS) {
4808 ERR("Can't create Printers key\n");
4809 return FALSE;
4811 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4812 != ERROR_SUCCESS) {
4813 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4814 RegCloseKey(hkeyPrinters);
4815 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4816 return FALSE;
4818 size = sizeof(DriverName);
4819 DriverName[0] = 0;
4820 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4821 (LPBYTE)DriverName, &size);
4822 RegCloseKey(hkeyPrinter);
4823 RegCloseKey(hkeyPrinters);
4824 if(ret != ERROR_SUCCESS) {
4825 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4826 return FALSE;
4829 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4830 if(!hkeyDrivers) {
4831 ERR("Can't create Drivers key\n");
4832 return FALSE;
4835 size = di_sizeof[Level];
4836 if ((size <= cbBuf) && pDriverInfo)
4837 ptr = pDriverInfo + size;
4839 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4840 env, Level, pDriverInfo, ptr,
4841 (cbBuf < size) ? 0 : cbBuf - size,
4842 &needed, unicode)) {
4843 RegCloseKey(hkeyDrivers);
4844 return FALSE;
4847 RegCloseKey(hkeyDrivers);
4849 if(pcbNeeded) *pcbNeeded = size + needed;
4850 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4851 if(cbBuf >= needed) return TRUE;
4852 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4853 return FALSE;
4856 /*****************************************************************************
4857 * GetPrinterDriverA [WINSPOOL.@]
4859 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4860 DWORD Level, LPBYTE pDriverInfo,
4861 DWORD cbBuf, LPDWORD pcbNeeded)
4863 BOOL ret;
4864 UNICODE_STRING pEnvW;
4865 PWSTR pwstrEnvW;
4867 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4868 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4869 cbBuf, pcbNeeded, FALSE);
4870 RtlFreeUnicodeString(&pEnvW);
4871 return ret;
4873 /*****************************************************************************
4874 * GetPrinterDriverW [WINSPOOL.@]
4876 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4877 DWORD Level, LPBYTE pDriverInfo,
4878 DWORD cbBuf, LPDWORD pcbNeeded)
4880 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4881 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4884 /*****************************************************************************
4885 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4887 * Return the PATH for the Printer-Drivers (UNICODE)
4889 * PARAMS
4890 * pName [I] Servername (NT only) or NULL (local Computer)
4891 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4892 * Level [I] Structure-Level (must be 1)
4893 * pDriverDirectory [O] PTR to Buffer that receives the Result
4894 * cbBuf [I] Size of Buffer at pDriverDirectory
4895 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4896 * required for pDriverDirectory
4898 * RETURNS
4899 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4900 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4901 * if cbBuf is too small
4903 * Native Values returned in pDriverDirectory on Success:
4904 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4905 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4906 *| win9x(Windows 4.0): "%winsysdir%"
4908 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4910 * FIXME
4911 *- Only NULL or "" is supported for pName
4914 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4915 DWORD Level, LPBYTE pDriverDirectory,
4916 DWORD cbBuf, LPDWORD pcbNeeded)
4918 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4919 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4921 if ((backend == NULL) && !load_backend()) return FALSE;
4923 if (Level != 1) {
4924 /* (Level != 1) is ignored in win9x */
4925 SetLastError(ERROR_INVALID_LEVEL);
4926 return FALSE;
4928 if (pcbNeeded == NULL) {
4929 /* (pcbNeeded == NULL) is ignored in win9x */
4930 SetLastError(RPC_X_NULL_REF_POINTER);
4931 return FALSE;
4934 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4935 pDriverDirectory, cbBuf, pcbNeeded);
4940 /*****************************************************************************
4941 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4943 * Return the PATH for the Printer-Drivers (ANSI)
4945 * See GetPrinterDriverDirectoryW.
4947 * NOTES
4948 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4951 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4952 DWORD Level, LPBYTE pDriverDirectory,
4953 DWORD cbBuf, LPDWORD pcbNeeded)
4955 UNICODE_STRING nameW, environmentW;
4956 BOOL ret;
4957 DWORD pcbNeededW;
4958 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4959 WCHAR *driverDirectoryW = NULL;
4961 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4962 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4964 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4966 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4967 else nameW.Buffer = NULL;
4968 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4969 else environmentW.Buffer = NULL;
4971 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4972 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4973 if (ret) {
4974 DWORD needed;
4975 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4976 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4977 if(pcbNeeded)
4978 *pcbNeeded = needed;
4979 ret = (needed <= cbBuf) ? TRUE : FALSE;
4980 } else
4981 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4983 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4985 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4986 RtlFreeUnicodeString(&environmentW);
4987 RtlFreeUnicodeString(&nameW);
4989 return ret;
4992 /*****************************************************************************
4993 * AddPrinterDriverA [WINSPOOL.@]
4995 * See AddPrinterDriverW.
4998 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5000 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5001 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5004 /******************************************************************************
5005 * AddPrinterDriverW (WINSPOOL.@)
5007 * Install a Printer Driver
5009 * PARAMS
5010 * pName [I] Servername or NULL (local Computer)
5011 * level [I] Level for the supplied DRIVER_INFO_*W struct
5012 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5014 * RESULTS
5015 * Success: TRUE
5016 * Failure: FALSE
5019 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5021 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5022 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5025 /*****************************************************************************
5026 * AddPrintProcessorA [WINSPOOL.@]
5028 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5029 LPSTR pPrintProcessorName)
5031 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5032 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5033 return FALSE;
5036 /*****************************************************************************
5037 * AddPrintProcessorW [WINSPOOL.@]
5039 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5040 LPWSTR pPrintProcessorName)
5042 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5043 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5044 return FALSE;
5047 /*****************************************************************************
5048 * AddPrintProvidorA [WINSPOOL.@]
5050 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5052 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5053 return FALSE;
5056 /*****************************************************************************
5057 * AddPrintProvidorW [WINSPOOL.@]
5059 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5061 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5062 return FALSE;
5065 /*****************************************************************************
5066 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5068 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5069 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5071 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5072 pDevModeOutput, pDevModeInput);
5073 return 0;
5076 /*****************************************************************************
5077 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5079 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5080 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5082 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5083 pDevModeOutput, pDevModeInput);
5084 return 0;
5087 /*****************************************************************************
5088 * PrinterProperties [WINSPOOL.@]
5090 * Displays a dialog to set the properties of the printer.
5092 * RETURNS
5093 * nonzero on success or zero on failure
5095 * BUGS
5096 * implemented as stub only
5098 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5099 HANDLE hPrinter /* [in] handle to printer object */
5101 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5102 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5103 return FALSE;
5106 /*****************************************************************************
5107 * EnumJobsA [WINSPOOL.@]
5110 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5111 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5112 LPDWORD pcReturned)
5114 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5115 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5117 if(pcbNeeded) *pcbNeeded = 0;
5118 if(pcReturned) *pcReturned = 0;
5119 return FALSE;
5123 /*****************************************************************************
5124 * EnumJobsW [WINSPOOL.@]
5127 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5128 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5129 LPDWORD pcReturned)
5131 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5132 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5134 if(pcbNeeded) *pcbNeeded = 0;
5135 if(pcReturned) *pcReturned = 0;
5136 return FALSE;
5139 /*****************************************************************************
5140 * WINSPOOL_EnumPrinterDrivers [internal]
5142 * Delivers information about all printer drivers installed on the
5143 * localhost or a given server
5145 * RETURNS
5146 * nonzero on success or zero on failure. If the buffer for the returned
5147 * information is too small the function will return an error
5149 * BUGS
5150 * - only implemented for localhost, foreign hosts will return an error
5152 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5153 DWORD Level, LPBYTE pDriverInfo,
5154 DWORD cbBuf, LPDWORD pcbNeeded,
5155 LPDWORD pcReturned, BOOL unicode)
5157 { HKEY hkeyDrivers;
5158 DWORD i, needed, number = 0, size = 0;
5159 WCHAR DriverNameW[255];
5160 PBYTE ptr;
5161 const printenv_t * env;
5163 TRACE("%s,%s,%d,%p,%d,%d\n",
5164 debugstr_w(pName), debugstr_w(pEnvironment),
5165 Level, pDriverInfo, cbBuf, unicode);
5167 /* check for local drivers */
5168 if((pName) && (pName[0])) {
5169 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5170 SetLastError(ERROR_ACCESS_DENIED);
5171 return FALSE;
5174 env = validate_envW(pEnvironment);
5175 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5177 /* check input parameter */
5178 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5179 SetLastError(ERROR_INVALID_LEVEL);
5180 return FALSE;
5183 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5184 SetLastError(RPC_X_NULL_REF_POINTER);
5185 return FALSE;
5188 /* initialize return values */
5189 if(pDriverInfo)
5190 memset( pDriverInfo, 0, cbBuf);
5191 *pcbNeeded = 0;
5192 *pcReturned = 0;
5194 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5195 if(!hkeyDrivers) {
5196 ERR("Can't open Drivers key\n");
5197 return FALSE;
5200 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5201 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5202 RegCloseKey(hkeyDrivers);
5203 ERR("Can't query Drivers key\n");
5204 return FALSE;
5206 TRACE("Found %d Drivers\n", number);
5208 /* get size of single struct
5209 * unicode and ascii structure have the same size
5211 size = di_sizeof[Level];
5213 /* calculate required buffer size */
5214 *pcbNeeded = size * number;
5216 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5217 i < number;
5218 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5219 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5220 != ERROR_SUCCESS) {
5221 ERR("Can't enum key number %d\n", i);
5222 RegCloseKey(hkeyDrivers);
5223 return FALSE;
5225 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5226 env, Level, ptr,
5227 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5228 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5229 &needed, unicode)) {
5230 RegCloseKey(hkeyDrivers);
5231 return FALSE;
5233 (*pcbNeeded) += needed;
5236 RegCloseKey(hkeyDrivers);
5238 if(cbBuf < *pcbNeeded){
5239 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5240 return FALSE;
5243 *pcReturned = number;
5244 return TRUE;
5247 /*****************************************************************************
5248 * EnumPrinterDriversW [WINSPOOL.@]
5250 * see function EnumPrinterDrivers for RETURNS, BUGS
5252 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5253 LPBYTE pDriverInfo, DWORD cbBuf,
5254 LPDWORD pcbNeeded, LPDWORD pcReturned)
5256 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5257 cbBuf, pcbNeeded, pcReturned, TRUE);
5260 /*****************************************************************************
5261 * EnumPrinterDriversA [WINSPOOL.@]
5263 * see function EnumPrinterDrivers for RETURNS, BUGS
5265 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5266 LPBYTE pDriverInfo, DWORD cbBuf,
5267 LPDWORD pcbNeeded, LPDWORD pcReturned)
5268 { BOOL ret;
5269 UNICODE_STRING pNameW, pEnvironmentW;
5270 PWSTR pwstrNameW, pwstrEnvironmentW;
5272 pwstrNameW = asciitounicode(&pNameW, pName);
5273 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5275 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5276 Level, pDriverInfo, cbBuf, pcbNeeded,
5277 pcReturned, FALSE);
5278 RtlFreeUnicodeString(&pNameW);
5279 RtlFreeUnicodeString(&pEnvironmentW);
5281 return ret;
5284 /******************************************************************************
5285 * EnumPortsA (WINSPOOL.@)
5287 * See EnumPortsW.
5290 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5291 LPDWORD pcbNeeded, LPDWORD pcReturned)
5293 BOOL res;
5294 LPBYTE bufferW = NULL;
5295 LPWSTR nameW = NULL;
5296 DWORD needed = 0;
5297 DWORD numentries = 0;
5298 INT len;
5300 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5301 cbBuf, pcbNeeded, pcReturned);
5303 /* convert servername to unicode */
5304 if (pName) {
5305 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5306 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5307 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5309 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5310 needed = cbBuf * sizeof(WCHAR);
5311 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5312 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5314 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5315 if (pcbNeeded) needed = *pcbNeeded;
5316 /* HeapReAlloc return NULL, when bufferW was NULL */
5317 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5318 HeapAlloc(GetProcessHeap(), 0, needed);
5320 /* Try again with the large Buffer */
5321 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5323 needed = pcbNeeded ? *pcbNeeded : 0;
5324 numentries = pcReturned ? *pcReturned : 0;
5327 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5328 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5330 if (res) {
5331 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5332 DWORD entrysize = 0;
5333 DWORD index;
5334 LPSTR ptr;
5335 LPPORT_INFO_2W pi2w;
5336 LPPORT_INFO_2A pi2a;
5338 needed = 0;
5339 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5341 /* First pass: calculate the size for all Entries */
5342 pi2w = (LPPORT_INFO_2W) bufferW;
5343 pi2a = (LPPORT_INFO_2A) pPorts;
5344 index = 0;
5345 while (index < numentries) {
5346 index++;
5347 needed += entrysize; /* PORT_INFO_?A */
5348 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5350 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5351 NULL, 0, NULL, NULL);
5352 if (Level > 1) {
5353 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5354 NULL, 0, NULL, NULL);
5355 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5356 NULL, 0, NULL, NULL);
5358 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5359 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5360 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5363 /* check for errors and quit on failure */
5364 if (cbBuf < needed) {
5365 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5366 res = FALSE;
5367 goto cleanup;
5369 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5370 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5371 cbBuf -= len ; /* free Bytes in the user-Buffer */
5372 pi2w = (LPPORT_INFO_2W) bufferW;
5373 pi2a = (LPPORT_INFO_2A) pPorts;
5374 index = 0;
5375 /* Second Pass: Fill the User Buffer (if we have one) */
5376 while ((index < numentries) && pPorts) {
5377 index++;
5378 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5379 pi2a->pPortName = ptr;
5380 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5381 ptr, cbBuf , NULL, NULL);
5382 ptr += len;
5383 cbBuf -= len;
5384 if (Level > 1) {
5385 pi2a->pMonitorName = ptr;
5386 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5387 ptr, cbBuf, NULL, NULL);
5388 ptr += len;
5389 cbBuf -= len;
5391 pi2a->pDescription = ptr;
5392 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5393 ptr, cbBuf, NULL, NULL);
5394 ptr += len;
5395 cbBuf -= len;
5397 pi2a->fPortType = pi2w->fPortType;
5398 pi2a->Reserved = 0; /* documented: "must be zero" */
5401 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5402 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5403 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5407 cleanup:
5408 if (pcbNeeded) *pcbNeeded = needed;
5409 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5411 HeapFree(GetProcessHeap(), 0, nameW);
5412 HeapFree(GetProcessHeap(), 0, bufferW);
5414 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5415 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5417 return (res);
5421 /******************************************************************************
5422 * EnumPortsW (WINSPOOL.@)
5424 * Enumerate available Ports
5426 * PARAMS
5427 * name [I] Servername or NULL (local Computer)
5428 * level [I] Structure-Level (1 or 2)
5429 * buffer [O] PTR to Buffer that receives the Result
5430 * bufsize [I] Size of Buffer at buffer
5431 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5432 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5434 * RETURNS
5435 * Success: TRUE
5436 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5440 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5442 DWORD needed = 0;
5443 DWORD numentries = 0;
5444 BOOL res = FALSE;
5446 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5447 cbBuf, pcbNeeded, pcReturned);
5449 if (pName && (pName[0])) {
5450 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5451 SetLastError(ERROR_ACCESS_DENIED);
5452 goto emP_cleanup;
5455 /* Level is not checked in win9x */
5456 if (!Level || (Level > 2)) {
5457 WARN("level (%d) is ignored in win9x\n", Level);
5458 SetLastError(ERROR_INVALID_LEVEL);
5459 goto emP_cleanup;
5461 if (!pcbNeeded) {
5462 SetLastError(RPC_X_NULL_REF_POINTER);
5463 goto emP_cleanup;
5466 EnterCriticalSection(&monitor_handles_cs);
5467 monitor_loadall();
5469 /* Scan all local Ports */
5470 numentries = 0;
5471 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5473 /* we calculated the needed buffersize. now do the error-checks */
5474 if (cbBuf < needed) {
5475 monitor_unloadall();
5476 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5477 goto emP_cleanup_cs;
5479 else if (!pPorts || !pcReturned) {
5480 monitor_unloadall();
5481 SetLastError(RPC_X_NULL_REF_POINTER);
5482 goto emP_cleanup_cs;
5485 /* Fill the Buffer */
5486 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5487 res = TRUE;
5488 monitor_unloadall();
5490 emP_cleanup_cs:
5491 LeaveCriticalSection(&monitor_handles_cs);
5493 emP_cleanup:
5494 if (pcbNeeded) *pcbNeeded = needed;
5495 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5497 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5498 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5500 return (res);
5503 /******************************************************************************
5504 * GetDefaultPrinterW (WINSPOOL.@)
5506 * FIXME
5507 * This function must read the value from data 'device' of key
5508 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5510 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5512 BOOL retval = TRUE;
5513 DWORD insize, len;
5514 WCHAR *buffer, *ptr;
5516 if (!namesize)
5518 SetLastError(ERROR_INVALID_PARAMETER);
5519 return FALSE;
5522 /* make the buffer big enough for the stuff from the profile/registry,
5523 * the content must fit into the local buffer to compute the correct
5524 * size even if the extern buffer is too small or not given.
5525 * (20 for ,driver,port) */
5526 insize = *namesize;
5527 len = max(100, (insize + 20));
5528 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5530 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5532 SetLastError (ERROR_FILE_NOT_FOUND);
5533 retval = FALSE;
5534 goto end;
5536 TRACE("%s\n", debugstr_w(buffer));
5538 if ((ptr = strchrW(buffer, ',')) == NULL)
5540 SetLastError(ERROR_INVALID_NAME);
5541 retval = FALSE;
5542 goto end;
5545 *ptr = 0;
5546 *namesize = strlenW(buffer) + 1;
5547 if(!name || (*namesize > insize))
5549 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5550 retval = FALSE;
5551 goto end;
5553 strcpyW(name, buffer);
5555 end:
5556 HeapFree( GetProcessHeap(), 0, buffer);
5557 return retval;
5561 /******************************************************************************
5562 * GetDefaultPrinterA (WINSPOOL.@)
5564 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5566 BOOL retval = TRUE;
5567 DWORD insize = 0;
5568 WCHAR *bufferW = NULL;
5570 if (!namesize)
5572 SetLastError(ERROR_INVALID_PARAMETER);
5573 return FALSE;
5576 if(name && *namesize) {
5577 insize = *namesize;
5578 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5581 if(!GetDefaultPrinterW( bufferW, namesize)) {
5582 retval = FALSE;
5583 goto end;
5586 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5587 NULL, NULL);
5588 if (!*namesize)
5590 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5591 retval = FALSE;
5593 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5595 end:
5596 HeapFree( GetProcessHeap(), 0, bufferW);
5597 return retval;
5601 /******************************************************************************
5602 * SetDefaultPrinterW (WINSPOOL.204)
5604 * Set the Name of the Default Printer
5606 * PARAMS
5607 * pszPrinter [I] Name of the Printer or NULL
5609 * RETURNS
5610 * Success: True
5611 * Failure: FALSE
5613 * NOTES
5614 * When the Parameter is NULL or points to an Empty String and
5615 * a Default Printer was already present, then this Function changes nothing.
5616 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5617 * the First enumerated local Printer is used.
5620 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5623 TRACE("(%s)\n", debugstr_w(pszPrinter));
5625 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5626 return FALSE;
5629 /******************************************************************************
5630 * SetDefaultPrinterA (WINSPOOL.202)
5632 * See SetDefaultPrinterW.
5635 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5638 TRACE("(%s)\n", debugstr_a(pszPrinter));
5640 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5641 return FALSE;
5645 /******************************************************************************
5646 * SetPrinterDataExA (WINSPOOL.@)
5648 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5649 LPCSTR pValueName, DWORD Type,
5650 LPBYTE pData, DWORD cbData)
5652 HKEY hkeyPrinter, hkeySubkey;
5653 DWORD ret;
5655 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5656 debugstr_a(pValueName), Type, pData, cbData);
5658 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5659 != ERROR_SUCCESS)
5660 return ret;
5662 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5663 != ERROR_SUCCESS) {
5664 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5665 RegCloseKey(hkeyPrinter);
5666 return ret;
5668 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5669 RegCloseKey(hkeySubkey);
5670 RegCloseKey(hkeyPrinter);
5671 return ret;
5674 /******************************************************************************
5675 * SetPrinterDataExW (WINSPOOL.@)
5677 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5678 LPCWSTR pValueName, DWORD Type,
5679 LPBYTE pData, DWORD cbData)
5681 HKEY hkeyPrinter, hkeySubkey;
5682 DWORD ret;
5684 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5685 debugstr_w(pValueName), Type, pData, cbData);
5687 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5688 != ERROR_SUCCESS)
5689 return ret;
5691 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5692 != ERROR_SUCCESS) {
5693 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5694 RegCloseKey(hkeyPrinter);
5695 return ret;
5697 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5698 RegCloseKey(hkeySubkey);
5699 RegCloseKey(hkeyPrinter);
5700 return ret;
5703 /******************************************************************************
5704 * SetPrinterDataA (WINSPOOL.@)
5706 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5707 LPBYTE pData, DWORD cbData)
5709 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5710 pData, cbData);
5713 /******************************************************************************
5714 * SetPrinterDataW (WINSPOOL.@)
5716 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5717 LPBYTE pData, DWORD cbData)
5719 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5720 pData, cbData);
5723 /******************************************************************************
5724 * GetPrinterDataExA (WINSPOOL.@)
5726 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5727 LPCSTR pValueName, LPDWORD pType,
5728 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5730 HKEY hkeyPrinter, hkeySubkey;
5731 DWORD ret;
5733 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5734 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5735 pcbNeeded);
5737 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5738 != ERROR_SUCCESS)
5739 return ret;
5741 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5742 != ERROR_SUCCESS) {
5743 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5744 RegCloseKey(hkeyPrinter);
5745 return ret;
5747 *pcbNeeded = nSize;
5748 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5749 RegCloseKey(hkeySubkey);
5750 RegCloseKey(hkeyPrinter);
5751 return ret;
5754 /******************************************************************************
5755 * GetPrinterDataExW (WINSPOOL.@)
5757 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5758 LPCWSTR pValueName, LPDWORD pType,
5759 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5761 HKEY hkeyPrinter, hkeySubkey;
5762 DWORD ret;
5764 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5765 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5766 pcbNeeded);
5768 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5769 != ERROR_SUCCESS)
5770 return ret;
5772 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5773 != ERROR_SUCCESS) {
5774 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5775 RegCloseKey(hkeyPrinter);
5776 return ret;
5778 *pcbNeeded = nSize;
5779 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5780 RegCloseKey(hkeySubkey);
5781 RegCloseKey(hkeyPrinter);
5782 return ret;
5785 /******************************************************************************
5786 * GetPrinterDataA (WINSPOOL.@)
5788 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5789 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5791 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5792 pData, nSize, pcbNeeded);
5795 /******************************************************************************
5796 * GetPrinterDataW (WINSPOOL.@)
5798 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5799 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5801 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5802 pData, nSize, pcbNeeded);
5805 /*******************************************************************************
5806 * EnumPrinterDataExW [WINSPOOL.@]
5808 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5809 LPBYTE pEnumValues, DWORD cbEnumValues,
5810 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5812 HKEY hkPrinter, hkSubKey;
5813 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5814 cbValueNameLen, cbMaxValueLen, cbValueLen,
5815 cbBufSize, dwType;
5816 LPWSTR lpValueName;
5817 HANDLE hHeap;
5818 PBYTE lpValue;
5819 PPRINTER_ENUM_VALUESW ppev;
5821 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5823 if (pKeyName == NULL || *pKeyName == 0)
5824 return ERROR_INVALID_PARAMETER;
5826 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5827 if (ret != ERROR_SUCCESS)
5829 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5830 hPrinter, ret);
5831 return ret;
5834 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5835 if (ret != ERROR_SUCCESS)
5837 r = RegCloseKey (hkPrinter);
5838 if (r != ERROR_SUCCESS)
5839 WARN ("RegCloseKey returned %i\n", r);
5840 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5841 debugstr_w (pKeyName), ret);
5842 return ret;
5845 ret = RegCloseKey (hkPrinter);
5846 if (ret != ERROR_SUCCESS)
5848 ERR ("RegCloseKey returned %i\n", ret);
5849 r = RegCloseKey (hkSubKey);
5850 if (r != ERROR_SUCCESS)
5851 WARN ("RegCloseKey returned %i\n", r);
5852 return ret;
5855 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5856 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5857 if (ret != ERROR_SUCCESS)
5859 r = RegCloseKey (hkSubKey);
5860 if (r != ERROR_SUCCESS)
5861 WARN ("RegCloseKey returned %i\n", r);
5862 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5863 return ret;
5866 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5867 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5869 if (cValues == 0) /* empty key */
5871 r = RegCloseKey (hkSubKey);
5872 if (r != ERROR_SUCCESS)
5873 WARN ("RegCloseKey returned %i\n", r);
5874 *pcbEnumValues = *pnEnumValues = 0;
5875 return ERROR_SUCCESS;
5878 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5880 hHeap = GetProcessHeap ();
5881 if (hHeap == NULL)
5883 ERR ("GetProcessHeap failed\n");
5884 r = RegCloseKey (hkSubKey);
5885 if (r != ERROR_SUCCESS)
5886 WARN ("RegCloseKey returned %i\n", r);
5887 return ERROR_OUTOFMEMORY;
5890 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5891 if (lpValueName == NULL)
5893 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5894 r = RegCloseKey (hkSubKey);
5895 if (r != ERROR_SUCCESS)
5896 WARN ("RegCloseKey returned %i\n", r);
5897 return ERROR_OUTOFMEMORY;
5900 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5901 if (lpValue == NULL)
5903 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5904 if (HeapFree (hHeap, 0, lpValueName) == 0)
5905 WARN ("HeapFree failed with code %i\n", GetLastError ());
5906 r = RegCloseKey (hkSubKey);
5907 if (r != ERROR_SUCCESS)
5908 WARN ("RegCloseKey returned %i\n", r);
5909 return ERROR_OUTOFMEMORY;
5912 TRACE ("pass 1: calculating buffer required for all names and values\n");
5914 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5916 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5918 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5920 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5921 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5922 NULL, NULL, lpValue, &cbValueLen);
5923 if (ret != ERROR_SUCCESS)
5925 if (HeapFree (hHeap, 0, lpValue) == 0)
5926 WARN ("HeapFree failed with code %i\n", GetLastError ());
5927 if (HeapFree (hHeap, 0, lpValueName) == 0)
5928 WARN ("HeapFree failed with code %i\n", GetLastError ());
5929 r = RegCloseKey (hkSubKey);
5930 if (r != ERROR_SUCCESS)
5931 WARN ("RegCloseKey returned %i\n", r);
5932 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5933 return ret;
5936 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5937 debugstr_w (lpValueName), dwIndex,
5938 cbValueNameLen + 1, cbValueLen);
5940 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5941 cbBufSize += cbValueLen;
5944 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5946 *pcbEnumValues = cbBufSize;
5947 *pnEnumValues = cValues;
5949 if (cbEnumValues < cbBufSize) /* buffer too small */
5951 if (HeapFree (hHeap, 0, lpValue) == 0)
5952 WARN ("HeapFree failed with code %i\n", GetLastError ());
5953 if (HeapFree (hHeap, 0, lpValueName) == 0)
5954 WARN ("HeapFree failed with code %i\n", GetLastError ());
5955 r = RegCloseKey (hkSubKey);
5956 if (r != ERROR_SUCCESS)
5957 WARN ("RegCloseKey returned %i\n", r);
5958 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5959 return ERROR_MORE_DATA;
5962 TRACE ("pass 2: copying all names and values to buffer\n");
5964 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5965 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5967 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5969 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5970 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5971 NULL, &dwType, lpValue, &cbValueLen);
5972 if (ret != ERROR_SUCCESS)
5974 if (HeapFree (hHeap, 0, lpValue) == 0)
5975 WARN ("HeapFree failed with code %i\n", GetLastError ());
5976 if (HeapFree (hHeap, 0, lpValueName) == 0)
5977 WARN ("HeapFree failed with code %i\n", GetLastError ());
5978 r = RegCloseKey (hkSubKey);
5979 if (r != ERROR_SUCCESS)
5980 WARN ("RegCloseKey returned %i\n", r);
5981 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5982 return ret;
5985 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5986 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5987 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5988 pEnumValues += cbValueNameLen;
5990 /* return # of *bytes* (including trailing \0), not # of chars */
5991 ppev[dwIndex].cbValueName = cbValueNameLen;
5993 ppev[dwIndex].dwType = dwType;
5995 memcpy (pEnumValues, lpValue, cbValueLen);
5996 ppev[dwIndex].pData = pEnumValues;
5997 pEnumValues += cbValueLen;
5999 ppev[dwIndex].cbData = cbValueLen;
6001 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6002 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6005 if (HeapFree (hHeap, 0, lpValue) == 0)
6007 ret = GetLastError ();
6008 ERR ("HeapFree failed with code %i\n", ret);
6009 if (HeapFree (hHeap, 0, lpValueName) == 0)
6010 WARN ("HeapFree failed with code %i\n", GetLastError ());
6011 r = RegCloseKey (hkSubKey);
6012 if (r != ERROR_SUCCESS)
6013 WARN ("RegCloseKey returned %i\n", r);
6014 return ret;
6017 if (HeapFree (hHeap, 0, lpValueName) == 0)
6019 ret = GetLastError ();
6020 ERR ("HeapFree failed with code %i\n", ret);
6021 r = RegCloseKey (hkSubKey);
6022 if (r != ERROR_SUCCESS)
6023 WARN ("RegCloseKey returned %i\n", r);
6024 return ret;
6027 ret = RegCloseKey (hkSubKey);
6028 if (ret != ERROR_SUCCESS)
6030 ERR ("RegCloseKey returned %i\n", ret);
6031 return ret;
6034 return ERROR_SUCCESS;
6037 /*******************************************************************************
6038 * EnumPrinterDataExA [WINSPOOL.@]
6040 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6041 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6042 * what Windows 2000 SP1 does.
6045 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6046 LPBYTE pEnumValues, DWORD cbEnumValues,
6047 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6049 INT len;
6050 LPWSTR pKeyNameW;
6051 DWORD ret, dwIndex, dwBufSize;
6052 HANDLE hHeap;
6053 LPSTR pBuffer;
6055 TRACE ("%p %s\n", hPrinter, pKeyName);
6057 if (pKeyName == NULL || *pKeyName == 0)
6058 return ERROR_INVALID_PARAMETER;
6060 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6061 if (len == 0)
6063 ret = GetLastError ();
6064 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6065 return ret;
6068 hHeap = GetProcessHeap ();
6069 if (hHeap == NULL)
6071 ERR ("GetProcessHeap failed\n");
6072 return ERROR_OUTOFMEMORY;
6075 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6076 if (pKeyNameW == NULL)
6078 ERR ("Failed to allocate %i bytes from process heap\n",
6079 (LONG)(len * sizeof (WCHAR)));
6080 return ERROR_OUTOFMEMORY;
6083 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6085 ret = GetLastError ();
6086 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6087 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6088 WARN ("HeapFree failed with code %i\n", GetLastError ());
6089 return ret;
6092 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6093 pcbEnumValues, pnEnumValues);
6094 if (ret != ERROR_SUCCESS)
6096 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6097 WARN ("HeapFree failed with code %i\n", GetLastError ());
6098 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6099 return ret;
6102 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6104 ret = GetLastError ();
6105 ERR ("HeapFree failed with code %i\n", ret);
6106 return ret;
6109 if (*pnEnumValues == 0) /* empty key */
6110 return ERROR_SUCCESS;
6112 dwBufSize = 0;
6113 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6115 PPRINTER_ENUM_VALUESW ppev =
6116 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6118 if (dwBufSize < ppev->cbValueName)
6119 dwBufSize = ppev->cbValueName;
6121 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6122 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6123 dwBufSize = ppev->cbData;
6126 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6128 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6129 if (pBuffer == NULL)
6131 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6132 return ERROR_OUTOFMEMORY;
6135 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6137 PPRINTER_ENUM_VALUESW ppev =
6138 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6140 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6141 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6142 NULL);
6143 if (len == 0)
6145 ret = GetLastError ();
6146 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6147 if (HeapFree (hHeap, 0, pBuffer) == 0)
6148 WARN ("HeapFree failed with code %i\n", GetLastError ());
6149 return ret;
6152 memcpy (ppev->pValueName, pBuffer, len);
6154 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6156 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6157 ppev->dwType != REG_MULTI_SZ)
6158 continue;
6160 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6161 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6162 if (len == 0)
6164 ret = GetLastError ();
6165 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6166 if (HeapFree (hHeap, 0, pBuffer) == 0)
6167 WARN ("HeapFree failed with code %i\n", GetLastError ());
6168 return ret;
6171 memcpy (ppev->pData, pBuffer, len);
6173 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6174 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6177 if (HeapFree (hHeap, 0, pBuffer) == 0)
6179 ret = GetLastError ();
6180 ERR ("HeapFree failed with code %i\n", ret);
6181 return ret;
6184 return ERROR_SUCCESS;
6187 /******************************************************************************
6188 * AbortPrinter (WINSPOOL.@)
6190 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6192 FIXME("(%p), stub!\n", hPrinter);
6193 return TRUE;
6196 /******************************************************************************
6197 * AddPortA (WINSPOOL.@)
6199 * See AddPortW.
6202 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6204 LPWSTR nameW = NULL;
6205 LPWSTR monitorW = NULL;
6206 DWORD len;
6207 BOOL res;
6209 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6211 if (pName) {
6212 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6213 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6214 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6217 if (pMonitorName) {
6218 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6219 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6220 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6222 res = AddPortW(nameW, hWnd, monitorW);
6223 HeapFree(GetProcessHeap(), 0, nameW);
6224 HeapFree(GetProcessHeap(), 0, monitorW);
6225 return res;
6228 /******************************************************************************
6229 * AddPortW (WINSPOOL.@)
6231 * Add a Port for a specific Monitor
6233 * PARAMS
6234 * pName [I] Servername or NULL (local Computer)
6235 * hWnd [I] Handle to parent Window for the Dialog-Box
6236 * pMonitorName [I] Name of the Monitor that manage the Port
6238 * RETURNS
6239 * Success: TRUE
6240 * Failure: FALSE
6243 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6245 monitor_t * pm;
6246 monitor_t * pui;
6247 DWORD res;
6249 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6251 if (pName && pName[0]) {
6252 SetLastError(ERROR_INVALID_PARAMETER);
6253 return FALSE;
6256 if (!pMonitorName) {
6257 SetLastError(RPC_X_NULL_REF_POINTER);
6258 return FALSE;
6261 /* an empty Monitorname is Invalid */
6262 if (!pMonitorName[0]) {
6263 SetLastError(ERROR_NOT_SUPPORTED);
6264 return FALSE;
6267 pm = monitor_load(pMonitorName, NULL);
6268 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6269 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6270 TRACE("got %d with %u\n", res, GetLastError());
6271 res = TRUE;
6273 else
6275 pui = monitor_loadui(pm);
6276 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6277 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6278 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6279 TRACE("got %d with %u\n", res, GetLastError());
6280 res = TRUE;
6282 else
6284 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6285 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6287 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6288 SetLastError(ERROR_NOT_SUPPORTED);
6289 res = FALSE;
6291 monitor_unload(pui);
6293 monitor_unload(pm);
6294 TRACE("returning %d with %u\n", res, GetLastError());
6295 return res;
6298 /******************************************************************************
6299 * AddPortExA (WINSPOOL.@)
6301 * See AddPortExW.
6304 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6306 PORT_INFO_2W pi2W;
6307 PORT_INFO_2A * pi2A;
6308 LPWSTR nameW = NULL;
6309 LPWSTR monitorW = NULL;
6310 DWORD len;
6311 BOOL res;
6313 pi2A = (PORT_INFO_2A *) pBuffer;
6315 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6316 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6318 if ((level < 1) || (level > 2)) {
6319 SetLastError(ERROR_INVALID_LEVEL);
6320 return FALSE;
6323 if (!pi2A) {
6324 SetLastError(ERROR_INVALID_PARAMETER);
6325 return FALSE;
6328 if (pName) {
6329 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6330 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6331 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6334 if (pMonitorName) {
6335 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6336 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6337 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6340 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6342 if (pi2A->pPortName) {
6343 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6344 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6345 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6348 if (level > 1) {
6349 if (pi2A->pMonitorName) {
6350 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6351 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6352 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6355 if (pi2A->pDescription) {
6356 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6357 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6358 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6360 pi2W.fPortType = pi2A->fPortType;
6361 pi2W.Reserved = pi2A->Reserved;
6364 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6366 HeapFree(GetProcessHeap(), 0, nameW);
6367 HeapFree(GetProcessHeap(), 0, monitorW);
6368 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6369 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6370 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6371 return res;
6375 /******************************************************************************
6376 * AddPortExW (WINSPOOL.@)
6378 * Add a Port for a specific Monitor, without presenting a user interface
6380 * PARAMS
6381 * pName [I] Servername or NULL (local Computer)
6382 * level [I] Structure-Level (1 or 2) for pBuffer
6383 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6384 * pMonitorName [I] Name of the Monitor that manage the Port
6386 * RETURNS
6387 * Success: TRUE
6388 * Failure: FALSE
6391 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6393 PORT_INFO_2W * pi2;
6394 monitor_t * pm;
6395 DWORD res = FALSE;
6397 pi2 = (PORT_INFO_2W *) pBuffer;
6399 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6400 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6401 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6402 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6405 if ((level < 1) || (level > 2)) {
6406 SetLastError(ERROR_INVALID_LEVEL);
6407 return FALSE;
6410 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6411 SetLastError(ERROR_INVALID_PARAMETER);
6412 return FALSE;
6415 /* load the Monitor */
6416 pm = monitor_load(pMonitorName, NULL);
6417 if (!pm) {
6418 SetLastError(ERROR_INVALID_PARAMETER);
6419 return FALSE;
6422 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6423 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6424 TRACE("got %u with %u\n", res, GetLastError());
6426 else
6428 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6430 monitor_unload(pm);
6431 return res;
6434 /******************************************************************************
6435 * AddPrinterConnectionA (WINSPOOL.@)
6437 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6439 FIXME("%s\n", debugstr_a(pName));
6440 return FALSE;
6443 /******************************************************************************
6444 * AddPrinterConnectionW (WINSPOOL.@)
6446 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6448 FIXME("%s\n", debugstr_w(pName));
6449 return FALSE;
6452 /******************************************************************************
6453 * AddPrinterDriverExW (WINSPOOL.@)
6455 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6457 * PARAMS
6458 * pName [I] Servername or NULL (local Computer)
6459 * level [I] Level for the supplied DRIVER_INFO_*W struct
6460 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6461 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6463 * RESULTS
6464 * Success: TRUE
6465 * Failure: FALSE
6468 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6470 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6472 if ((backend == NULL) && !load_backend()) return FALSE;
6474 if (level < 2 || level == 5 || level == 7 || level > 8) {
6475 SetLastError(ERROR_INVALID_LEVEL);
6476 return FALSE;
6479 if (!pDriverInfo) {
6480 SetLastError(ERROR_INVALID_PARAMETER);
6481 return FALSE;
6484 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6487 /******************************************************************************
6488 * AddPrinterDriverExA (WINSPOOL.@)
6490 * See AddPrinterDriverExW.
6493 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6495 DRIVER_INFO_8A *diA;
6496 DRIVER_INFO_8W diW;
6497 LPWSTR nameW = NULL;
6498 DWORD lenA;
6499 DWORD len;
6500 DWORD res = FALSE;
6502 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6504 diA = (DRIVER_INFO_8A *) pDriverInfo;
6505 ZeroMemory(&diW, sizeof(diW));
6507 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6508 SetLastError(ERROR_INVALID_LEVEL);
6509 return FALSE;
6512 if (diA == NULL) {
6513 SetLastError(ERROR_INVALID_PARAMETER);
6514 return FALSE;
6517 /* convert servername to unicode */
6518 if (pName) {
6519 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6520 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6521 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6524 /* common fields */
6525 diW.cVersion = diA->cVersion;
6527 if (diA->pName) {
6528 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6529 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6530 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6533 if (diA->pEnvironment) {
6534 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6535 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6536 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6539 if (diA->pDriverPath) {
6540 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6541 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6542 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6545 if (diA->pDataFile) {
6546 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6547 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6548 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6551 if (diA->pConfigFile) {
6552 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6553 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6554 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6557 if ((Level > 2) && diA->pDependentFiles) {
6558 lenA = multi_sz_lenA(diA->pDependentFiles);
6559 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6560 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6561 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6564 if ((Level > 2) && diA->pMonitorName) {
6565 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6566 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6567 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6570 if ((Level > 3) && diA->pDefaultDataType) {
6571 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6572 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6573 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6576 if ((Level > 3) && diA->pszzPreviousNames) {
6577 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6578 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6579 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6580 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6583 if ((Level > 5) && diA->pszMfgName) {
6584 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6585 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6586 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6589 if ((Level > 5) && diA->pszOEMUrl) {
6590 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6591 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6592 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6595 if ((Level > 5) && diA->pszHardwareID) {
6596 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6597 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6598 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6601 if ((Level > 5) && diA->pszProvider) {
6602 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6603 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6604 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6607 if (Level > 7) {
6608 FIXME("level %u is incomplete\n", Level);
6611 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6612 TRACE("got %u with %u\n", res, GetLastError());
6613 HeapFree(GetProcessHeap(), 0, nameW);
6614 HeapFree(GetProcessHeap(), 0, diW.pName);
6615 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6616 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6617 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6618 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6619 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6620 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6621 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6622 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6623 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6624 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6625 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6626 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6628 TRACE("=> %u with %u\n", res, GetLastError());
6629 return res;
6632 /******************************************************************************
6633 * ConfigurePortA (WINSPOOL.@)
6635 * See ConfigurePortW.
6638 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6640 LPWSTR nameW = NULL;
6641 LPWSTR portW = NULL;
6642 INT len;
6643 DWORD res;
6645 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6647 /* convert servername to unicode */
6648 if (pName) {
6649 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6650 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6651 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6654 /* convert portname to unicode */
6655 if (pPortName) {
6656 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6657 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6658 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6661 res = ConfigurePortW(nameW, hWnd, portW);
6662 HeapFree(GetProcessHeap(), 0, nameW);
6663 HeapFree(GetProcessHeap(), 0, portW);
6664 return res;
6667 /******************************************************************************
6668 * ConfigurePortW (WINSPOOL.@)
6670 * Display the Configuration-Dialog for a specific Port
6672 * PARAMS
6673 * pName [I] Servername or NULL (local Computer)
6674 * hWnd [I] Handle to parent Window for the Dialog-Box
6675 * pPortName [I] Name of the Port, that should be configured
6677 * RETURNS
6678 * Success: TRUE
6679 * Failure: FALSE
6682 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6684 monitor_t * pm;
6685 monitor_t * pui;
6686 DWORD res;
6688 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6690 if (pName && pName[0]) {
6691 SetLastError(ERROR_INVALID_PARAMETER);
6692 return FALSE;
6695 if (!pPortName) {
6696 SetLastError(RPC_X_NULL_REF_POINTER);
6697 return FALSE;
6700 /* an empty Portname is Invalid, but can popup a Dialog */
6701 if (!pPortName[0]) {
6702 SetLastError(ERROR_NOT_SUPPORTED);
6703 return FALSE;
6706 pm = monitor_load_by_port(pPortName);
6707 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6708 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6709 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6710 TRACE("got %d with %u\n", res, GetLastError());
6712 else
6714 pui = monitor_loadui(pm);
6715 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6716 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6717 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6718 TRACE("got %d with %u\n", res, GetLastError());
6720 else
6722 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6723 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6725 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6726 SetLastError(ERROR_NOT_SUPPORTED);
6727 res = FALSE;
6729 monitor_unload(pui);
6731 monitor_unload(pm);
6733 TRACE("returning %d with %u\n", res, GetLastError());
6734 return res;
6737 /******************************************************************************
6738 * ConnectToPrinterDlg (WINSPOOL.@)
6740 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6742 FIXME("%p %x\n", hWnd, Flags);
6743 return NULL;
6746 /******************************************************************************
6747 * DeletePrinterConnectionA (WINSPOOL.@)
6749 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6751 FIXME("%s\n", debugstr_a(pName));
6752 return TRUE;
6755 /******************************************************************************
6756 * DeletePrinterConnectionW (WINSPOOL.@)
6758 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6760 FIXME("%s\n", debugstr_w(pName));
6761 return TRUE;
6764 /******************************************************************************
6765 * DeletePrinterDriverExW (WINSPOOL.@)
6767 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6768 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6770 HKEY hkey_drivers;
6771 BOOL ret = FALSE;
6773 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6774 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6776 if(pName && pName[0])
6778 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6779 SetLastError(ERROR_INVALID_PARAMETER);
6780 return FALSE;
6783 if(dwDeleteFlag)
6785 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6786 SetLastError(ERROR_INVALID_PARAMETER);
6787 return FALSE;
6790 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6792 if(!hkey_drivers)
6794 ERR("Can't open drivers key\n");
6795 return FALSE;
6798 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6799 ret = TRUE;
6801 RegCloseKey(hkey_drivers);
6803 return ret;
6806 /******************************************************************************
6807 * DeletePrinterDriverExA (WINSPOOL.@)
6809 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6810 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6812 UNICODE_STRING NameW, EnvW, DriverW;
6813 BOOL ret;
6815 asciitounicode(&NameW, pName);
6816 asciitounicode(&EnvW, pEnvironment);
6817 asciitounicode(&DriverW, pDriverName);
6819 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6821 RtlFreeUnicodeString(&DriverW);
6822 RtlFreeUnicodeString(&EnvW);
6823 RtlFreeUnicodeString(&NameW);
6825 return ret;
6828 /******************************************************************************
6829 * DeletePrinterDataExW (WINSPOOL.@)
6831 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6832 LPCWSTR pValueName)
6834 FIXME("%p %s %s\n", hPrinter,
6835 debugstr_w(pKeyName), debugstr_w(pValueName));
6836 return ERROR_INVALID_PARAMETER;
6839 /******************************************************************************
6840 * DeletePrinterDataExA (WINSPOOL.@)
6842 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6843 LPCSTR pValueName)
6845 FIXME("%p %s %s\n", hPrinter,
6846 debugstr_a(pKeyName), debugstr_a(pValueName));
6847 return ERROR_INVALID_PARAMETER;
6850 /******************************************************************************
6851 * DeletePrintProcessorA (WINSPOOL.@)
6853 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6855 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6856 debugstr_a(pPrintProcessorName));
6857 return TRUE;
6860 /******************************************************************************
6861 * DeletePrintProcessorW (WINSPOOL.@)
6863 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6865 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6866 debugstr_w(pPrintProcessorName));
6867 return TRUE;
6870 /******************************************************************************
6871 * DeletePrintProvidorA (WINSPOOL.@)
6873 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6875 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6876 debugstr_a(pPrintProviderName));
6877 return TRUE;
6880 /******************************************************************************
6881 * DeletePrintProvidorW (WINSPOOL.@)
6883 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6885 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6886 debugstr_w(pPrintProviderName));
6887 return TRUE;
6890 /******************************************************************************
6891 * EnumFormsA (WINSPOOL.@)
6893 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6894 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6896 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6898 return FALSE;
6901 /******************************************************************************
6902 * EnumFormsW (WINSPOOL.@)
6904 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6905 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6907 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6908 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6909 return FALSE;
6912 /*****************************************************************************
6913 * EnumMonitorsA [WINSPOOL.@]
6915 * See EnumMonitorsW.
6918 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6919 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6921 BOOL res;
6922 LPBYTE bufferW = NULL;
6923 LPWSTR nameW = NULL;
6924 DWORD needed = 0;
6925 DWORD numentries = 0;
6926 INT len;
6928 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6929 cbBuf, pcbNeeded, pcReturned);
6931 /* convert servername to unicode */
6932 if (pName) {
6933 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6934 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6935 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6937 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6938 needed = cbBuf * sizeof(WCHAR);
6939 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6940 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6942 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6943 if (pcbNeeded) needed = *pcbNeeded;
6944 /* HeapReAlloc return NULL, when bufferW was NULL */
6945 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6946 HeapAlloc(GetProcessHeap(), 0, needed);
6948 /* Try again with the large Buffer */
6949 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6951 numentries = pcReturned ? *pcReturned : 0;
6952 needed = 0;
6954 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6955 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6957 if (res) {
6958 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6959 DWORD entrysize = 0;
6960 DWORD index;
6961 LPSTR ptr;
6962 LPMONITOR_INFO_2W mi2w;
6963 LPMONITOR_INFO_2A mi2a;
6965 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6966 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6968 /* First pass: calculate the size for all Entries */
6969 mi2w = (LPMONITOR_INFO_2W) bufferW;
6970 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6971 index = 0;
6972 while (index < numentries) {
6973 index++;
6974 needed += entrysize; /* MONITOR_INFO_?A */
6975 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6977 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6978 NULL, 0, NULL, NULL);
6979 if (Level > 1) {
6980 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6981 NULL, 0, NULL, NULL);
6982 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6983 NULL, 0, NULL, NULL);
6985 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6986 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6987 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6990 /* check for errors and quit on failure */
6991 if (cbBuf < needed) {
6992 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6993 res = FALSE;
6994 goto emA_cleanup;
6996 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6997 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6998 cbBuf -= len ; /* free Bytes in the user-Buffer */
6999 mi2w = (LPMONITOR_INFO_2W) bufferW;
7000 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7001 index = 0;
7002 /* Second Pass: Fill the User Buffer (if we have one) */
7003 while ((index < numentries) && pMonitors) {
7004 index++;
7005 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7006 mi2a->pName = ptr;
7007 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7008 ptr, cbBuf , NULL, NULL);
7009 ptr += len;
7010 cbBuf -= len;
7011 if (Level > 1) {
7012 mi2a->pEnvironment = ptr;
7013 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7014 ptr, cbBuf, NULL, NULL);
7015 ptr += len;
7016 cbBuf -= len;
7018 mi2a->pDLLName = ptr;
7019 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7020 ptr, cbBuf, NULL, NULL);
7021 ptr += len;
7022 cbBuf -= len;
7024 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7025 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7026 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7029 emA_cleanup:
7030 if (pcbNeeded) *pcbNeeded = needed;
7031 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7033 HeapFree(GetProcessHeap(), 0, nameW);
7034 HeapFree(GetProcessHeap(), 0, bufferW);
7036 TRACE("returning %d with %d (%d byte for %d entries)\n",
7037 (res), GetLastError(), needed, numentries);
7039 return (res);
7043 /*****************************************************************************
7044 * EnumMonitorsW [WINSPOOL.@]
7046 * Enumerate available Port-Monitors
7048 * PARAMS
7049 * pName [I] Servername or NULL (local Computer)
7050 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7051 * pMonitors [O] PTR to Buffer that receives the Result
7052 * cbBuf [I] Size of Buffer at pMonitors
7053 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7054 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7056 * RETURNS
7057 * Success: TRUE
7058 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7060 * NOTES
7061 * Windows reads the Registry once and cache the Results.
7063 *| Language-Monitors are also installed in the same Registry-Location but
7064 *| they are filtered in Windows (not returned by EnumMonitors).
7065 *| We do no filtering to simplify our Code.
7068 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7069 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7071 DWORD needed = 0;
7072 DWORD numentries = 0;
7073 BOOL res = FALSE;
7075 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7076 cbBuf, pcbNeeded, pcReturned);
7078 if (pName && (lstrlenW(pName))) {
7079 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7080 SetLastError(ERROR_ACCESS_DENIED);
7081 goto emW_cleanup;
7084 /* Level is not checked in win9x */
7085 if (!Level || (Level > 2)) {
7086 WARN("level (%d) is ignored in win9x\n", Level);
7087 SetLastError(ERROR_INVALID_LEVEL);
7088 goto emW_cleanup;
7090 if (!pcbNeeded) {
7091 SetLastError(RPC_X_NULL_REF_POINTER);
7092 goto emW_cleanup;
7095 /* Scan all Monitor-Keys */
7096 numentries = 0;
7097 needed = get_local_monitors(Level, NULL, 0, &numentries);
7099 /* we calculated the needed buffersize. now do the error-checks */
7100 if (cbBuf < needed) {
7101 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7102 goto emW_cleanup;
7104 else if (!pMonitors || !pcReturned) {
7105 SetLastError(RPC_X_NULL_REF_POINTER);
7106 goto emW_cleanup;
7109 /* fill the Buffer with the Monitor-Keys */
7110 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7111 res = TRUE;
7113 emW_cleanup:
7114 if (pcbNeeded) *pcbNeeded = needed;
7115 if (pcReturned) *pcReturned = numentries;
7117 TRACE("returning %d with %d (%d byte for %d entries)\n",
7118 res, GetLastError(), needed, numentries);
7120 return (res);
7123 /******************************************************************************
7124 * SpoolerInit (WINSPOOL.@)
7126 * Initialize the Spooler
7128 * RETURNS
7129 * Success: TRUE
7130 * Failure: FALSE
7132 * NOTES
7133 * The function fails on windows, when the spooler service is not running
7136 BOOL WINAPI SpoolerInit(void)
7139 if ((backend == NULL) && !load_backend()) return FALSE;
7140 return TRUE;
7143 /******************************************************************************
7144 * XcvDataW (WINSPOOL.@)
7146 * Execute commands in the Printmonitor DLL
7148 * PARAMS
7149 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7150 * pszDataName [i] Name of the command to execute
7151 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7152 * cbInputData [i] Size in Bytes of Buffer at pInputData
7153 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7154 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7155 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7156 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7158 * RETURNS
7159 * Success: TRUE
7160 * Failure: FALSE
7162 * NOTES
7163 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7164 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7166 * Minimal List of commands, that a Printmonitor DLL should support:
7168 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7169 *| "AddPort" : Add a Port
7170 *| "DeletePort": Delete a Port
7172 * Many Printmonitors support additional commands. Examples for localspl.dll:
7173 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7174 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7177 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7178 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7179 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7181 opened_printer_t *printer;
7183 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7184 pInputData, cbInputData, pOutputData,
7185 cbOutputData, pcbOutputNeeded, pdwStatus);
7187 printer = get_opened_printer(hXcv);
7188 if (!printer || (!printer->hXcv)) {
7189 SetLastError(ERROR_INVALID_HANDLE);
7190 return FALSE;
7193 if (!pcbOutputNeeded) {
7194 SetLastError(ERROR_INVALID_PARAMETER);
7195 return FALSE;
7198 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7199 SetLastError(RPC_X_NULL_REF_POINTER);
7200 return FALSE;
7203 *pcbOutputNeeded = 0;
7205 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7206 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7208 return TRUE;
7211 /*****************************************************************************
7212 * EnumPrinterDataA [WINSPOOL.@]
7215 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7216 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7217 DWORD cbData, LPDWORD pcbData )
7219 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7220 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7221 return ERROR_NO_MORE_ITEMS;
7224 /*****************************************************************************
7225 * EnumPrinterDataW [WINSPOOL.@]
7228 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7229 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7230 DWORD cbData, LPDWORD pcbData )
7232 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7233 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7234 return ERROR_NO_MORE_ITEMS;
7237 /*****************************************************************************
7238 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7241 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7242 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7243 LPDWORD pcbNeeded, LPDWORD pcReturned)
7245 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7246 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7247 pcbNeeded, pcReturned);
7248 return FALSE;
7251 /*****************************************************************************
7252 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7255 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7256 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7257 LPDWORD pcbNeeded, LPDWORD pcReturned)
7259 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7260 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7261 pcbNeeded, pcReturned);
7262 return FALSE;
7265 /*****************************************************************************
7266 * EnumPrintProcessorsA [WINSPOOL.@]
7269 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7270 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7272 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7273 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7274 return FALSE;
7277 /*****************************************************************************
7278 * EnumPrintProcessorsW [WINSPOOL.@]
7281 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7282 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7284 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7285 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7286 cbBuf, pcbNeeded, pcbReturned);
7287 return FALSE;
7290 /*****************************************************************************
7291 * ExtDeviceMode [WINSPOOL.@]
7294 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7295 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7296 DWORD fMode)
7298 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7299 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7300 debugstr_a(pProfile), fMode);
7301 return -1;
7304 /*****************************************************************************
7305 * FindClosePrinterChangeNotification [WINSPOOL.@]
7308 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7310 FIXME("Stub: %p\n", hChange);
7311 return TRUE;
7314 /*****************************************************************************
7315 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7318 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7319 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7321 FIXME("Stub: %p %x %x %p\n",
7322 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7323 return INVALID_HANDLE_VALUE;
7326 /*****************************************************************************
7327 * FindNextPrinterChangeNotification [WINSPOOL.@]
7330 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7331 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7333 FIXME("Stub: %p %p %p %p\n",
7334 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7335 return FALSE;
7338 /*****************************************************************************
7339 * FreePrinterNotifyInfo [WINSPOOL.@]
7342 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7344 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7345 return TRUE;
7348 /*****************************************************************************
7349 * string_to_buf
7351 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7352 * ansi depending on the unicode parameter.
7354 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7356 if(!str)
7358 *size = 0;
7359 return TRUE;
7362 if(unicode)
7364 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7365 if(*size <= cb)
7367 memcpy(ptr, str, *size);
7368 return TRUE;
7370 return FALSE;
7372 else
7374 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7375 if(*size <= cb)
7377 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7378 return TRUE;
7380 return FALSE;
7384 /*****************************************************************************
7385 * get_job_info_1
7387 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7388 LPDWORD pcbNeeded, BOOL unicode)
7390 DWORD size, left = cbBuf;
7391 BOOL space = (cbBuf > 0);
7392 LPBYTE ptr = buf;
7394 *pcbNeeded = 0;
7396 if(space)
7398 ji1->JobId = job->job_id;
7401 string_to_buf(job->document_title, ptr, left, &size, unicode);
7402 if(space && size <= left)
7404 ji1->pDocument = (LPWSTR)ptr;
7405 ptr += size;
7406 left -= size;
7408 else
7409 space = FALSE;
7410 *pcbNeeded += size;
7412 return space;
7415 /*****************************************************************************
7416 * get_job_info_2
7418 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7419 LPDWORD pcbNeeded, BOOL unicode)
7421 DWORD size, left = cbBuf;
7422 BOOL space = (cbBuf > 0);
7423 LPBYTE ptr = buf;
7425 *pcbNeeded = 0;
7427 if(space)
7429 ji2->JobId = job->job_id;
7432 string_to_buf(job->document_title, ptr, left, &size, unicode);
7433 if(space && size <= left)
7435 ji2->pDocument = (LPWSTR)ptr;
7436 ptr += size;
7437 left -= size;
7439 else
7440 space = FALSE;
7441 *pcbNeeded += size;
7443 return space;
7446 /*****************************************************************************
7447 * get_job_info
7449 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7450 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7452 BOOL ret = FALSE;
7453 DWORD needed = 0, size;
7454 job_t *job;
7455 LPBYTE ptr = pJob;
7457 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7459 EnterCriticalSection(&printer_handles_cs);
7460 job = get_job(hPrinter, JobId);
7461 if(!job)
7462 goto end;
7464 switch(Level)
7466 case 1:
7467 size = sizeof(JOB_INFO_1W);
7468 if(cbBuf >= size)
7470 cbBuf -= size;
7471 ptr += size;
7472 memset(pJob, 0, size);
7474 else
7475 cbBuf = 0;
7476 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7477 needed += size;
7478 break;
7480 case 2:
7481 size = sizeof(JOB_INFO_2W);
7482 if(cbBuf >= size)
7484 cbBuf -= size;
7485 ptr += size;
7486 memset(pJob, 0, size);
7488 else
7489 cbBuf = 0;
7490 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7491 needed += size;
7492 break;
7494 case 3:
7495 size = sizeof(JOB_INFO_3);
7496 if(cbBuf >= size)
7498 cbBuf -= size;
7499 memset(pJob, 0, size);
7500 ret = TRUE;
7502 else
7503 cbBuf = 0;
7504 needed = size;
7505 break;
7507 default:
7508 SetLastError(ERROR_INVALID_LEVEL);
7509 goto end;
7511 if(pcbNeeded)
7512 *pcbNeeded = needed;
7513 end:
7514 LeaveCriticalSection(&printer_handles_cs);
7515 return ret;
7518 /*****************************************************************************
7519 * GetJobA [WINSPOOL.@]
7522 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7523 DWORD cbBuf, LPDWORD pcbNeeded)
7525 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7528 /*****************************************************************************
7529 * GetJobW [WINSPOOL.@]
7532 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7533 DWORD cbBuf, LPDWORD pcbNeeded)
7535 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7538 /*****************************************************************************
7539 * schedule_lpr
7541 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7543 char *unixname, *queue, *cmd;
7544 char fmt[] = "lpr -P%s %s";
7545 DWORD len;
7547 if(!(unixname = wine_get_unix_file_name(filename)))
7548 return FALSE;
7550 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7551 queue = HeapAlloc(GetProcessHeap(), 0, len);
7552 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7554 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7555 sprintf(cmd, fmt, queue, unixname);
7557 TRACE("printing with: %s\n", cmd);
7558 system(cmd);
7560 HeapFree(GetProcessHeap(), 0, cmd);
7561 HeapFree(GetProcessHeap(), 0, queue);
7562 HeapFree(GetProcessHeap(), 0, unixname);
7563 return TRUE;
7566 /*****************************************************************************
7567 * schedule_cups
7569 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7571 #ifdef SONAME_LIBCUPS
7572 if(pcupsPrintFile)
7574 char *unixname, *queue, *doc_titleA;
7575 DWORD len;
7576 BOOL ret;
7578 if(!(unixname = wine_get_unix_file_name(filename)))
7579 return FALSE;
7581 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7582 queue = HeapAlloc(GetProcessHeap(), 0, len);
7583 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7585 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7586 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7587 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7589 TRACE("printing via cups\n");
7590 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7591 HeapFree(GetProcessHeap(), 0, doc_titleA);
7592 HeapFree(GetProcessHeap(), 0, queue);
7593 HeapFree(GetProcessHeap(), 0, unixname);
7594 return ret;
7596 else
7597 #endif
7599 return schedule_lpr(printer_name, filename);
7603 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7605 LPWSTR filename;
7607 switch(msg)
7609 case WM_INITDIALOG:
7610 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7611 return TRUE;
7613 case WM_COMMAND:
7614 if(HIWORD(wparam) == BN_CLICKED)
7616 if(LOWORD(wparam) == IDOK)
7618 HANDLE hf;
7619 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7620 LPWSTR *output;
7622 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7623 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7625 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7627 WCHAR caption[200], message[200];
7628 int mb_ret;
7630 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7631 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7632 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7633 if(mb_ret == IDCANCEL)
7635 HeapFree(GetProcessHeap(), 0, filename);
7636 return TRUE;
7639 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7640 if(hf == INVALID_HANDLE_VALUE)
7642 WCHAR caption[200], message[200];
7644 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7645 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7646 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7647 HeapFree(GetProcessHeap(), 0, filename);
7648 return TRUE;
7650 CloseHandle(hf);
7651 DeleteFileW(filename);
7652 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7653 *output = filename;
7654 EndDialog(hwnd, IDOK);
7655 return TRUE;
7657 if(LOWORD(wparam) == IDCANCEL)
7659 EndDialog(hwnd, IDCANCEL);
7660 return TRUE;
7663 return FALSE;
7665 return FALSE;
7668 /*****************************************************************************
7669 * get_filename
7671 static BOOL get_filename(LPWSTR *filename)
7673 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7674 file_dlg_proc, (LPARAM)filename) == IDOK;
7677 /*****************************************************************************
7678 * schedule_file
7680 static BOOL schedule_file(LPCWSTR filename)
7682 LPWSTR output = NULL;
7684 if(get_filename(&output))
7686 TRACE("copy to %s\n", debugstr_w(output));
7687 CopyFileW(filename, output, FALSE);
7688 HeapFree(GetProcessHeap(), 0, output);
7689 return TRUE;
7691 return FALSE;
7694 /*****************************************************************************
7695 * schedule_pipe
7697 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7699 #ifdef HAVE_FORK
7700 char *unixname, *cmdA;
7701 DWORD len;
7702 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7703 BOOL ret = FALSE;
7704 char buf[1024];
7706 if(!(unixname = wine_get_unix_file_name(filename)))
7707 return FALSE;
7709 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7710 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7711 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7713 TRACE("printing with: %s\n", cmdA);
7715 if((file_fd = open(unixname, O_RDONLY)) == -1)
7716 goto end;
7718 if (pipe(fds))
7720 ERR("pipe() failed!\n");
7721 goto end;
7724 if (fork() == 0)
7726 close(0);
7727 dup2(fds[0], 0);
7728 close(fds[1]);
7730 /* reset signals that we previously set to SIG_IGN */
7731 signal(SIGPIPE, SIG_DFL);
7732 signal(SIGCHLD, SIG_DFL);
7734 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7735 _exit(1);
7738 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7739 write(fds[1], buf, no_read);
7741 ret = TRUE;
7743 end:
7744 if(file_fd != -1) close(file_fd);
7745 if(fds[0] != -1) close(fds[0]);
7746 if(fds[1] != -1) close(fds[1]);
7748 HeapFree(GetProcessHeap(), 0, cmdA);
7749 HeapFree(GetProcessHeap(), 0, unixname);
7750 return ret;
7751 #else
7752 return FALSE;
7753 #endif
7756 /*****************************************************************************
7757 * schedule_unixfile
7759 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7761 int in_fd, out_fd, no_read;
7762 char buf[1024];
7763 BOOL ret = FALSE;
7764 char *unixname, *outputA;
7765 DWORD len;
7767 if(!(unixname = wine_get_unix_file_name(filename)))
7768 return FALSE;
7770 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7771 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7772 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7774 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7775 in_fd = open(unixname, O_RDONLY);
7776 if(out_fd == -1 || in_fd == -1)
7777 goto end;
7779 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7780 write(out_fd, buf, no_read);
7782 ret = TRUE;
7783 end:
7784 if(in_fd != -1) close(in_fd);
7785 if(out_fd != -1) close(out_fd);
7786 HeapFree(GetProcessHeap(), 0, outputA);
7787 HeapFree(GetProcessHeap(), 0, unixname);
7788 return ret;
7791 /*****************************************************************************
7792 * ScheduleJob [WINSPOOL.@]
7795 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7797 opened_printer_t *printer;
7798 BOOL ret = FALSE;
7799 struct list *cursor, *cursor2;
7801 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7802 EnterCriticalSection(&printer_handles_cs);
7803 printer = get_opened_printer(hPrinter);
7804 if(!printer)
7805 goto end;
7807 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7809 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7810 HANDLE hf;
7812 if(job->job_id != dwJobID) continue;
7814 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7815 if(hf != INVALID_HANDLE_VALUE)
7817 PRINTER_INFO_5W *pi5;
7818 DWORD needed;
7819 HKEY hkey;
7820 WCHAR output[1024];
7821 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7822 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7824 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7825 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7826 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7827 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7828 debugstr_w(pi5->pPortName));
7830 output[0] = 0;
7832 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7833 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7835 DWORD type, count = sizeof(output);
7836 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7837 RegCloseKey(hkey);
7839 if(output[0] == '|')
7841 schedule_pipe(output + 1, job->filename);
7843 else if(output[0])
7845 schedule_unixfile(output, job->filename);
7847 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7849 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7851 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7853 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7855 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7857 schedule_file(job->filename);
7859 else
7861 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7863 HeapFree(GetProcessHeap(), 0, pi5);
7864 CloseHandle(hf);
7865 DeleteFileW(job->filename);
7867 list_remove(cursor);
7868 HeapFree(GetProcessHeap(), 0, job->document_title);
7869 HeapFree(GetProcessHeap(), 0, job->filename);
7870 HeapFree(GetProcessHeap(), 0, job);
7871 ret = TRUE;
7872 break;
7874 end:
7875 LeaveCriticalSection(&printer_handles_cs);
7876 return ret;
7879 /*****************************************************************************
7880 * StartDocDlgA [WINSPOOL.@]
7882 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7884 UNICODE_STRING usBuffer;
7885 DOCINFOW docW;
7886 LPWSTR retW;
7887 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7888 LPSTR ret = NULL;
7890 docW.cbSize = sizeof(docW);
7891 if (doc->lpszDocName)
7893 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7894 if (!(docW.lpszDocName = docnameW)) return NULL;
7896 if (doc->lpszOutput)
7898 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7899 if (!(docW.lpszOutput = outputW)) return NULL;
7901 if (doc->lpszDatatype)
7903 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7904 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7906 docW.fwType = doc->fwType;
7908 retW = StartDocDlgW(hPrinter, &docW);
7910 if(retW)
7912 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7913 ret = HeapAlloc(GetProcessHeap(), 0, len);
7914 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7915 HeapFree(GetProcessHeap(), 0, retW);
7918 HeapFree(GetProcessHeap(), 0, datatypeW);
7919 HeapFree(GetProcessHeap(), 0, outputW);
7920 HeapFree(GetProcessHeap(), 0, docnameW);
7922 return ret;
7925 /*****************************************************************************
7926 * StartDocDlgW [WINSPOOL.@]
7928 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7929 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7930 * port is "FILE:". Also returns the full path if passed a relative path.
7932 * The caller should free the returned string from the process heap.
7934 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7936 LPWSTR ret = NULL;
7937 DWORD len, attr;
7939 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7941 PRINTER_INFO_5W *pi5;
7942 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7943 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7944 return NULL;
7945 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7946 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7947 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7949 HeapFree(GetProcessHeap(), 0, pi5);
7950 return NULL;
7952 HeapFree(GetProcessHeap(), 0, pi5);
7955 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7957 LPWSTR name;
7959 if (get_filename(&name))
7961 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7963 HeapFree(GetProcessHeap(), 0, name);
7964 return NULL;
7966 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7967 GetFullPathNameW(name, len, ret, NULL);
7968 HeapFree(GetProcessHeap(), 0, name);
7970 return ret;
7973 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7974 return NULL;
7976 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7977 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7979 attr = GetFileAttributesW(ret);
7980 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7982 HeapFree(GetProcessHeap(), 0, ret);
7983 ret = NULL;
7985 return ret;