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>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
63 #include "ddk/winsplp.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
68 /* ############################### */
70 static CRITICAL_SECTION monitor_handles_cs
;
71 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
73 0, 0, &monitor_handles_cs
,
74 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
75 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
77 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
80 static CRITICAL_SECTION printer_handles_cs
;
81 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
83 0, 0, &printer_handles_cs
,
84 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
85 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
87 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
89 /* ############################### */
125 WCHAR
*document_title
;
133 LPCWSTR versionregpath
;
134 LPCWSTR versionsubdir
;
137 /* ############################### */
139 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
140 static monitor_t
* pm_localport
;
142 static opened_printer_t
**printer_handles
;
143 static int nb_printer_handles
;
144 static LONG next_job_id
= 1;
146 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
147 WORD fwCapability
, LPSTR lpszOutput
,
149 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
150 LPSTR lpszDevice
, LPSTR lpszPort
,
151 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
154 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
155 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
156 'c','o','n','t','r','o','l','\\',
157 'P','r','i','n','t','\\',
158 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
159 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
161 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
162 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
163 'C','o','n','t','r','o','l','\\',
164 'P','r','i','n','t','\\',
165 'M','o','n','i','t','o','r','s','\\',0};
167 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
168 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
169 'C','o','n','t','r','o','l','\\',
170 'P','r','i','n','t','\\',
171 'P','r','i','n','t','e','r','s',0};
173 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
175 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
176 'M','i','c','r','o','s','o','f','t','\\',
177 'W','i','n','d','o','w','s',' ','N','T','\\',
178 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
179 'W','i','n','d','o','w','s',0};
181 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
182 'M','i','c','r','o','s','o','f','t','\\',
183 'W','i','n','d','o','w','s',' ','N','T','\\',
184 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
185 'D','e','v','i','c','e','s',0};
187 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
188 'M','i','c','r','o','s','o','f','t','\\',
189 'W','i','n','d','o','w','s',' ','N','T','\\',
190 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
191 'P','o','r','t','s',0};
193 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
194 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
195 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
196 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
197 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
198 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
199 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
201 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
202 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',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',
210 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
212 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
213 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
214 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
215 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',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 ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
220 static const WCHAR PortW
[] = {'P','o','r','t',0};
221 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
222 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
224 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
226 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
227 'v','e','r','D','a','t','a',0};
228 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
230 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',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};
249 /******************************************************************
250 * validate the user-supplied printing-environment [internal]
253 * env [I] PTR to Environment-String or NULL
257 * Success: PTR to printenv_t
260 * An empty string is handled the same way as NULL.
261 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
265 static const printenv_t
* validate_envW(LPCWSTR env
)
267 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
268 3, Version3_RegPathW
, Version3_SubdirW
};
269 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
270 0, emptyStringW
, emptyStringW
};
271 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
273 const printenv_t
*result
= NULL
;
276 TRACE("testing %s\n", debugstr_w(env
));
279 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
281 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
283 result
= all_printenv
[i
];
288 if (result
== NULL
) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
290 SetLastError(ERROR_INVALID_ENVIRONMENT
);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
296 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
298 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
312 return usBufferPtr
->Buffer
;
314 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
318 static LPWSTR
strdupW(LPCWSTR p
)
324 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
325 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
330 static LPSTR
strdupWtoA( LPCWSTR str
)
335 if (!str
) return NULL
;
336 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
337 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
338 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
342 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
343 The result includes all \0s (specifically the last two). */
344 static int multi_sz_lenA(const char *str
)
346 const char *ptr
= str
;
350 ptr
+= lstrlenA(ptr
) + 1;
353 return ptr
- str
+ 1;
357 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
360 /* If forcing, or no profile string entry for device yet, set the entry
362 * The always change entry if not WINEPS yet is discussable.
365 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
367 !strstr(qbuf
,"WINEPS.DRV")
369 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
372 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
373 WriteProfileStringA("windows","device",buf
);
374 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
375 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
378 HeapFree(GetProcessHeap(),0,buf
);
382 static BOOL
add_printer_driver(const char *name
)
386 static char driver_path
[] = "wineps16",
387 data_file
[] = "<datafile?>",
388 config_file
[] = "wineps16",
389 help_file
[] = "<helpfile?>",
390 dep_file
[] = "<dependent files?>\0",
391 monitor_name
[] = "<monitor name?>",
392 default_data_type
[] = "RAW";
394 di3a
.cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
395 di3a
.pName
= (char *)name
;
396 di3a
.pEnvironment
= NULL
; /* NULL means auto */
397 di3a
.pDriverPath
= driver_path
;
398 di3a
.pDataFile
= data_file
;
399 di3a
.pConfigFile
= config_file
;
400 di3a
.pHelpFile
= help_file
;
401 di3a
.pDependentFiles
= dep_file
;
402 di3a
.pMonitorName
= monitor_name
;
403 di3a
.pDefaultDataType
= default_data_type
;
405 if (!AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
))
407 ERR("Failed adding driver (%d)\n", GetLastError());
413 #ifdef HAVE_CUPS_CUPS_H
414 static typeof(cupsGetDests
) *pcupsGetDests
;
415 static typeof(cupsGetPPD
) *pcupsGetPPD
;
416 static typeof(cupsPrintFile
) *pcupsPrintFile
;
417 static void *cupshandle
;
419 static BOOL
CUPS_LoadPrinters(void)
422 BOOL hadprinter
= FALSE
;
424 PRINTER_INFO_2A pinfo2a
;
426 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
428 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
431 TRACE("loaded %s\n", SONAME_LIBCUPS
);
434 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
435 if (!p##x) return FALSE;
438 DYNCUPS(cupsGetDests
);
439 DYNCUPS(cupsPrintFile
);
442 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
444 ERR("Can't create Printers key\n");
448 nrofdests
= pcupsGetDests(&dests
);
449 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
450 for (i
=0;i
<nrofdests
;i
++) {
451 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
452 sprintf(port
,"LPR:%s",dests
[i
].name
);
453 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
454 sprintf(devline
,"WINEPS.DRV,%s",port
);
455 WriteProfileStringA("devices",dests
[i
].name
,devline
);
456 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
457 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
460 HeapFree(GetProcessHeap(),0,devline
);
462 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
463 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
464 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
466 TRACE("Printer already exists\n");
467 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
468 RegCloseKey(hkeyPrinter
);
470 static CHAR data_type
[] = "RAW",
471 print_proc
[] = "WinPrint",
472 comment
[] = "WINEPS Printer using CUPS",
473 location
[] = "<physical location of printer>",
474 params
[] = "<parameters?>",
475 share_name
[] = "<share name?>",
476 sep_file
[] = "<sep file?>";
478 add_printer_driver(dests
[i
].name
);
480 memset(&pinfo2a
,0,sizeof(pinfo2a
));
481 pinfo2a
.pPrinterName
= dests
[i
].name
;
482 pinfo2a
.pDatatype
= data_type
;
483 pinfo2a
.pPrintProcessor
= print_proc
;
484 pinfo2a
.pDriverName
= dests
[i
].name
;
485 pinfo2a
.pComment
= comment
;
486 pinfo2a
.pLocation
= location
;
487 pinfo2a
.pPortName
= port
;
488 pinfo2a
.pParameters
= params
;
489 pinfo2a
.pShareName
= share_name
;
490 pinfo2a
.pSepFile
= sep_file
;
492 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
493 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
494 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
497 HeapFree(GetProcessHeap(),0,port
);
500 if (dests
[i
].is_default
)
501 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
503 RegCloseKey(hkeyPrinters
);
509 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
510 PRINTER_INFO_2A pinfo2a
;
511 char *e
,*s
,*name
,*prettyname
,*devname
;
512 BOOL ret
= FALSE
, set_default
= FALSE
;
513 char *port
,*devline
,*env_default
;
514 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
516 while (isspace(*pent
)) pent
++;
517 s
= strchr(pent
,':');
519 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
527 TRACE("name=%s entry=%s\n",name
, pent
);
529 if(ispunct(*name
)) { /* a tc entry, not a real printer */
530 TRACE("skipping tc entry\n");
534 if(strstr(pent
,":server")) { /* server only version so skip */
535 TRACE("skipping server entry\n");
539 /* Determine whether this is a postscript printer. */
542 env_default
= getenv("PRINTER");
544 /* Get longest name, usually the one at the right for later display. */
545 while((s
=strchr(prettyname
,'|'))) {
548 while(isspace(*--e
)) *e
= '\0';
549 TRACE("\t%s\n", debugstr_a(prettyname
));
550 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
551 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
554 e
= prettyname
+ strlen(prettyname
);
555 while(isspace(*--e
)) *e
= '\0';
556 TRACE("\t%s\n", debugstr_a(prettyname
));
557 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
559 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
560 * if it is too long, we use it as comment below. */
561 devname
= prettyname
;
562 if (strlen(devname
)>=CCHDEVICENAME
-1)
564 if (strlen(devname
)>=CCHDEVICENAME
-1) {
569 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
570 sprintf(port
,"LPR:%s",name
);
572 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
573 sprintf(devline
,"WINEPS.DRV,%s",port
);
574 WriteProfileStringA("devices",devname
,devline
);
575 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
576 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
579 HeapFree(GetProcessHeap(),0,devline
);
581 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
583 ERR("Can't create Printers key\n");
587 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
588 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
590 TRACE("Printer already exists\n");
591 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
592 RegCloseKey(hkeyPrinter
);
594 static CHAR data_type
[] = "RAW",
595 print_proc
[] = "WinPrint",
596 comment
[] = "WINEPS Printer using LPR",
597 params
[] = "<parameters?>",
598 share_name
[] = "<share name?>",
599 sep_file
[] = "<sep file?>";
601 add_printer_driver(devname
);
603 memset(&pinfo2a
,0,sizeof(pinfo2a
));
604 pinfo2a
.pPrinterName
= devname
;
605 pinfo2a
.pDatatype
= data_type
;
606 pinfo2a
.pPrintProcessor
= print_proc
;
607 pinfo2a
.pDriverName
= devname
;
608 pinfo2a
.pComment
= comment
;
609 pinfo2a
.pLocation
= prettyname
;
610 pinfo2a
.pPortName
= port
;
611 pinfo2a
.pParameters
= params
;
612 pinfo2a
.pShareName
= share_name
;
613 pinfo2a
.pSepFile
= sep_file
;
615 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
616 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
617 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
620 RegCloseKey(hkeyPrinters
);
622 if (isfirst
|| set_default
)
623 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
625 HeapFree(GetProcessHeap(), 0, port
);
627 HeapFree(GetProcessHeap(), 0, name
);
632 PRINTCAP_LoadPrinters(void) {
633 BOOL hadprinter
= FALSE
;
637 BOOL had_bash
= FALSE
;
639 f
= fopen("/etc/printcap","r");
643 while(fgets(buf
,sizeof(buf
),f
)) {
646 end
=strchr(buf
,'\n');
650 while(isspace(*start
)) start
++;
651 if(*start
== '#' || *start
== '\0')
654 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
655 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
656 HeapFree(GetProcessHeap(),0,pent
);
660 if (end
&& *--end
== '\\') {
667 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
670 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
676 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
677 HeapFree(GetProcessHeap(),0,pent
);
683 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
686 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
687 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
689 return ERROR_FILE_NOT_FOUND
;
692 /*****************************************************************************
693 * enumerate the local monitors (INTERNAL)
695 * returns the needed size (in bytes) for pMonitors
696 * and *lpreturned is set to number of entries returned in pMonitors
699 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
704 LPMONITOR_INFO_2W mi
;
705 WCHAR buffer
[MAX_PATH
];
706 WCHAR dllname
[MAX_PATH
];
714 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
716 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
717 len
= entrysize
* numentries
;
718 ptr
= (LPWSTR
) &pMonitors
[len
];
721 len
= sizeof(buffer
);
724 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
725 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
726 /* Scan all Monitor-Registry-Keys */
727 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
728 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
729 dllsize
= sizeof(dllname
);
732 /* The Monitor must have a Driver-DLL */
733 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
734 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
735 /* We found a valid DLL for this Monitor. */
736 TRACE("using Driver: %s\n", debugstr_w(dllname
));
741 /* Windows returns only Port-Monitors here, but to simplify our code,
742 we do no filtering for Language-Monitors */
746 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
748 /* we install and return only monitors for "Windows NT x86" */
749 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
753 /* required size is calculated. Now fill the user-buffer */
754 if (pMonitors
&& (cbBuf
>= needed
)){
755 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
756 pMonitors
+= entrysize
;
758 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
760 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
761 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
763 mi
->pEnvironment
= ptr
;
764 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
765 ptr
+= (lstrlenW(envname_x86W
)+1);
768 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
769 ptr
+= (dllsize
/ sizeof(WCHAR
));
774 len
= sizeof(buffer
);
779 *lpreturned
= numentries
;
780 TRACE("need %d byte for %d entries\n", needed
, numentries
);
784 /******************************************************************
785 * monitor_unload [internal]
787 * release a printmonitor and unload it from memory, when needed
790 static void monitor_unload(monitor_t
* pm
)
792 if (pm
== NULL
) return;
793 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
795 EnterCriticalSection(&monitor_handles_cs
);
797 if (pm
->refcount
) pm
->refcount
--;
799 if (pm
->refcount
== 0) {
800 list_remove(&pm
->entry
);
801 FreeLibrary(pm
->hdll
);
802 HeapFree(GetProcessHeap(), 0, pm
->name
);
803 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
804 HeapFree(GetProcessHeap(), 0, pm
);
806 LeaveCriticalSection(&monitor_handles_cs
);
809 /******************************************************************
810 * monitor_unloadall [internal]
812 * release all printmonitors and unload them from memory, when needed
815 static void monitor_unloadall(void)
820 EnterCriticalSection(&monitor_handles_cs
);
821 /* iterate through the list, with safety against removal */
822 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
826 LeaveCriticalSection(&monitor_handles_cs
);
829 /******************************************************************
830 * monitor_load [internal]
832 * load a printmonitor, get the dllname from the registry, when needed
833 * initialize the monitor and dump found function-pointers
835 * On failure, SetLastError() is called and NULL is returned
838 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
840 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
841 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
842 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
843 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
844 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
846 monitor_t
* pm
= NULL
;
848 LPWSTR regroot
= NULL
;
849 LPWSTR driver
= dllname
;
851 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
852 /* Is the Monitor already loaded? */
853 EnterCriticalSection(&monitor_handles_cs
);
856 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
858 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
866 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
867 if (pm
== NULL
) goto cleanup
;
868 list_add_tail(&monitor_handles
, &pm
->entry
);
872 if (pm
->name
== NULL
) {
873 /* Load the monitor */
874 LPMONITOREX pmonitorEx
;
878 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
879 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
883 lstrcpyW(regroot
, MonitorsW
);
884 lstrcatW(regroot
, name
);
885 /* Get the Driver from the Registry */
886 if (driver
== NULL
) {
889 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
890 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
891 &namesize
) == ERROR_SUCCESS
) {
892 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
893 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
900 pm
->name
= strdupW(name
);
901 pm
->dllname
= strdupW(driver
);
903 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
905 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
910 pm
->hdll
= LoadLibraryW(driver
);
911 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
913 if (pm
->hdll
== NULL
) {
915 SetLastError(ERROR_MOD_NOT_FOUND
);
920 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
921 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
922 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
923 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
924 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
927 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
928 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
929 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
930 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
931 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
933 if (pInitializePrintMonitorUI
!= NULL
) {
934 pm
->monitorUI
= pInitializePrintMonitorUI();
935 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
937 TRACE( "0x%08x: dwMonitorSize (%d)\n",
938 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
943 if (pInitializePrintMonitor
&& regroot
) {
944 pmonitorEx
= pInitializePrintMonitor(regroot
);
945 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
946 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
949 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
950 pm
->monitor
= &(pmonitorEx
->Monitor
);
955 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
959 if (!pm
->monitor
&& regroot
) {
960 if (pInitializePrintMonitor2
!= NULL
) {
961 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
963 if (pInitializeMonitorEx
!= NULL
) {
964 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
966 if (pInitializeMonitor
!= NULL
) {
967 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
970 if (!pm
->monitor
&& !pm
->monitorUI
) {
972 SetLastError(ERROR_PROC_NOT_FOUND
);
977 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
981 LeaveCriticalSection(&monitor_handles_cs
);
982 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
983 HeapFree(GetProcessHeap(), 0, regroot
);
984 TRACE("=> %p\n", pm
);
988 /******************************************************************
989 * monitor_loadall [internal]
991 * Load all registered monitors
994 static DWORD
monitor_loadall(void)
997 DWORD registered
= 0;
1000 WCHAR buffer
[MAX_PATH
];
1003 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1004 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1005 NULL
, NULL
, NULL
, NULL
, NULL
);
1007 TRACE("%d monitors registered\n", registered
);
1009 EnterCriticalSection(&monitor_handles_cs
);
1010 while (id
< registered
) {
1012 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1013 pm
= monitor_load(buffer
, NULL
);
1017 LeaveCriticalSection(&monitor_handles_cs
);
1018 RegCloseKey(hmonitors
);
1020 TRACE("%d monitors loaded\n", loaded
);
1024 /******************************************************************
1025 * monitor_loadui [internal]
1027 * load the userinterface-dll for a given portmonitor
1029 * On failure, NULL is returned
1032 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1034 monitor_t
* pui
= NULL
;
1035 LPWSTR buffer
[MAX_PATH
];
1040 if (pm
== NULL
) return NULL
;
1041 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1043 /* Try the Portmonitor first; works for many monitors */
1044 if (pm
->monitorUI
) {
1045 EnterCriticalSection(&monitor_handles_cs
);
1047 LeaveCriticalSection(&monitor_handles_cs
);
1051 /* query the userinterface-dllname from the Portmonitor */
1052 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1053 /* building (",XcvMonitor %s",pm->name) not needed yet */
1054 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1055 TRACE("got %u with %p\n", res
, hXcv
);
1057 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1058 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1059 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1060 pm
->monitor
->pfnXcvClosePort(hXcv
);
1067 /******************************************************************
1068 * monitor_load_by_port [internal]
1070 * load a printmonitor for a given port
1072 * On failure, NULL is returned
1075 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1080 monitor_t
* pm
= NULL
;
1081 DWORD registered
= 0;
1085 TRACE("(%s)\n", debugstr_w(portname
));
1087 /* Try the Local Monitor first */
1088 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1089 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1090 /* found the portname */
1092 return monitor_load(LocalPortW
, NULL
);
1097 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1098 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1099 if (buffer
== NULL
) return NULL
;
1101 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1102 EnterCriticalSection(&monitor_handles_cs
);
1103 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1105 while ((pm
== NULL
) && (id
< registered
)) {
1107 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1108 TRACE("testing %s\n", debugstr_w(buffer
));
1109 len
= lstrlenW(buffer
);
1110 lstrcatW(buffer
, bs_Ports_bsW
);
1111 lstrcatW(buffer
, portname
);
1112 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1114 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1115 pm
= monitor_load(buffer
, NULL
);
1119 LeaveCriticalSection(&monitor_handles_cs
);
1122 HeapFree(GetProcessHeap(), 0, buffer
);
1126 /******************************************************************
1127 * enumerate the local Ports from all loaded monitors (internal)
1129 * returns the needed size (in bytes) for pPorts
1130 * and *lpreturned is set to number of entries returned in pPorts
1133 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1137 LPPORT_INFO_2W cache
;
1139 LPBYTE pi_buffer
= NULL
;
1140 DWORD pi_allocated
= 0;
1151 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1152 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1154 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1155 needed
= entrysize
* numentries
;
1156 ptr
= (LPWSTR
) &pPorts
[needed
];
1161 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1163 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1166 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1167 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1168 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1169 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1170 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1171 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1172 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1174 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1175 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1177 numentries
+= pi_returned
;
1178 needed
+= pi_needed
;
1180 /* fill the output-buffer (pPorts), if we have one */
1181 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1183 while (pi_returned
> pi_index
) {
1184 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1185 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1186 out
->pPortName
= ptr
;
1187 lstrcpyW(ptr
, cache
->pPortName
);
1188 ptr
+= (lstrlenW(ptr
)+1);
1190 out
->pMonitorName
= ptr
;
1191 lstrcpyW(ptr
, cache
->pMonitorName
);
1192 ptr
+= (lstrlenW(ptr
)+1);
1194 out
->pDescription
= ptr
;
1195 lstrcpyW(ptr
, cache
->pDescription
);
1196 ptr
+= (lstrlenW(ptr
)+1);
1197 out
->fPortType
= cache
->fPortType
;
1198 out
->Reserved
= cache
->Reserved
;
1206 /* the temporary portinfo-buffer is no longer needed */
1207 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1209 *lpreturned
= numentries
;
1210 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1214 /******************************************************************
1215 * get_servername_from_name (internal)
1217 * for an external server, a copy of the serverpart from the full name is returned
1220 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1224 WCHAR buffer
[MAX_PATH
];
1227 if (name
== NULL
) return NULL
;
1228 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1230 server
= strdupW(&name
[2]); /* skip over both backslash */
1231 if (server
== NULL
) return NULL
;
1233 /* strip '\' and the printername */
1234 ptr
= strchrW(server
, '\\');
1235 if (ptr
) ptr
[0] = '\0';
1237 TRACE("found %s\n", debugstr_w(server
));
1239 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1240 if (GetComputerNameW(buffer
, &len
)) {
1241 if (lstrcmpW(buffer
, server
) == 0) {
1242 /* The requested Servername is our computername */
1243 HeapFree(GetProcessHeap(), 0, server
);
1250 /******************************************************************
1251 * get_basename_from_name (internal)
1253 * skip over the serverpart from the full name
1256 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1258 if (name
== NULL
) return NULL
;
1259 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1260 /* skip over the servername and search for the following '\' */
1261 name
= strchrW(&name
[2], '\\');
1262 if ((name
) && (name
[1])) {
1263 /* found a separator ('\') followed by a name:
1264 skip over the separator and return the rest */
1269 /* no basename present (we found only a servername) */
1276 /******************************************************************
1277 * get_opened_printer_entry
1278 * Get the first place empty in the opened printer table
1281 * - pDefault is ignored
1283 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1285 UINT_PTR handle
= nb_printer_handles
, i
;
1286 jobqueue_t
*queue
= NULL
;
1287 opened_printer_t
*printer
= NULL
;
1289 LPCWSTR printername
;
1294 servername
= get_servername_from_name(name
);
1296 FIXME("server %s not supported\n", debugstr_w(servername
));
1297 HeapFree(GetProcessHeap(), 0, servername
);
1298 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1302 printername
= get_basename_from_name(name
);
1303 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1305 /* an empty printername is invalid */
1306 if (printername
&& (!printername
[0])) {
1307 SetLastError(ERROR_INVALID_PARAMETER
);
1311 EnterCriticalSection(&printer_handles_cs
);
1313 for (i
= 0; i
< nb_printer_handles
; i
++)
1315 if (!printer_handles
[i
])
1317 if(handle
== nb_printer_handles
)
1322 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1323 queue
= printer_handles
[i
]->queue
;
1327 if (handle
>= nb_printer_handles
)
1329 opened_printer_t
**new_array
;
1330 if (printer_handles
)
1331 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1332 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1334 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1335 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1342 printer_handles
= new_array
;
1343 nb_printer_handles
+= 16;
1346 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1353 /* clone the base name. This is NULL for the printserver */
1354 printer
->printername
= strdupW(printername
);
1356 /* clone the full name */
1357 printer
->name
= strdupW(name
);
1358 if (name
&& (!printer
->name
)) {
1364 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1365 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1366 /* OpenPrinter(",XcvMonitor " detected */
1367 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1368 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1369 if (printer
->pm
== NULL
) {
1370 SetLastError(ERROR_UNKNOWN_PORT
);
1377 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1378 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1379 /* OpenPrinter(",XcvPort " detected */
1380 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1381 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1382 if (printer
->pm
== NULL
) {
1383 SetLastError(ERROR_UNKNOWN_PORT
);
1391 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1392 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1393 pDefault
? pDefault
->DesiredAccess
: 0,
1396 if (printer
->hXcv
== NULL
) {
1397 SetLastError(ERROR_INVALID_PARAMETER
);
1404 /* Does the Printer exist? */
1405 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1406 ERR("Can't create Printers key\n");
1410 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1411 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1412 RegCloseKey(hkeyPrinters
);
1413 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1417 RegCloseKey(hkeyPrinter
);
1418 RegCloseKey(hkeyPrinters
);
1423 TRACE("using the local printserver\n");
1427 printer
->queue
= queue
;
1430 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1431 if (!printer
->queue
) {
1435 list_init(&printer
->queue
->jobs
);
1436 printer
->queue
->ref
= 0;
1438 InterlockedIncrement(&printer
->queue
->ref
);
1440 printer_handles
[handle
] = printer
;
1443 LeaveCriticalSection(&printer_handles_cs
);
1444 if (!handle
&& printer
) {
1445 /* Something failed: Free all resources */
1446 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1447 monitor_unload(printer
->pm
);
1448 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1449 HeapFree(GetProcessHeap(), 0, printer
->name
);
1450 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1451 HeapFree(GetProcessHeap(), 0, printer
);
1454 return (HANDLE
)handle
;
1457 /******************************************************************
1458 * get_opened_printer
1459 * Get the pointer to the opened printer referred by the handle
1461 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1463 UINT_PTR idx
= (UINT_PTR
)hprn
;
1464 opened_printer_t
*ret
= NULL
;
1466 EnterCriticalSection(&printer_handles_cs
);
1468 if ((idx
<= 0) || (idx
> nb_printer_handles
))
1471 ret
= printer_handles
[idx
- 1];
1473 LeaveCriticalSection(&printer_handles_cs
);
1477 /******************************************************************
1478 * get_opened_printer_name
1479 * Get the pointer to the opened printer name referred by the handle
1481 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1483 opened_printer_t
*printer
= get_opened_printer(hprn
);
1484 if(!printer
) return NULL
;
1485 return printer
->name
;
1488 /******************************************************************
1489 * WINSPOOL_GetOpenedPrinterRegKey
1492 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1494 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1498 if(!name
) return ERROR_INVALID_HANDLE
;
1500 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1504 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1506 ERR("Can't find opened printer %s in registry\n",
1508 RegCloseKey(hkeyPrinters
);
1509 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1511 RegCloseKey(hkeyPrinters
);
1512 return ERROR_SUCCESS
;
1515 void WINSPOOL_LoadSystemPrinters(void)
1517 HKEY hkey
, hkeyPrinters
;
1519 DWORD needed
, num
, i
;
1520 WCHAR PrinterName
[256];
1523 /* This ensures that all printer entries have a valid Name value. If causes
1524 problems later if they don't. If one is found to be missed we create one
1525 and set it equal to the name of the key */
1526 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1527 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1528 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1529 for(i
= 0; i
< num
; i
++) {
1530 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
1531 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1532 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1533 set_reg_szW(hkey
, NameW
, PrinterName
);
1540 RegCloseKey(hkeyPrinters
);
1543 /* We want to avoid calling AddPrinter on printers as much as
1544 possible, because on cups printers this will (eventually) lead
1545 to a call to cupsGetPPD which takes forever, even with non-cups
1546 printers AddPrinter takes a while. So we'll tag all printers that
1547 were automatically added last time around, if they still exist
1548 we'll leave them be otherwise we'll delete them. */
1549 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1551 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1552 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1553 for(i
= 0; i
< num
; i
++) {
1554 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1555 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1556 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1558 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1566 HeapFree(GetProcessHeap(), 0, pi
);
1570 #ifdef HAVE_CUPS_CUPS_H
1571 done
= CUPS_LoadPrinters();
1574 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1575 PRINTCAP_LoadPrinters();
1577 /* Now enumerate the list again and delete any printers that a still tagged */
1578 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1580 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1581 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1582 for(i
= 0; i
< num
; i
++) {
1583 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1584 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1585 BOOL delete_driver
= FALSE
;
1586 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1587 DWORD dw
, type
, size
= sizeof(dw
);
1588 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1589 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1590 DeletePrinter(hprn
);
1591 delete_driver
= TRUE
;
1597 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1602 HeapFree(GetProcessHeap(), 0, pi
);
1609 /******************************************************************
1612 * Get the pointer to the specified job.
1613 * Should hold the printer_handles_cs before calling.
1615 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1617 opened_printer_t
*printer
= get_opened_printer(hprn
);
1620 if(!printer
) return NULL
;
1621 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1623 if(job
->job_id
== JobId
)
1629 /***********************************************************
1632 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1635 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1638 Formname
= (dmA
->dmSize
> off_formname
);
1639 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1640 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1641 dmW
->dmDeviceName
, CCHDEVICENAME
);
1643 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1644 dmA
->dmSize
- CCHDEVICENAME
);
1646 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1647 off_formname
- CCHDEVICENAME
);
1648 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1649 dmW
->dmFormName
, CCHFORMNAME
);
1650 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1651 (off_formname
+ CCHFORMNAME
));
1654 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1655 dmA
->dmDriverExtra
);
1659 /***********************************************************
1661 * Creates an ascii copy of supplied devmode on heap
1663 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1668 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1670 if(!dmW
) return NULL
;
1671 Formname
= (dmW
->dmSize
> off_formname
);
1672 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1673 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1674 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1675 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1677 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1678 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1680 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1681 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1682 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1683 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1684 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1685 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1688 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1689 dmW
->dmDriverExtra
);
1693 /***********************************************************
1694 * PRINTER_INFO_2AtoW
1695 * Creates a unicode copy of PRINTER_INFO_2A on heap
1697 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1699 LPPRINTER_INFO_2W piW
;
1700 UNICODE_STRING usBuffer
;
1702 if(!piA
) return NULL
;
1703 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1704 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1706 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1707 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1708 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1709 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1710 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1711 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1712 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1713 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1714 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1715 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1716 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1717 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1721 /***********************************************************
1722 * FREE_PRINTER_INFO_2W
1723 * Free PRINTER_INFO_2W and all strings
1725 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1729 HeapFree(heap
,0,piW
->pServerName
);
1730 HeapFree(heap
,0,piW
->pPrinterName
);
1731 HeapFree(heap
,0,piW
->pShareName
);
1732 HeapFree(heap
,0,piW
->pPortName
);
1733 HeapFree(heap
,0,piW
->pDriverName
);
1734 HeapFree(heap
,0,piW
->pComment
);
1735 HeapFree(heap
,0,piW
->pLocation
);
1736 HeapFree(heap
,0,piW
->pDevMode
);
1737 HeapFree(heap
,0,piW
->pSepFile
);
1738 HeapFree(heap
,0,piW
->pPrintProcessor
);
1739 HeapFree(heap
,0,piW
->pDatatype
);
1740 HeapFree(heap
,0,piW
->pParameters
);
1741 HeapFree(heap
,0,piW
);
1745 /******************************************************************
1746 * DeviceCapabilities [WINSPOOL.@]
1747 * DeviceCapabilitiesA [WINSPOOL.@]
1750 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1751 LPSTR pOutput
, LPDEVMODEA lpdm
)
1755 if (!GDI_CallDeviceCapabilities16
)
1757 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1759 if (!GDI_CallDeviceCapabilities16
) return -1;
1761 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1763 /* If DC_PAPERSIZE map POINT16s to POINTs */
1764 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1765 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1766 POINT
*pt
= (POINT
*)pOutput
;
1768 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1769 for(i
= 0; i
< ret
; i
++, pt
++)
1774 HeapFree( GetProcessHeap(), 0, tmp
);
1780 /*****************************************************************************
1781 * DeviceCapabilitiesW [WINSPOOL.@]
1783 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1786 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1787 WORD fwCapability
, LPWSTR pOutput
,
1788 const DEVMODEW
*pDevMode
)
1790 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1791 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1792 LPSTR pPortA
= strdupWtoA(pPort
);
1795 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1796 fwCapability
== DC_FILEDEPENDENCIES
||
1797 fwCapability
== DC_PAPERNAMES
)) {
1798 /* These need A -> W translation */
1801 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1805 switch(fwCapability
) {
1810 case DC_FILEDEPENDENCIES
:
1814 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1815 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1817 for(i
= 0; i
< ret
; i
++)
1818 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1819 pOutput
+ (i
* size
), size
);
1820 HeapFree(GetProcessHeap(), 0, pOutputA
);
1822 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1823 (LPSTR
)pOutput
, dmA
);
1825 HeapFree(GetProcessHeap(),0,pPortA
);
1826 HeapFree(GetProcessHeap(),0,pDeviceA
);
1827 HeapFree(GetProcessHeap(),0,dmA
);
1831 /******************************************************************
1832 * DocumentPropertiesA [WINSPOOL.@]
1834 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1836 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1837 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1838 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1840 LPSTR lpName
= pDeviceName
;
1841 static CHAR port
[] = "LPT1:";
1844 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1845 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1849 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1851 ERR("no name from hPrinter?\n");
1852 SetLastError(ERROR_INVALID_HANDLE
);
1855 lpName
= strdupWtoA(lpNameW
);
1858 if (!GDI_CallExtDeviceMode16
)
1860 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1862 if (!GDI_CallExtDeviceMode16
) {
1863 ERR("No CallExtDeviceMode16?\n");
1867 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1868 pDevModeInput
, NULL
, fMode
);
1871 HeapFree(GetProcessHeap(),0,lpName
);
1876 /*****************************************************************************
1877 * DocumentPropertiesW (WINSPOOL.@)
1879 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1881 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1883 LPDEVMODEW pDevModeOutput
,
1884 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1887 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1888 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1889 LPDEVMODEA pDevModeOutputA
= NULL
;
1892 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1893 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1895 if(pDevModeOutput
) {
1896 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1897 if(ret
< 0) return ret
;
1898 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1900 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1901 pDevModeInputA
, fMode
);
1902 if(pDevModeOutput
) {
1903 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1904 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1906 if(fMode
== 0 && ret
> 0)
1907 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1908 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1909 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1913 /******************************************************************
1914 * OpenPrinterA [WINSPOOL.@]
1919 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1920 LPPRINTER_DEFAULTSA pDefault
)
1922 UNICODE_STRING lpPrinterNameW
;
1923 UNICODE_STRING usBuffer
;
1924 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1925 PWSTR pwstrPrinterNameW
;
1928 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1931 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1932 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1933 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1934 pDefaultW
= &DefaultW
;
1936 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1938 RtlFreeUnicodeString(&usBuffer
);
1939 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1941 RtlFreeUnicodeString(&lpPrinterNameW
);
1945 /******************************************************************
1946 * OpenPrinterW [WINSPOOL.@]
1948 * Open a Printer / Printserver or a Printer-Object
1951 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1952 * phPrinter [O] The resulting Handle is stored here
1953 * pDefault [I] PTR to Default Printer Settings or NULL
1960 * lpPrinterName is one of:
1961 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1962 *| Printer: "PrinterName"
1963 *| Printer-Object: "PrinterName,Job xxx"
1964 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1965 *| XcvPort: "Servername,XcvPort PortName"
1968 *| Printer-Object not supported
1969 *| pDefaults is ignored
1972 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1975 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1977 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1978 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1982 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1983 SetLastError(ERROR_INVALID_PARAMETER
);
1987 /* Get the unique handle of the printer or Printserver */
1988 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1989 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1990 return (*phPrinter
!= 0);
1993 /******************************************************************
1994 * AddMonitorA [WINSPOOL.@]
1999 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2001 LPWSTR nameW
= NULL
;
2004 LPMONITOR_INFO_2A mi2a
;
2005 MONITOR_INFO_2W mi2w
;
2007 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2008 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2009 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2010 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2011 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2014 SetLastError(ERROR_INVALID_LEVEL
);
2018 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2024 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2025 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2026 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2029 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2031 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2032 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2033 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2035 if (mi2a
->pEnvironment
) {
2036 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2037 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2038 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2040 if (mi2a
->pDLLName
) {
2041 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2042 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2043 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2046 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2048 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2049 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2050 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2052 HeapFree(GetProcessHeap(), 0, nameW
);
2056 /******************************************************************************
2057 * AddMonitorW [WINSPOOL.@]
2059 * Install a Printmonitor
2062 * pName [I] Servername or NULL (local Computer)
2063 * Level [I] Structure-Level (Must be 2)
2064 * pMonitors [I] PTR to MONITOR_INFO_2
2071 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2074 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2076 monitor_t
* pm
= NULL
;
2077 LPMONITOR_INFO_2W mi2w
;
2083 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2084 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2085 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2086 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2087 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2090 SetLastError(ERROR_INVALID_LEVEL
);
2094 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2099 if (pName
&& (pName
[0])) {
2100 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2101 SetLastError(ERROR_ACCESS_DENIED
);
2106 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2107 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2108 SetLastError(ERROR_INVALID_PARAMETER
);
2111 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2112 WARN("Environment %s requested (we support only %s)\n",
2113 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2114 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2118 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2119 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2120 SetLastError(ERROR_INVALID_PARAMETER
);
2124 /* Load and initialize the monitor. SetLastError() is called on failure */
2125 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2130 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2131 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2135 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2136 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2137 &disposition
) == ERROR_SUCCESS
) {
2139 /* Some installers set options for the port before calling AddMonitor.
2140 We query the "Driver" entry to verify that the monitor is installed,
2141 before we return an error.
2142 When a user installs two print monitors at the same time with the
2143 same name but with a different driver DLL and a task switch comes
2144 between RegQueryValueExW and RegSetValueExW, a race condition
2145 is possible but silently ignored. */
2149 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2150 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2151 &namesize
) == ERROR_SUCCESS
)) {
2152 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2153 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2154 9x: ERROR_ALREADY_EXISTS (183) */
2155 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2160 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2161 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2162 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2164 RegCloseKey(hentry
);
2171 /******************************************************************
2172 * DeletePrinterDriverA [WINSPOOL.@]
2175 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2177 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2180 /******************************************************************
2181 * DeletePrinterDriverW [WINSPOOL.@]
2184 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2186 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2189 /******************************************************************
2190 * DeleteMonitorA [WINSPOOL.@]
2192 * See DeleteMonitorW.
2195 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2197 LPWSTR nameW
= NULL
;
2198 LPWSTR EnvironmentW
= NULL
;
2199 LPWSTR MonitorNameW
= NULL
;
2204 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2205 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2206 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2210 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2211 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2212 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2215 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2216 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2217 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2220 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2222 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2223 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2224 HeapFree(GetProcessHeap(), 0, nameW
);
2228 /******************************************************************
2229 * DeleteMonitorW [WINSPOOL.@]
2231 * Delete a specific Printmonitor from a Printing-Environment
2234 * pName [I] Servername or NULL (local Computer)
2235 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2236 * pMonitorName [I] Name of the Monitor, that should be deleted
2243 * pEnvironment is ignored in Windows for the local Computer.
2247 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2251 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2252 debugstr_w(pMonitorName
));
2254 if (pName
&& (pName
[0])) {
2255 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2256 SetLastError(ERROR_ACCESS_DENIED
);
2260 /* pEnvironment is ignored in Windows for the local Computer */
2262 if (!pMonitorName
|| !pMonitorName
[0]) {
2263 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2264 SetLastError(ERROR_INVALID_PARAMETER
);
2268 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2269 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2273 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2274 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2275 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2280 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2283 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2284 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2288 /******************************************************************
2289 * DeletePortA [WINSPOOL.@]
2294 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2296 LPWSTR nameW
= NULL
;
2297 LPWSTR portW
= NULL
;
2301 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2303 /* convert servername to unicode */
2305 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2306 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2307 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2310 /* convert portname to unicode */
2312 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2313 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2314 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2317 res
= DeletePortW(nameW
, hWnd
, portW
);
2318 HeapFree(GetProcessHeap(), 0, nameW
);
2319 HeapFree(GetProcessHeap(), 0, portW
);
2323 /******************************************************************
2324 * DeletePortW [WINSPOOL.@]
2326 * Delete a specific Port
2329 * pName [I] Servername or NULL (local Computer)
2330 * hWnd [I] Handle to parent Window for the Dialog-Box
2331 * pPortName [I] Name of the Port, that should be deleted
2338 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2344 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2346 if (pName
&& pName
[0]) {
2347 SetLastError(ERROR_INVALID_PARAMETER
);
2352 SetLastError(RPC_X_NULL_REF_POINTER
);
2356 /* an empty Portname is Invalid */
2357 if (!pPortName
[0]) {
2358 SetLastError(ERROR_NOT_SUPPORTED
);
2362 pm
= monitor_load_by_port(pPortName
);
2363 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2364 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2365 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2366 TRACE("got %d with %u\n", res
, GetLastError());
2370 pui
= monitor_loadui(pm
);
2371 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2372 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2373 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2374 TRACE("got %d with %u\n", res
, GetLastError());
2378 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2379 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2381 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2382 SetLastError(ERROR_NOT_SUPPORTED
);
2385 monitor_unload(pui
);
2389 TRACE("returning %d with %u\n", res
, GetLastError());
2393 /******************************************************************************
2394 * SetPrinterW [WINSPOOL.@]
2396 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2398 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2399 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2403 /******************************************************************************
2404 * WritePrinter [WINSPOOL.@]
2406 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2408 opened_printer_t
*printer
;
2411 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2413 EnterCriticalSection(&printer_handles_cs
);
2414 printer
= get_opened_printer(hPrinter
);
2417 SetLastError(ERROR_INVALID_HANDLE
);
2423 SetLastError(ERROR_SPL_NO_STARTDOC
);
2427 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2429 LeaveCriticalSection(&printer_handles_cs
);
2433 /*****************************************************************************
2434 * AddFormA [WINSPOOL.@]
2436 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2438 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2442 /*****************************************************************************
2443 * AddFormW [WINSPOOL.@]
2445 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2447 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2451 /*****************************************************************************
2452 * AddJobA [WINSPOOL.@]
2454 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2457 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2461 SetLastError(ERROR_INVALID_LEVEL
);
2465 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2468 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2469 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2470 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2471 if(*pcbNeeded
> cbBuf
) {
2472 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2475 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2476 addjobA
->JobId
= addjobW
->JobId
;
2477 addjobA
->Path
= (char *)(addjobA
+ 1);
2478 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2484 /*****************************************************************************
2485 * AddJobW [WINSPOOL.@]
2487 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2489 opened_printer_t
*printer
;
2492 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2493 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2494 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2496 ADDJOB_INFO_1W
*addjob
;
2498 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2500 EnterCriticalSection(&printer_handles_cs
);
2502 printer
= get_opened_printer(hPrinter
);
2505 SetLastError(ERROR_INVALID_HANDLE
);
2510 SetLastError(ERROR_INVALID_LEVEL
);
2514 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2518 job
->job_id
= InterlockedIncrement(&next_job_id
);
2520 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2521 if(path
[len
- 1] != '\\')
2523 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2524 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2526 len
= strlenW(filename
);
2527 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2528 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2529 job
->document_title
= strdupW(default_doc_title
);
2530 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2532 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2533 if(*pcbNeeded
<= cbBuf
) {
2534 addjob
= (ADDJOB_INFO_1W
*)pData
;
2535 addjob
->JobId
= job
->job_id
;
2536 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2537 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2540 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2543 LeaveCriticalSection(&printer_handles_cs
);
2547 /*****************************************************************************
2548 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2550 * Return the PATH for the Print-Processors
2552 * See GetPrintProcessorDirectoryW.
2556 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2557 DWORD level
, LPBYTE Info
,
2558 DWORD cbBuf
, LPDWORD pcbNeeded
)
2560 LPWSTR serverW
= NULL
;
2565 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2566 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2570 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2571 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2572 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2576 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2577 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2578 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2581 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2582 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2584 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2587 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2588 cbBuf
, NULL
, NULL
) > 0;
2591 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2592 HeapFree(GetProcessHeap(), 0, envW
);
2593 HeapFree(GetProcessHeap(), 0, serverW
);
2597 /*****************************************************************************
2598 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2600 * Return the PATH for the Print-Processors
2603 * server [I] Servername (NT only) or NULL (local Computer)
2604 * env [I] Printing-Environment (see below) or NULL (Default)
2605 * level [I] Structure-Level (must be 1)
2606 * Info [O] PTR to Buffer that receives the Result
2607 * cbBuf [I] Size of Buffer at "Info"
2608 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2609 * required for the Buffer at "Info"
2612 * Success: TRUE and in pcbNeeded the Bytes used in Info
2613 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2614 * if cbBuf is too small
2616 * Native Values returned in Info on Success:
2617 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2618 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2619 *| win9x(Windows 4.0): "%winsysdir%"
2621 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2624 * Only NULL or "" is supported for server
2627 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2628 DWORD level
, LPBYTE Info
,
2629 DWORD cbBuf
, LPDWORD pcbNeeded
)
2632 const printenv_t
* env_t
;
2634 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2635 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2637 if(server
!= NULL
&& server
[0]) {
2638 FIXME("server not supported: %s\n", debugstr_w(server
));
2639 SetLastError(ERROR_INVALID_PARAMETER
);
2643 env_t
= validate_envW(env
);
2644 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2647 WARN("(Level: %d) is ignored in win9x\n", level
);
2648 SetLastError(ERROR_INVALID_LEVEL
);
2652 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2653 needed
= GetSystemDirectoryW(NULL
, 0);
2654 /* add the Size for the Subdirectories */
2655 needed
+= lstrlenW(spoolprtprocsW
);
2656 needed
+= lstrlenW(env_t
->subdir
);
2657 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2659 if(pcbNeeded
) *pcbNeeded
= needed
;
2660 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2661 if (needed
> cbBuf
) {
2662 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2665 if(pcbNeeded
== NULL
) {
2666 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2667 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2668 SetLastError(RPC_X_NULL_REF_POINTER
);
2672 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2673 SetLastError(RPC_X_NULL_REF_POINTER
);
2677 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2678 /* add the Subdirectories */
2679 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2680 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2681 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2685 /*****************************************************************************
2686 * WINSPOOL_OpenDriverReg [internal]
2688 * opens the registry for the printer drivers depending on the given input
2689 * variable pEnvironment
2692 * the opened hkey on success
2695 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2699 const printenv_t
* env
;
2702 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2704 if (!pEnvironment
|| unicode
) {
2705 /* pEnvironment was NULL or an Unicode-String: use it direct */
2706 env
= validate_envW(pEnvironment
);
2710 /* pEnvironment was an ANSI-String: convert to unicode first */
2712 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2713 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2714 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2715 env
= validate_envW(buffer
);
2716 HeapFree(GetProcessHeap(), 0, buffer
);
2718 if (!env
) return NULL
;
2720 buffer
= HeapAlloc( GetProcessHeap(), 0,
2721 (strlenW(DriversW
) + strlenW(env
->envname
) +
2722 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2724 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2725 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2726 HeapFree(GetProcessHeap(), 0, buffer
);
2731 /*****************************************************************************
2732 * AddPrinterW [WINSPOOL.@]
2734 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2736 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2740 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2742 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2743 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2744 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2745 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2746 statusW
[] = {'S','t','a','t','u','s',0},
2747 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2749 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2752 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2753 SetLastError(ERROR_INVALID_PARAMETER
);
2757 ERR("Level = %d, unsupported!\n", Level
);
2758 SetLastError(ERROR_INVALID_LEVEL
);
2762 SetLastError(ERROR_INVALID_PARAMETER
);
2765 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2767 ERR("Can't create Printers key\n");
2770 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2771 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2772 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2773 RegCloseKey(hkeyPrinter
);
2774 RegCloseKey(hkeyPrinters
);
2777 RegCloseKey(hkeyPrinter
);
2779 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2781 ERR("Can't create Drivers key\n");
2782 RegCloseKey(hkeyPrinters
);
2785 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2787 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2788 RegCloseKey(hkeyPrinters
);
2789 RegCloseKey(hkeyDrivers
);
2790 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2793 RegCloseKey(hkeyDriver
);
2794 RegCloseKey(hkeyDrivers
);
2796 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2797 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2798 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2799 RegCloseKey(hkeyPrinters
);
2803 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2805 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2806 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2807 RegCloseKey(hkeyPrinters
);
2810 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2811 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2812 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2814 /* See if we can load the driver. We may need the devmode structure anyway
2817 * Note that DocumentPropertiesW will briefly try to open the printer we
2818 * just create to find a DEVMODEA struct (it will use the WINEPS default
2819 * one in case it is not there, so we are ok).
2821 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2824 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2825 size
= sizeof(DEVMODEW
);
2831 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2833 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2835 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2836 HeapFree(GetProcessHeap(),0,dmW
);
2841 /* set devmode to printer name */
2842 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2846 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2847 and we support these drivers. NT writes DEVMODEW so somehow
2848 we'll need to distinguish between these when we support NT
2852 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2853 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2854 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2855 HeapFree(GetProcessHeap(), 0, dmA
);
2857 HeapFree(GetProcessHeap(), 0, dmW
);
2859 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2860 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2861 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2862 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2864 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2865 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2866 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2867 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2868 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2869 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2870 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2871 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2872 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2873 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2874 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2875 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2876 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2878 RegCloseKey(hkeyPrinter
);
2879 RegCloseKey(hkeyPrinters
);
2880 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2881 ERR("OpenPrinter failing\n");
2887 /*****************************************************************************
2888 * AddPrinterA [WINSPOOL.@]
2890 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2892 UNICODE_STRING pNameW
;
2894 PRINTER_INFO_2W
*piW
;
2895 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2898 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2900 ERR("Level = %d, unsupported!\n", Level
);
2901 SetLastError(ERROR_INVALID_LEVEL
);
2904 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2905 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2907 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2909 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2910 RtlFreeUnicodeString(&pNameW
);
2915 /*****************************************************************************
2916 * ClosePrinter [WINSPOOL.@]
2918 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2920 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2921 opened_printer_t
*printer
= NULL
;
2924 TRACE("(%p)\n", hPrinter
);
2926 EnterCriticalSection(&printer_handles_cs
);
2928 if ((i
> 0) && (i
<= nb_printer_handles
))
2929 printer
= printer_handles
[i
- 1];
2934 struct list
*cursor
, *cursor2
;
2936 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2937 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2938 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2941 EndDocPrinter(hPrinter
);
2943 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2945 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2947 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2948 ScheduleJob(hPrinter
, job
->job_id
);
2950 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2952 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2953 monitor_unload(printer
->pm
);
2954 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2955 HeapFree(GetProcessHeap(), 0, printer
->name
);
2956 HeapFree(GetProcessHeap(), 0, printer
);
2957 printer_handles
[i
- 1] = NULL
;
2960 LeaveCriticalSection(&printer_handles_cs
);
2964 /*****************************************************************************
2965 * DeleteFormA [WINSPOOL.@]
2967 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2969 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2973 /*****************************************************************************
2974 * DeleteFormW [WINSPOOL.@]
2976 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2978 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2982 /*****************************************************************************
2983 * DeletePrinter [WINSPOOL.@]
2985 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2987 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2988 HKEY hkeyPrinters
, hkey
;
2991 SetLastError(ERROR_INVALID_HANDLE
);
2994 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2995 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2996 RegCloseKey(hkeyPrinters
);
2998 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2999 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3000 RegDeleteValueW(hkey
, lpNameW
);
3006 /*****************************************************************************
3007 * SetPrinterA [WINSPOOL.@]
3009 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3012 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3016 /*****************************************************************************
3017 * SetJobA [WINSPOOL.@]
3019 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3020 LPBYTE pJob
, DWORD Command
)
3024 UNICODE_STRING usBuffer
;
3026 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3028 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3029 are all ignored by SetJob, so we don't bother copying them */
3037 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3038 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3040 JobW
= (LPBYTE
)info1W
;
3041 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3042 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3043 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3044 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3045 info1W
->Status
= info1A
->Status
;
3046 info1W
->Priority
= info1A
->Priority
;
3047 info1W
->Position
= info1A
->Position
;
3048 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3053 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3054 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3056 JobW
= (LPBYTE
)info2W
;
3057 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3058 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3059 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3060 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3061 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3062 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3063 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3064 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3065 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3066 info2W
->Status
= info2A
->Status
;
3067 info2W
->Priority
= info2A
->Priority
;
3068 info2W
->Position
= info2A
->Position
;
3069 info2W
->StartTime
= info2A
->StartTime
;
3070 info2W
->UntilTime
= info2A
->UntilTime
;
3071 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3075 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3076 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3079 SetLastError(ERROR_INVALID_LEVEL
);
3083 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3089 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3090 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3091 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3092 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3093 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3098 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3099 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3100 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3101 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3102 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3103 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3104 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3105 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3106 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3110 HeapFree(GetProcessHeap(), 0, JobW
);
3115 /*****************************************************************************
3116 * SetJobW [WINSPOOL.@]
3118 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3119 LPBYTE pJob
, DWORD Command
)
3124 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3125 FIXME("Ignoring everything other than document title\n");
3127 EnterCriticalSection(&printer_handles_cs
);
3128 job
= get_job(hPrinter
, JobId
);
3138 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3139 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3140 job
->document_title
= strdupW(info1
->pDocument
);
3145 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3146 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3147 job
->document_title
= strdupW(info2
->pDocument
);
3153 SetLastError(ERROR_INVALID_LEVEL
);
3158 LeaveCriticalSection(&printer_handles_cs
);
3162 /*****************************************************************************
3163 * EndDocPrinter [WINSPOOL.@]
3165 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3167 opened_printer_t
*printer
;
3169 TRACE("(%p)\n", hPrinter
);
3171 EnterCriticalSection(&printer_handles_cs
);
3173 printer
= get_opened_printer(hPrinter
);
3176 SetLastError(ERROR_INVALID_HANDLE
);
3182 SetLastError(ERROR_SPL_NO_STARTDOC
);
3186 CloseHandle(printer
->doc
->hf
);
3187 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3188 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3189 printer
->doc
= NULL
;
3192 LeaveCriticalSection(&printer_handles_cs
);
3196 /*****************************************************************************
3197 * EndPagePrinter [WINSPOOL.@]
3199 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3201 FIXME("(%p): stub\n", hPrinter
);
3205 /*****************************************************************************
3206 * StartDocPrinterA [WINSPOOL.@]
3208 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3210 UNICODE_STRING usBuffer
;
3212 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3215 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3216 or one (DOC_INFO_3) extra DWORDs */
3220 doc2W
.JobId
= doc2
->JobId
;
3223 doc2W
.dwMode
= doc2
->dwMode
;
3226 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3227 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3228 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3232 SetLastError(ERROR_INVALID_LEVEL
);
3236 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3238 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3239 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3240 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3245 /*****************************************************************************
3246 * StartDocPrinterW [WINSPOOL.@]
3248 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3250 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3251 opened_printer_t
*printer
;
3252 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3253 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3254 JOB_INFO_1W job_info
;
3255 DWORD needed
, ret
= 0;
3259 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3260 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3261 debugstr_w(doc
->pDatatype
));
3263 if(Level
< 1 || Level
> 3)
3265 SetLastError(ERROR_INVALID_LEVEL
);
3269 EnterCriticalSection(&printer_handles_cs
);
3270 printer
= get_opened_printer(hPrinter
);
3273 SetLastError(ERROR_INVALID_HANDLE
);
3279 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3283 /* Even if we're printing to a file we still add a print job, we'll
3284 just ignore the spool file name */
3286 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3288 ERR("AddJob failed gle %u\n", GetLastError());
3292 if(doc
->pOutputFile
)
3293 filename
= doc
->pOutputFile
;
3295 filename
= addjob
->Path
;
3297 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3298 if(hf
== INVALID_HANDLE_VALUE
)
3301 memset(&job_info
, 0, sizeof(job_info
));
3302 job_info
.pDocument
= doc
->pDocName
;
3303 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3305 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3306 printer
->doc
->hf
= hf
;
3307 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3309 LeaveCriticalSection(&printer_handles_cs
);
3314 /*****************************************************************************
3315 * StartPagePrinter [WINSPOOL.@]
3317 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3319 FIXME("(%p): stub\n", hPrinter
);
3323 /*****************************************************************************
3324 * GetFormA [WINSPOOL.@]
3326 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3327 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3329 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3330 Level
,pForm
,cbBuf
,pcbNeeded
);
3334 /*****************************************************************************
3335 * GetFormW [WINSPOOL.@]
3337 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3338 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3340 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3341 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3345 /*****************************************************************************
3346 * SetFormA [WINSPOOL.@]
3348 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3351 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3355 /*****************************************************************************
3356 * SetFormW [WINSPOOL.@]
3358 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3361 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3365 /*****************************************************************************
3366 * ReadPrinter [WINSPOOL.@]
3368 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3369 LPDWORD pNoBytesRead
)
3371 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3375 /*****************************************************************************
3376 * ResetPrinterA [WINSPOOL.@]
3378 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3380 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3384 /*****************************************************************************
3385 * ResetPrinterW [WINSPOOL.@]
3387 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3389 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3393 /*****************************************************************************
3394 * WINSPOOL_GetDWORDFromReg
3396 * Return DWORD associated with ValueName from hkey.
3398 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3400 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3403 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3405 if(ret
!= ERROR_SUCCESS
) {
3406 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3409 if(type
!= REG_DWORD
) {
3410 ERR("Got type %d\n", type
);
3416 /*****************************************************************************
3417 * WINSPOOL_GetStringFromReg
3419 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3420 * String is stored either as unicode or ascii.
3421 * Bit of a hack here to get the ValueName if we want ascii.
3423 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3424 DWORD buflen
, DWORD
*needed
,
3427 DWORD sz
= buflen
, type
;
3431 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3433 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3434 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3435 HeapFree(GetProcessHeap(),0,ValueNameA
);
3437 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3438 WARN("Got ret = %d\n", ret
);
3442 /* add space for terminating '\0' */
3443 sz
+= unicode
? sizeof(WCHAR
) : 1;
3447 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3452 /*****************************************************************************
3453 * WINSPOOL_GetDefaultDevMode
3455 * Get a default DevMode values for wineps.
3459 static void WINSPOOL_GetDefaultDevMode(
3461 DWORD buflen
, DWORD
*needed
,
3465 static const char szwps
[] = "wineps.drv";
3467 /* fill default DEVMODE - should be read from ppd... */
3468 ZeroMemory( &dm
, sizeof(dm
) );
3469 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3470 dm
.dmSpecVersion
= DM_SPECVERSION
;
3471 dm
.dmDriverVersion
= 1;
3472 dm
.dmSize
= sizeof(DEVMODEA
);
3473 dm
.dmDriverExtra
= 0;
3475 DM_ORIENTATION
| DM_PAPERSIZE
|
3476 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3479 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3480 DM_YRESOLUTION
| DM_TTOPTION
;
3482 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3483 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3484 dm
.u1
.s1
.dmPaperLength
= 2970;
3485 dm
.u1
.s1
.dmPaperWidth
= 2100;
3489 dm
.dmDefaultSource
= DMBIN_AUTO
;
3490 dm
.dmPrintQuality
= DMRES_MEDIUM
;
3493 dm
.dmYResolution
= 300; /* 300dpi */
3494 dm
.dmTTOption
= DMTT_BITMAP
;
3497 /* dm.dmLogPixels */
3498 /* dm.dmBitsPerPel */
3499 /* dm.dmPelsWidth */
3500 /* dm.dmPelsHeight */
3501 /* dm.dmDisplayFlags */
3502 /* dm.dmDisplayFrequency */
3503 /* dm.dmICMMethod */
3504 /* dm.dmICMIntent */
3505 /* dm.dmMediaType */
3506 /* dm.dmDitherType */
3507 /* dm.dmReserved1 */
3508 /* dm.dmReserved2 */
3509 /* dm.dmPanningWidth */
3510 /* dm.dmPanningHeight */
3513 if(buflen
>= sizeof(DEVMODEW
)) {
3514 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3515 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3516 HeapFree(GetProcessHeap(),0,pdmW
);
3518 *needed
= sizeof(DEVMODEW
);
3522 if(buflen
>= sizeof(DEVMODEA
)) {
3523 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3525 *needed
= sizeof(DEVMODEA
);
3529 /*****************************************************************************
3530 * WINSPOOL_GetDevModeFromReg
3532 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3533 * DevMode is stored either as unicode or ascii.
3535 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3537 DWORD buflen
, DWORD
*needed
,
3540 DWORD sz
= buflen
, type
;
3543 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3544 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3545 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3546 if (sz
< sizeof(DEVMODEA
))
3548 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3551 /* ensures that dmSize is not erratically bogus if registry is invalid */
3552 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3553 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3555 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3557 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3558 memcpy(ptr
, dmW
, sz
);
3559 HeapFree(GetProcessHeap(),0,dmW
);
3566 /*********************************************************************
3567 * WINSPOOL_GetPrinter_1
3569 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3570 * The strings are either stored as unicode or ascii.
3572 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3573 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3576 DWORD size
, left
= cbBuf
;
3577 BOOL space
= (cbBuf
> 0);
3582 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3584 if(space
&& size
<= left
) {
3585 pi1
->pName
= (LPWSTR
)ptr
;
3593 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3594 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3596 if(space
&& size
<= left
) {
3597 pi1
->pDescription
= (LPWSTR
)ptr
;
3605 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3607 if(space
&& size
<= left
) {
3608 pi1
->pComment
= (LPWSTR
)ptr
;
3616 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3618 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3619 memset(pi1
, 0, sizeof(*pi1
));
3623 /*********************************************************************
3624 * WINSPOOL_GetPrinter_2
3626 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3627 * The strings are either stored as unicode or ascii.
3629 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3630 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3633 DWORD size
, left
= cbBuf
;
3634 BOOL space
= (cbBuf
> 0);
3639 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3641 if(space
&& size
<= left
) {
3642 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3649 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3651 if(space
&& size
<= left
) {
3652 pi2
->pShareName
= (LPWSTR
)ptr
;
3659 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3661 if(space
&& size
<= left
) {
3662 pi2
->pPortName
= (LPWSTR
)ptr
;
3669 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3671 if(space
&& size
<= left
) {
3672 pi2
->pDriverName
= (LPWSTR
)ptr
;
3679 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3681 if(space
&& size
<= left
) {
3682 pi2
->pComment
= (LPWSTR
)ptr
;
3689 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3691 if(space
&& size
<= left
) {
3692 pi2
->pLocation
= (LPWSTR
)ptr
;
3699 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3701 if(space
&& size
<= left
) {
3702 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3711 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3712 if(space
&& size
<= left
) {
3713 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3720 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3722 if(space
&& size
<= left
) {
3723 pi2
->pSepFile
= (LPWSTR
)ptr
;
3730 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3732 if(space
&& size
<= left
) {
3733 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3740 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3742 if(space
&& size
<= left
) {
3743 pi2
->pDatatype
= (LPWSTR
)ptr
;
3750 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3752 if(space
&& size
<= left
) {
3753 pi2
->pParameters
= (LPWSTR
)ptr
;
3761 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3762 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3763 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3764 "Default Priority");
3765 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3766 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3769 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3770 memset(pi2
, 0, sizeof(*pi2
));
3775 /*********************************************************************
3776 * WINSPOOL_GetPrinter_4
3778 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3780 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3781 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3784 DWORD size
, left
= cbBuf
;
3785 BOOL space
= (cbBuf
> 0);
3790 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3792 if(space
&& size
<= left
) {
3793 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3801 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3804 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3805 memset(pi4
, 0, sizeof(*pi4
));
3810 /*********************************************************************
3811 * WINSPOOL_GetPrinter_5
3813 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3815 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3816 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3819 DWORD size
, left
= cbBuf
;
3820 BOOL space
= (cbBuf
> 0);
3825 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3827 if(space
&& size
<= left
) {
3828 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3835 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3837 if(space
&& size
<= left
) {
3838 pi5
->pPortName
= (LPWSTR
)ptr
;
3846 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3847 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3849 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3853 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3854 memset(pi5
, 0, sizeof(*pi5
));
3859 /*****************************************************************************
3860 * WINSPOOL_GetPrinter
3862 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3863 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3864 * just a collection of pointers to strings.
3866 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3867 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3870 DWORD size
, needed
= 0;
3872 HKEY hkeyPrinter
, hkeyPrinters
;
3875 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3877 if (!(name
= get_opened_printer_name(hPrinter
))) {
3878 SetLastError(ERROR_INVALID_HANDLE
);
3882 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3884 ERR("Can't create Printers key\n");
3887 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3889 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3890 RegCloseKey(hkeyPrinters
);
3891 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3898 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3900 size
= sizeof(PRINTER_INFO_2W
);
3902 ptr
= pPrinter
+ size
;
3904 memset(pPrinter
, 0, size
);
3909 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
3917 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3919 size
= sizeof(PRINTER_INFO_4W
);
3921 ptr
= pPrinter
+ size
;
3923 memset(pPrinter
, 0, size
);
3928 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
3937 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3939 size
= sizeof(PRINTER_INFO_5W
);
3941 ptr
= pPrinter
+ size
;
3943 memset(pPrinter
, 0, size
);
3949 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
3956 FIXME("Unimplemented level %d\n", Level
);
3957 SetLastError(ERROR_INVALID_LEVEL
);
3958 RegCloseKey(hkeyPrinters
);
3959 RegCloseKey(hkeyPrinter
);
3963 RegCloseKey(hkeyPrinter
);
3964 RegCloseKey(hkeyPrinters
);
3966 TRACE("returning %d needed = %d\n", ret
, needed
);
3967 if(pcbNeeded
) *pcbNeeded
= needed
;
3969 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3973 /*****************************************************************************
3974 * GetPrinterW [WINSPOOL.@]
3976 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3977 DWORD cbBuf
, LPDWORD pcbNeeded
)
3979 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3983 /*****************************************************************************
3984 * GetPrinterA [WINSPOOL.@]
3986 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3987 DWORD cbBuf
, LPDWORD pcbNeeded
)
3989 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3993 /*****************************************************************************
3994 * WINSPOOL_EnumPrinters
3996 * Implementation of EnumPrintersA|W
3998 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
3999 DWORD dwLevel
, LPBYTE lpbPrinters
,
4000 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4001 LPDWORD lpdwReturned
, BOOL unicode
)
4004 HKEY hkeyPrinters
, hkeyPrinter
;
4005 WCHAR PrinterName
[255];
4006 DWORD needed
= 0, number
= 0;
4007 DWORD used
, i
, left
;
4011 memset(lpbPrinters
, 0, cbBuf
);
4017 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4018 if(dwType
== PRINTER_ENUM_DEFAULT
)
4021 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4022 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4023 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4025 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4033 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4034 FIXME("dwType = %08x\n", dwType
);
4035 SetLastError(ERROR_INVALID_FLAGS
);
4039 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4041 ERR("Can't create Printers key\n");
4045 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4046 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4047 RegCloseKey(hkeyPrinters
);
4048 ERR("Can't query Printers key\n");
4051 TRACE("Found %d printers\n", number
);
4055 used
= number
* sizeof(PRINTER_INFO_1W
);
4058 used
= number
* sizeof(PRINTER_INFO_2W
);
4061 used
= number
* sizeof(PRINTER_INFO_4W
);
4064 used
= number
* sizeof(PRINTER_INFO_5W
);
4068 SetLastError(ERROR_INVALID_LEVEL
);
4069 RegCloseKey(hkeyPrinters
);
4072 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4074 for(i
= 0; i
< number
; i
++) {
4075 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
4077 ERR("Can't enum key number %d\n", i
);
4078 RegCloseKey(hkeyPrinters
);
4081 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4082 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4084 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4085 RegCloseKey(hkeyPrinters
);
4090 buf
= lpbPrinters
+ used
;
4091 left
= cbBuf
- used
;
4099 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4100 left
, &needed
, unicode
);
4102 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4105 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4106 left
, &needed
, unicode
);
4108 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4111 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4112 left
, &needed
, unicode
);
4114 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4117 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4118 left
, &needed
, unicode
);
4120 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4123 ERR("Shouldn't be here!\n");
4124 RegCloseKey(hkeyPrinter
);
4125 RegCloseKey(hkeyPrinters
);
4128 RegCloseKey(hkeyPrinter
);
4130 RegCloseKey(hkeyPrinters
);
4137 memset(lpbPrinters
, 0, cbBuf
);
4138 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4142 *lpdwReturned
= number
;
4143 SetLastError(ERROR_SUCCESS
);
4148 /******************************************************************
4149 * EnumPrintersW [WINSPOOL.@]
4151 * Enumerates the available printers, print servers and print
4152 * providers, depending on the specified flags, name and level.
4156 * If level is set to 1:
4157 * Returns an array of PRINTER_INFO_1 data structures in the
4158 * lpbPrinters buffer.
4160 * If level is set to 2:
4161 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4162 * Returns an array of PRINTER_INFO_2 data structures in the
4163 * lpbPrinters buffer. Note that according to MSDN also an
4164 * OpenPrinter should be performed on every remote printer.
4166 * If level is set to 4 (officially WinNT only):
4167 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4168 * Fast: Only the registry is queried to retrieve printer names,
4169 * no connection to the driver is made.
4170 * Returns an array of PRINTER_INFO_4 data structures in the
4171 * lpbPrinters buffer.
4173 * If level is set to 5 (officially WinNT4/Win9x only):
4174 * Fast: Only the registry is queried to retrieve printer names,
4175 * no connection to the driver is made.
4176 * Returns an array of PRINTER_INFO_5 data structures in the
4177 * lpbPrinters buffer.
4179 * If level set to 3 or 6+:
4180 * returns zero (failure!)
4182 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4186 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4187 * - Only levels 2, 4 and 5 are implemented at the moment.
4188 * - 16-bit printer drivers are not enumerated.
4189 * - Returned amount of bytes used/needed does not match the real Windoze
4190 * implementation (as in this implementation, all strings are part
4191 * of the buffer, whereas Win32 keeps them somewhere else)
4192 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4195 * - In a regular Wine installation, no registry settings for printers
4196 * exist, which makes this function return an empty list.
4198 BOOL WINAPI
EnumPrintersW(
4199 DWORD dwType
, /* [in] Types of print objects to enumerate */
4200 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4201 DWORD dwLevel
, /* [in] type of printer info structure */
4202 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4203 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4204 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4205 LPDWORD lpdwReturned
/* [out] number of entries returned */
4208 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4209 lpdwNeeded
, lpdwReturned
, TRUE
);
4212 /******************************************************************
4213 * EnumPrintersA [WINSPOOL.@]
4216 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4217 DWORD dwLevel
, LPBYTE lpbPrinters
,
4218 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4219 LPDWORD lpdwReturned
)
4221 BOOL ret
, unicode
= FALSE
;
4222 UNICODE_STRING lpszNameW
;
4225 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4226 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4227 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4228 lpdwNeeded
, lpdwReturned
, unicode
);
4229 RtlFreeUnicodeString(&lpszNameW
);
4233 /*****************************************************************************
4234 * WINSPOOL_GetDriverInfoFromReg [internal]
4236 * Enters the information from the registry into the DRIVER_INFO struct
4239 * zero if the printer driver does not exist in the registry
4240 * (only if Level > 1) otherwise nonzero
4242 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4245 LPCWSTR pEnvironment
,
4247 LPBYTE ptr
, /* DRIVER_INFO */
4248 LPBYTE pDriverStrings
, /* strings buffer */
4249 DWORD cbBuf
, /* size of string buffer */
4250 LPDWORD pcbNeeded
, /* space needed for str. */
4251 BOOL unicode
) /* type of strings */
4255 LPBYTE strPtr
= pDriverStrings
;
4257 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4258 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
4259 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
4262 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4263 if (*pcbNeeded
<= cbBuf
)
4264 strcpyW((LPWSTR
)strPtr
, DriverName
);
4266 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
4268 if(*pcbNeeded
<= cbBuf
)
4269 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
4270 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4274 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
4278 ((PDRIVER_INFO_2W
) ptr
)->pName
= (LPWSTR
) strPtr
;
4279 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4282 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4283 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4284 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4289 ((PDRIVER_INFO_2A
) ptr
)->cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4292 pEnvironment
= DefaultEnvironmentW
;
4294 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
4296 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
4299 if(*pcbNeeded
<= cbBuf
) {
4301 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
4303 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
4304 (LPSTR
)strPtr
, size
, NULL
, NULL
);
4306 ((PDRIVER_INFO_2W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
4307 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4310 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
4313 if(*pcbNeeded
<= cbBuf
)
4314 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
4317 ((PDRIVER_INFO_2W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
4318 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4321 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
4324 if(*pcbNeeded
<= cbBuf
)
4325 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
4328 ((PDRIVER_INFO_2W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
4329 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4332 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4333 0, &size
, unicode
)) {
4335 if(*pcbNeeded
<= cbBuf
)
4336 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4337 size
, &tmp
, unicode
);
4339 ((PDRIVER_INFO_2W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
4340 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4344 RegCloseKey(hkeyDriver
);
4345 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4349 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
4352 if(*pcbNeeded
<= cbBuf
)
4353 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
4354 size
, &tmp
, unicode
);
4356 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
4357 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4360 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
4363 if(*pcbNeeded
<= cbBuf
)
4364 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
4365 size
, &tmp
, unicode
);
4367 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
4368 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4371 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
4374 if(*pcbNeeded
<= cbBuf
)
4375 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
4376 size
, &tmp
, unicode
);
4378 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
4379 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4382 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
4385 if(*pcbNeeded
<= cbBuf
)
4386 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
4387 size
, &tmp
, unicode
);
4389 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
4390 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4393 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4394 RegCloseKey(hkeyDriver
);
4398 /*****************************************************************************
4399 * WINSPOOL_GetPrinterDriver
4401 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4402 DWORD Level
, LPBYTE pDriverInfo
,
4403 DWORD cbBuf
, LPDWORD pcbNeeded
,
4407 WCHAR DriverName
[100];
4408 DWORD ret
, type
, size
, needed
= 0;
4410 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4412 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4413 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4415 ZeroMemory(pDriverInfo
, cbBuf
);
4417 if (!(name
= get_opened_printer_name(hPrinter
))) {
4418 SetLastError(ERROR_INVALID_HANDLE
);
4421 if(Level
< 1 || Level
> 6) {
4422 SetLastError(ERROR_INVALID_LEVEL
);
4425 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4427 ERR("Can't create Printers key\n");
4430 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4432 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4433 RegCloseKey(hkeyPrinters
);
4434 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4437 size
= sizeof(DriverName
);
4439 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4440 (LPBYTE
)DriverName
, &size
);
4441 RegCloseKey(hkeyPrinter
);
4442 RegCloseKey(hkeyPrinters
);
4443 if(ret
!= ERROR_SUCCESS
) {
4444 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4448 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4450 ERR("Can't create Drivers key\n");
4456 size
= sizeof(DRIVER_INFO_1W
);
4459 size
= sizeof(DRIVER_INFO_2W
);
4462 size
= sizeof(DRIVER_INFO_3W
);
4465 size
= sizeof(DRIVER_INFO_4W
);
4468 size
= sizeof(DRIVER_INFO_5W
);
4471 size
= sizeof(DRIVER_INFO_6W
);
4474 ERR("Invalid level\n");
4479 ptr
= pDriverInfo
+ size
;
4481 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4482 pEnvironment
, Level
, pDriverInfo
,
4483 (cbBuf
< size
) ? NULL
: ptr
,
4484 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4485 &needed
, unicode
)) {
4486 RegCloseKey(hkeyDrivers
);
4490 RegCloseKey(hkeyDrivers
);
4492 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4493 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4494 if(cbBuf
>= needed
) return TRUE
;
4495 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4499 /*****************************************************************************
4500 * GetPrinterDriverA [WINSPOOL.@]
4502 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4503 DWORD Level
, LPBYTE pDriverInfo
,
4504 DWORD cbBuf
, LPDWORD pcbNeeded
)
4507 UNICODE_STRING pEnvW
;
4510 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4511 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4512 cbBuf
, pcbNeeded
, FALSE
);
4513 RtlFreeUnicodeString(&pEnvW
);
4516 /*****************************************************************************
4517 * GetPrinterDriverW [WINSPOOL.@]
4519 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4520 DWORD Level
, LPBYTE pDriverInfo
,
4521 DWORD cbBuf
, LPDWORD pcbNeeded
)
4523 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4524 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4527 /*****************************************************************************
4528 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4530 * Return the PATH for the Printer-Drivers (UNICODE)
4533 * pName [I] Servername (NT only) or NULL (local Computer)
4534 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4535 * Level [I] Structure-Level (must be 1)
4536 * pDriverDirectory [O] PTR to Buffer that receives the Result
4537 * cbBuf [I] Size of Buffer at pDriverDirectory
4538 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4539 * required for pDriverDirectory
4542 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4543 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4544 * if cbBuf is too small
4546 * Native Values returned in pDriverDirectory on Success:
4547 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4548 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4549 *| win9x(Windows 4.0): "%winsysdir%"
4551 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4554 *- Only NULL or "" is supported for pName
4557 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4558 DWORD Level
, LPBYTE pDriverDirectory
,
4559 DWORD cbBuf
, LPDWORD pcbNeeded
)
4562 const printenv_t
* env
;
4564 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4565 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4566 if(pName
!= NULL
&& pName
[0]) {
4567 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
4568 SetLastError(ERROR_INVALID_PARAMETER
);
4572 env
= validate_envW(pEnvironment
);
4573 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
4576 WARN("(Level: %d) is ignored in win9x\n", Level
);
4577 SetLastError(ERROR_INVALID_LEVEL
);
4581 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4582 needed
= GetSystemDirectoryW(NULL
, 0);
4583 /* add the Size for the Subdirectories */
4584 needed
+= lstrlenW(spooldriversW
);
4585 needed
+= lstrlenW(env
->subdir
);
4586 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
4589 *pcbNeeded
= needed
;
4590 TRACE("required: 0x%x/%d\n", needed
, needed
);
4591 if(needed
> cbBuf
) {
4592 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4595 if(pcbNeeded
== NULL
) {
4596 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4597 SetLastError(RPC_X_NULL_REF_POINTER
);
4600 if(pDriverDirectory
== NULL
) {
4601 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4602 SetLastError(ERROR_INVALID_USER_BUFFER
);
4606 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
4607 /* add the Subdirectories */
4608 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
4609 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
4610 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
4615 /*****************************************************************************
4616 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4618 * Return the PATH for the Printer-Drivers (ANSI)
4620 * See GetPrinterDriverDirectoryW.
4623 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4626 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4627 DWORD Level
, LPBYTE pDriverDirectory
,
4628 DWORD cbBuf
, LPDWORD pcbNeeded
)
4630 UNICODE_STRING nameW
, environmentW
;
4633 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4634 WCHAR
*driverDirectoryW
= NULL
;
4636 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4637 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4639 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4641 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4642 else nameW
.Buffer
= NULL
;
4643 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4644 else environmentW
.Buffer
= NULL
;
4646 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4647 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4650 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4651 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4653 *pcbNeeded
= needed
;
4654 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4656 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4658 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4660 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4661 RtlFreeUnicodeString(&environmentW
);
4662 RtlFreeUnicodeString(&nameW
);
4667 /*****************************************************************************
4668 * AddPrinterDriverA [WINSPOOL.@]
4670 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4673 HKEY hkeyDrivers
, hkeyName
;
4674 static CHAR empty
[] = "",
4677 TRACE("(%s,%d,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
4679 if(level
!= 2 && level
!= 3) {
4680 SetLastError(ERROR_INVALID_LEVEL
);
4683 if ((pName
) && (pName
[0])) {
4684 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
4685 SetLastError(ERROR_INVALID_PARAMETER
);
4689 WARN("pDriverInfo == NULL\n");
4690 SetLastError(ERROR_INVALID_PARAMETER
);
4695 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
4697 memset(&di3
, 0, sizeof(di3
));
4698 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
4701 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
4703 SetLastError(ERROR_INVALID_PARAMETER
);
4707 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= empty
;
4708 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= nullnull
;
4709 if(!di3
.pHelpFile
) di3
.pHelpFile
= empty
;
4710 if(!di3
.pMonitorName
) di3
.pMonitorName
= empty
;
4712 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
4715 ERR("Can't create Drivers key\n");
4719 if(level
== 2) { /* apparently can't overwrite with level2 */
4720 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
4721 RegCloseKey(hkeyName
);
4722 RegCloseKey(hkeyDrivers
);
4723 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
4724 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
4728 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
4729 RegCloseKey(hkeyDrivers
);
4730 ERR("Can't create Name key\n");
4733 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
4734 lstrlenA(di3
.pConfigFile
) + 1);
4735 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, lstrlenA(di3
.pDataFile
) + 1);
4736 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, lstrlenA(di3
.pDriverPath
) + 1);
4737 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
4739 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, lstrlenA(di3
.pDefaultDataType
));
4740 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
4741 (LPBYTE
) di3
.pDependentFiles
, multi_sz_lenA(di3
.pDependentFiles
));
4742 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, lstrlenA(di3
.pHelpFile
) + 1);
4743 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, lstrlenA(di3
.pMonitorName
) + 1);
4744 RegCloseKey(hkeyName
);
4745 RegCloseKey(hkeyDrivers
);
4750 /*****************************************************************************
4751 * AddPrinterDriverW [WINSPOOL.@]
4753 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
4756 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName
),
4761 /*****************************************************************************
4762 * AddPrintProcessorA [WINSPOOL.@]
4764 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4765 LPSTR pPrintProcessorName
)
4767 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4768 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4772 /*****************************************************************************
4773 * AddPrintProcessorW [WINSPOOL.@]
4775 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4776 LPWSTR pPrintProcessorName
)
4778 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4779 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4783 /*****************************************************************************
4784 * AddPrintProvidorA [WINSPOOL.@]
4786 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4788 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4792 /*****************************************************************************
4793 * AddPrintProvidorW [WINSPOOL.@]
4795 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4797 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4801 /*****************************************************************************
4802 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4804 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4805 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4807 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4808 pDevModeOutput
, pDevModeInput
);
4812 /*****************************************************************************
4813 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4815 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4816 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4818 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4819 pDevModeOutput
, pDevModeInput
);
4823 /*****************************************************************************
4824 * PrinterProperties [WINSPOOL.@]
4826 * Displays a dialog to set the properties of the printer.
4829 * nonzero on success or zero on failure
4832 * implemented as stub only
4834 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4835 HANDLE hPrinter
/* [in] handle to printer object */
4837 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4838 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4842 /*****************************************************************************
4843 * EnumJobsA [WINSPOOL.@]
4846 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4847 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4850 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4851 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4853 if(pcbNeeded
) *pcbNeeded
= 0;
4854 if(pcReturned
) *pcReturned
= 0;
4859 /*****************************************************************************
4860 * EnumJobsW [WINSPOOL.@]
4863 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4864 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4867 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4868 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4870 if(pcbNeeded
) *pcbNeeded
= 0;
4871 if(pcReturned
) *pcReturned
= 0;
4875 /*****************************************************************************
4876 * WINSPOOL_EnumPrinterDrivers [internal]
4878 * Delivers information about all printer drivers installed on the
4879 * localhost or a given server
4882 * nonzero on success or zero on failure. If the buffer for the returned
4883 * information is too small the function will return an error
4886 * - only implemented for localhost, foreign hosts will return an error
4888 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4889 DWORD Level
, LPBYTE pDriverInfo
,
4890 DWORD cbBuf
, LPDWORD pcbNeeded
,
4891 LPDWORD pcReturned
, BOOL unicode
)
4894 DWORD i
, needed
, number
= 0, size
= 0;
4895 WCHAR DriverNameW
[255];
4898 TRACE("%s,%s,%d,%p,%d,%d\n",
4899 debugstr_w(pName
), debugstr_w(pEnvironment
),
4900 Level
, pDriverInfo
, cbBuf
, unicode
);
4902 /* check for local drivers */
4903 if((pName
) && (pName
[0])) {
4904 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4905 SetLastError(ERROR_ACCESS_DENIED
);
4909 /* check input parameter */
4910 if((Level
< 1) || (Level
> 3)) {
4911 ERR("unsupported level %d\n", Level
);
4912 SetLastError(ERROR_INVALID_LEVEL
);
4916 /* initialize return values */
4918 memset( pDriverInfo
, 0, cbBuf
);
4922 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
4924 ERR("Can't open Drivers key\n");
4928 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4929 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4930 RegCloseKey(hkeyDrivers
);
4931 ERR("Can't query Drivers key\n");
4934 TRACE("Found %d Drivers\n", number
);
4936 /* get size of single struct
4937 * unicode and ascii structure have the same size
4941 size
= sizeof(DRIVER_INFO_1A
);
4944 size
= sizeof(DRIVER_INFO_2A
);
4947 size
= sizeof(DRIVER_INFO_3A
);
4951 /* calculate required buffer size */
4952 *pcbNeeded
= size
* number
;
4954 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
4956 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
4957 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
4959 ERR("Can't enum key number %d\n", i
);
4960 RegCloseKey(hkeyDrivers
);
4963 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4964 pEnvironment
, Level
, ptr
,
4965 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
4966 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4967 &needed
, unicode
)) {
4968 RegCloseKey(hkeyDrivers
);
4971 (*pcbNeeded
) += needed
;
4974 RegCloseKey(hkeyDrivers
);
4976 if(cbBuf
< *pcbNeeded
){
4977 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4981 *pcReturned
= number
;
4985 /*****************************************************************************
4986 * EnumPrinterDriversW [WINSPOOL.@]
4988 * see function EnumPrinterDrivers for RETURNS, BUGS
4990 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4991 LPBYTE pDriverInfo
, DWORD cbBuf
,
4992 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4994 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4995 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
4998 /*****************************************************************************
4999 * EnumPrinterDriversA [WINSPOOL.@]
5001 * see function EnumPrinterDrivers for RETURNS, BUGS
5003 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5004 LPBYTE pDriverInfo
, DWORD cbBuf
,
5005 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5007 UNICODE_STRING pNameW
, pEnvironmentW
;
5008 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5010 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5011 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5013 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5014 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5016 RtlFreeUnicodeString(&pNameW
);
5017 RtlFreeUnicodeString(&pEnvironmentW
);
5022 /******************************************************************************
5023 * EnumPortsA (WINSPOOL.@)
5028 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5029 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5032 LPBYTE bufferW
= NULL
;
5033 LPWSTR nameW
= NULL
;
5035 DWORD numentries
= 0;
5038 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5039 cbBuf
, pcbNeeded
, pcReturned
);
5041 /* convert servername to unicode */
5043 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5044 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5045 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5047 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5048 needed
= cbBuf
* sizeof(WCHAR
);
5049 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5050 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5052 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5053 if (pcbNeeded
) needed
= *pcbNeeded
;
5054 /* HeapReAlloc return NULL, when bufferW was NULL */
5055 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5056 HeapAlloc(GetProcessHeap(), 0, needed
);
5058 /* Try again with the large Buffer */
5059 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5061 needed
= pcbNeeded
? *pcbNeeded
: 0;
5062 numentries
= pcReturned
? *pcReturned
: 0;
5065 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5066 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5069 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5070 DWORD entrysize
= 0;
5073 LPPORT_INFO_2W pi2w
;
5074 LPPORT_INFO_2A pi2a
;
5077 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5079 /* First pass: calculate the size for all Entries */
5080 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5081 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5083 while (index
< numentries
) {
5085 needed
+= entrysize
; /* PORT_INFO_?A */
5086 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5088 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5089 NULL
, 0, NULL
, NULL
);
5091 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5092 NULL
, 0, NULL
, NULL
);
5093 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5094 NULL
, 0, NULL
, NULL
);
5096 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5097 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5098 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5101 /* check for errors and quit on failure */
5102 if (cbBuf
< needed
) {
5103 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5107 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5108 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5109 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5110 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5111 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5113 /* Second Pass: Fill the User Buffer (if we have one) */
5114 while ((index
< numentries
) && pPorts
) {
5116 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5117 pi2a
->pPortName
= ptr
;
5118 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5119 ptr
, cbBuf
, NULL
, NULL
);
5123 pi2a
->pMonitorName
= ptr
;
5124 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5125 ptr
, cbBuf
, NULL
, NULL
);
5129 pi2a
->pDescription
= ptr
;
5130 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5131 ptr
, cbBuf
, NULL
, NULL
);
5135 pi2a
->fPortType
= pi2w
->fPortType
;
5136 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5139 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5140 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5141 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5146 if (pcbNeeded
) *pcbNeeded
= needed
;
5147 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5149 HeapFree(GetProcessHeap(), 0, nameW
);
5150 HeapFree(GetProcessHeap(), 0, bufferW
);
5152 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5153 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5159 /******************************************************************************
5160 * EnumPortsW (WINSPOOL.@)
5162 * Enumerate available Ports
5165 * name [I] Servername or NULL (local Computer)
5166 * level [I] Structure-Level (1 or 2)
5167 * buffer [O] PTR to Buffer that receives the Result
5168 * bufsize [I] Size of Buffer at buffer
5169 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5170 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5174 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5178 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5181 DWORD numentries
= 0;
5184 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5185 cbBuf
, pcbNeeded
, pcReturned
);
5187 if (pName
&& (pName
[0])) {
5188 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5189 SetLastError(ERROR_ACCESS_DENIED
);
5193 /* Level is not checked in win9x */
5194 if (!Level
|| (Level
> 2)) {
5195 WARN("level (%d) is ignored in win9x\n", Level
);
5196 SetLastError(ERROR_INVALID_LEVEL
);
5200 SetLastError(RPC_X_NULL_REF_POINTER
);
5204 EnterCriticalSection(&monitor_handles_cs
);
5207 /* Scan all local Ports */
5209 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5211 /* we calculated the needed buffersize. now do the error-checks */
5212 if (cbBuf
< needed
) {
5213 monitor_unloadall();
5214 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5215 goto emP_cleanup_cs
;
5217 else if (!pPorts
|| !pcReturned
) {
5218 monitor_unloadall();
5219 SetLastError(RPC_X_NULL_REF_POINTER
);
5220 goto emP_cleanup_cs
;
5223 /* Fill the Buffer */
5224 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5226 monitor_unloadall();
5229 LeaveCriticalSection(&monitor_handles_cs
);
5232 if (pcbNeeded
) *pcbNeeded
= needed
;
5233 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5235 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5236 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5241 /******************************************************************************
5242 * GetDefaultPrinterW (WINSPOOL.@)
5245 * This function must read the value from data 'device' of key
5246 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5248 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5252 WCHAR
*buffer
, *ptr
;
5256 SetLastError(ERROR_INVALID_PARAMETER
);
5260 /* make the buffer big enough for the stuff from the profile/registry,
5261 * the content must fit into the local buffer to compute the correct
5262 * size even if the extern buffer is too small or not given.
5263 * (20 for ,driver,port) */
5265 len
= max(100, (insize
+ 20));
5266 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5268 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5270 SetLastError (ERROR_FILE_NOT_FOUND
);
5274 TRACE("%s\n", debugstr_w(buffer
));
5276 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5278 SetLastError(ERROR_INVALID_NAME
);
5284 *namesize
= strlenW(buffer
) + 1;
5285 if(!name
|| (*namesize
> insize
))
5287 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5291 strcpyW(name
, buffer
);
5294 HeapFree( GetProcessHeap(), 0, buffer
);
5299 /******************************************************************************
5300 * GetDefaultPrinterA (WINSPOOL.@)
5302 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5306 WCHAR
*bufferW
= NULL
;
5310 SetLastError(ERROR_INVALID_PARAMETER
);
5314 if(name
&& *namesize
) {
5316 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5319 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5324 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5328 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5331 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5334 HeapFree( GetProcessHeap(), 0, bufferW
);
5339 /******************************************************************************
5340 * SetDefaultPrinterW (WINSPOOL.204)
5342 * Set the Name of the Default Printer
5345 * pszPrinter [I] Name of the Printer or NULL
5352 * When the Parameter is NULL or points to an Empty String and
5353 * a Default Printer was already present, then this Function changes nothing.
5354 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5355 * the First enumerated local Printer is used.
5358 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5361 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5363 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5367 /******************************************************************************
5368 * SetDefaultPrinterA (WINSPOOL.202)
5370 * See SetDefaultPrinterW.
5373 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5376 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5378 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5383 /******************************************************************************
5384 * SetPrinterDataExA (WINSPOOL.@)
5386 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5387 LPCSTR pValueName
, DWORD Type
,
5388 LPBYTE pData
, DWORD cbData
)
5390 HKEY hkeyPrinter
, hkeySubkey
;
5393 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5394 debugstr_a(pValueName
), Type
, pData
, cbData
);
5396 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5400 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5402 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5403 RegCloseKey(hkeyPrinter
);
5406 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5407 RegCloseKey(hkeySubkey
);
5408 RegCloseKey(hkeyPrinter
);
5412 /******************************************************************************
5413 * SetPrinterDataExW (WINSPOOL.@)
5415 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5416 LPCWSTR pValueName
, DWORD Type
,
5417 LPBYTE pData
, DWORD cbData
)
5419 HKEY hkeyPrinter
, hkeySubkey
;
5422 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5423 debugstr_w(pValueName
), Type
, pData
, cbData
);
5425 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5429 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5431 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5432 RegCloseKey(hkeyPrinter
);
5435 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5436 RegCloseKey(hkeySubkey
);
5437 RegCloseKey(hkeyPrinter
);
5441 /******************************************************************************
5442 * SetPrinterDataA (WINSPOOL.@)
5444 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5445 LPBYTE pData
, DWORD cbData
)
5447 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5451 /******************************************************************************
5452 * SetPrinterDataW (WINSPOOL.@)
5454 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5455 LPBYTE pData
, DWORD cbData
)
5457 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5461 /******************************************************************************
5462 * GetPrinterDataExA (WINSPOOL.@)
5464 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5465 LPCSTR pValueName
, LPDWORD pType
,
5466 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5468 HKEY hkeyPrinter
, hkeySubkey
;
5471 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5472 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5475 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5479 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5481 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5482 RegCloseKey(hkeyPrinter
);
5486 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5487 RegCloseKey(hkeySubkey
);
5488 RegCloseKey(hkeyPrinter
);
5492 /******************************************************************************
5493 * GetPrinterDataExW (WINSPOOL.@)
5495 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5496 LPCWSTR pValueName
, LPDWORD pType
,
5497 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5499 HKEY hkeyPrinter
, hkeySubkey
;
5502 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5503 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5506 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5510 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5512 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5513 RegCloseKey(hkeyPrinter
);
5517 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5518 RegCloseKey(hkeySubkey
);
5519 RegCloseKey(hkeyPrinter
);
5523 /******************************************************************************
5524 * GetPrinterDataA (WINSPOOL.@)
5526 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5527 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5529 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5530 pData
, nSize
, pcbNeeded
);
5533 /******************************************************************************
5534 * GetPrinterDataW (WINSPOOL.@)
5536 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5537 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5539 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5540 pData
, nSize
, pcbNeeded
);
5543 /*******************************************************************************
5544 * EnumPrinterDataExW [WINSPOOL.@]
5546 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5547 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5548 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5550 HKEY hkPrinter
, hkSubKey
;
5551 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5552 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5557 PPRINTER_ENUM_VALUESW ppev
;
5559 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5561 if (pKeyName
== NULL
|| *pKeyName
== 0)
5562 return ERROR_INVALID_PARAMETER
;
5564 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5565 if (ret
!= ERROR_SUCCESS
)
5567 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5572 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5573 if (ret
!= ERROR_SUCCESS
)
5575 r
= RegCloseKey (hkPrinter
);
5576 if (r
!= ERROR_SUCCESS
)
5577 WARN ("RegCloseKey returned %i\n", r
);
5578 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5579 debugstr_w (pKeyName
), ret
);
5583 ret
= RegCloseKey (hkPrinter
);
5584 if (ret
!= ERROR_SUCCESS
)
5586 ERR ("RegCloseKey returned %i\n", ret
);
5587 r
= RegCloseKey (hkSubKey
);
5588 if (r
!= ERROR_SUCCESS
)
5589 WARN ("RegCloseKey returned %i\n", r
);
5593 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5594 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5595 if (ret
!= ERROR_SUCCESS
)
5597 r
= RegCloseKey (hkSubKey
);
5598 if (r
!= ERROR_SUCCESS
)
5599 WARN ("RegCloseKey returned %i\n", r
);
5600 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5604 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5605 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5607 if (cValues
== 0) /* empty key */
5609 r
= RegCloseKey (hkSubKey
);
5610 if (r
!= ERROR_SUCCESS
)
5611 WARN ("RegCloseKey returned %i\n", r
);
5612 *pcbEnumValues
= *pnEnumValues
= 0;
5613 return ERROR_SUCCESS
;
5616 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5618 hHeap
= GetProcessHeap ();
5621 ERR ("GetProcessHeap failed\n");
5622 r
= RegCloseKey (hkSubKey
);
5623 if (r
!= ERROR_SUCCESS
)
5624 WARN ("RegCloseKey returned %i\n", r
);
5625 return ERROR_OUTOFMEMORY
;
5628 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5629 if (lpValueName
== NULL
)
5631 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5632 r
= RegCloseKey (hkSubKey
);
5633 if (r
!= ERROR_SUCCESS
)
5634 WARN ("RegCloseKey returned %i\n", r
);
5635 return ERROR_OUTOFMEMORY
;
5638 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5639 if (lpValue
== NULL
)
5641 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5642 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5643 WARN ("HeapFree failed with code %i\n", GetLastError ());
5644 r
= RegCloseKey (hkSubKey
);
5645 if (r
!= ERROR_SUCCESS
)
5646 WARN ("RegCloseKey returned %i\n", r
);
5647 return ERROR_OUTOFMEMORY
;
5650 TRACE ("pass 1: calculating buffer required for all names and values\n");
5652 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5654 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5656 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5658 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5659 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5660 NULL
, NULL
, lpValue
, &cbValueLen
);
5661 if (ret
!= ERROR_SUCCESS
)
5663 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5664 WARN ("HeapFree failed with code %i\n", GetLastError ());
5665 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5666 WARN ("HeapFree failed with code %i\n", GetLastError ());
5667 r
= RegCloseKey (hkSubKey
);
5668 if (r
!= ERROR_SUCCESS
)
5669 WARN ("RegCloseKey returned %i\n", r
);
5670 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5674 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5675 debugstr_w (lpValueName
), dwIndex
,
5676 cbValueNameLen
+ 1, cbValueLen
);
5678 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5679 cbBufSize
+= cbValueLen
;
5682 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5684 *pcbEnumValues
= cbBufSize
;
5685 *pnEnumValues
= cValues
;
5687 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5689 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5690 WARN ("HeapFree failed with code %i\n", GetLastError ());
5691 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5692 WARN ("HeapFree failed with code %i\n", GetLastError ());
5693 r
= RegCloseKey (hkSubKey
);
5694 if (r
!= ERROR_SUCCESS
)
5695 WARN ("RegCloseKey returned %i\n", r
);
5696 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5697 return ERROR_MORE_DATA
;
5700 TRACE ("pass 2: copying all names and values to buffer\n");
5702 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5703 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5705 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5707 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5708 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5709 NULL
, &dwType
, lpValue
, &cbValueLen
);
5710 if (ret
!= ERROR_SUCCESS
)
5712 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5713 WARN ("HeapFree failed with code %i\n", GetLastError ());
5714 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5715 WARN ("HeapFree failed with code %i\n", GetLastError ());
5716 r
= RegCloseKey (hkSubKey
);
5717 if (r
!= ERROR_SUCCESS
)
5718 WARN ("RegCloseKey returned %i\n", r
);
5719 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5723 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5724 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5725 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5726 pEnumValues
+= cbValueNameLen
;
5728 /* return # of *bytes* (including trailing \0), not # of chars */
5729 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5731 ppev
[dwIndex
].dwType
= dwType
;
5733 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5734 ppev
[dwIndex
].pData
= pEnumValues
;
5735 pEnumValues
+= cbValueLen
;
5737 ppev
[dwIndex
].cbData
= cbValueLen
;
5739 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5740 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5743 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5745 ret
= GetLastError ();
5746 ERR ("HeapFree failed with code %i\n", ret
);
5747 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5748 WARN ("HeapFree failed with code %i\n", GetLastError ());
5749 r
= RegCloseKey (hkSubKey
);
5750 if (r
!= ERROR_SUCCESS
)
5751 WARN ("RegCloseKey returned %i\n", r
);
5755 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5757 ret
= GetLastError ();
5758 ERR ("HeapFree failed with code %i\n", ret
);
5759 r
= RegCloseKey (hkSubKey
);
5760 if (r
!= ERROR_SUCCESS
)
5761 WARN ("RegCloseKey returned %i\n", r
);
5765 ret
= RegCloseKey (hkSubKey
);
5766 if (ret
!= ERROR_SUCCESS
)
5768 ERR ("RegCloseKey returned %i\n", ret
);
5772 return ERROR_SUCCESS
;
5775 /*******************************************************************************
5776 * EnumPrinterDataExA [WINSPOOL.@]
5778 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5779 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5780 * what Windows 2000 SP1 does.
5783 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5784 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5785 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5789 DWORD ret
, dwIndex
, dwBufSize
;
5793 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5795 if (pKeyName
== NULL
|| *pKeyName
== 0)
5796 return ERROR_INVALID_PARAMETER
;
5798 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5801 ret
= GetLastError ();
5802 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5806 hHeap
= GetProcessHeap ();
5809 ERR ("GetProcessHeap failed\n");
5810 return ERROR_OUTOFMEMORY
;
5813 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5814 if (pKeyNameW
== NULL
)
5816 ERR ("Failed to allocate %i bytes from process heap\n",
5817 (LONG
)(len
* sizeof (WCHAR
)));
5818 return ERROR_OUTOFMEMORY
;
5821 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5823 ret
= GetLastError ();
5824 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5825 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5826 WARN ("HeapFree failed with code %i\n", GetLastError ());
5830 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5831 pcbEnumValues
, pnEnumValues
);
5832 if (ret
!= ERROR_SUCCESS
)
5834 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5835 WARN ("HeapFree failed with code %i\n", GetLastError ());
5836 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5840 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5842 ret
= GetLastError ();
5843 ERR ("HeapFree failed with code %i\n", ret
);
5847 if (*pnEnumValues
== 0) /* empty key */
5848 return ERROR_SUCCESS
;
5851 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5853 PPRINTER_ENUM_VALUESW ppev
=
5854 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5856 if (dwBufSize
< ppev
->cbValueName
)
5857 dwBufSize
= ppev
->cbValueName
;
5859 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5860 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5861 dwBufSize
= ppev
->cbData
;
5864 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5866 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5867 if (pBuffer
== NULL
)
5869 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5870 return ERROR_OUTOFMEMORY
;
5873 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5875 PPRINTER_ENUM_VALUESW ppev
=
5876 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5878 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5879 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5883 ret
= GetLastError ();
5884 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5885 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5886 WARN ("HeapFree failed with code %i\n", GetLastError ());
5890 memcpy (ppev
->pValueName
, pBuffer
, len
);
5892 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5894 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5895 ppev
->dwType
!= REG_MULTI_SZ
)
5898 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5899 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5902 ret
= GetLastError ();
5903 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5904 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5905 WARN ("HeapFree failed with code %i\n", GetLastError ());
5909 memcpy (ppev
->pData
, pBuffer
, len
);
5911 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5912 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5915 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5917 ret
= GetLastError ();
5918 ERR ("HeapFree failed with code %i\n", ret
);
5922 return ERROR_SUCCESS
;
5925 /******************************************************************************
5926 * AbortPrinter (WINSPOOL.@)
5928 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5930 FIXME("(%p), stub!\n", hPrinter
);
5934 /******************************************************************************
5935 * AddPortA (WINSPOOL.@)
5940 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5942 LPWSTR nameW
= NULL
;
5943 LPWSTR monitorW
= NULL
;
5947 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
5950 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5951 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5952 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5956 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5957 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5958 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5960 res
= AddPortW(nameW
, hWnd
, monitorW
);
5961 HeapFree(GetProcessHeap(), 0, nameW
);
5962 HeapFree(GetProcessHeap(), 0, monitorW
);
5966 /******************************************************************************
5967 * AddPortW (WINSPOOL.@)
5969 * Add a Port for a specific Monitor
5972 * pName [I] Servername or NULL (local Computer)
5973 * hWnd [I] Handle to parent Window for the Dialog-Box
5974 * pMonitorName [I] Name of the Monitor that manage the Port
5981 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
5987 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
5989 if (pName
&& pName
[0]) {
5990 SetLastError(ERROR_INVALID_PARAMETER
);
5994 if (!pMonitorName
) {
5995 SetLastError(RPC_X_NULL_REF_POINTER
);
5999 /* an empty Monitorname is Invalid */
6000 if (!pMonitorName
[0]) {
6001 SetLastError(ERROR_NOT_SUPPORTED
);
6005 pm
= monitor_load(pMonitorName
, NULL
);
6006 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6007 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6008 TRACE("got %d with %u\n", res
, GetLastError());
6013 pui
= monitor_loadui(pm
);
6014 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6015 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6016 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6017 TRACE("got %d with %u\n", res
, GetLastError());
6022 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6023 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6025 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6026 SetLastError(ERROR_NOT_SUPPORTED
);
6029 monitor_unload(pui
);
6032 TRACE("returning %d with %u\n", res
, GetLastError());
6036 /******************************************************************************
6037 * AddPortExA (WINSPOOL.@)
6042 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6045 PORT_INFO_2A
* pi2A
;
6046 LPWSTR nameW
= NULL
;
6047 LPWSTR monitorW
= NULL
;
6051 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6053 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6054 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6056 if ((level
< 1) || (level
> 2)) {
6057 SetLastError(ERROR_INVALID_LEVEL
);
6062 SetLastError(ERROR_INVALID_PARAMETER
);
6067 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6068 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6069 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6073 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6074 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6075 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6078 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6080 if (pi2A
->pPortName
) {
6081 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6082 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6083 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6087 if (pi2A
->pMonitorName
) {
6088 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6089 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6090 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6093 if (pi2A
->pDescription
) {
6094 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6095 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6096 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6098 pi2W
.fPortType
= pi2A
->fPortType
;
6099 pi2W
.Reserved
= pi2A
->Reserved
;
6102 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6104 HeapFree(GetProcessHeap(), 0, nameW
);
6105 HeapFree(GetProcessHeap(), 0, monitorW
);
6106 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6107 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6108 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6113 /******************************************************************************
6114 * AddPortExW (WINSPOOL.@)
6116 * Add a Port for a specific Monitor, without presenting a user interface
6119 * pName [I] Servername or NULL (local Computer)
6120 * level [I] Structure-Level (1 or 2) for pBuffer
6121 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6122 * pMonitorName [I] Name of the Monitor that manage the Port
6129 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6135 pi2
= (PORT_INFO_2W
*) pBuffer
;
6137 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6138 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6139 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6140 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6143 if ((level
< 1) || (level
> 2)) {
6144 SetLastError(ERROR_INVALID_LEVEL
);
6149 SetLastError(ERROR_INVALID_PARAMETER
);
6153 /* we need a valid Monitorname */
6154 if (!pMonitorName
) {
6155 SetLastError(RPC_X_NULL_REF_POINTER
);
6158 if (!pMonitorName
[0]) {
6159 SetLastError(ERROR_NOT_SUPPORTED
);
6163 /* load the Monitor */
6164 pm
= monitor_load(pMonitorName
, NULL
);
6165 if (!pm
) return FALSE
;
6167 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6168 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6169 TRACE("got %u with %u\n", res
, GetLastError());
6175 /******************************************************************************
6176 * AddPrinterConnectionA (WINSPOOL.@)
6178 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6180 FIXME("%s\n", debugstr_a(pName
));
6184 /******************************************************************************
6185 * AddPrinterConnectionW (WINSPOOL.@)
6187 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6189 FIXME("%s\n", debugstr_w(pName
));
6193 /******************************************************************************
6194 * AddPrinterDriverExW (WINSPOOL.@)
6196 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
6197 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6199 FIXME("%s %d %p %d\n", debugstr_w(pName
),
6200 Level
, pDriverInfo
, dwFileCopyFlags
);
6201 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6205 /******************************************************************************
6206 * AddPrinterDriverExA (WINSPOOL.@)
6208 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
6209 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6211 FIXME("%s %d %p %d\n", debugstr_a(pName
),
6212 Level
, pDriverInfo
, dwFileCopyFlags
);
6213 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6217 /******************************************************************************
6218 * ConfigurePortA (WINSPOOL.@)
6220 * See ConfigurePortW.
6223 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6225 LPWSTR nameW
= NULL
;
6226 LPWSTR portW
= NULL
;
6230 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6232 /* convert servername to unicode */
6234 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6235 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6236 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6239 /* convert portname to unicode */
6241 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6242 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6243 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6246 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6247 HeapFree(GetProcessHeap(), 0, nameW
);
6248 HeapFree(GetProcessHeap(), 0, portW
);
6252 /******************************************************************************
6253 * ConfigurePortW (WINSPOOL.@)
6255 * Display the Configuration-Dialog for a specific Port
6258 * pName [I] Servername or NULL (local Computer)
6259 * hWnd [I] Handle to parent Window for the Dialog-Box
6260 * pPortName [I] Name of the Port, that should be configured
6267 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6273 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6275 if (pName
&& pName
[0]) {
6276 SetLastError(ERROR_INVALID_PARAMETER
);
6281 SetLastError(RPC_X_NULL_REF_POINTER
);
6285 /* an empty Portname is Invalid, but can popup a Dialog */
6286 if (!pPortName
[0]) {
6287 SetLastError(ERROR_NOT_SUPPORTED
);
6291 pm
= monitor_load_by_port(pPortName
);
6292 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6293 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6294 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6295 TRACE("got %d with %u\n", res
, GetLastError());
6299 pui
= monitor_loadui(pm
);
6300 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6301 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6302 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6303 TRACE("got %d with %u\n", res
, GetLastError());
6307 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6308 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6310 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6311 SetLastError(ERROR_NOT_SUPPORTED
);
6314 monitor_unload(pui
);
6318 TRACE("returning %d with %u\n", res
, GetLastError());
6322 /******************************************************************************
6323 * ConnectToPrinterDlg (WINSPOOL.@)
6325 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6327 FIXME("%p %x\n", hWnd
, Flags
);
6331 /******************************************************************************
6332 * DeletePrinterConnectionA (WINSPOOL.@)
6334 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6336 FIXME("%s\n", debugstr_a(pName
));
6340 /******************************************************************************
6341 * DeletePrinterConnectionW (WINSPOOL.@)
6343 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6345 FIXME("%s\n", debugstr_w(pName
));
6349 /******************************************************************************
6350 * DeletePrinterDriverExW (WINSPOOL.@)
6352 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6353 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6358 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6359 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6361 if(pName
&& pName
[0])
6363 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6364 SetLastError(ERROR_INVALID_PARAMETER
);
6370 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6371 SetLastError(ERROR_INVALID_PARAMETER
);
6375 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6379 ERR("Can't open drivers key\n");
6383 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6386 RegCloseKey(hkey_drivers
);
6391 /******************************************************************************
6392 * DeletePrinterDriverExA (WINSPOOL.@)
6394 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6395 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6397 UNICODE_STRING NameW
, EnvW
, DriverW
;
6400 asciitounicode(&NameW
, pName
);
6401 asciitounicode(&EnvW
, pEnvironment
);
6402 asciitounicode(&DriverW
, pDriverName
);
6404 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6406 RtlFreeUnicodeString(&DriverW
);
6407 RtlFreeUnicodeString(&EnvW
);
6408 RtlFreeUnicodeString(&NameW
);
6413 /******************************************************************************
6414 * DeletePrinterDataExW (WINSPOOL.@)
6416 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6419 FIXME("%p %s %s\n", hPrinter
,
6420 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6421 return ERROR_INVALID_PARAMETER
;
6424 /******************************************************************************
6425 * DeletePrinterDataExA (WINSPOOL.@)
6427 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6430 FIXME("%p %s %s\n", hPrinter
,
6431 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6432 return ERROR_INVALID_PARAMETER
;
6435 /******************************************************************************
6436 * DeletePrintProcessorA (WINSPOOL.@)
6438 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6440 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6441 debugstr_a(pPrintProcessorName
));
6445 /******************************************************************************
6446 * DeletePrintProcessorW (WINSPOOL.@)
6448 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6450 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6451 debugstr_w(pPrintProcessorName
));
6455 /******************************************************************************
6456 * DeletePrintProvidorA (WINSPOOL.@)
6458 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6460 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6461 debugstr_a(pPrintProviderName
));
6465 /******************************************************************************
6466 * DeletePrintProvidorW (WINSPOOL.@)
6468 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6470 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6471 debugstr_w(pPrintProviderName
));
6475 /******************************************************************************
6476 * EnumFormsA (WINSPOOL.@)
6478 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6479 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6481 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6482 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6486 /******************************************************************************
6487 * EnumFormsW (WINSPOOL.@)
6489 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6490 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6492 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6493 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6497 /*****************************************************************************
6498 * EnumMonitorsA [WINSPOOL.@]
6500 * See EnumMonitorsW.
6503 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6504 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6507 LPBYTE bufferW
= NULL
;
6508 LPWSTR nameW
= NULL
;
6510 DWORD numentries
= 0;
6513 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6514 cbBuf
, pcbNeeded
, pcReturned
);
6516 /* convert servername to unicode */
6518 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6519 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6520 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6522 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6523 needed
= cbBuf
* sizeof(WCHAR
);
6524 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6525 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6527 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6528 if (pcbNeeded
) needed
= *pcbNeeded
;
6529 /* HeapReAlloc return NULL, when bufferW was NULL */
6530 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6531 HeapAlloc(GetProcessHeap(), 0, needed
);
6533 /* Try again with the large Buffer */
6534 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6536 numentries
= pcReturned
? *pcReturned
: 0;
6539 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6540 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6543 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6544 DWORD entrysize
= 0;
6547 LPMONITOR_INFO_2W mi2w
;
6548 LPMONITOR_INFO_2A mi2a
;
6550 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6551 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6553 /* First pass: calculate the size for all Entries */
6554 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6555 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6557 while (index
< numentries
) {
6559 needed
+= entrysize
; /* MONITOR_INFO_?A */
6560 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6562 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6563 NULL
, 0, NULL
, NULL
);
6565 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6566 NULL
, 0, NULL
, NULL
);
6567 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6568 NULL
, 0, NULL
, NULL
);
6570 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6571 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6572 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6575 /* check for errors and quit on failure */
6576 if (cbBuf
< needed
) {
6577 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6581 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6582 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6583 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6584 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6585 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6587 /* Second Pass: Fill the User Buffer (if we have one) */
6588 while ((index
< numentries
) && pMonitors
) {
6590 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6592 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6593 ptr
, cbBuf
, NULL
, NULL
);
6597 mi2a
->pEnvironment
= ptr
;
6598 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6599 ptr
, cbBuf
, NULL
, NULL
);
6603 mi2a
->pDLLName
= ptr
;
6604 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6605 ptr
, cbBuf
, NULL
, NULL
);
6609 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6610 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6611 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6615 if (pcbNeeded
) *pcbNeeded
= needed
;
6616 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6618 HeapFree(GetProcessHeap(), 0, nameW
);
6619 HeapFree(GetProcessHeap(), 0, bufferW
);
6621 TRACE("returning %d with %d (%d byte for %d entries)\n",
6622 (res
), GetLastError(), needed
, numentries
);
6628 /*****************************************************************************
6629 * EnumMonitorsW [WINSPOOL.@]
6631 * Enumerate available Port-Monitors
6634 * pName [I] Servername or NULL (local Computer)
6635 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6636 * pMonitors [O] PTR to Buffer that receives the Result
6637 * cbBuf [I] Size of Buffer at pMonitors
6638 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6639 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6643 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6646 * Windows reads the Registry once and cache the Results.
6648 *| Language-Monitors are also installed in the same Registry-Location but
6649 *| they are filtered in Windows (not returned by EnumMonitors).
6650 *| We do no filtering to simplify our Code.
6653 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6654 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6657 DWORD numentries
= 0;
6660 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6661 cbBuf
, pcbNeeded
, pcReturned
);
6663 if (pName
&& (lstrlenW(pName
))) {
6664 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
6665 SetLastError(ERROR_ACCESS_DENIED
);
6669 /* Level is not checked in win9x */
6670 if (!Level
|| (Level
> 2)) {
6671 WARN("level (%d) is ignored in win9x\n", Level
);
6672 SetLastError(ERROR_INVALID_LEVEL
);
6676 SetLastError(RPC_X_NULL_REF_POINTER
);
6680 /* Scan all Monitor-Keys */
6682 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
6684 /* we calculated the needed buffersize. now do the error-checks */
6685 if (cbBuf
< needed
) {
6686 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6689 else if (!pMonitors
|| !pcReturned
) {
6690 SetLastError(RPC_X_NULL_REF_POINTER
);
6694 /* fill the Buffer with the Monitor-Keys */
6695 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
6699 if (pcbNeeded
) *pcbNeeded
= needed
;
6700 if (pcReturned
) *pcReturned
= numentries
;
6702 TRACE("returning %d with %d (%d byte for %d entries)\n",
6703 res
, GetLastError(), needed
, numentries
);
6708 /******************************************************************************
6709 * XcvDataW (WINSPOOL.@)
6711 * Execute commands in the Printmonitor DLL
6714 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6715 * pszDataName [i] Name of the command to execute
6716 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6717 * cbInputData [i] Size in Bytes of Buffer at pInputData
6718 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6719 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6720 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6721 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6728 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6729 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6731 * Minimal List of commands, that a Printmonitor DLL should support:
6733 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6734 *| "AddPort" : Add a Port
6735 *| "DeletePort": Delete a Port
6737 * Many Printmonitors support additional commands. Examples for localspl.dll:
6738 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6739 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6742 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6743 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6744 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6746 opened_printer_t
*printer
;
6748 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6749 pInputData
, cbInputData
, pOutputData
,
6750 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6752 printer
= get_opened_printer(hXcv
);
6753 if (!printer
|| (!printer
->hXcv
)) {
6754 SetLastError(ERROR_INVALID_HANDLE
);
6758 if (!pcbOutputNeeded
) {
6759 SetLastError(ERROR_INVALID_PARAMETER
);
6763 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6764 SetLastError(RPC_X_NULL_REF_POINTER
);
6768 *pcbOutputNeeded
= 0;
6770 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
6771 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
6776 /*****************************************************************************
6777 * EnumPrinterDataA [WINSPOOL.@]
6780 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6781 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6782 DWORD cbData
, LPDWORD pcbData
)
6784 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6785 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6786 return ERROR_NO_MORE_ITEMS
;
6789 /*****************************************************************************
6790 * EnumPrinterDataW [WINSPOOL.@]
6793 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6794 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6795 DWORD cbData
, LPDWORD pcbData
)
6797 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6798 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6799 return ERROR_NO_MORE_ITEMS
;
6802 /*****************************************************************************
6803 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6806 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6807 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6808 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6810 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6811 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6812 pcbNeeded
, pcReturned
);
6816 /*****************************************************************************
6817 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6820 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6821 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6822 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6824 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6825 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6826 pcbNeeded
, pcReturned
);
6830 /*****************************************************************************
6831 * EnumPrintProcessorsA [WINSPOOL.@]
6834 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6835 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6837 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
6838 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
6842 /*****************************************************************************
6843 * EnumPrintProcessorsW [WINSPOOL.@]
6846 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6847 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6849 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6850 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
6851 cbBuf
, pcbNeeded
, pcbReturned
);
6855 /*****************************************************************************
6856 * ExtDeviceMode [WINSPOOL.@]
6859 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6860 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6863 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6864 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6865 debugstr_a(pProfile
), fMode
);
6869 /*****************************************************************************
6870 * FindClosePrinterChangeNotification [WINSPOOL.@]
6873 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6875 FIXME("Stub: %p\n", hChange
);
6879 /*****************************************************************************
6880 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6883 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6884 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6886 FIXME("Stub: %p %x %x %p\n",
6887 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6888 return INVALID_HANDLE_VALUE
;
6891 /*****************************************************************************
6892 * FindNextPrinterChangeNotification [WINSPOOL.@]
6895 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6896 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6898 FIXME("Stub: %p %p %p %p\n",
6899 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
6903 /*****************************************************************************
6904 * FreePrinterNotifyInfo [WINSPOOL.@]
6907 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
6909 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
6913 /*****************************************************************************
6916 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6917 * ansi depending on the unicode parameter.
6919 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
6929 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
6932 memcpy(ptr
, str
, *size
);
6939 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
6942 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
6949 /*****************************************************************************
6952 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
6953 LPDWORD pcbNeeded
, BOOL unicode
)
6955 DWORD size
, left
= cbBuf
;
6956 BOOL space
= (cbBuf
> 0);
6963 ji1
->JobId
= job
->job_id
;
6966 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6967 if(space
&& size
<= left
)
6969 ji1
->pDocument
= (LPWSTR
)ptr
;
6980 /*****************************************************************************
6983 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
6984 LPDWORD pcbNeeded
, BOOL unicode
)
6986 DWORD size
, left
= cbBuf
;
6987 BOOL space
= (cbBuf
> 0);
6994 ji2
->JobId
= job
->job_id
;
6997 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6998 if(space
&& size
<= left
)
7000 ji2
->pDocument
= (LPWSTR
)ptr
;
7011 /*****************************************************************************
7014 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7015 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7018 DWORD needed
= 0, size
;
7022 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7024 EnterCriticalSection(&printer_handles_cs
);
7025 job
= get_job(hPrinter
, JobId
);
7032 size
= sizeof(JOB_INFO_1W
);
7037 memset(pJob
, 0, size
);
7041 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7046 size
= sizeof(JOB_INFO_2W
);
7051 memset(pJob
, 0, size
);
7055 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7060 size
= sizeof(JOB_INFO_3
);
7064 memset(pJob
, 0, size
);
7073 SetLastError(ERROR_INVALID_LEVEL
);
7077 *pcbNeeded
= needed
;
7079 LeaveCriticalSection(&printer_handles_cs
);
7083 /*****************************************************************************
7084 * GetJobA [WINSPOOL.@]
7087 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7088 DWORD cbBuf
, LPDWORD pcbNeeded
)
7090 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7093 /*****************************************************************************
7094 * GetJobW [WINSPOOL.@]
7097 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7098 DWORD cbBuf
, LPDWORD pcbNeeded
)
7100 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7103 /*****************************************************************************
7106 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7108 char *unixname
, *queue
, *cmd
;
7109 char fmt
[] = "lpr -P%s %s";
7112 if(!(unixname
= wine_get_unix_file_name(filename
)))
7115 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7116 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7117 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7119 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7120 sprintf(cmd
, fmt
, queue
, unixname
);
7122 TRACE("printing with: %s\n", cmd
);
7125 HeapFree(GetProcessHeap(), 0, cmd
);
7126 HeapFree(GetProcessHeap(), 0, queue
);
7127 HeapFree(GetProcessHeap(), 0, unixname
);
7131 /*****************************************************************************
7134 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7136 #if HAVE_CUPS_CUPS_H
7139 char *unixname
, *queue
, *doc_titleA
;
7143 if(!(unixname
= wine_get_unix_file_name(filename
)))
7146 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7147 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7148 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7150 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7151 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7152 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7154 TRACE("printing via cups\n");
7155 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7156 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7157 HeapFree(GetProcessHeap(), 0, queue
);
7158 HeapFree(GetProcessHeap(), 0, unixname
);
7164 return schedule_lpr(printer_name
, filename
);
7168 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7175 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7179 if(HIWORD(wparam
) == BN_CLICKED
)
7181 if(LOWORD(wparam
) == IDOK
)
7184 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7187 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7188 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7190 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7192 WCHAR caption
[200], message
[200];
7195 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7196 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7197 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7198 if(mb_ret
== IDCANCEL
)
7200 HeapFree(GetProcessHeap(), 0, filename
);
7204 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7205 if(hf
== INVALID_HANDLE_VALUE
)
7207 WCHAR caption
[200], message
[200];
7209 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7210 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7211 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7212 HeapFree(GetProcessHeap(), 0, filename
);
7216 DeleteFileW(filename
);
7217 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7219 EndDialog(hwnd
, IDOK
);
7222 if(LOWORD(wparam
) == IDCANCEL
)
7224 EndDialog(hwnd
, IDCANCEL
);
7233 /*****************************************************************************
7236 static BOOL
get_filename(LPWSTR
*filename
)
7238 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7239 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7242 /*****************************************************************************
7245 static BOOL
schedule_file(LPCWSTR filename
)
7247 LPWSTR output
= NULL
;
7249 if(get_filename(&output
))
7251 TRACE("copy to %s\n", debugstr_w(output
));
7252 CopyFileW(filename
, output
, FALSE
);
7253 HeapFree(GetProcessHeap(), 0, output
);
7259 /*****************************************************************************
7262 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7265 char *unixname
, *cmdA
;
7267 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7271 if(!(unixname
= wine_get_unix_file_name(filename
)))
7274 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7275 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7276 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7278 TRACE("printing with: %s\n", cmdA
);
7280 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7285 ERR("pipe() failed!\n");
7295 /* reset signals that we previously set to SIG_IGN */
7296 signal(SIGPIPE
, SIG_DFL
);
7297 signal(SIGCHLD
, SIG_DFL
);
7299 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7303 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7304 write(fds
[1], buf
, no_read
);
7309 if(file_fd
!= -1) close(file_fd
);
7310 if(fds
[0] != -1) close(fds
[0]);
7311 if(fds
[1] != -1) close(fds
[1]);
7313 HeapFree(GetProcessHeap(), 0, cmdA
);
7314 HeapFree(GetProcessHeap(), 0, unixname
);
7321 /*****************************************************************************
7324 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7326 int in_fd
, out_fd
, no_read
;
7329 char *unixname
, *outputA
;
7332 if(!(unixname
= wine_get_unix_file_name(filename
)))
7335 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7336 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7337 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7339 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7340 in_fd
= open(unixname
, O_RDONLY
);
7341 if(out_fd
== -1 || in_fd
== -1)
7344 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7345 write(out_fd
, buf
, no_read
);
7349 if(in_fd
!= -1) close(in_fd
);
7350 if(out_fd
!= -1) close(out_fd
);
7351 HeapFree(GetProcessHeap(), 0, outputA
);
7352 HeapFree(GetProcessHeap(), 0, unixname
);
7356 /*****************************************************************************
7357 * ScheduleJob [WINSPOOL.@]
7360 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7362 opened_printer_t
*printer
;
7364 struct list
*cursor
, *cursor2
;
7366 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7367 EnterCriticalSection(&printer_handles_cs
);
7368 printer
= get_opened_printer(hPrinter
);
7372 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7374 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7377 if(job
->job_id
!= dwJobID
) continue;
7379 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7380 if(hf
!= INVALID_HANDLE_VALUE
)
7382 PRINTER_INFO_5W
*pi5
;
7386 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7387 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7389 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7390 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7391 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7392 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7393 debugstr_w(pi5
->pPortName
));
7397 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7398 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7400 DWORD type
, count
= sizeof(output
);
7401 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7404 if(output
[0] == '|')
7406 schedule_pipe(output
+ 1, job
->filename
);
7410 schedule_unixfile(output
, job
->filename
);
7412 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7414 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7416 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7418 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7420 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7422 schedule_file(job
->filename
);
7426 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7428 HeapFree(GetProcessHeap(), 0, pi5
);
7430 DeleteFileW(job
->filename
);
7432 list_remove(cursor
);
7433 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7434 HeapFree(GetProcessHeap(), 0, job
->filename
);
7435 HeapFree(GetProcessHeap(), 0, job
);
7440 LeaveCriticalSection(&printer_handles_cs
);
7444 /*****************************************************************************
7445 * StartDocDlgA [WINSPOOL.@]
7447 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7449 UNICODE_STRING usBuffer
;
7452 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7455 docW
.cbSize
= sizeof(docW
);
7456 if (doc
->lpszDocName
)
7458 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7459 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7461 if (doc
->lpszOutput
)
7463 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7464 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7466 if (doc
->lpszDatatype
)
7468 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7469 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7471 docW
.fwType
= doc
->fwType
;
7473 retW
= StartDocDlgW(hPrinter
, &docW
);
7477 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7478 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7479 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7480 HeapFree(GetProcessHeap(), 0, retW
);
7483 HeapFree(GetProcessHeap(), 0, datatypeW
);
7484 HeapFree(GetProcessHeap(), 0, outputW
);
7485 HeapFree(GetProcessHeap(), 0, docnameW
);
7490 /*****************************************************************************
7491 * StartDocDlgW [WINSPOOL.@]
7493 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7494 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7495 * port is "FILE:". Also returns the full path if passed a relative path.
7497 * The caller should free the returned string from the process heap.
7499 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7504 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7506 PRINTER_INFO_5W
*pi5
;
7507 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7508 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7510 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7511 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7512 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7514 HeapFree(GetProcessHeap(), 0, pi5
);
7517 HeapFree(GetProcessHeap(), 0, pi5
);
7520 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7524 if (get_filename(&name
))
7526 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7528 HeapFree(GetProcessHeap(), 0, name
);
7531 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7532 GetFullPathNameW(name
, len
, ret
, NULL
);
7533 HeapFree(GetProcessHeap(), 0, name
);
7538 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7541 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7542 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7544 attr
= GetFileAttributesW(ret
);
7545 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7547 HeapFree(GetProcessHeap(), 0, ret
);