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, 2006, 2007 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
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.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 /* ############################### */
122 WCHAR
*document_title
;
130 LPCWSTR versionregpath
;
131 LPCWSTR versionsubdir
;
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
,
146 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
147 LPSTR lpszDevice
, LPSTR lpszPort
,
148 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
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 OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
220 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
221 static const WCHAR PortW
[] = {'P','o','r','t',0};
222 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
223 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
224 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
225 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
226 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
227 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
228 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
229 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
230 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
231 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
232 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
233 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
234 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
235 static const WCHAR emptyStringW
[] = {0};
236 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
237 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
239 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
241 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
242 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
243 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
245 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
246 'D','o','c','u','m','e','n','t',0};
248 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
249 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
250 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
251 0, sizeof(DRIVER_INFO_8W
)};
253 /******************************************************************
254 * validate the user-supplied printing-environment [internal]
257 * env [I] PTR to Environment-String or NULL
261 * Success: PTR to printenv_t
264 * An empty string is handled the same way as NULL.
265 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
269 static const printenv_t
* validate_envW(LPCWSTR env
)
271 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
272 3, Version3_RegPathW
, Version3_SubdirW
};
273 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
274 0, Version0_RegPathW
, Version0_SubdirW
};
276 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
278 const printenv_t
*result
= NULL
;
281 TRACE("testing %s\n", debugstr_w(env
));
284 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
286 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
288 result
= all_printenv
[i
];
293 if (result
== NULL
) {
294 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
295 SetLastError(ERROR_INVALID_ENVIRONMENT
);
297 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
301 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
303 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
309 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
310 if passed a NULL string. This returns NULLs to the result.
312 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
316 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
317 return usBufferPtr
->Buffer
;
319 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
323 static LPWSTR
strdupW(LPCWSTR p
)
329 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
330 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
335 static LPSTR
strdupWtoA( LPCWSTR str
)
340 if (!str
) return NULL
;
341 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
342 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
343 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
347 /******************************************************************
348 * Return the number of bytes for an multi_sz string.
349 * The result includes all \0s
350 * (specifically the extra \0, that is needed as multi_sz terminator).
353 static int multi_sz_lenW(const WCHAR
*str
)
355 const WCHAR
*ptr
= str
;
359 ptr
+= lstrlenW(ptr
) + 1;
362 return (ptr
- str
+ 1) * sizeof(WCHAR
);
365 /* ################################ */
367 static int multi_sz_lenA(const char *str
)
369 const char *ptr
= str
;
373 ptr
+= lstrlenA(ptr
) + 1;
376 return ptr
- str
+ 1;
380 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
383 /* If forcing, or no profile string entry for device yet, set the entry
385 * The always change entry if not WINEPS yet is discussable.
388 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
390 !strstr(qbuf
,"WINEPS.DRV")
392 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
395 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
396 WriteProfileStringA("windows","device",buf
);
397 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
398 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
401 HeapFree(GetProcessHeap(),0,buf
);
405 static BOOL
add_printer_driver(const char *name
)
409 static char driver_9x
[] = "wineps16.drv",
410 driver_nt
[] = "wineps.drv",
411 env_9x
[] = "Windows 4.0",
412 env_nt
[] = "Windows NT x86",
413 data_file
[] = "generic.ppd",
414 default_data_type
[] = "RAW";
416 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
418 di3a
.pName
= (char *)name
;
419 di3a
.pEnvironment
= env_nt
;
420 di3a
.pDriverPath
= driver_nt
;
421 di3a
.pDataFile
= data_file
;
422 di3a
.pConfigFile
= driver_nt
;
423 di3a
.pDefaultDataType
= default_data_type
;
425 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
426 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
429 di3a
.pEnvironment
= env_9x
;
430 di3a
.pDriverPath
= driver_9x
;
431 di3a
.pConfigFile
= driver_9x
;
432 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
433 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
438 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
439 debugstr_a(di3a
.pEnvironment
), GetLastError());
443 #ifdef SONAME_LIBCUPS
444 static typeof(cupsGetDests
) *pcupsGetDests
;
445 static typeof(cupsGetPPD
) *pcupsGetPPD
;
446 static typeof(cupsPrintFile
) *pcupsPrintFile
;
447 static void *cupshandle
;
449 static BOOL
CUPS_LoadPrinters(void)
452 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
454 PRINTER_INFO_2A pinfo2a
;
456 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
459 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
461 TRACE("%s\n", loaderror
);
464 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
467 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
468 if (!p##x) return FALSE;
471 DYNCUPS(cupsGetDests
);
472 DYNCUPS(cupsPrintFile
);
475 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
477 ERR("Can't create Printers key\n");
481 nrofdests
= pcupsGetDests(&dests
);
482 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
483 for (i
=0;i
<nrofdests
;i
++) {
484 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
485 sprintf(port
,"LPR:%s",dests
[i
].name
);
486 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
487 sprintf(devline
,"WINEPS.DRV,%s",port
);
488 WriteProfileStringA("devices",dests
[i
].name
,devline
);
489 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
490 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
493 HeapFree(GetProcessHeap(),0,devline
);
495 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
496 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
497 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
499 TRACE("Printer already exists\n");
500 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
501 RegCloseKey(hkeyPrinter
);
503 static CHAR data_type
[] = "RAW",
504 print_proc
[] = "WinPrint",
505 comment
[] = "WINEPS Printer using CUPS",
506 location
[] = "<physical location of printer>",
507 params
[] = "<parameters?>",
508 share_name
[] = "<share name?>",
509 sep_file
[] = "<sep file?>";
511 add_printer_driver(dests
[i
].name
);
513 memset(&pinfo2a
,0,sizeof(pinfo2a
));
514 pinfo2a
.pPrinterName
= dests
[i
].name
;
515 pinfo2a
.pDatatype
= data_type
;
516 pinfo2a
.pPrintProcessor
= print_proc
;
517 pinfo2a
.pDriverName
= dests
[i
].name
;
518 pinfo2a
.pComment
= comment
;
519 pinfo2a
.pLocation
= location
;
520 pinfo2a
.pPortName
= port
;
521 pinfo2a
.pParameters
= params
;
522 pinfo2a
.pShareName
= share_name
;
523 pinfo2a
.pSepFile
= sep_file
;
525 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
526 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
527 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
530 HeapFree(GetProcessHeap(),0,port
);
533 if (dests
[i
].is_default
) {
534 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
538 if (hadprinter
& !haddefault
)
539 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
540 RegCloseKey(hkeyPrinters
);
546 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
547 PRINTER_INFO_2A pinfo2a
;
548 char *e
,*s
,*name
,*prettyname
,*devname
;
549 BOOL ret
= FALSE
, set_default
= FALSE
;
550 char *port
= NULL
, *devline
,*env_default
;
551 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
553 while (isspace(*pent
)) pent
++;
554 s
= strchr(pent
,':');
556 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
564 TRACE("name=%s entry=%s\n",name
, pent
);
566 if(ispunct(*name
)) { /* a tc entry, not a real printer */
567 TRACE("skipping tc entry\n");
571 if(strstr(pent
,":server")) { /* server only version so skip */
572 TRACE("skipping server entry\n");
576 /* Determine whether this is a postscript printer. */
579 env_default
= getenv("PRINTER");
581 /* Get longest name, usually the one at the right for later display. */
582 while((s
=strchr(prettyname
,'|'))) {
585 while(isspace(*--e
)) *e
= '\0';
586 TRACE("\t%s\n", debugstr_a(prettyname
));
587 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
588 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
591 e
= prettyname
+ strlen(prettyname
);
592 while(isspace(*--e
)) *e
= '\0';
593 TRACE("\t%s\n", debugstr_a(prettyname
));
594 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
596 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
597 * if it is too long, we use it as comment below. */
598 devname
= prettyname
;
599 if (strlen(devname
)>=CCHDEVICENAME
-1)
601 if (strlen(devname
)>=CCHDEVICENAME
-1) {
606 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
607 sprintf(port
,"LPR:%s",name
);
609 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
610 sprintf(devline
,"WINEPS.DRV,%s",port
);
611 WriteProfileStringA("devices",devname
,devline
);
612 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
613 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
616 HeapFree(GetProcessHeap(),0,devline
);
618 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
620 ERR("Can't create Printers key\n");
624 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
625 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
627 TRACE("Printer already exists\n");
628 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
629 RegCloseKey(hkeyPrinter
);
631 static CHAR data_type
[] = "RAW",
632 print_proc
[] = "WinPrint",
633 comment
[] = "WINEPS Printer using LPR",
634 params
[] = "<parameters?>",
635 share_name
[] = "<share name?>",
636 sep_file
[] = "<sep file?>";
638 add_printer_driver(devname
);
640 memset(&pinfo2a
,0,sizeof(pinfo2a
));
641 pinfo2a
.pPrinterName
= devname
;
642 pinfo2a
.pDatatype
= data_type
;
643 pinfo2a
.pPrintProcessor
= print_proc
;
644 pinfo2a
.pDriverName
= devname
;
645 pinfo2a
.pComment
= comment
;
646 pinfo2a
.pLocation
= prettyname
;
647 pinfo2a
.pPortName
= port
;
648 pinfo2a
.pParameters
= params
;
649 pinfo2a
.pShareName
= share_name
;
650 pinfo2a
.pSepFile
= sep_file
;
652 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
653 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
654 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
657 RegCloseKey(hkeyPrinters
);
659 if (isfirst
|| set_default
)
660 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
663 HeapFree(GetProcessHeap(), 0, port
);
664 HeapFree(GetProcessHeap(), 0, name
);
669 PRINTCAP_LoadPrinters(void) {
670 BOOL hadprinter
= FALSE
;
674 BOOL had_bash
= FALSE
;
676 f
= fopen("/etc/printcap","r");
680 while(fgets(buf
,sizeof(buf
),f
)) {
683 end
=strchr(buf
,'\n');
687 while(isspace(*start
)) start
++;
688 if(*start
== '#' || *start
== '\0')
691 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
692 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
693 HeapFree(GetProcessHeap(),0,pent
);
697 if (end
&& *--end
== '\\') {
704 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
707 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
713 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
714 HeapFree(GetProcessHeap(),0,pent
);
720 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
723 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
724 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
726 return ERROR_FILE_NOT_FOUND
;
729 /*****************************************************************************
730 * enumerate the local monitors (INTERNAL)
732 * returns the needed size (in bytes) for pMonitors
733 * and *lpreturned is set to number of entries returned in pMonitors
736 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
741 LPMONITOR_INFO_2W mi
;
742 WCHAR buffer
[MAX_PATH
];
743 WCHAR dllname
[MAX_PATH
];
751 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
753 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
754 len
= entrysize
* numentries
;
755 ptr
= (LPWSTR
) &pMonitors
[len
];
758 len
= sizeof(buffer
)/sizeof(buffer
[0]);
761 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
762 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
763 /* Scan all Monitor-Registry-Keys */
764 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
765 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
766 dllsize
= sizeof(dllname
);
769 /* The Monitor must have a Driver-DLL */
770 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
771 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
772 /* We found a valid DLL for this Monitor. */
773 TRACE("using Driver: %s\n", debugstr_w(dllname
));
778 /* Windows returns only Port-Monitors here, but to simplify our code,
779 we do no filtering for Language-Monitors */
783 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
785 /* we install and return only monitors for "Windows NT x86" */
786 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
790 /* required size is calculated. Now fill the user-buffer */
791 if (pMonitors
&& (cbBuf
>= needed
)){
792 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
793 pMonitors
+= entrysize
;
795 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
797 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
798 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
800 mi
->pEnvironment
= ptr
;
801 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
802 ptr
+= (lstrlenW(envname_x86W
)+1);
805 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
806 ptr
+= (dllsize
/ sizeof(WCHAR
));
811 len
= sizeof(buffer
);
816 *lpreturned
= numentries
;
817 TRACE("need %d byte for %d entries\n", needed
, numentries
);
821 /******************************************************************
822 * monitor_unload [internal]
824 * release a printmonitor and unload it from memory, when needed
827 static void monitor_unload(monitor_t
* pm
)
829 if (pm
== NULL
) return;
830 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
832 EnterCriticalSection(&monitor_handles_cs
);
834 if (pm
->refcount
) pm
->refcount
--;
836 if (pm
->refcount
== 0) {
837 list_remove(&pm
->entry
);
838 FreeLibrary(pm
->hdll
);
839 HeapFree(GetProcessHeap(), 0, pm
->name
);
840 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
841 HeapFree(GetProcessHeap(), 0, pm
);
843 LeaveCriticalSection(&monitor_handles_cs
);
846 /******************************************************************
847 * monitor_unloadall [internal]
849 * release all printmonitors and unload them from memory, when needed
852 static void monitor_unloadall(void)
857 EnterCriticalSection(&monitor_handles_cs
);
858 /* iterate through the list, with safety against removal */
859 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
863 LeaveCriticalSection(&monitor_handles_cs
);
866 /******************************************************************
867 * monitor_load [internal]
869 * load a printmonitor, get the dllname from the registry, when needed
870 * initialize the monitor and dump found function-pointers
872 * On failure, SetLastError() is called and NULL is returned
875 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
877 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
878 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
879 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
880 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
881 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
883 monitor_t
* pm
= NULL
;
885 LPWSTR regroot
= NULL
;
886 LPWSTR driver
= dllname
;
888 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
889 /* Is the Monitor already loaded? */
890 EnterCriticalSection(&monitor_handles_cs
);
893 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
895 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
903 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
904 if (pm
== NULL
) goto cleanup
;
905 list_add_tail(&monitor_handles
, &pm
->entry
);
909 if (pm
->name
== NULL
) {
910 /* Load the monitor */
911 LPMONITOREX pmonitorEx
;
915 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
916 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
920 lstrcpyW(regroot
, MonitorsW
);
921 lstrcatW(regroot
, name
);
922 /* Get the Driver from the Registry */
923 if (driver
== NULL
) {
926 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
927 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
928 &namesize
) == ERROR_SUCCESS
) {
929 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
930 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
937 pm
->name
= strdupW(name
);
938 pm
->dllname
= strdupW(driver
);
940 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
942 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
947 pm
->hdll
= LoadLibraryW(driver
);
948 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
950 if (pm
->hdll
== NULL
) {
952 SetLastError(ERROR_MOD_NOT_FOUND
);
957 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
958 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
959 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
960 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
961 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
964 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
965 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
966 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
967 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
968 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
970 if (pInitializePrintMonitorUI
!= NULL
) {
971 pm
->monitorUI
= pInitializePrintMonitorUI();
972 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
974 TRACE( "0x%08x: dwMonitorSize (%d)\n",
975 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
980 if (pInitializePrintMonitor
&& regroot
) {
981 pmonitorEx
= pInitializePrintMonitor(regroot
);
982 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
983 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
986 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
987 pm
->monitor
= &(pmonitorEx
->Monitor
);
992 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
996 if (!pm
->monitor
&& regroot
) {
997 if (pInitializePrintMonitor2
!= NULL
) {
998 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
1000 if (pInitializeMonitorEx
!= NULL
) {
1001 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
1003 if (pInitializeMonitor
!= NULL
) {
1004 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
1007 if (!pm
->monitor
&& !pm
->monitorUI
) {
1009 SetLastError(ERROR_PROC_NOT_FOUND
);
1014 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
1018 LeaveCriticalSection(&monitor_handles_cs
);
1019 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
1020 HeapFree(GetProcessHeap(), 0, regroot
);
1021 TRACE("=> %p\n", pm
);
1025 /******************************************************************
1026 * monitor_loadall [internal]
1028 * Load all registered monitors
1031 static DWORD
monitor_loadall(void)
1034 DWORD registered
= 0;
1037 WCHAR buffer
[MAX_PATH
];
1040 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1041 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1042 NULL
, NULL
, NULL
, NULL
, NULL
);
1044 TRACE("%d monitors registered\n", registered
);
1046 EnterCriticalSection(&monitor_handles_cs
);
1047 while (id
< registered
) {
1049 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1050 pm
= monitor_load(buffer
, NULL
);
1054 LeaveCriticalSection(&monitor_handles_cs
);
1055 RegCloseKey(hmonitors
);
1057 TRACE("%d monitors loaded\n", loaded
);
1061 /******************************************************************
1062 * monitor_loadui [internal]
1064 * load the userinterface-dll for a given portmonitor
1066 * On failure, NULL is returned
1069 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1071 monitor_t
* pui
= NULL
;
1072 LPWSTR buffer
[MAX_PATH
];
1077 if (pm
== NULL
) return NULL
;
1078 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1080 /* Try the Portmonitor first; works for many monitors */
1081 if (pm
->monitorUI
) {
1082 EnterCriticalSection(&monitor_handles_cs
);
1084 LeaveCriticalSection(&monitor_handles_cs
);
1088 /* query the userinterface-dllname from the Portmonitor */
1089 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1090 /* building (",XcvMonitor %s",pm->name) not needed yet */
1091 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1092 TRACE("got %u with %p\n", res
, hXcv
);
1094 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1095 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1096 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1097 pm
->monitor
->pfnXcvClosePort(hXcv
);
1104 /******************************************************************
1105 * monitor_load_by_port [internal]
1107 * load a printmonitor for a given port
1109 * On failure, NULL is returned
1112 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1117 monitor_t
* pm
= NULL
;
1118 DWORD registered
= 0;
1122 TRACE("(%s)\n", debugstr_w(portname
));
1124 /* Try the Local Monitor first */
1125 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1126 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1127 /* found the portname */
1129 return monitor_load(LocalPortW
, NULL
);
1134 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1135 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1136 if (buffer
== NULL
) return NULL
;
1138 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1139 EnterCriticalSection(&monitor_handles_cs
);
1140 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1142 while ((pm
== NULL
) && (id
< registered
)) {
1144 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1145 TRACE("testing %s\n", debugstr_w(buffer
));
1146 len
= lstrlenW(buffer
);
1147 lstrcatW(buffer
, bs_Ports_bsW
);
1148 lstrcatW(buffer
, portname
);
1149 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1151 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1152 pm
= monitor_load(buffer
, NULL
);
1156 LeaveCriticalSection(&monitor_handles_cs
);
1159 HeapFree(GetProcessHeap(), 0, buffer
);
1163 /******************************************************************
1164 * enumerate the local Ports from all loaded monitors (internal)
1166 * returns the needed size (in bytes) for pPorts
1167 * and *lpreturned is set to number of entries returned in pPorts
1170 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1174 LPPORT_INFO_2W cache
;
1176 LPBYTE pi_buffer
= NULL
;
1177 DWORD pi_allocated
= 0;
1188 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1189 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1191 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1192 needed
= entrysize
* numentries
;
1193 ptr
= (LPWSTR
) &pPorts
[needed
];
1198 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1200 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1203 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1204 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1205 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1206 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1207 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1208 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1209 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1211 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1212 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1214 numentries
+= pi_returned
;
1215 needed
+= pi_needed
;
1217 /* fill the output-buffer (pPorts), if we have one */
1218 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1220 while (pi_returned
> pi_index
) {
1221 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1222 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1223 out
->pPortName
= ptr
;
1224 lstrcpyW(ptr
, cache
->pPortName
);
1225 ptr
+= (lstrlenW(ptr
)+1);
1227 out
->pMonitorName
= ptr
;
1228 lstrcpyW(ptr
, cache
->pMonitorName
);
1229 ptr
+= (lstrlenW(ptr
)+1);
1231 out
->pDescription
= ptr
;
1232 lstrcpyW(ptr
, cache
->pDescription
);
1233 ptr
+= (lstrlenW(ptr
)+1);
1234 out
->fPortType
= cache
->fPortType
;
1235 out
->Reserved
= cache
->Reserved
;
1243 /* the temporary portinfo-buffer is no longer needed */
1244 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1246 *lpreturned
= numentries
;
1247 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1251 /******************************************************************
1252 * get_servername_from_name (internal)
1254 * for an external server, a copy of the serverpart from the full name is returned
1257 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1261 WCHAR buffer
[MAX_PATH
];
1264 if (name
== NULL
) return NULL
;
1265 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1267 server
= strdupW(&name
[2]); /* skip over both backslash */
1268 if (server
== NULL
) return NULL
;
1270 /* strip '\' and the printername */
1271 ptr
= strchrW(server
, '\\');
1272 if (ptr
) ptr
[0] = '\0';
1274 TRACE("found %s\n", debugstr_w(server
));
1276 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1277 if (GetComputerNameW(buffer
, &len
)) {
1278 if (lstrcmpW(buffer
, server
) == 0) {
1279 /* The requested Servername is our computername */
1280 HeapFree(GetProcessHeap(), 0, server
);
1287 /******************************************************************
1288 * get_basename_from_name (internal)
1290 * skip over the serverpart from the full name
1293 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1295 if (name
== NULL
) return NULL
;
1296 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1297 /* skip over the servername and search for the following '\' */
1298 name
= strchrW(&name
[2], '\\');
1299 if ((name
) && (name
[1])) {
1300 /* found a separator ('\') followed by a name:
1301 skip over the separator and return the rest */
1306 /* no basename present (we found only a servername) */
1313 /******************************************************************
1314 * get_opened_printer_entry
1315 * Get the first place empty in the opened printer table
1318 * - pDefault is ignored
1320 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1322 UINT_PTR handle
= nb_printer_handles
, i
;
1323 jobqueue_t
*queue
= NULL
;
1324 opened_printer_t
*printer
= NULL
;
1326 LPCWSTR printername
;
1331 servername
= get_servername_from_name(name
);
1333 FIXME("server %s not supported\n", debugstr_w(servername
));
1334 HeapFree(GetProcessHeap(), 0, servername
);
1335 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1339 printername
= get_basename_from_name(name
);
1340 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1342 /* an empty printername is invalid */
1343 if (printername
&& (!printername
[0])) {
1344 SetLastError(ERROR_INVALID_PARAMETER
);
1348 EnterCriticalSection(&printer_handles_cs
);
1350 for (i
= 0; i
< nb_printer_handles
; i
++)
1352 if (!printer_handles
[i
])
1354 if(handle
== nb_printer_handles
)
1359 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1360 queue
= printer_handles
[i
]->queue
;
1364 if (handle
>= nb_printer_handles
)
1366 opened_printer_t
**new_array
;
1367 if (printer_handles
)
1368 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1369 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1371 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1372 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1379 printer_handles
= new_array
;
1380 nb_printer_handles
+= 16;
1383 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1390 /* clone the base name. This is NULL for the printserver */
1391 printer
->printername
= strdupW(printername
);
1393 /* clone the full name */
1394 printer
->name
= strdupW(name
);
1395 if (name
&& (!printer
->name
)) {
1401 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1402 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1403 /* OpenPrinter(",XcvMonitor " detected */
1404 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1405 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1406 if (printer
->pm
== NULL
) {
1407 SetLastError(ERROR_UNKNOWN_PORT
);
1414 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1415 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1416 /* OpenPrinter(",XcvPort " detected */
1417 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1418 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1419 if (printer
->pm
== NULL
) {
1420 SetLastError(ERROR_UNKNOWN_PORT
);
1428 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1429 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1430 pDefault
? pDefault
->DesiredAccess
: 0,
1433 if (printer
->hXcv
== NULL
) {
1434 SetLastError(ERROR_INVALID_PARAMETER
);
1441 /* Does the Printer exist? */
1442 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1443 ERR("Can't create Printers key\n");
1447 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1448 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1449 RegCloseKey(hkeyPrinters
);
1450 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1454 RegCloseKey(hkeyPrinter
);
1455 RegCloseKey(hkeyPrinters
);
1460 TRACE("using the local printserver\n");
1464 printer
->queue
= queue
;
1467 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1468 if (!printer
->queue
) {
1472 list_init(&printer
->queue
->jobs
);
1473 printer
->queue
->ref
= 0;
1475 InterlockedIncrement(&printer
->queue
->ref
);
1477 printer_handles
[handle
] = printer
;
1480 LeaveCriticalSection(&printer_handles_cs
);
1481 if (!handle
&& printer
) {
1482 /* Something failed: Free all resources */
1483 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1484 monitor_unload(printer
->pm
);
1485 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1486 HeapFree(GetProcessHeap(), 0, printer
->name
);
1487 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1488 HeapFree(GetProcessHeap(), 0, printer
);
1491 return (HANDLE
)handle
;
1494 /******************************************************************
1495 * get_opened_printer
1496 * Get the pointer to the opened printer referred by the handle
1498 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1500 UINT_PTR idx
= (UINT_PTR
)hprn
;
1501 opened_printer_t
*ret
= NULL
;
1503 EnterCriticalSection(&printer_handles_cs
);
1505 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
1506 ret
= printer_handles
[idx
- 1];
1508 LeaveCriticalSection(&printer_handles_cs
);
1512 /******************************************************************
1513 * get_opened_printer_name
1514 * Get the pointer to the opened printer name referred by the handle
1516 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1518 opened_printer_t
*printer
= get_opened_printer(hprn
);
1519 if(!printer
) return NULL
;
1520 return printer
->name
;
1523 /******************************************************************
1524 * WINSPOOL_GetOpenedPrinterRegKey
1527 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1529 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1533 if(!name
) return ERROR_INVALID_HANDLE
;
1535 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1539 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1541 ERR("Can't find opened printer %s in registry\n",
1543 RegCloseKey(hkeyPrinters
);
1544 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1546 RegCloseKey(hkeyPrinters
);
1547 return ERROR_SUCCESS
;
1550 void WINSPOOL_LoadSystemPrinters(void)
1552 HKEY hkey
, hkeyPrinters
;
1554 DWORD needed
, num
, i
;
1555 WCHAR PrinterName
[256];
1558 /* This ensures that all printer entries have a valid Name value. If causes
1559 problems later if they don't. If one is found to be missed we create one
1560 and set it equal to the name of the key */
1561 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1562 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1563 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1564 for(i
= 0; i
< num
; i
++) {
1565 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1566 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1567 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1568 set_reg_szW(hkey
, NameW
, PrinterName
);
1575 RegCloseKey(hkeyPrinters
);
1578 /* We want to avoid calling AddPrinter on printers as much as
1579 possible, because on cups printers this will (eventually) lead
1580 to a call to cupsGetPPD which takes forever, even with non-cups
1581 printers AddPrinter takes a while. So we'll tag all printers that
1582 were automatically added last time around, if they still exist
1583 we'll leave them be otherwise we'll delete them. */
1584 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1586 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1587 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1588 for(i
= 0; i
< num
; i
++) {
1589 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1590 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1591 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1593 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1601 HeapFree(GetProcessHeap(), 0, pi
);
1605 #ifdef SONAME_LIBCUPS
1606 done
= CUPS_LoadPrinters();
1609 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1610 PRINTCAP_LoadPrinters();
1612 /* Now enumerate the list again and delete any printers that are still tagged */
1613 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1615 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1616 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1617 for(i
= 0; i
< num
; i
++) {
1618 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1619 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1620 BOOL delete_driver
= FALSE
;
1621 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1622 DWORD dw
, type
, size
= sizeof(dw
);
1623 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1624 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1625 DeletePrinter(hprn
);
1626 delete_driver
= TRUE
;
1632 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1637 HeapFree(GetProcessHeap(), 0, pi
);
1644 /******************************************************************
1647 * Get the pointer to the specified job.
1648 * Should hold the printer_handles_cs before calling.
1650 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1652 opened_printer_t
*printer
= get_opened_printer(hprn
);
1655 if(!printer
) return NULL
;
1656 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1658 if(job
->job_id
== JobId
)
1664 /***********************************************************
1667 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1670 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1673 Formname
= (dmA
->dmSize
> off_formname
);
1674 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1675 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1676 dmW
->dmDeviceName
, CCHDEVICENAME
);
1678 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1679 dmA
->dmSize
- CCHDEVICENAME
);
1681 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1682 off_formname
- CCHDEVICENAME
);
1683 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1684 dmW
->dmFormName
, CCHFORMNAME
);
1685 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1686 (off_formname
+ CCHFORMNAME
));
1689 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1690 dmA
->dmDriverExtra
);
1694 /***********************************************************
1696 * Creates an ascii copy of supplied devmode on heap
1698 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1703 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1705 if(!dmW
) return NULL
;
1706 Formname
= (dmW
->dmSize
> off_formname
);
1707 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1708 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1709 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1710 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1712 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1713 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1715 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1716 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1717 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1718 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1719 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1720 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1723 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1724 dmW
->dmDriverExtra
);
1728 /***********************************************************
1729 * PRINTER_INFO_2AtoW
1730 * Creates a unicode copy of PRINTER_INFO_2A on heap
1732 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1734 LPPRINTER_INFO_2W piW
;
1735 UNICODE_STRING usBuffer
;
1737 if(!piA
) return NULL
;
1738 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1739 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1741 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1742 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1743 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1744 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1745 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1746 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1747 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1748 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1749 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1750 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1751 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1752 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1756 /***********************************************************
1757 * FREE_PRINTER_INFO_2W
1758 * Free PRINTER_INFO_2W and all strings
1760 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1764 HeapFree(heap
,0,piW
->pServerName
);
1765 HeapFree(heap
,0,piW
->pPrinterName
);
1766 HeapFree(heap
,0,piW
->pShareName
);
1767 HeapFree(heap
,0,piW
->pPortName
);
1768 HeapFree(heap
,0,piW
->pDriverName
);
1769 HeapFree(heap
,0,piW
->pComment
);
1770 HeapFree(heap
,0,piW
->pLocation
);
1771 HeapFree(heap
,0,piW
->pDevMode
);
1772 HeapFree(heap
,0,piW
->pSepFile
);
1773 HeapFree(heap
,0,piW
->pPrintProcessor
);
1774 HeapFree(heap
,0,piW
->pDatatype
);
1775 HeapFree(heap
,0,piW
->pParameters
);
1776 HeapFree(heap
,0,piW
);
1780 /******************************************************************
1781 * DeviceCapabilities [WINSPOOL.@]
1782 * DeviceCapabilitiesA [WINSPOOL.@]
1785 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1786 LPSTR pOutput
, LPDEVMODEA lpdm
)
1790 if (!GDI_CallDeviceCapabilities16
)
1792 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1794 if (!GDI_CallDeviceCapabilities16
) return -1;
1796 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1798 /* If DC_PAPERSIZE map POINT16s to POINTs */
1799 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1800 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1801 POINT
*pt
= (POINT
*)pOutput
;
1803 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1804 for(i
= 0; i
< ret
; i
++, pt
++)
1809 HeapFree( GetProcessHeap(), 0, tmp
);
1815 /*****************************************************************************
1816 * DeviceCapabilitiesW [WINSPOOL.@]
1818 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1821 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1822 WORD fwCapability
, LPWSTR pOutput
,
1823 const DEVMODEW
*pDevMode
)
1825 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1826 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1827 LPSTR pPortA
= strdupWtoA(pPort
);
1830 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1831 fwCapability
== DC_FILEDEPENDENCIES
||
1832 fwCapability
== DC_PAPERNAMES
)) {
1833 /* These need A -> W translation */
1836 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1840 switch(fwCapability
) {
1845 case DC_FILEDEPENDENCIES
:
1849 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1850 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1852 for(i
= 0; i
< ret
; i
++)
1853 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1854 pOutput
+ (i
* size
), size
);
1855 HeapFree(GetProcessHeap(), 0, pOutputA
);
1857 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1858 (LPSTR
)pOutput
, dmA
);
1860 HeapFree(GetProcessHeap(),0,pPortA
);
1861 HeapFree(GetProcessHeap(),0,pDeviceA
);
1862 HeapFree(GetProcessHeap(),0,dmA
);
1866 /******************************************************************
1867 * DocumentPropertiesA [WINSPOOL.@]
1869 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1871 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1872 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1873 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1875 LPSTR lpName
= pDeviceName
;
1876 static CHAR port
[] = "LPT1:";
1879 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1880 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1884 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1886 ERR("no name from hPrinter?\n");
1887 SetLastError(ERROR_INVALID_HANDLE
);
1890 lpName
= strdupWtoA(lpNameW
);
1893 if (!GDI_CallExtDeviceMode16
)
1895 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1897 if (!GDI_CallExtDeviceMode16
) {
1898 ERR("No CallExtDeviceMode16?\n");
1902 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1903 pDevModeInput
, NULL
, fMode
);
1906 HeapFree(GetProcessHeap(),0,lpName
);
1911 /*****************************************************************************
1912 * DocumentPropertiesW (WINSPOOL.@)
1914 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1916 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1918 LPDEVMODEW pDevModeOutput
,
1919 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1922 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1923 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1924 LPDEVMODEA pDevModeOutputA
= NULL
;
1927 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1928 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1930 if(pDevModeOutput
) {
1931 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1932 if(ret
< 0) return ret
;
1933 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1935 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1936 pDevModeInputA
, fMode
);
1937 if(pDevModeOutput
) {
1938 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1939 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1941 if(fMode
== 0 && ret
> 0)
1942 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1943 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1944 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1948 /******************************************************************
1949 * OpenPrinterA [WINSPOOL.@]
1954 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1955 LPPRINTER_DEFAULTSA pDefault
)
1957 UNICODE_STRING lpPrinterNameW
;
1958 UNICODE_STRING usBuffer
;
1959 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1960 PWSTR pwstrPrinterNameW
;
1963 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1966 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1967 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1968 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1969 pDefaultW
= &DefaultW
;
1971 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1973 RtlFreeUnicodeString(&usBuffer
);
1974 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1976 RtlFreeUnicodeString(&lpPrinterNameW
);
1980 /******************************************************************
1981 * OpenPrinterW [WINSPOOL.@]
1983 * Open a Printer / Printserver or a Printer-Object
1986 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1987 * phPrinter [O] The resulting Handle is stored here
1988 * pDefault [I] PTR to Default Printer Settings or NULL
1995 * lpPrinterName is one of:
1996 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1997 *| Printer: "PrinterName"
1998 *| Printer-Object: "PrinterName,Job xxx"
1999 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2000 *| XcvPort: "Servername,XcvPort PortName"
2003 *| Printer-Object not supported
2004 *| pDefaults is ignored
2007 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2010 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2012 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2013 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2017 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2018 SetLastError(ERROR_INVALID_PARAMETER
);
2022 /* Get the unique handle of the printer or Printserver */
2023 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2024 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2025 return (*phPrinter
!= 0);
2028 /******************************************************************
2029 * AddMonitorA [WINSPOOL.@]
2034 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2036 LPWSTR nameW
= NULL
;
2039 LPMONITOR_INFO_2A mi2a
;
2040 MONITOR_INFO_2W mi2w
;
2042 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2043 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2044 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2045 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2046 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2049 SetLastError(ERROR_INVALID_LEVEL
);
2053 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2059 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2060 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2061 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2064 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2066 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2067 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2068 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2070 if (mi2a
->pEnvironment
) {
2071 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2072 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2073 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2075 if (mi2a
->pDLLName
) {
2076 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2077 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2078 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2081 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2083 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2084 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2085 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2087 HeapFree(GetProcessHeap(), 0, nameW
);
2091 /******************************************************************************
2092 * AddMonitorW [WINSPOOL.@]
2094 * Install a Printmonitor
2097 * pName [I] Servername or NULL (local Computer)
2098 * Level [I] Structure-Level (Must be 2)
2099 * pMonitors [I] PTR to MONITOR_INFO_2
2106 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2109 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2111 monitor_t
* pm
= NULL
;
2112 LPMONITOR_INFO_2W mi2w
;
2118 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2119 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2120 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2121 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2122 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2125 SetLastError(ERROR_INVALID_LEVEL
);
2129 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2134 if (pName
&& (pName
[0])) {
2135 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2136 SetLastError(ERROR_ACCESS_DENIED
);
2141 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2142 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2143 SetLastError(ERROR_INVALID_PARAMETER
);
2146 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2147 WARN("Environment %s requested (we support only %s)\n",
2148 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2149 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2153 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2154 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2155 SetLastError(ERROR_INVALID_PARAMETER
);
2159 /* Load and initialize the monitor. SetLastError() is called on failure */
2160 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2165 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2166 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2170 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2171 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2172 &disposition
) == ERROR_SUCCESS
) {
2174 /* Some installers set options for the port before calling AddMonitor.
2175 We query the "Driver" entry to verify that the monitor is installed,
2176 before we return an error.
2177 When a user installs two print monitors at the same time with the
2178 same name but with a different driver DLL and a task switch comes
2179 between RegQueryValueExW and RegSetValueExW, a race condition
2180 is possible but silently ignored. */
2184 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2185 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2186 &namesize
) == ERROR_SUCCESS
)) {
2187 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2188 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2189 9x: ERROR_ALREADY_EXISTS (183) */
2190 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2195 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2196 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2197 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2199 RegCloseKey(hentry
);
2206 /******************************************************************
2207 * DeletePrinterDriverA [WINSPOOL.@]
2210 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2212 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2215 /******************************************************************
2216 * DeletePrinterDriverW [WINSPOOL.@]
2219 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2221 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2224 /******************************************************************
2225 * DeleteMonitorA [WINSPOOL.@]
2227 * See DeleteMonitorW.
2230 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2232 LPWSTR nameW
= NULL
;
2233 LPWSTR EnvironmentW
= NULL
;
2234 LPWSTR MonitorNameW
= NULL
;
2239 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2240 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2241 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2245 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2246 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2247 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2250 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2251 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2252 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2255 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2257 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2258 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2259 HeapFree(GetProcessHeap(), 0, nameW
);
2263 /******************************************************************
2264 * DeleteMonitorW [WINSPOOL.@]
2266 * Delete a specific Printmonitor from a Printing-Environment
2269 * pName [I] Servername or NULL (local Computer)
2270 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2271 * pMonitorName [I] Name of the Monitor, that should be deleted
2278 * pEnvironment is ignored in Windows for the local Computer.
2282 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2286 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2287 debugstr_w(pMonitorName
));
2289 if (pName
&& (pName
[0])) {
2290 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2291 SetLastError(ERROR_ACCESS_DENIED
);
2295 /* pEnvironment is ignored in Windows for the local Computer */
2297 if (!pMonitorName
|| !pMonitorName
[0]) {
2298 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2299 SetLastError(ERROR_INVALID_PARAMETER
);
2303 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2304 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2308 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2309 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2314 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2317 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2318 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2322 /******************************************************************
2323 * DeletePortA [WINSPOOL.@]
2328 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2330 LPWSTR nameW
= NULL
;
2331 LPWSTR portW
= NULL
;
2335 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2337 /* convert servername to unicode */
2339 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2340 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2341 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2344 /* convert portname to unicode */
2346 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2347 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2348 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2351 res
= DeletePortW(nameW
, hWnd
, portW
);
2352 HeapFree(GetProcessHeap(), 0, nameW
);
2353 HeapFree(GetProcessHeap(), 0, portW
);
2357 /******************************************************************
2358 * DeletePortW [WINSPOOL.@]
2360 * Delete a specific Port
2363 * pName [I] Servername or NULL (local Computer)
2364 * hWnd [I] Handle to parent Window for the Dialog-Box
2365 * pPortName [I] Name of the Port, that should be deleted
2372 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2378 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2380 if (pName
&& pName
[0]) {
2381 SetLastError(ERROR_INVALID_PARAMETER
);
2386 SetLastError(RPC_X_NULL_REF_POINTER
);
2390 /* an empty Portname is Invalid */
2391 if (!pPortName
[0]) {
2392 SetLastError(ERROR_NOT_SUPPORTED
);
2396 pm
= monitor_load_by_port(pPortName
);
2397 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2398 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2399 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2400 TRACE("got %d with %u\n", res
, GetLastError());
2404 pui
= monitor_loadui(pm
);
2405 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2406 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2407 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2408 TRACE("got %d with %u\n", res
, GetLastError());
2412 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2413 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2415 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2416 SetLastError(ERROR_NOT_SUPPORTED
);
2419 monitor_unload(pui
);
2423 TRACE("returning %d with %u\n", res
, GetLastError());
2427 /******************************************************************************
2428 * SetPrinterW [WINSPOOL.@]
2430 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2432 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2433 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2437 /******************************************************************************
2438 * WritePrinter [WINSPOOL.@]
2440 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2442 opened_printer_t
*printer
;
2445 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2447 EnterCriticalSection(&printer_handles_cs
);
2448 printer
= get_opened_printer(hPrinter
);
2451 SetLastError(ERROR_INVALID_HANDLE
);
2457 SetLastError(ERROR_SPL_NO_STARTDOC
);
2461 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2463 LeaveCriticalSection(&printer_handles_cs
);
2467 /*****************************************************************************
2468 * AddFormA [WINSPOOL.@]
2470 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2472 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2476 /*****************************************************************************
2477 * AddFormW [WINSPOOL.@]
2479 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2481 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2485 /*****************************************************************************
2486 * AddJobA [WINSPOOL.@]
2488 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2491 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2495 SetLastError(ERROR_INVALID_LEVEL
);
2499 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2502 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2503 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2504 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2505 if(*pcbNeeded
> cbBuf
) {
2506 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2509 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2510 addjobA
->JobId
= addjobW
->JobId
;
2511 addjobA
->Path
= (char *)(addjobA
+ 1);
2512 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2518 /*****************************************************************************
2519 * AddJobW [WINSPOOL.@]
2521 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2523 opened_printer_t
*printer
;
2526 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2527 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2528 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2530 ADDJOB_INFO_1W
*addjob
;
2532 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2534 EnterCriticalSection(&printer_handles_cs
);
2536 printer
= get_opened_printer(hPrinter
);
2539 SetLastError(ERROR_INVALID_HANDLE
);
2544 SetLastError(ERROR_INVALID_LEVEL
);
2548 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2552 job
->job_id
= InterlockedIncrement(&next_job_id
);
2554 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2555 if(path
[len
- 1] != '\\')
2557 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2558 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2560 len
= strlenW(filename
);
2561 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2562 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2563 job
->document_title
= strdupW(default_doc_title
);
2564 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2566 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2567 if(*pcbNeeded
<= cbBuf
) {
2568 addjob
= (ADDJOB_INFO_1W
*)pData
;
2569 addjob
->JobId
= job
->job_id
;
2570 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2571 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2574 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2577 LeaveCriticalSection(&printer_handles_cs
);
2581 /*****************************************************************************
2582 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2584 * Return the PATH for the Print-Processors
2586 * See GetPrintProcessorDirectoryW.
2590 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2591 DWORD level
, LPBYTE Info
,
2592 DWORD cbBuf
, LPDWORD pcbNeeded
)
2594 LPWSTR serverW
= NULL
;
2599 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2600 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2604 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2605 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2606 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2610 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2611 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2612 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2615 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2616 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2618 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2621 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2622 cbBuf
, NULL
, NULL
) > 0;
2625 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2626 HeapFree(GetProcessHeap(), 0, envW
);
2627 HeapFree(GetProcessHeap(), 0, serverW
);
2631 /*****************************************************************************
2632 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2634 * Return the PATH for the Print-Processors
2637 * server [I] Servername (NT only) or NULL (local Computer)
2638 * env [I] Printing-Environment (see below) or NULL (Default)
2639 * level [I] Structure-Level (must be 1)
2640 * Info [O] PTR to Buffer that receives the Result
2641 * cbBuf [I] Size of Buffer at "Info"
2642 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2643 * required for the Buffer at "Info"
2646 * Success: TRUE and in pcbNeeded the Bytes used in Info
2647 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2648 * if cbBuf is too small
2650 * Native Values returned in Info on Success:
2651 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2652 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2653 *| win9x(Windows 4.0): "%winsysdir%"
2655 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2658 * Only NULL or "" is supported for server
2661 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2662 DWORD level
, LPBYTE Info
,
2663 DWORD cbBuf
, LPDWORD pcbNeeded
)
2666 const printenv_t
* env_t
;
2668 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2669 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2671 if(server
!= NULL
&& server
[0]) {
2672 FIXME("server not supported: %s\n", debugstr_w(server
));
2673 SetLastError(ERROR_INVALID_PARAMETER
);
2677 env_t
= validate_envW(env
);
2678 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2681 WARN("(Level: %d) is ignored in win9x\n", level
);
2682 SetLastError(ERROR_INVALID_LEVEL
);
2686 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2687 needed
= GetSystemDirectoryW(NULL
, 0);
2688 /* add the Size for the Subdirectories */
2689 needed
+= lstrlenW(spoolprtprocsW
);
2690 needed
+= lstrlenW(env_t
->subdir
);
2691 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2693 if(pcbNeeded
) *pcbNeeded
= needed
;
2694 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2695 if (needed
> cbBuf
) {
2696 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2699 if(pcbNeeded
== NULL
) {
2700 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2701 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2702 SetLastError(RPC_X_NULL_REF_POINTER
);
2706 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2707 SetLastError(RPC_X_NULL_REF_POINTER
);
2711 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2712 /* add the Subdirectories */
2713 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2714 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2715 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2719 /*****************************************************************************
2720 * WINSPOOL_OpenDriverReg [internal]
2722 * opens the registry for the printer drivers depending on the given input
2723 * variable pEnvironment
2726 * the opened hkey on success
2729 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2733 const printenv_t
* env
;
2736 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2738 if (!pEnvironment
|| unicode
) {
2739 /* pEnvironment was NULL or an Unicode-String: use it direct */
2740 env
= validate_envW(pEnvironment
);
2744 /* pEnvironment was an ANSI-String: convert to unicode first */
2746 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2747 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2748 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2749 env
= validate_envW(buffer
);
2750 HeapFree(GetProcessHeap(), 0, buffer
);
2752 if (!env
) return NULL
;
2754 buffer
= HeapAlloc( GetProcessHeap(), 0,
2755 (strlenW(DriversW
) + strlenW(env
->envname
) +
2756 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2758 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2759 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2760 HeapFree(GetProcessHeap(), 0, buffer
);
2765 /*****************************************************************************
2766 * AddPrinterW [WINSPOOL.@]
2768 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2770 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2774 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2776 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2777 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2778 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2779 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2780 statusW
[] = {'S','t','a','t','u','s',0},
2781 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2783 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2786 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2787 SetLastError(ERROR_INVALID_PARAMETER
);
2791 ERR("Level = %d, unsupported!\n", Level
);
2792 SetLastError(ERROR_INVALID_LEVEL
);
2796 SetLastError(ERROR_INVALID_PARAMETER
);
2799 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2801 ERR("Can't create Printers key\n");
2804 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2805 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2806 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2807 RegCloseKey(hkeyPrinter
);
2808 RegCloseKey(hkeyPrinters
);
2811 RegCloseKey(hkeyPrinter
);
2813 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2815 ERR("Can't create Drivers key\n");
2816 RegCloseKey(hkeyPrinters
);
2819 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2821 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2822 RegCloseKey(hkeyPrinters
);
2823 RegCloseKey(hkeyDrivers
);
2824 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2827 RegCloseKey(hkeyDriver
);
2828 RegCloseKey(hkeyDrivers
);
2830 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2831 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2832 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2833 RegCloseKey(hkeyPrinters
);
2837 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2839 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2840 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2841 RegCloseKey(hkeyPrinters
);
2844 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2845 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2846 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2848 /* See if we can load the driver. We may need the devmode structure anyway
2851 * Note that DocumentPropertiesW will briefly try to open the printer we
2852 * just create to find a DEVMODEA struct (it will use the WINEPS default
2853 * one in case it is not there, so we are ok).
2855 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2858 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2859 size
= sizeof(DEVMODEW
);
2865 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2867 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2869 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2870 HeapFree(GetProcessHeap(),0,dmW
);
2875 /* set devmode to printer name */
2876 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2880 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2881 and we support these drivers. NT writes DEVMODEW so somehow
2882 we'll need to distinguish between these when we support NT
2886 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2887 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2888 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2889 HeapFree(GetProcessHeap(), 0, dmA
);
2891 HeapFree(GetProcessHeap(), 0, dmW
);
2893 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2894 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2895 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2896 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2898 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2899 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2900 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2901 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2902 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2903 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2904 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2905 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2906 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2907 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2908 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2909 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2910 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2912 RegCloseKey(hkeyPrinter
);
2913 RegCloseKey(hkeyPrinters
);
2914 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2915 ERR("OpenPrinter failing\n");
2921 /*****************************************************************************
2922 * AddPrinterA [WINSPOOL.@]
2924 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2926 UNICODE_STRING pNameW
;
2928 PRINTER_INFO_2W
*piW
;
2929 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2932 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2934 ERR("Level = %d, unsupported!\n", Level
);
2935 SetLastError(ERROR_INVALID_LEVEL
);
2938 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2939 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2941 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2943 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2944 RtlFreeUnicodeString(&pNameW
);
2949 /*****************************************************************************
2950 * ClosePrinter [WINSPOOL.@]
2952 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2954 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2955 opened_printer_t
*printer
= NULL
;
2958 TRACE("(%p)\n", hPrinter
);
2960 EnterCriticalSection(&printer_handles_cs
);
2962 if ((i
> 0) && (i
<= nb_printer_handles
))
2963 printer
= printer_handles
[i
- 1];
2968 struct list
*cursor
, *cursor2
;
2970 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2971 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2972 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2975 EndDocPrinter(hPrinter
);
2977 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2979 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2981 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2982 ScheduleJob(hPrinter
, job
->job_id
);
2984 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2986 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2987 monitor_unload(printer
->pm
);
2988 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2989 HeapFree(GetProcessHeap(), 0, printer
->name
);
2990 HeapFree(GetProcessHeap(), 0, printer
);
2991 printer_handles
[i
- 1] = NULL
;
2994 LeaveCriticalSection(&printer_handles_cs
);
2998 /*****************************************************************************
2999 * DeleteFormA [WINSPOOL.@]
3001 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3003 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3007 /*****************************************************************************
3008 * DeleteFormW [WINSPOOL.@]
3010 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3012 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3016 /*****************************************************************************
3017 * DeletePrinter [WINSPOOL.@]
3019 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3021 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3022 HKEY hkeyPrinters
, hkey
;
3025 SetLastError(ERROR_INVALID_HANDLE
);
3028 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3029 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3030 RegCloseKey(hkeyPrinters
);
3032 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3033 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3034 RegDeleteValueW(hkey
, lpNameW
);
3040 /*****************************************************************************
3041 * SetPrinterA [WINSPOOL.@]
3043 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3046 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3050 /*****************************************************************************
3051 * SetJobA [WINSPOOL.@]
3053 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3054 LPBYTE pJob
, DWORD Command
)
3058 UNICODE_STRING usBuffer
;
3060 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3062 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3063 are all ignored by SetJob, so we don't bother copying them */
3071 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3072 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3074 JobW
= (LPBYTE
)info1W
;
3075 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3076 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3077 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3078 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3079 info1W
->Status
= info1A
->Status
;
3080 info1W
->Priority
= info1A
->Priority
;
3081 info1W
->Position
= info1A
->Position
;
3082 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3087 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3088 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3090 JobW
= (LPBYTE
)info2W
;
3091 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3092 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3093 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3094 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3095 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3096 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3097 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3098 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3099 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3100 info2W
->Status
= info2A
->Status
;
3101 info2W
->Priority
= info2A
->Priority
;
3102 info2W
->Position
= info2A
->Position
;
3103 info2W
->StartTime
= info2A
->StartTime
;
3104 info2W
->UntilTime
= info2A
->UntilTime
;
3105 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3109 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3110 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3113 SetLastError(ERROR_INVALID_LEVEL
);
3117 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3123 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3124 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3125 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3126 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3127 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3132 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3133 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3134 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3135 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3136 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3137 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3138 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3139 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3140 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3144 HeapFree(GetProcessHeap(), 0, JobW
);
3149 /*****************************************************************************
3150 * SetJobW [WINSPOOL.@]
3152 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3153 LPBYTE pJob
, DWORD Command
)
3158 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3159 FIXME("Ignoring everything other than document title\n");
3161 EnterCriticalSection(&printer_handles_cs
);
3162 job
= get_job(hPrinter
, JobId
);
3172 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3173 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3174 job
->document_title
= strdupW(info1
->pDocument
);
3179 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3180 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3181 job
->document_title
= strdupW(info2
->pDocument
);
3187 SetLastError(ERROR_INVALID_LEVEL
);
3192 LeaveCriticalSection(&printer_handles_cs
);
3196 /*****************************************************************************
3197 * EndDocPrinter [WINSPOOL.@]
3199 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3201 opened_printer_t
*printer
;
3203 TRACE("(%p)\n", hPrinter
);
3205 EnterCriticalSection(&printer_handles_cs
);
3207 printer
= get_opened_printer(hPrinter
);
3210 SetLastError(ERROR_INVALID_HANDLE
);
3216 SetLastError(ERROR_SPL_NO_STARTDOC
);
3220 CloseHandle(printer
->doc
->hf
);
3221 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3222 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3223 printer
->doc
= NULL
;
3226 LeaveCriticalSection(&printer_handles_cs
);
3230 /*****************************************************************************
3231 * EndPagePrinter [WINSPOOL.@]
3233 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3235 FIXME("(%p): stub\n", hPrinter
);
3239 /*****************************************************************************
3240 * StartDocPrinterA [WINSPOOL.@]
3242 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3244 UNICODE_STRING usBuffer
;
3246 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3249 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3250 or one (DOC_INFO_3) extra DWORDs */
3254 doc2W
.JobId
= doc2
->JobId
;
3257 doc2W
.dwMode
= doc2
->dwMode
;
3260 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3261 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3262 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3266 SetLastError(ERROR_INVALID_LEVEL
);
3270 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3272 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3273 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3274 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3279 /*****************************************************************************
3280 * StartDocPrinterW [WINSPOOL.@]
3282 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3284 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3285 opened_printer_t
*printer
;
3286 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3287 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3288 JOB_INFO_1W job_info
;
3289 DWORD needed
, ret
= 0;
3293 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3294 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3295 debugstr_w(doc
->pDatatype
));
3297 if(Level
< 1 || Level
> 3)
3299 SetLastError(ERROR_INVALID_LEVEL
);
3303 EnterCriticalSection(&printer_handles_cs
);
3304 printer
= get_opened_printer(hPrinter
);
3307 SetLastError(ERROR_INVALID_HANDLE
);
3313 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3317 /* Even if we're printing to a file we still add a print job, we'll
3318 just ignore the spool file name */
3320 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3322 ERR("AddJob failed gle %u\n", GetLastError());
3326 if(doc
->pOutputFile
)
3327 filename
= doc
->pOutputFile
;
3329 filename
= addjob
->Path
;
3331 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3332 if(hf
== INVALID_HANDLE_VALUE
)
3335 memset(&job_info
, 0, sizeof(job_info
));
3336 job_info
.pDocument
= doc
->pDocName
;
3337 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3339 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3340 printer
->doc
->hf
= hf
;
3341 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3343 LeaveCriticalSection(&printer_handles_cs
);
3348 /*****************************************************************************
3349 * StartPagePrinter [WINSPOOL.@]
3351 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3353 FIXME("(%p): stub\n", hPrinter
);
3357 /*****************************************************************************
3358 * GetFormA [WINSPOOL.@]
3360 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3361 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3363 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3364 Level
,pForm
,cbBuf
,pcbNeeded
);
3368 /*****************************************************************************
3369 * GetFormW [WINSPOOL.@]
3371 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3372 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3374 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3375 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3379 /*****************************************************************************
3380 * SetFormA [WINSPOOL.@]
3382 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3385 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3389 /*****************************************************************************
3390 * SetFormW [WINSPOOL.@]
3392 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3395 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3399 /*****************************************************************************
3400 * ReadPrinter [WINSPOOL.@]
3402 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3403 LPDWORD pNoBytesRead
)
3405 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3409 /*****************************************************************************
3410 * ResetPrinterA [WINSPOOL.@]
3412 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3414 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3418 /*****************************************************************************
3419 * ResetPrinterW [WINSPOOL.@]
3421 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3423 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3427 /*****************************************************************************
3428 * WINSPOOL_GetDWORDFromReg
3430 * Return DWORD associated with ValueName from hkey.
3432 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3434 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3437 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3439 if(ret
!= ERROR_SUCCESS
) {
3440 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3443 if(type
!= REG_DWORD
) {
3444 ERR("Got type %d\n", type
);
3451 /*****************************************************************************
3452 * get_filename_from_reg [internal]
3454 * Get ValueName from hkey storing result in out
3455 * when the Value in the registry has only a filename, use driverdir as prefix
3456 * outlen is space left in out
3457 * String is stored either as unicode or ascii
3461 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3462 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3464 WCHAR filename
[MAX_PATH
];
3468 LPWSTR buffer
= filename
;
3472 size
= sizeof(filename
);
3474 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3475 if (ret
== ERROR_MORE_DATA
) {
3476 TRACE("need dynamic buffer: %u\n", size
);
3477 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3479 /* No Memory is bad */
3483 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3486 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3487 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3493 /* do we have a full path ? */
3494 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3495 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3498 /* we must build the full Path */
3500 if ((out
) && (outlen
> dirlen
)) {
3502 lstrcpyW((LPWSTR
)out
, driverdir
);
3506 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3515 /* write the filename */
3517 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3518 if ((out
) && (outlen
>= size
)) {
3519 lstrcpyW((LPWSTR
)out
, ptr
);
3528 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3529 if ((out
) && (outlen
>= size
)) {
3530 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3538 ptr
+= lstrlenW(ptr
)+1;
3539 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3542 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3544 /* write the multisz-termination */
3545 if (type
== REG_MULTI_SZ
) {
3546 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3549 if (out
&& (outlen
>= size
)) {
3550 memset (out
, 0, size
);
3556 /*****************************************************************************
3557 * WINSPOOL_GetStringFromReg
3559 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3560 * String is stored either as unicode or ascii.
3561 * Bit of a hack here to get the ValueName if we want ascii.
3563 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3564 DWORD buflen
, DWORD
*needed
,
3567 DWORD sz
= buflen
, type
;
3571 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3573 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3574 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3575 HeapFree(GetProcessHeap(),0,ValueNameA
);
3577 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3578 WARN("Got ret = %d\n", ret
);
3582 /* add space for terminating '\0' */
3583 sz
+= unicode
? sizeof(WCHAR
) : 1;
3587 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3592 /*****************************************************************************
3593 * WINSPOOL_GetDefaultDevMode
3595 * Get a default DevMode values for wineps.
3599 static void WINSPOOL_GetDefaultDevMode(
3601 DWORD buflen
, DWORD
*needed
,
3605 static const char szwps
[] = "wineps.drv";
3607 /* fill default DEVMODE - should be read from ppd... */
3608 ZeroMemory( &dm
, sizeof(dm
) );
3609 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3610 dm
.dmSpecVersion
= DM_SPECVERSION
;
3611 dm
.dmDriverVersion
= 1;
3612 dm
.dmSize
= sizeof(DEVMODEA
);
3613 dm
.dmDriverExtra
= 0;
3615 DM_ORIENTATION
| DM_PAPERSIZE
|
3616 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3619 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3620 DM_YRESOLUTION
| DM_TTOPTION
;
3622 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3623 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3624 dm
.u1
.s1
.dmPaperLength
= 2970;
3625 dm
.u1
.s1
.dmPaperWidth
= 2100;
3627 dm
.u1
.s1
.dmScale
= 100;
3628 dm
.u1
.s1
.dmCopies
= 1;
3629 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3630 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3633 dm
.dmYResolution
= 300; /* 300dpi */
3634 dm
.dmTTOption
= DMTT_BITMAP
;
3637 /* dm.dmLogPixels */
3638 /* dm.dmBitsPerPel */
3639 /* dm.dmPelsWidth */
3640 /* dm.dmPelsHeight */
3641 /* dm.u2.dmDisplayFlags */
3642 /* dm.dmDisplayFrequency */
3643 /* dm.dmICMMethod */
3644 /* dm.dmICMIntent */
3645 /* dm.dmMediaType */
3646 /* dm.dmDitherType */
3647 /* dm.dmReserved1 */
3648 /* dm.dmReserved2 */
3649 /* dm.dmPanningWidth */
3650 /* dm.dmPanningHeight */
3653 if(buflen
>= sizeof(DEVMODEW
)) {
3654 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3655 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3656 HeapFree(GetProcessHeap(),0,pdmW
);
3658 *needed
= sizeof(DEVMODEW
);
3662 if(buflen
>= sizeof(DEVMODEA
)) {
3663 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3665 *needed
= sizeof(DEVMODEA
);
3669 /*****************************************************************************
3670 * WINSPOOL_GetDevModeFromReg
3672 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3673 * DevMode is stored either as unicode or ascii.
3675 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3677 DWORD buflen
, DWORD
*needed
,
3680 DWORD sz
= buflen
, type
;
3683 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3684 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3685 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3686 if (sz
< sizeof(DEVMODEA
))
3688 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3691 /* ensures that dmSize is not erratically bogus if registry is invalid */
3692 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3693 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3695 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3697 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3698 memcpy(ptr
, dmW
, sz
);
3699 HeapFree(GetProcessHeap(),0,dmW
);
3706 /*********************************************************************
3707 * WINSPOOL_GetPrinter_1
3709 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3710 * The strings are either stored as unicode or ascii.
3712 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3713 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3716 DWORD size
, left
= cbBuf
;
3717 BOOL space
= (cbBuf
> 0);
3722 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3724 if(space
&& size
<= left
) {
3725 pi1
->pName
= (LPWSTR
)ptr
;
3733 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3734 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3736 if(space
&& size
<= left
) {
3737 pi1
->pDescription
= (LPWSTR
)ptr
;
3745 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3747 if(space
&& size
<= left
) {
3748 pi1
->pComment
= (LPWSTR
)ptr
;
3756 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3758 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3759 memset(pi1
, 0, sizeof(*pi1
));
3763 /*********************************************************************
3764 * WINSPOOL_GetPrinter_2
3766 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3767 * The strings are either stored as unicode or ascii.
3769 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3770 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3773 DWORD size
, left
= cbBuf
;
3774 BOOL space
= (cbBuf
> 0);
3779 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3781 if(space
&& size
<= left
) {
3782 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3789 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3791 if(space
&& size
<= left
) {
3792 pi2
->pShareName
= (LPWSTR
)ptr
;
3799 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3801 if(space
&& size
<= left
) {
3802 pi2
->pPortName
= (LPWSTR
)ptr
;
3809 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3811 if(space
&& size
<= left
) {
3812 pi2
->pDriverName
= (LPWSTR
)ptr
;
3819 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3821 if(space
&& size
<= left
) {
3822 pi2
->pComment
= (LPWSTR
)ptr
;
3829 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3831 if(space
&& size
<= left
) {
3832 pi2
->pLocation
= (LPWSTR
)ptr
;
3839 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3841 if(space
&& size
<= left
) {
3842 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3851 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3852 if(space
&& size
<= left
) {
3853 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3860 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3862 if(space
&& size
<= left
) {
3863 pi2
->pSepFile
= (LPWSTR
)ptr
;
3870 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3872 if(space
&& size
<= left
) {
3873 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3880 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3882 if(space
&& size
<= left
) {
3883 pi2
->pDatatype
= (LPWSTR
)ptr
;
3890 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3892 if(space
&& size
<= left
) {
3893 pi2
->pParameters
= (LPWSTR
)ptr
;
3901 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3902 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3903 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3904 "Default Priority");
3905 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3906 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3909 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3910 memset(pi2
, 0, sizeof(*pi2
));
3915 /*********************************************************************
3916 * WINSPOOL_GetPrinter_4
3918 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3920 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3921 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3924 DWORD size
, left
= cbBuf
;
3925 BOOL space
= (cbBuf
> 0);
3930 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3932 if(space
&& size
<= left
) {
3933 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3941 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3944 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3945 memset(pi4
, 0, sizeof(*pi4
));
3950 /*********************************************************************
3951 * WINSPOOL_GetPrinter_5
3953 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3955 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3956 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3959 DWORD size
, left
= cbBuf
;
3960 BOOL space
= (cbBuf
> 0);
3965 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3967 if(space
&& size
<= left
) {
3968 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3975 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3977 if(space
&& size
<= left
) {
3978 pi5
->pPortName
= (LPWSTR
)ptr
;
3986 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3987 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3989 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3993 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3994 memset(pi5
, 0, sizeof(*pi5
));
3999 /*****************************************************************************
4000 * WINSPOOL_GetPrinter
4002 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4003 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4004 * just a collection of pointers to strings.
4006 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4007 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4010 DWORD size
, needed
= 0;
4012 HKEY hkeyPrinter
, hkeyPrinters
;
4015 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4017 if (!(name
= get_opened_printer_name(hPrinter
))) {
4018 SetLastError(ERROR_INVALID_HANDLE
);
4022 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4024 ERR("Can't create Printers key\n");
4027 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4029 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4030 RegCloseKey(hkeyPrinters
);
4031 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4038 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4040 size
= sizeof(PRINTER_INFO_2W
);
4042 ptr
= pPrinter
+ size
;
4044 memset(pPrinter
, 0, size
);
4049 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4057 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4059 size
= sizeof(PRINTER_INFO_4W
);
4061 ptr
= pPrinter
+ size
;
4063 memset(pPrinter
, 0, size
);
4068 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4077 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4079 size
= sizeof(PRINTER_INFO_5W
);
4081 ptr
= pPrinter
+ size
;
4083 memset(pPrinter
, 0, size
);
4089 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4096 FIXME("Unimplemented level %d\n", Level
);
4097 SetLastError(ERROR_INVALID_LEVEL
);
4098 RegCloseKey(hkeyPrinters
);
4099 RegCloseKey(hkeyPrinter
);
4103 RegCloseKey(hkeyPrinter
);
4104 RegCloseKey(hkeyPrinters
);
4106 TRACE("returning %d needed = %d\n", ret
, needed
);
4107 if(pcbNeeded
) *pcbNeeded
= needed
;
4109 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4113 /*****************************************************************************
4114 * GetPrinterW [WINSPOOL.@]
4116 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4117 DWORD cbBuf
, LPDWORD pcbNeeded
)
4119 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4123 /*****************************************************************************
4124 * GetPrinterA [WINSPOOL.@]
4126 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4127 DWORD cbBuf
, LPDWORD pcbNeeded
)
4129 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4133 /*****************************************************************************
4134 * WINSPOOL_EnumPrinters
4136 * Implementation of EnumPrintersA|W
4138 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4139 DWORD dwLevel
, LPBYTE lpbPrinters
,
4140 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4141 LPDWORD lpdwReturned
, BOOL unicode
)
4144 HKEY hkeyPrinters
, hkeyPrinter
;
4145 WCHAR PrinterName
[255];
4146 DWORD needed
= 0, number
= 0;
4147 DWORD used
, i
, left
;
4151 memset(lpbPrinters
, 0, cbBuf
);
4157 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4158 if(dwType
== PRINTER_ENUM_DEFAULT
)
4161 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4162 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4163 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4165 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4173 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4174 FIXME("dwType = %08x\n", dwType
);
4175 SetLastError(ERROR_INVALID_FLAGS
);
4179 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4181 ERR("Can't create Printers key\n");
4185 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4186 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4187 RegCloseKey(hkeyPrinters
);
4188 ERR("Can't query Printers key\n");
4191 TRACE("Found %d printers\n", number
);
4195 used
= number
* sizeof(PRINTER_INFO_1W
);
4198 used
= number
* sizeof(PRINTER_INFO_2W
);
4201 used
= number
* sizeof(PRINTER_INFO_4W
);
4204 used
= number
* sizeof(PRINTER_INFO_5W
);
4208 SetLastError(ERROR_INVALID_LEVEL
);
4209 RegCloseKey(hkeyPrinters
);
4212 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4214 for(i
= 0; i
< number
; i
++) {
4215 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4217 ERR("Can't enum key number %d\n", i
);
4218 RegCloseKey(hkeyPrinters
);
4221 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4222 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4224 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4225 RegCloseKey(hkeyPrinters
);
4230 buf
= lpbPrinters
+ used
;
4231 left
= cbBuf
- used
;
4239 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4240 left
, &needed
, unicode
);
4242 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4245 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4246 left
, &needed
, unicode
);
4248 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4251 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4252 left
, &needed
, unicode
);
4254 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4257 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4258 left
, &needed
, unicode
);
4260 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4263 ERR("Shouldn't be here!\n");
4264 RegCloseKey(hkeyPrinter
);
4265 RegCloseKey(hkeyPrinters
);
4268 RegCloseKey(hkeyPrinter
);
4270 RegCloseKey(hkeyPrinters
);
4277 memset(lpbPrinters
, 0, cbBuf
);
4278 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4282 *lpdwReturned
= number
;
4283 SetLastError(ERROR_SUCCESS
);
4288 /******************************************************************
4289 * EnumPrintersW [WINSPOOL.@]
4291 * Enumerates the available printers, print servers and print
4292 * providers, depending on the specified flags, name and level.
4296 * If level is set to 1:
4297 * Returns an array of PRINTER_INFO_1 data structures in the
4298 * lpbPrinters buffer.
4300 * If level is set to 2:
4301 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4302 * Returns an array of PRINTER_INFO_2 data structures in the
4303 * lpbPrinters buffer. Note that according to MSDN also an
4304 * OpenPrinter should be performed on every remote printer.
4306 * If level is set to 4 (officially WinNT only):
4307 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4308 * Fast: Only the registry is queried to retrieve printer names,
4309 * no connection to the driver is made.
4310 * Returns an array of PRINTER_INFO_4 data structures in the
4311 * lpbPrinters buffer.
4313 * If level is set to 5 (officially WinNT4/Win9x only):
4314 * Fast: Only the registry is queried to retrieve printer names,
4315 * no connection to the driver is made.
4316 * Returns an array of PRINTER_INFO_5 data structures in the
4317 * lpbPrinters buffer.
4319 * If level set to 3 or 6+:
4320 * returns zero (failure!)
4322 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4326 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4327 * - Only levels 2, 4 and 5 are implemented at the moment.
4328 * - 16-bit printer drivers are not enumerated.
4329 * - Returned amount of bytes used/needed does not match the real Windoze
4330 * implementation (as in this implementation, all strings are part
4331 * of the buffer, whereas Win32 keeps them somewhere else)
4332 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4335 * - In a regular Wine installation, no registry settings for printers
4336 * exist, which makes this function return an empty list.
4338 BOOL WINAPI
EnumPrintersW(
4339 DWORD dwType
, /* [in] Types of print objects to enumerate */
4340 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4341 DWORD dwLevel
, /* [in] type of printer info structure */
4342 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4343 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4344 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4345 LPDWORD lpdwReturned
/* [out] number of entries returned */
4348 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4349 lpdwNeeded
, lpdwReturned
, TRUE
);
4352 /******************************************************************
4353 * EnumPrintersA [WINSPOOL.@]
4356 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4357 DWORD dwLevel
, LPBYTE lpbPrinters
,
4358 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4359 LPDWORD lpdwReturned
)
4361 BOOL ret
, unicode
= FALSE
;
4362 UNICODE_STRING lpszNameW
;
4365 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4366 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4367 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4368 lpdwNeeded
, lpdwReturned
, unicode
);
4369 RtlFreeUnicodeString(&lpszNameW
);
4373 /*****************************************************************************
4374 * WINSPOOL_GetDriverInfoFromReg [internal]
4376 * Enters the information from the registry into the DRIVER_INFO struct
4379 * zero if the printer driver does not exist in the registry
4380 * (only if Level > 1) otherwise nonzero
4382 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4385 const printenv_t
* env
,
4387 LPBYTE ptr
, /* DRIVER_INFO */
4388 LPBYTE pDriverStrings
, /* strings buffer */
4389 DWORD cbBuf
, /* size of string buffer */
4390 LPDWORD pcbNeeded
, /* space needed for str. */
4391 BOOL unicode
) /* type of strings */
4395 WCHAR driverdir
[MAX_PATH
];
4397 LPBYTE strPtr
= pDriverStrings
;
4398 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4400 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4401 debugstr_w(DriverName
), env
,
4402 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4404 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4407 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4408 if (*pcbNeeded
<= cbBuf
)
4409 strcpyW((LPWSTR
)strPtr
, DriverName
);
4413 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4414 if (*pcbNeeded
<= cbBuf
)
4415 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4418 /* pName for level 1 has a different offset! */
4420 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4424 /* .cVersion and .pName for level > 1 */
4426 di
->cVersion
= env
->driverversion
;
4427 di
->pName
= (LPWSTR
) strPtr
;
4428 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4431 /* Reserve Space for the largest subdir and a Backslash*/
4432 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4433 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4434 /* Should never Fail */
4437 lstrcatW(driverdir
, env
->versionsubdir
);
4438 lstrcatW(driverdir
, backslashW
);
4440 /* dirlen must not include the terminating zero */
4441 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4442 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4444 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4445 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4446 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4452 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4454 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4457 if (*pcbNeeded
<= cbBuf
) {
4459 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4463 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4465 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4466 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4469 /* .pDriverPath is the Graphics rendering engine.
4470 The full Path is required to avoid a crash in some apps */
4471 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4473 if (*pcbNeeded
<= cbBuf
)
4474 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4476 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4477 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4480 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4481 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4483 if (*pcbNeeded
<= cbBuf
)
4484 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4486 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4487 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4490 /* .pConfigFile is the Driver user Interface */
4491 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4493 if (*pcbNeeded
<= cbBuf
)
4494 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4496 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4497 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4501 RegCloseKey(hkeyDriver
);
4502 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4507 RegCloseKey(hkeyDriver
);
4508 FIXME("level 5: incomplete\n");
4513 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4515 if (*pcbNeeded
<= cbBuf
)
4516 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4518 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4519 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4522 /* .pDependentFiles */
4523 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4525 if (*pcbNeeded
<= cbBuf
)
4526 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4528 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4529 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4531 else if (GetVersion() & 0x80000000) {
4532 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4533 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4535 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4537 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4538 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4541 /* .pMonitorName is the optional Language Monitor */
4542 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4544 if (*pcbNeeded
<= cbBuf
)
4545 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4547 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4548 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4551 /* .pDefaultDataType */
4552 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4554 if(*pcbNeeded
<= cbBuf
)
4555 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4557 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4558 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4562 RegCloseKey(hkeyDriver
);
4563 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4567 /* .pszzPreviousNames */
4568 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4570 if(*pcbNeeded
<= cbBuf
)
4571 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4573 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4574 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4578 RegCloseKey(hkeyDriver
);
4579 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4583 /* support is missing, but not important enough for a FIXME */
4584 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4587 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4589 if(*pcbNeeded
<= cbBuf
)
4590 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4592 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4593 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4597 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4599 if(*pcbNeeded
<= cbBuf
)
4600 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4602 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4603 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4606 /* .pszHardwareID */
4607 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4609 if(*pcbNeeded
<= cbBuf
)
4610 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4612 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4613 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4617 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4619 if(*pcbNeeded
<= cbBuf
)
4620 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4622 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4623 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4627 RegCloseKey(hkeyDriver
);
4631 /* support is missing, but not important enough for a FIXME */
4632 TRACE("level 8: incomplete\n");
4634 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4635 RegCloseKey(hkeyDriver
);
4639 /*****************************************************************************
4640 * WINSPOOL_GetPrinterDriver
4642 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4643 DWORD Level
, LPBYTE pDriverInfo
,
4644 DWORD cbBuf
, LPDWORD pcbNeeded
,
4648 WCHAR DriverName
[100];
4649 DWORD ret
, type
, size
, needed
= 0;
4651 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4652 const printenv_t
* env
;
4654 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4655 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4658 if (!(name
= get_opened_printer_name(hPrinter
))) {
4659 SetLastError(ERROR_INVALID_HANDLE
);
4663 if (Level
< 1 || Level
== 7 || Level
> 8) {
4664 SetLastError(ERROR_INVALID_LEVEL
);
4668 env
= validate_envW(pEnvironment
);
4669 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4671 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4673 ERR("Can't create Printers key\n");
4676 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4678 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4679 RegCloseKey(hkeyPrinters
);
4680 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4683 size
= sizeof(DriverName
);
4685 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4686 (LPBYTE
)DriverName
, &size
);
4687 RegCloseKey(hkeyPrinter
);
4688 RegCloseKey(hkeyPrinters
);
4689 if(ret
!= ERROR_SUCCESS
) {
4690 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4694 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4696 ERR("Can't create Drivers key\n");
4700 size
= di_sizeof
[Level
];
4701 if ((size
<= cbBuf
) && pDriverInfo
)
4702 ptr
= pDriverInfo
+ size
;
4704 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4705 env
, Level
, pDriverInfo
, ptr
,
4706 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4707 &needed
, unicode
)) {
4708 RegCloseKey(hkeyDrivers
);
4712 RegCloseKey(hkeyDrivers
);
4714 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4715 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4716 if(cbBuf
>= needed
) return TRUE
;
4717 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4721 /*****************************************************************************
4722 * GetPrinterDriverA [WINSPOOL.@]
4724 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4725 DWORD Level
, LPBYTE pDriverInfo
,
4726 DWORD cbBuf
, LPDWORD pcbNeeded
)
4729 UNICODE_STRING pEnvW
;
4732 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4733 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4734 cbBuf
, pcbNeeded
, FALSE
);
4735 RtlFreeUnicodeString(&pEnvW
);
4738 /*****************************************************************************
4739 * GetPrinterDriverW [WINSPOOL.@]
4741 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4742 DWORD Level
, LPBYTE pDriverInfo
,
4743 DWORD cbBuf
, LPDWORD pcbNeeded
)
4745 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4746 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4749 /*****************************************************************************
4750 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4752 * Return the PATH for the Printer-Drivers (UNICODE)
4755 * pName [I] Servername (NT only) or NULL (local Computer)
4756 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4757 * Level [I] Structure-Level (must be 1)
4758 * pDriverDirectory [O] PTR to Buffer that receives the Result
4759 * cbBuf [I] Size of Buffer at pDriverDirectory
4760 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4761 * required for pDriverDirectory
4764 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4765 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4766 * if cbBuf is too small
4768 * Native Values returned in pDriverDirectory on Success:
4769 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4770 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4771 *| win9x(Windows 4.0): "%winsysdir%"
4773 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4776 *- Only NULL or "" is supported for pName
4779 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4780 DWORD Level
, LPBYTE pDriverDirectory
,
4781 DWORD cbBuf
, LPDWORD pcbNeeded
)
4783 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4784 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4786 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4789 /* (Level != 1) is ignored in win9x */
4790 SetLastError(ERROR_INVALID_LEVEL
);
4793 if (pcbNeeded
== NULL
) {
4794 /* (pcbNeeded == NULL) is ignored in win9x */
4795 SetLastError(RPC_X_NULL_REF_POINTER
);
4799 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4800 pDriverDirectory
, cbBuf
, pcbNeeded
);
4805 /*****************************************************************************
4806 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4808 * Return the PATH for the Printer-Drivers (ANSI)
4810 * See GetPrinterDriverDirectoryW.
4813 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4816 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4817 DWORD Level
, LPBYTE pDriverDirectory
,
4818 DWORD cbBuf
, LPDWORD pcbNeeded
)
4820 UNICODE_STRING nameW
, environmentW
;
4823 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4824 WCHAR
*driverDirectoryW
= NULL
;
4826 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4827 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4829 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4831 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4832 else nameW
.Buffer
= NULL
;
4833 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4834 else environmentW
.Buffer
= NULL
;
4836 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4837 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4840 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4841 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4843 *pcbNeeded
= needed
;
4844 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4846 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4848 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4850 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4851 RtlFreeUnicodeString(&environmentW
);
4852 RtlFreeUnicodeString(&nameW
);
4857 /*****************************************************************************
4858 * AddPrinterDriverA [WINSPOOL.@]
4860 * See AddPrinterDriverW.
4863 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4865 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4866 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4869 /******************************************************************************
4870 * AddPrinterDriverW (WINSPOOL.@)
4872 * Install a Printer Driver
4875 * pName [I] Servername or NULL (local Computer)
4876 * level [I] Level for the supplied DRIVER_INFO_*W struct
4877 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4884 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4886 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4887 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4890 /*****************************************************************************
4891 * AddPrintProcessorA [WINSPOOL.@]
4893 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4894 LPSTR pPrintProcessorName
)
4896 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4897 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4901 /*****************************************************************************
4902 * AddPrintProcessorW [WINSPOOL.@]
4904 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4905 LPWSTR pPrintProcessorName
)
4907 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4908 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4912 /*****************************************************************************
4913 * AddPrintProvidorA [WINSPOOL.@]
4915 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4917 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4921 /*****************************************************************************
4922 * AddPrintProvidorW [WINSPOOL.@]
4924 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4926 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4930 /*****************************************************************************
4931 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4933 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4934 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4936 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4937 pDevModeOutput
, pDevModeInput
);
4941 /*****************************************************************************
4942 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4944 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4945 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4947 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4948 pDevModeOutput
, pDevModeInput
);
4952 /*****************************************************************************
4953 * PrinterProperties [WINSPOOL.@]
4955 * Displays a dialog to set the properties of the printer.
4958 * nonzero on success or zero on failure
4961 * implemented as stub only
4963 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4964 HANDLE hPrinter
/* [in] handle to printer object */
4966 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4967 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4971 /*****************************************************************************
4972 * EnumJobsA [WINSPOOL.@]
4975 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4976 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4979 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4980 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4982 if(pcbNeeded
) *pcbNeeded
= 0;
4983 if(pcReturned
) *pcReturned
= 0;
4988 /*****************************************************************************
4989 * EnumJobsW [WINSPOOL.@]
4992 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4993 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4996 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4997 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4999 if(pcbNeeded
) *pcbNeeded
= 0;
5000 if(pcReturned
) *pcReturned
= 0;
5004 /*****************************************************************************
5005 * WINSPOOL_EnumPrinterDrivers [internal]
5007 * Delivers information about all printer drivers installed on the
5008 * localhost or a given server
5011 * nonzero on success or zero on failure. If the buffer for the returned
5012 * information is too small the function will return an error
5015 * - only implemented for localhost, foreign hosts will return an error
5017 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5018 DWORD Level
, LPBYTE pDriverInfo
,
5019 DWORD cbBuf
, LPDWORD pcbNeeded
,
5020 LPDWORD pcReturned
, BOOL unicode
)
5023 DWORD i
, needed
, number
= 0, size
= 0;
5024 WCHAR DriverNameW
[255];
5026 const printenv_t
* env
;
5028 TRACE("%s,%s,%d,%p,%d,%d\n",
5029 debugstr_w(pName
), debugstr_w(pEnvironment
),
5030 Level
, pDriverInfo
, cbBuf
, unicode
);
5032 /* check for local drivers */
5033 if((pName
) && (pName
[0])) {
5034 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5035 SetLastError(ERROR_ACCESS_DENIED
);
5039 env
= validate_envW(pEnvironment
);
5040 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5042 /* check input parameter */
5043 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5044 SetLastError(ERROR_INVALID_LEVEL
);
5048 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
5049 SetLastError(RPC_X_NULL_REF_POINTER
);
5053 /* initialize return values */
5055 memset( pDriverInfo
, 0, cbBuf
);
5059 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5061 ERR("Can't open Drivers key\n");
5065 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5066 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5067 RegCloseKey(hkeyDrivers
);
5068 ERR("Can't query Drivers key\n");
5071 TRACE("Found %d Drivers\n", number
);
5073 /* get size of single struct
5074 * unicode and ascii structure have the same size
5076 size
= di_sizeof
[Level
];
5078 /* calculate required buffer size */
5079 *pcbNeeded
= size
* number
;
5081 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5083 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5084 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
5086 ERR("Can't enum key number %d\n", i
);
5087 RegCloseKey(hkeyDrivers
);
5090 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5092 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5093 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5094 &needed
, unicode
)) {
5095 RegCloseKey(hkeyDrivers
);
5098 (*pcbNeeded
) += needed
;
5101 RegCloseKey(hkeyDrivers
);
5103 if(cbBuf
< *pcbNeeded
){
5104 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5108 *pcReturned
= number
;
5112 /*****************************************************************************
5113 * EnumPrinterDriversW [WINSPOOL.@]
5115 * see function EnumPrinterDrivers for RETURNS, BUGS
5117 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5118 LPBYTE pDriverInfo
, DWORD cbBuf
,
5119 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5121 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5122 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5125 /*****************************************************************************
5126 * EnumPrinterDriversA [WINSPOOL.@]
5128 * see function EnumPrinterDrivers for RETURNS, BUGS
5130 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5131 LPBYTE pDriverInfo
, DWORD cbBuf
,
5132 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5134 UNICODE_STRING pNameW
, pEnvironmentW
;
5135 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5137 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5138 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5140 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5141 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5143 RtlFreeUnicodeString(&pNameW
);
5144 RtlFreeUnicodeString(&pEnvironmentW
);
5149 /******************************************************************************
5150 * EnumPortsA (WINSPOOL.@)
5155 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5156 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5159 LPBYTE bufferW
= NULL
;
5160 LPWSTR nameW
= NULL
;
5162 DWORD numentries
= 0;
5165 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5166 cbBuf
, pcbNeeded
, pcReturned
);
5168 /* convert servername to unicode */
5170 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5171 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5172 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5174 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5175 needed
= cbBuf
* sizeof(WCHAR
);
5176 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5177 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5179 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5180 if (pcbNeeded
) needed
= *pcbNeeded
;
5181 /* HeapReAlloc return NULL, when bufferW was NULL */
5182 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5183 HeapAlloc(GetProcessHeap(), 0, needed
);
5185 /* Try again with the large Buffer */
5186 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5188 needed
= pcbNeeded
? *pcbNeeded
: 0;
5189 numentries
= pcReturned
? *pcReturned
: 0;
5192 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5193 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5196 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5197 DWORD entrysize
= 0;
5200 LPPORT_INFO_2W pi2w
;
5201 LPPORT_INFO_2A pi2a
;
5204 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5206 /* First pass: calculate the size for all Entries */
5207 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5208 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5210 while (index
< numentries
) {
5212 needed
+= entrysize
; /* PORT_INFO_?A */
5213 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5215 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5216 NULL
, 0, NULL
, NULL
);
5218 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5219 NULL
, 0, NULL
, NULL
);
5220 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5221 NULL
, 0, NULL
, NULL
);
5223 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5224 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5225 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5228 /* check for errors and quit on failure */
5229 if (cbBuf
< needed
) {
5230 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5234 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5235 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5236 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5237 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5238 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5240 /* Second Pass: Fill the User Buffer (if we have one) */
5241 while ((index
< numentries
) && pPorts
) {
5243 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5244 pi2a
->pPortName
= ptr
;
5245 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5246 ptr
, cbBuf
, NULL
, NULL
);
5250 pi2a
->pMonitorName
= ptr
;
5251 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5252 ptr
, cbBuf
, NULL
, NULL
);
5256 pi2a
->pDescription
= ptr
;
5257 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5258 ptr
, cbBuf
, NULL
, NULL
);
5262 pi2a
->fPortType
= pi2w
->fPortType
;
5263 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5266 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5267 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5268 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5273 if (pcbNeeded
) *pcbNeeded
= needed
;
5274 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5276 HeapFree(GetProcessHeap(), 0, nameW
);
5277 HeapFree(GetProcessHeap(), 0, bufferW
);
5279 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5280 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5286 /******************************************************************************
5287 * EnumPortsW (WINSPOOL.@)
5289 * Enumerate available Ports
5292 * name [I] Servername or NULL (local Computer)
5293 * level [I] Structure-Level (1 or 2)
5294 * buffer [O] PTR to Buffer that receives the Result
5295 * bufsize [I] Size of Buffer at buffer
5296 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5297 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5301 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5305 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5308 DWORD numentries
= 0;
5311 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5312 cbBuf
, pcbNeeded
, pcReturned
);
5314 if (pName
&& (pName
[0])) {
5315 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5316 SetLastError(ERROR_ACCESS_DENIED
);
5320 /* Level is not checked in win9x */
5321 if (!Level
|| (Level
> 2)) {
5322 WARN("level (%d) is ignored in win9x\n", Level
);
5323 SetLastError(ERROR_INVALID_LEVEL
);
5327 SetLastError(RPC_X_NULL_REF_POINTER
);
5331 EnterCriticalSection(&monitor_handles_cs
);
5334 /* Scan all local Ports */
5336 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5338 /* we calculated the needed buffersize. now do the error-checks */
5339 if (cbBuf
< needed
) {
5340 monitor_unloadall();
5341 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5342 goto emP_cleanup_cs
;
5344 else if (!pPorts
|| !pcReturned
) {
5345 monitor_unloadall();
5346 SetLastError(RPC_X_NULL_REF_POINTER
);
5347 goto emP_cleanup_cs
;
5350 /* Fill the Buffer */
5351 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5353 monitor_unloadall();
5356 LeaveCriticalSection(&monitor_handles_cs
);
5359 if (pcbNeeded
) *pcbNeeded
= needed
;
5360 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5362 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5363 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5368 /******************************************************************************
5369 * GetDefaultPrinterW (WINSPOOL.@)
5372 * This function must read the value from data 'device' of key
5373 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5375 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5379 WCHAR
*buffer
, *ptr
;
5383 SetLastError(ERROR_INVALID_PARAMETER
);
5387 /* make the buffer big enough for the stuff from the profile/registry,
5388 * the content must fit into the local buffer to compute the correct
5389 * size even if the extern buffer is too small or not given.
5390 * (20 for ,driver,port) */
5392 len
= max(100, (insize
+ 20));
5393 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5395 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5397 SetLastError (ERROR_FILE_NOT_FOUND
);
5401 TRACE("%s\n", debugstr_w(buffer
));
5403 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5405 SetLastError(ERROR_INVALID_NAME
);
5411 *namesize
= strlenW(buffer
) + 1;
5412 if(!name
|| (*namesize
> insize
))
5414 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5418 strcpyW(name
, buffer
);
5421 HeapFree( GetProcessHeap(), 0, buffer
);
5426 /******************************************************************************
5427 * GetDefaultPrinterA (WINSPOOL.@)
5429 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5433 WCHAR
*bufferW
= NULL
;
5437 SetLastError(ERROR_INVALID_PARAMETER
);
5441 if(name
&& *namesize
) {
5443 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5446 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5451 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5455 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5458 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5461 HeapFree( GetProcessHeap(), 0, bufferW
);
5466 /******************************************************************************
5467 * SetDefaultPrinterW (WINSPOOL.204)
5469 * Set the Name of the Default Printer
5472 * pszPrinter [I] Name of the Printer or NULL
5479 * When the Parameter is NULL or points to an Empty String and
5480 * a Default Printer was already present, then this Function changes nothing.
5481 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5482 * the First enumerated local Printer is used.
5485 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5488 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5490 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5494 /******************************************************************************
5495 * SetDefaultPrinterA (WINSPOOL.202)
5497 * See SetDefaultPrinterW.
5500 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5503 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5505 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5510 /******************************************************************************
5511 * SetPrinterDataExA (WINSPOOL.@)
5513 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5514 LPCSTR pValueName
, DWORD Type
,
5515 LPBYTE pData
, DWORD cbData
)
5517 HKEY hkeyPrinter
, hkeySubkey
;
5520 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5521 debugstr_a(pValueName
), Type
, pData
, cbData
);
5523 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5527 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5529 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5530 RegCloseKey(hkeyPrinter
);
5533 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5534 RegCloseKey(hkeySubkey
);
5535 RegCloseKey(hkeyPrinter
);
5539 /******************************************************************************
5540 * SetPrinterDataExW (WINSPOOL.@)
5542 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5543 LPCWSTR pValueName
, DWORD Type
,
5544 LPBYTE pData
, DWORD cbData
)
5546 HKEY hkeyPrinter
, hkeySubkey
;
5549 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5550 debugstr_w(pValueName
), Type
, pData
, cbData
);
5552 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5556 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5558 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5559 RegCloseKey(hkeyPrinter
);
5562 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5563 RegCloseKey(hkeySubkey
);
5564 RegCloseKey(hkeyPrinter
);
5568 /******************************************************************************
5569 * SetPrinterDataA (WINSPOOL.@)
5571 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5572 LPBYTE pData
, DWORD cbData
)
5574 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5578 /******************************************************************************
5579 * SetPrinterDataW (WINSPOOL.@)
5581 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5582 LPBYTE pData
, DWORD cbData
)
5584 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5588 /******************************************************************************
5589 * GetPrinterDataExA (WINSPOOL.@)
5591 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5592 LPCSTR pValueName
, LPDWORD pType
,
5593 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5595 HKEY hkeyPrinter
, hkeySubkey
;
5598 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5599 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5602 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5606 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5608 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5609 RegCloseKey(hkeyPrinter
);
5613 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5614 RegCloseKey(hkeySubkey
);
5615 RegCloseKey(hkeyPrinter
);
5619 /******************************************************************************
5620 * GetPrinterDataExW (WINSPOOL.@)
5622 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5623 LPCWSTR pValueName
, LPDWORD pType
,
5624 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5626 HKEY hkeyPrinter
, hkeySubkey
;
5629 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5630 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5633 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5637 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5639 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5640 RegCloseKey(hkeyPrinter
);
5644 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5645 RegCloseKey(hkeySubkey
);
5646 RegCloseKey(hkeyPrinter
);
5650 /******************************************************************************
5651 * GetPrinterDataA (WINSPOOL.@)
5653 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5654 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5656 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5657 pData
, nSize
, pcbNeeded
);
5660 /******************************************************************************
5661 * GetPrinterDataW (WINSPOOL.@)
5663 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5664 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5666 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5667 pData
, nSize
, pcbNeeded
);
5670 /*******************************************************************************
5671 * EnumPrinterDataExW [WINSPOOL.@]
5673 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5674 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5675 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5677 HKEY hkPrinter
, hkSubKey
;
5678 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5679 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5684 PPRINTER_ENUM_VALUESW ppev
;
5686 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5688 if (pKeyName
== NULL
|| *pKeyName
== 0)
5689 return ERROR_INVALID_PARAMETER
;
5691 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5692 if (ret
!= ERROR_SUCCESS
)
5694 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5699 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5700 if (ret
!= ERROR_SUCCESS
)
5702 r
= RegCloseKey (hkPrinter
);
5703 if (r
!= ERROR_SUCCESS
)
5704 WARN ("RegCloseKey returned %i\n", r
);
5705 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5706 debugstr_w (pKeyName
), ret
);
5710 ret
= RegCloseKey (hkPrinter
);
5711 if (ret
!= ERROR_SUCCESS
)
5713 ERR ("RegCloseKey returned %i\n", ret
);
5714 r
= RegCloseKey (hkSubKey
);
5715 if (r
!= ERROR_SUCCESS
)
5716 WARN ("RegCloseKey returned %i\n", r
);
5720 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5721 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5722 if (ret
!= ERROR_SUCCESS
)
5724 r
= RegCloseKey (hkSubKey
);
5725 if (r
!= ERROR_SUCCESS
)
5726 WARN ("RegCloseKey returned %i\n", r
);
5727 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5731 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5732 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5734 if (cValues
== 0) /* empty key */
5736 r
= RegCloseKey (hkSubKey
);
5737 if (r
!= ERROR_SUCCESS
)
5738 WARN ("RegCloseKey returned %i\n", r
);
5739 *pcbEnumValues
= *pnEnumValues
= 0;
5740 return ERROR_SUCCESS
;
5743 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5745 hHeap
= GetProcessHeap ();
5748 ERR ("GetProcessHeap failed\n");
5749 r
= RegCloseKey (hkSubKey
);
5750 if (r
!= ERROR_SUCCESS
)
5751 WARN ("RegCloseKey returned %i\n", r
);
5752 return ERROR_OUTOFMEMORY
;
5755 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5756 if (lpValueName
== NULL
)
5758 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5759 r
= RegCloseKey (hkSubKey
);
5760 if (r
!= ERROR_SUCCESS
)
5761 WARN ("RegCloseKey returned %i\n", r
);
5762 return ERROR_OUTOFMEMORY
;
5765 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5766 if (lpValue
== NULL
)
5768 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5769 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5770 WARN ("HeapFree failed with code %i\n", GetLastError ());
5771 r
= RegCloseKey (hkSubKey
);
5772 if (r
!= ERROR_SUCCESS
)
5773 WARN ("RegCloseKey returned %i\n", r
);
5774 return ERROR_OUTOFMEMORY
;
5777 TRACE ("pass 1: calculating buffer required for all names and values\n");
5779 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5781 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5783 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5785 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5786 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5787 NULL
, NULL
, lpValue
, &cbValueLen
);
5788 if (ret
!= ERROR_SUCCESS
)
5790 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5791 WARN ("HeapFree failed with code %i\n", GetLastError ());
5792 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5793 WARN ("HeapFree failed with code %i\n", GetLastError ());
5794 r
= RegCloseKey (hkSubKey
);
5795 if (r
!= ERROR_SUCCESS
)
5796 WARN ("RegCloseKey returned %i\n", r
);
5797 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5801 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5802 debugstr_w (lpValueName
), dwIndex
,
5803 cbValueNameLen
+ 1, cbValueLen
);
5805 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5806 cbBufSize
+= cbValueLen
;
5809 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5811 *pcbEnumValues
= cbBufSize
;
5812 *pnEnumValues
= cValues
;
5814 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5816 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5817 WARN ("HeapFree failed with code %i\n", GetLastError ());
5818 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5819 WARN ("HeapFree failed with code %i\n", GetLastError ());
5820 r
= RegCloseKey (hkSubKey
);
5821 if (r
!= ERROR_SUCCESS
)
5822 WARN ("RegCloseKey returned %i\n", r
);
5823 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5824 return ERROR_MORE_DATA
;
5827 TRACE ("pass 2: copying all names and values to buffer\n");
5829 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5830 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5832 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5834 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5835 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5836 NULL
, &dwType
, lpValue
, &cbValueLen
);
5837 if (ret
!= ERROR_SUCCESS
)
5839 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5840 WARN ("HeapFree failed with code %i\n", GetLastError ());
5841 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5842 WARN ("HeapFree failed with code %i\n", GetLastError ());
5843 r
= RegCloseKey (hkSubKey
);
5844 if (r
!= ERROR_SUCCESS
)
5845 WARN ("RegCloseKey returned %i\n", r
);
5846 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5850 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5851 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5852 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5853 pEnumValues
+= cbValueNameLen
;
5855 /* return # of *bytes* (including trailing \0), not # of chars */
5856 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5858 ppev
[dwIndex
].dwType
= dwType
;
5860 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5861 ppev
[dwIndex
].pData
= pEnumValues
;
5862 pEnumValues
+= cbValueLen
;
5864 ppev
[dwIndex
].cbData
= cbValueLen
;
5866 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5867 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5870 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5872 ret
= GetLastError ();
5873 ERR ("HeapFree failed with code %i\n", ret
);
5874 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5875 WARN ("HeapFree failed with code %i\n", GetLastError ());
5876 r
= RegCloseKey (hkSubKey
);
5877 if (r
!= ERROR_SUCCESS
)
5878 WARN ("RegCloseKey returned %i\n", r
);
5882 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5884 ret
= GetLastError ();
5885 ERR ("HeapFree failed with code %i\n", ret
);
5886 r
= RegCloseKey (hkSubKey
);
5887 if (r
!= ERROR_SUCCESS
)
5888 WARN ("RegCloseKey returned %i\n", r
);
5892 ret
= RegCloseKey (hkSubKey
);
5893 if (ret
!= ERROR_SUCCESS
)
5895 ERR ("RegCloseKey returned %i\n", ret
);
5899 return ERROR_SUCCESS
;
5902 /*******************************************************************************
5903 * EnumPrinterDataExA [WINSPOOL.@]
5905 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5906 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5907 * what Windows 2000 SP1 does.
5910 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5911 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5912 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5916 DWORD ret
, dwIndex
, dwBufSize
;
5920 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5922 if (pKeyName
== NULL
|| *pKeyName
== 0)
5923 return ERROR_INVALID_PARAMETER
;
5925 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5928 ret
= GetLastError ();
5929 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5933 hHeap
= GetProcessHeap ();
5936 ERR ("GetProcessHeap failed\n");
5937 return ERROR_OUTOFMEMORY
;
5940 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5941 if (pKeyNameW
== NULL
)
5943 ERR ("Failed to allocate %i bytes from process heap\n",
5944 (LONG
)(len
* sizeof (WCHAR
)));
5945 return ERROR_OUTOFMEMORY
;
5948 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5950 ret
= GetLastError ();
5951 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5952 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5953 WARN ("HeapFree failed with code %i\n", GetLastError ());
5957 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5958 pcbEnumValues
, pnEnumValues
);
5959 if (ret
!= ERROR_SUCCESS
)
5961 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5962 WARN ("HeapFree failed with code %i\n", GetLastError ());
5963 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5967 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5969 ret
= GetLastError ();
5970 ERR ("HeapFree failed with code %i\n", ret
);
5974 if (*pnEnumValues
== 0) /* empty key */
5975 return ERROR_SUCCESS
;
5978 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5980 PPRINTER_ENUM_VALUESW ppev
=
5981 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5983 if (dwBufSize
< ppev
->cbValueName
)
5984 dwBufSize
= ppev
->cbValueName
;
5986 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5987 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5988 dwBufSize
= ppev
->cbData
;
5991 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5993 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5994 if (pBuffer
== NULL
)
5996 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5997 return ERROR_OUTOFMEMORY
;
6000 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6002 PPRINTER_ENUM_VALUESW ppev
=
6003 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6005 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6006 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6010 ret
= GetLastError ();
6011 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6012 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6013 WARN ("HeapFree failed with code %i\n", GetLastError ());
6017 memcpy (ppev
->pValueName
, pBuffer
, len
);
6019 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6021 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6022 ppev
->dwType
!= REG_MULTI_SZ
)
6025 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6026 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6029 ret
= GetLastError ();
6030 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6031 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6032 WARN ("HeapFree failed with code %i\n", GetLastError ());
6036 memcpy (ppev
->pData
, pBuffer
, len
);
6038 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6039 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6042 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6044 ret
= GetLastError ();
6045 ERR ("HeapFree failed with code %i\n", ret
);
6049 return ERROR_SUCCESS
;
6052 /******************************************************************************
6053 * AbortPrinter (WINSPOOL.@)
6055 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6057 FIXME("(%p), stub!\n", hPrinter
);
6061 /******************************************************************************
6062 * AddPortA (WINSPOOL.@)
6067 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6069 LPWSTR nameW
= NULL
;
6070 LPWSTR monitorW
= NULL
;
6074 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6077 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6078 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6079 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6083 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6084 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6085 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6087 res
= AddPortW(nameW
, hWnd
, monitorW
);
6088 HeapFree(GetProcessHeap(), 0, nameW
);
6089 HeapFree(GetProcessHeap(), 0, monitorW
);
6093 /******************************************************************************
6094 * AddPortW (WINSPOOL.@)
6096 * Add a Port for a specific Monitor
6099 * pName [I] Servername or NULL (local Computer)
6100 * hWnd [I] Handle to parent Window for the Dialog-Box
6101 * pMonitorName [I] Name of the Monitor that manage the Port
6108 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6114 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6116 if (pName
&& pName
[0]) {
6117 SetLastError(ERROR_INVALID_PARAMETER
);
6121 if (!pMonitorName
) {
6122 SetLastError(RPC_X_NULL_REF_POINTER
);
6126 /* an empty Monitorname is Invalid */
6127 if (!pMonitorName
[0]) {
6128 SetLastError(ERROR_NOT_SUPPORTED
);
6132 pm
= monitor_load(pMonitorName
, NULL
);
6133 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6134 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6135 TRACE("got %d with %u\n", res
, GetLastError());
6140 pui
= monitor_loadui(pm
);
6141 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6142 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6143 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6144 TRACE("got %d with %u\n", res
, GetLastError());
6149 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6150 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6152 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6153 SetLastError(ERROR_NOT_SUPPORTED
);
6156 monitor_unload(pui
);
6159 TRACE("returning %d with %u\n", res
, GetLastError());
6163 /******************************************************************************
6164 * AddPortExA (WINSPOOL.@)
6169 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6172 PORT_INFO_2A
* pi2A
;
6173 LPWSTR nameW
= NULL
;
6174 LPWSTR monitorW
= NULL
;
6178 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6180 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6181 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6183 if ((level
< 1) || (level
> 2)) {
6184 SetLastError(ERROR_INVALID_LEVEL
);
6189 SetLastError(ERROR_INVALID_PARAMETER
);
6194 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6195 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6196 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6200 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6201 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6202 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6205 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6207 if (pi2A
->pPortName
) {
6208 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6209 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6210 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6214 if (pi2A
->pMonitorName
) {
6215 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6216 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6217 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6220 if (pi2A
->pDescription
) {
6221 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6222 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6223 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6225 pi2W
.fPortType
= pi2A
->fPortType
;
6226 pi2W
.Reserved
= pi2A
->Reserved
;
6229 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6231 HeapFree(GetProcessHeap(), 0, nameW
);
6232 HeapFree(GetProcessHeap(), 0, monitorW
);
6233 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6234 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6235 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6240 /******************************************************************************
6241 * AddPortExW (WINSPOOL.@)
6243 * Add a Port for a specific Monitor, without presenting a user interface
6246 * pName [I] Servername or NULL (local Computer)
6247 * level [I] Structure-Level (1 or 2) for pBuffer
6248 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6249 * pMonitorName [I] Name of the Monitor that manage the Port
6256 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6262 pi2
= (PORT_INFO_2W
*) pBuffer
;
6264 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6265 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6266 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6267 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6270 if ((level
< 1) || (level
> 2)) {
6271 SetLastError(ERROR_INVALID_LEVEL
);
6275 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6276 SetLastError(ERROR_INVALID_PARAMETER
);
6280 /* load the Monitor */
6281 pm
= monitor_load(pMonitorName
, NULL
);
6283 SetLastError(ERROR_INVALID_PARAMETER
);
6287 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6288 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6289 TRACE("got %u with %u\n", res
, GetLastError());
6293 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6299 /******************************************************************************
6300 * AddPrinterConnectionA (WINSPOOL.@)
6302 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6304 FIXME("%s\n", debugstr_a(pName
));
6308 /******************************************************************************
6309 * AddPrinterConnectionW (WINSPOOL.@)
6311 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6313 FIXME("%s\n", debugstr_w(pName
));
6317 /******************************************************************************
6318 * AddPrinterDriverExW (WINSPOOL.@)
6320 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6323 * pName [I] Servername or NULL (local Computer)
6324 * level [I] Level for the supplied DRIVER_INFO_*W struct
6325 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6326 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6333 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6335 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6337 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6339 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6340 SetLastError(ERROR_INVALID_LEVEL
);
6345 SetLastError(ERROR_INVALID_PARAMETER
);
6349 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6352 /******************************************************************************
6353 * AddPrinterDriverExA (WINSPOOL.@)
6355 * See AddPrinterDriverExW.
6358 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6360 DRIVER_INFO_8A
*diA
;
6362 LPWSTR nameW
= NULL
;
6367 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6369 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6370 ZeroMemory(&diW
, sizeof(diW
));
6372 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6373 SetLastError(ERROR_INVALID_LEVEL
);
6378 SetLastError(ERROR_INVALID_PARAMETER
);
6382 /* convert servername to unicode */
6384 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6385 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6386 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6390 diW
.cVersion
= diA
->cVersion
;
6393 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6394 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6395 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6398 if (diA
->pEnvironment
) {
6399 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6400 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6401 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6404 if (diA
->pDriverPath
) {
6405 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6406 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6407 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6410 if (diA
->pDataFile
) {
6411 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6412 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6413 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6416 if (diA
->pConfigFile
) {
6417 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6418 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6419 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6422 if ((Level
> 2) && diA
->pDependentFiles
) {
6423 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6424 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6425 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6426 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6429 if ((Level
> 2) && diA
->pMonitorName
) {
6430 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6431 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6432 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6435 if ((Level
> 3) && diA
->pDefaultDataType
) {
6436 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6437 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6438 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6441 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6442 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6443 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6444 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6445 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6448 if ((Level
> 5) && diA
->pszMfgName
) {
6449 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6450 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6451 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6454 if ((Level
> 5) && diA
->pszOEMUrl
) {
6455 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6456 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6457 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6460 if ((Level
> 5) && diA
->pszHardwareID
) {
6461 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6462 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6463 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6466 if ((Level
> 5) && diA
->pszProvider
) {
6467 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6468 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6469 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6473 FIXME("level %u is incomplete\n", Level
);
6476 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6477 TRACE("got %u with %u\n", res
, GetLastError());
6478 HeapFree(GetProcessHeap(), 0, nameW
);
6479 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6480 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6481 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6482 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6483 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6484 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6485 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6486 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6487 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6488 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6489 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6490 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6491 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6493 TRACE("=> %u with %u\n", res
, GetLastError());
6497 /******************************************************************************
6498 * ConfigurePortA (WINSPOOL.@)
6500 * See ConfigurePortW.
6503 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6505 LPWSTR nameW
= NULL
;
6506 LPWSTR portW
= NULL
;
6510 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6512 /* convert servername to unicode */
6514 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6515 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6516 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6519 /* convert portname to unicode */
6521 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6522 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6523 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6526 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6527 HeapFree(GetProcessHeap(), 0, nameW
);
6528 HeapFree(GetProcessHeap(), 0, portW
);
6532 /******************************************************************************
6533 * ConfigurePortW (WINSPOOL.@)
6535 * Display the Configuration-Dialog for a specific Port
6538 * pName [I] Servername or NULL (local Computer)
6539 * hWnd [I] Handle to parent Window for the Dialog-Box
6540 * pPortName [I] Name of the Port, that should be configured
6547 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6553 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6555 if (pName
&& pName
[0]) {
6556 SetLastError(ERROR_INVALID_PARAMETER
);
6561 SetLastError(RPC_X_NULL_REF_POINTER
);
6565 /* an empty Portname is Invalid, but can popup a Dialog */
6566 if (!pPortName
[0]) {
6567 SetLastError(ERROR_NOT_SUPPORTED
);
6571 pm
= monitor_load_by_port(pPortName
);
6572 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6573 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6574 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6575 TRACE("got %d with %u\n", res
, GetLastError());
6579 pui
= monitor_loadui(pm
);
6580 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6581 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6582 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6583 TRACE("got %d with %u\n", res
, GetLastError());
6587 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6588 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6590 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6591 SetLastError(ERROR_NOT_SUPPORTED
);
6594 monitor_unload(pui
);
6598 TRACE("returning %d with %u\n", res
, GetLastError());
6602 /******************************************************************************
6603 * ConnectToPrinterDlg (WINSPOOL.@)
6605 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6607 FIXME("%p %x\n", hWnd
, Flags
);
6611 /******************************************************************************
6612 * DeletePrinterConnectionA (WINSPOOL.@)
6614 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6616 FIXME("%s\n", debugstr_a(pName
));
6620 /******************************************************************************
6621 * DeletePrinterConnectionW (WINSPOOL.@)
6623 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6625 FIXME("%s\n", debugstr_w(pName
));
6629 /******************************************************************************
6630 * DeletePrinterDriverExW (WINSPOOL.@)
6632 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6633 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6638 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6639 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6641 if(pName
&& pName
[0])
6643 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6644 SetLastError(ERROR_INVALID_PARAMETER
);
6650 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6651 SetLastError(ERROR_INVALID_PARAMETER
);
6655 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6659 ERR("Can't open drivers key\n");
6663 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6666 RegCloseKey(hkey_drivers
);
6671 /******************************************************************************
6672 * DeletePrinterDriverExA (WINSPOOL.@)
6674 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6675 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6677 UNICODE_STRING NameW
, EnvW
, DriverW
;
6680 asciitounicode(&NameW
, pName
);
6681 asciitounicode(&EnvW
, pEnvironment
);
6682 asciitounicode(&DriverW
, pDriverName
);
6684 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6686 RtlFreeUnicodeString(&DriverW
);
6687 RtlFreeUnicodeString(&EnvW
);
6688 RtlFreeUnicodeString(&NameW
);
6693 /******************************************************************************
6694 * DeletePrinterDataExW (WINSPOOL.@)
6696 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6699 FIXME("%p %s %s\n", hPrinter
,
6700 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6701 return ERROR_INVALID_PARAMETER
;
6704 /******************************************************************************
6705 * DeletePrinterDataExA (WINSPOOL.@)
6707 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6710 FIXME("%p %s %s\n", hPrinter
,
6711 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6712 return ERROR_INVALID_PARAMETER
;
6715 /******************************************************************************
6716 * DeletePrintProcessorA (WINSPOOL.@)
6718 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6720 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6721 debugstr_a(pPrintProcessorName
));
6725 /******************************************************************************
6726 * DeletePrintProcessorW (WINSPOOL.@)
6728 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6730 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6731 debugstr_w(pPrintProcessorName
));
6735 /******************************************************************************
6736 * DeletePrintProvidorA (WINSPOOL.@)
6738 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6740 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6741 debugstr_a(pPrintProviderName
));
6745 /******************************************************************************
6746 * DeletePrintProvidorW (WINSPOOL.@)
6748 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6750 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6751 debugstr_w(pPrintProviderName
));
6755 /******************************************************************************
6756 * EnumFormsA (WINSPOOL.@)
6758 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6759 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6761 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6762 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6766 /******************************************************************************
6767 * EnumFormsW (WINSPOOL.@)
6769 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6770 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6772 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6773 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6777 /*****************************************************************************
6778 * EnumMonitorsA [WINSPOOL.@]
6780 * See EnumMonitorsW.
6783 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6784 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6787 LPBYTE bufferW
= NULL
;
6788 LPWSTR nameW
= NULL
;
6790 DWORD numentries
= 0;
6793 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6794 cbBuf
, pcbNeeded
, pcReturned
);
6796 /* convert servername to unicode */
6798 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6799 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6800 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6802 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6803 needed
= cbBuf
* sizeof(WCHAR
);
6804 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6805 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6807 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6808 if (pcbNeeded
) needed
= *pcbNeeded
;
6809 /* HeapReAlloc return NULL, when bufferW was NULL */
6810 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6811 HeapAlloc(GetProcessHeap(), 0, needed
);
6813 /* Try again with the large Buffer */
6814 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6816 numentries
= pcReturned
? *pcReturned
: 0;
6819 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6820 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6823 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6824 DWORD entrysize
= 0;
6827 LPMONITOR_INFO_2W mi2w
;
6828 LPMONITOR_INFO_2A mi2a
;
6830 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6831 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6833 /* First pass: calculate the size for all Entries */
6834 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6835 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6837 while (index
< numentries
) {
6839 needed
+= entrysize
; /* MONITOR_INFO_?A */
6840 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6842 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6843 NULL
, 0, NULL
, NULL
);
6845 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6846 NULL
, 0, NULL
, NULL
);
6847 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6848 NULL
, 0, NULL
, NULL
);
6850 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6851 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6852 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6855 /* check for errors and quit on failure */
6856 if (cbBuf
< needed
) {
6857 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6861 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6862 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6863 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6864 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6865 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6867 /* Second Pass: Fill the User Buffer (if we have one) */
6868 while ((index
< numentries
) && pMonitors
) {
6870 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6872 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6873 ptr
, cbBuf
, NULL
, NULL
);
6877 mi2a
->pEnvironment
= ptr
;
6878 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6879 ptr
, cbBuf
, NULL
, NULL
);
6883 mi2a
->pDLLName
= ptr
;
6884 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6885 ptr
, cbBuf
, NULL
, NULL
);
6889 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6890 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6891 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6895 if (pcbNeeded
) *pcbNeeded
= needed
;
6896 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6898 HeapFree(GetProcessHeap(), 0, nameW
);
6899 HeapFree(GetProcessHeap(), 0, bufferW
);
6901 TRACE("returning %d with %d (%d byte for %d entries)\n",
6902 (res
), GetLastError(), needed
, numentries
);
6908 /*****************************************************************************
6909 * EnumMonitorsW [WINSPOOL.@]
6911 * Enumerate available Port-Monitors
6914 * pName [I] Servername or NULL (local Computer)
6915 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6916 * pMonitors [O] PTR to Buffer that receives the Result
6917 * cbBuf [I] Size of Buffer at pMonitors
6918 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6919 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6923 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6926 * Windows reads the Registry once and cache the Results.
6928 *| Language-Monitors are also installed in the same Registry-Location but
6929 *| they are filtered in Windows (not returned by EnumMonitors).
6930 *| We do no filtering to simplify our Code.
6933 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6934 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6937 DWORD numentries
= 0;
6940 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6941 cbBuf
, pcbNeeded
, pcReturned
);
6943 if (pName
&& (lstrlenW(pName
))) {
6944 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
6945 SetLastError(ERROR_ACCESS_DENIED
);
6949 /* Level is not checked in win9x */
6950 if (!Level
|| (Level
> 2)) {
6951 WARN("level (%d) is ignored in win9x\n", Level
);
6952 SetLastError(ERROR_INVALID_LEVEL
);
6956 SetLastError(RPC_X_NULL_REF_POINTER
);
6960 /* Scan all Monitor-Keys */
6962 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
6964 /* we calculated the needed buffersize. now do the error-checks */
6965 if (cbBuf
< needed
) {
6966 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6969 else if (!pMonitors
|| !pcReturned
) {
6970 SetLastError(RPC_X_NULL_REF_POINTER
);
6974 /* fill the Buffer with the Monitor-Keys */
6975 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
6979 if (pcbNeeded
) *pcbNeeded
= needed
;
6980 if (pcReturned
) *pcReturned
= numentries
;
6982 TRACE("returning %d with %d (%d byte for %d entries)\n",
6983 res
, GetLastError(), needed
, numentries
);
6988 /******************************************************************************
6989 * XcvDataW (WINSPOOL.@)
6991 * Execute commands in the Printmonitor DLL
6994 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6995 * pszDataName [i] Name of the command to execute
6996 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6997 * cbInputData [i] Size in Bytes of Buffer at pInputData
6998 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6999 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7000 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7001 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7008 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7009 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7011 * Minimal List of commands, that a Printmonitor DLL should support:
7013 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7014 *| "AddPort" : Add a Port
7015 *| "DeletePort": Delete a Port
7017 * Many Printmonitors support additional commands. Examples for localspl.dll:
7018 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7019 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7022 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7023 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7024 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7026 opened_printer_t
*printer
;
7028 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7029 pInputData
, cbInputData
, pOutputData
,
7030 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7032 printer
= get_opened_printer(hXcv
);
7033 if (!printer
|| (!printer
->hXcv
)) {
7034 SetLastError(ERROR_INVALID_HANDLE
);
7038 if (!pcbOutputNeeded
) {
7039 SetLastError(ERROR_INVALID_PARAMETER
);
7043 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7044 SetLastError(RPC_X_NULL_REF_POINTER
);
7048 *pcbOutputNeeded
= 0;
7050 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
7051 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
7056 /*****************************************************************************
7057 * EnumPrinterDataA [WINSPOOL.@]
7060 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7061 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7062 DWORD cbData
, LPDWORD pcbData
)
7064 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7065 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7066 return ERROR_NO_MORE_ITEMS
;
7069 /*****************************************************************************
7070 * EnumPrinterDataW [WINSPOOL.@]
7073 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7074 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7075 DWORD cbData
, LPDWORD pcbData
)
7077 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7078 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7079 return ERROR_NO_MORE_ITEMS
;
7082 /*****************************************************************************
7083 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7086 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7087 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7088 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7090 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7091 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7092 pcbNeeded
, pcReturned
);
7096 /*****************************************************************************
7097 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7100 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7101 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7102 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7104 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7105 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7106 pcbNeeded
, pcReturned
);
7110 /*****************************************************************************
7111 * EnumPrintProcessorsA [WINSPOOL.@]
7114 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7115 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7117 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7118 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7122 /*****************************************************************************
7123 * EnumPrintProcessorsW [WINSPOOL.@]
7126 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7127 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7129 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7130 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7131 cbBuf
, pcbNeeded
, pcbReturned
);
7135 /*****************************************************************************
7136 * ExtDeviceMode [WINSPOOL.@]
7139 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7140 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7143 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7144 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7145 debugstr_a(pProfile
), fMode
);
7149 /*****************************************************************************
7150 * FindClosePrinterChangeNotification [WINSPOOL.@]
7153 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7155 FIXME("Stub: %p\n", hChange
);
7159 /*****************************************************************************
7160 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7163 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7164 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7166 FIXME("Stub: %p %x %x %p\n",
7167 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7168 return INVALID_HANDLE_VALUE
;
7171 /*****************************************************************************
7172 * FindNextPrinterChangeNotification [WINSPOOL.@]
7175 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7176 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7178 FIXME("Stub: %p %p %p %p\n",
7179 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7183 /*****************************************************************************
7184 * FreePrinterNotifyInfo [WINSPOOL.@]
7187 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7189 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7193 /*****************************************************************************
7196 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7197 * ansi depending on the unicode parameter.
7199 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7209 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7212 memcpy(ptr
, str
, *size
);
7219 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7222 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7229 /*****************************************************************************
7232 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7233 LPDWORD pcbNeeded
, BOOL unicode
)
7235 DWORD size
, left
= cbBuf
;
7236 BOOL space
= (cbBuf
> 0);
7243 ji1
->JobId
= job
->job_id
;
7246 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7247 if(space
&& size
<= left
)
7249 ji1
->pDocument
= (LPWSTR
)ptr
;
7260 /*****************************************************************************
7263 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7264 LPDWORD pcbNeeded
, BOOL unicode
)
7266 DWORD size
, left
= cbBuf
;
7267 BOOL space
= (cbBuf
> 0);
7274 ji2
->JobId
= job
->job_id
;
7277 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7278 if(space
&& size
<= left
)
7280 ji2
->pDocument
= (LPWSTR
)ptr
;
7291 /*****************************************************************************
7294 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7295 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7298 DWORD needed
= 0, size
;
7302 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7304 EnterCriticalSection(&printer_handles_cs
);
7305 job
= get_job(hPrinter
, JobId
);
7312 size
= sizeof(JOB_INFO_1W
);
7317 memset(pJob
, 0, size
);
7321 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7326 size
= sizeof(JOB_INFO_2W
);
7331 memset(pJob
, 0, size
);
7335 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7340 size
= sizeof(JOB_INFO_3
);
7344 memset(pJob
, 0, size
);
7353 SetLastError(ERROR_INVALID_LEVEL
);
7357 *pcbNeeded
= needed
;
7359 LeaveCriticalSection(&printer_handles_cs
);
7363 /*****************************************************************************
7364 * GetJobA [WINSPOOL.@]
7367 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7368 DWORD cbBuf
, LPDWORD pcbNeeded
)
7370 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7373 /*****************************************************************************
7374 * GetJobW [WINSPOOL.@]
7377 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7378 DWORD cbBuf
, LPDWORD pcbNeeded
)
7380 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7383 /*****************************************************************************
7386 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7388 char *unixname
, *queue
, *cmd
;
7389 char fmt
[] = "lpr -P%s %s";
7392 if(!(unixname
= wine_get_unix_file_name(filename
)))
7395 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7396 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7397 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7399 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7400 sprintf(cmd
, fmt
, queue
, unixname
);
7402 TRACE("printing with: %s\n", cmd
);
7405 HeapFree(GetProcessHeap(), 0, cmd
);
7406 HeapFree(GetProcessHeap(), 0, queue
);
7407 HeapFree(GetProcessHeap(), 0, unixname
);
7411 /*****************************************************************************
7414 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7416 #ifdef SONAME_LIBCUPS
7419 char *unixname
, *queue
, *doc_titleA
;
7423 if(!(unixname
= wine_get_unix_file_name(filename
)))
7426 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7427 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7428 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7430 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7431 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7432 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7434 TRACE("printing via cups\n");
7435 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7436 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7437 HeapFree(GetProcessHeap(), 0, queue
);
7438 HeapFree(GetProcessHeap(), 0, unixname
);
7444 return schedule_lpr(printer_name
, filename
);
7448 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7455 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7459 if(HIWORD(wparam
) == BN_CLICKED
)
7461 if(LOWORD(wparam
) == IDOK
)
7464 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7467 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7468 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7470 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7472 WCHAR caption
[200], message
[200];
7475 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7476 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7477 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7478 if(mb_ret
== IDCANCEL
)
7480 HeapFree(GetProcessHeap(), 0, filename
);
7484 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7485 if(hf
== INVALID_HANDLE_VALUE
)
7487 WCHAR caption
[200], message
[200];
7489 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7490 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7491 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7492 HeapFree(GetProcessHeap(), 0, filename
);
7496 DeleteFileW(filename
);
7497 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7499 EndDialog(hwnd
, IDOK
);
7502 if(LOWORD(wparam
) == IDCANCEL
)
7504 EndDialog(hwnd
, IDCANCEL
);
7513 /*****************************************************************************
7516 static BOOL
get_filename(LPWSTR
*filename
)
7518 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7519 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7522 /*****************************************************************************
7525 static BOOL
schedule_file(LPCWSTR filename
)
7527 LPWSTR output
= NULL
;
7529 if(get_filename(&output
))
7531 TRACE("copy to %s\n", debugstr_w(output
));
7532 CopyFileW(filename
, output
, FALSE
);
7533 HeapFree(GetProcessHeap(), 0, output
);
7539 /*****************************************************************************
7542 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7545 char *unixname
, *cmdA
;
7547 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7551 if(!(unixname
= wine_get_unix_file_name(filename
)))
7554 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7555 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7556 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7558 TRACE("printing with: %s\n", cmdA
);
7560 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7565 ERR("pipe() failed!\n");
7575 /* reset signals that we previously set to SIG_IGN */
7576 signal(SIGPIPE
, SIG_DFL
);
7577 signal(SIGCHLD
, SIG_DFL
);
7579 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7583 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7584 write(fds
[1], buf
, no_read
);
7589 if(file_fd
!= -1) close(file_fd
);
7590 if(fds
[0] != -1) close(fds
[0]);
7591 if(fds
[1] != -1) close(fds
[1]);
7593 HeapFree(GetProcessHeap(), 0, cmdA
);
7594 HeapFree(GetProcessHeap(), 0, unixname
);
7601 /*****************************************************************************
7604 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7606 int in_fd
, out_fd
, no_read
;
7609 char *unixname
, *outputA
;
7612 if(!(unixname
= wine_get_unix_file_name(filename
)))
7615 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7616 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7617 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7619 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7620 in_fd
= open(unixname
, O_RDONLY
);
7621 if(out_fd
== -1 || in_fd
== -1)
7624 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7625 write(out_fd
, buf
, no_read
);
7629 if(in_fd
!= -1) close(in_fd
);
7630 if(out_fd
!= -1) close(out_fd
);
7631 HeapFree(GetProcessHeap(), 0, outputA
);
7632 HeapFree(GetProcessHeap(), 0, unixname
);
7636 /*****************************************************************************
7637 * ScheduleJob [WINSPOOL.@]
7640 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7642 opened_printer_t
*printer
;
7644 struct list
*cursor
, *cursor2
;
7646 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7647 EnterCriticalSection(&printer_handles_cs
);
7648 printer
= get_opened_printer(hPrinter
);
7652 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7654 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7657 if(job
->job_id
!= dwJobID
) continue;
7659 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7660 if(hf
!= INVALID_HANDLE_VALUE
)
7662 PRINTER_INFO_5W
*pi5
;
7666 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7667 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7669 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7670 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7671 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7672 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7673 debugstr_w(pi5
->pPortName
));
7677 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7678 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7680 DWORD type
, count
= sizeof(output
);
7681 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7684 if(output
[0] == '|')
7686 schedule_pipe(output
+ 1, job
->filename
);
7690 schedule_unixfile(output
, job
->filename
);
7692 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7694 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7696 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7698 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7700 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7702 schedule_file(job
->filename
);
7706 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7708 HeapFree(GetProcessHeap(), 0, pi5
);
7710 DeleteFileW(job
->filename
);
7712 list_remove(cursor
);
7713 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7714 HeapFree(GetProcessHeap(), 0, job
->filename
);
7715 HeapFree(GetProcessHeap(), 0, job
);
7720 LeaveCriticalSection(&printer_handles_cs
);
7724 /*****************************************************************************
7725 * StartDocDlgA [WINSPOOL.@]
7727 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7729 UNICODE_STRING usBuffer
;
7732 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7735 docW
.cbSize
= sizeof(docW
);
7736 if (doc
->lpszDocName
)
7738 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7739 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7741 if (doc
->lpszOutput
)
7743 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7744 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7746 if (doc
->lpszDatatype
)
7748 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7749 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7751 docW
.fwType
= doc
->fwType
;
7753 retW
= StartDocDlgW(hPrinter
, &docW
);
7757 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7758 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7759 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7760 HeapFree(GetProcessHeap(), 0, retW
);
7763 HeapFree(GetProcessHeap(), 0, datatypeW
);
7764 HeapFree(GetProcessHeap(), 0, outputW
);
7765 HeapFree(GetProcessHeap(), 0, docnameW
);
7770 /*****************************************************************************
7771 * StartDocDlgW [WINSPOOL.@]
7773 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7774 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7775 * port is "FILE:". Also returns the full path if passed a relative path.
7777 * The caller should free the returned string from the process heap.
7779 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7784 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7786 PRINTER_INFO_5W
*pi5
;
7787 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7788 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7790 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7791 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7792 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7794 HeapFree(GetProcessHeap(), 0, pi5
);
7797 HeapFree(GetProcessHeap(), 0, pi5
);
7800 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7804 if (get_filename(&name
))
7806 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7808 HeapFree(GetProcessHeap(), 0, name
);
7811 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7812 GetFullPathNameW(name
, len
, ret
, NULL
);
7813 HeapFree(GetProcessHeap(), 0, name
);
7818 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7821 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7822 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7824 attr
= GetFileAttributesW(ret
);
7825 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7827 HeapFree(GetProcessHeap(), 0, ret
);