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 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2274 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2279 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2282 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2283 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2287 /******************************************************************
2288 * DeletePortA [WINSPOOL.@]
2293 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2295 LPWSTR nameW
= NULL
;
2296 LPWSTR portW
= NULL
;
2300 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2302 /* convert servername to unicode */
2304 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2305 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2306 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2309 /* convert portname to unicode */
2311 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2312 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2313 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2316 res
= DeletePortW(nameW
, hWnd
, portW
);
2317 HeapFree(GetProcessHeap(), 0, nameW
);
2318 HeapFree(GetProcessHeap(), 0, portW
);
2322 /******************************************************************
2323 * DeletePortW [WINSPOOL.@]
2325 * Delete a specific Port
2328 * pName [I] Servername or NULL (local Computer)
2329 * hWnd [I] Handle to parent Window for the Dialog-Box
2330 * pPortName [I] Name of the Port, that should be deleted
2337 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2343 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2345 if (pName
&& pName
[0]) {
2346 SetLastError(ERROR_INVALID_PARAMETER
);
2351 SetLastError(RPC_X_NULL_REF_POINTER
);
2355 /* an empty Portname is Invalid */
2356 if (!pPortName
[0]) {
2357 SetLastError(ERROR_NOT_SUPPORTED
);
2361 pm
= monitor_load_by_port(pPortName
);
2362 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2363 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2364 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2365 TRACE("got %d with %u\n", res
, GetLastError());
2369 pui
= monitor_loadui(pm
);
2370 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2371 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2372 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2373 TRACE("got %d with %u\n", res
, GetLastError());
2377 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2378 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2380 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2381 SetLastError(ERROR_NOT_SUPPORTED
);
2384 monitor_unload(pui
);
2388 TRACE("returning %d with %u\n", res
, GetLastError());
2392 /******************************************************************************
2393 * SetPrinterW [WINSPOOL.@]
2395 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2397 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2398 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2402 /******************************************************************************
2403 * WritePrinter [WINSPOOL.@]
2405 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2407 opened_printer_t
*printer
;
2410 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2412 EnterCriticalSection(&printer_handles_cs
);
2413 printer
= get_opened_printer(hPrinter
);
2416 SetLastError(ERROR_INVALID_HANDLE
);
2422 SetLastError(ERROR_SPL_NO_STARTDOC
);
2426 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2428 LeaveCriticalSection(&printer_handles_cs
);
2432 /*****************************************************************************
2433 * AddFormA [WINSPOOL.@]
2435 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2437 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2441 /*****************************************************************************
2442 * AddFormW [WINSPOOL.@]
2444 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2446 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2450 /*****************************************************************************
2451 * AddJobA [WINSPOOL.@]
2453 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2456 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2460 SetLastError(ERROR_INVALID_LEVEL
);
2464 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2467 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2468 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2469 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2470 if(*pcbNeeded
> cbBuf
) {
2471 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2474 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2475 addjobA
->JobId
= addjobW
->JobId
;
2476 addjobA
->Path
= (char *)(addjobA
+ 1);
2477 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2483 /*****************************************************************************
2484 * AddJobW [WINSPOOL.@]
2486 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2488 opened_printer_t
*printer
;
2491 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2492 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2493 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2495 ADDJOB_INFO_1W
*addjob
;
2497 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2499 EnterCriticalSection(&printer_handles_cs
);
2501 printer
= get_opened_printer(hPrinter
);
2504 SetLastError(ERROR_INVALID_HANDLE
);
2509 SetLastError(ERROR_INVALID_LEVEL
);
2513 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2517 job
->job_id
= InterlockedIncrement(&next_job_id
);
2519 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2520 if(path
[len
- 1] != '\\')
2522 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2523 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2525 len
= strlenW(filename
);
2526 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2527 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2528 job
->document_title
= strdupW(default_doc_title
);
2529 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2531 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2532 if(*pcbNeeded
<= cbBuf
) {
2533 addjob
= (ADDJOB_INFO_1W
*)pData
;
2534 addjob
->JobId
= job
->job_id
;
2535 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2536 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2539 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2542 LeaveCriticalSection(&printer_handles_cs
);
2546 /*****************************************************************************
2547 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2549 * Return the PATH for the Print-Processors
2551 * See GetPrintProcessorDirectoryW.
2555 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2556 DWORD level
, LPBYTE Info
,
2557 DWORD cbBuf
, LPDWORD pcbNeeded
)
2559 LPWSTR serverW
= NULL
;
2564 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2565 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2569 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2570 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2571 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2575 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2576 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2577 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2580 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2581 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2583 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2586 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2587 cbBuf
, NULL
, NULL
) > 0;
2590 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2591 HeapFree(GetProcessHeap(), 0, envW
);
2592 HeapFree(GetProcessHeap(), 0, serverW
);
2596 /*****************************************************************************
2597 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2599 * Return the PATH for the Print-Processors
2602 * server [I] Servername (NT only) or NULL (local Computer)
2603 * env [I] Printing-Environment (see below) or NULL (Default)
2604 * level [I] Structure-Level (must be 1)
2605 * Info [O] PTR to Buffer that receives the Result
2606 * cbBuf [I] Size of Buffer at "Info"
2607 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2608 * required for the Buffer at "Info"
2611 * Success: TRUE and in pcbNeeded the Bytes used in Info
2612 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2613 * if cbBuf is too small
2615 * Native Values returned in Info on Success:
2616 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2617 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2618 *| win9x(Windows 4.0): "%winsysdir%"
2620 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2623 * Only NULL or "" is supported for server
2626 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2627 DWORD level
, LPBYTE Info
,
2628 DWORD cbBuf
, LPDWORD pcbNeeded
)
2631 const printenv_t
* env_t
;
2633 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2634 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2636 if(server
!= NULL
&& server
[0]) {
2637 FIXME("server not supported: %s\n", debugstr_w(server
));
2638 SetLastError(ERROR_INVALID_PARAMETER
);
2642 env_t
= validate_envW(env
);
2643 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2646 WARN("(Level: %d) is ignored in win9x\n", level
);
2647 SetLastError(ERROR_INVALID_LEVEL
);
2651 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2652 needed
= GetSystemDirectoryW(NULL
, 0);
2653 /* add the Size for the Subdirectories */
2654 needed
+= lstrlenW(spoolprtprocsW
);
2655 needed
+= lstrlenW(env_t
->subdir
);
2656 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2658 if(pcbNeeded
) *pcbNeeded
= needed
;
2659 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2660 if (needed
> cbBuf
) {
2661 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2664 if(pcbNeeded
== NULL
) {
2665 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2666 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2667 SetLastError(RPC_X_NULL_REF_POINTER
);
2671 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2672 SetLastError(RPC_X_NULL_REF_POINTER
);
2676 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2677 /* add the Subdirectories */
2678 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2679 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2680 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2684 /*****************************************************************************
2685 * WINSPOOL_OpenDriverReg [internal]
2687 * opens the registry for the printer drivers depending on the given input
2688 * variable pEnvironment
2691 * the opened hkey on success
2694 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2698 const printenv_t
* env
;
2701 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2703 if (!pEnvironment
|| unicode
) {
2704 /* pEnvironment was NULL or an Unicode-String: use it direct */
2705 env
= validate_envW(pEnvironment
);
2709 /* pEnvironment was an ANSI-String: convert to unicode first */
2711 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2712 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2713 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2714 env
= validate_envW(buffer
);
2715 HeapFree(GetProcessHeap(), 0, buffer
);
2717 if (!env
) return NULL
;
2719 buffer
= HeapAlloc( GetProcessHeap(), 0,
2720 (strlenW(DriversW
) + strlenW(env
->envname
) +
2721 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2723 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2724 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2725 HeapFree(GetProcessHeap(), 0, buffer
);
2730 /*****************************************************************************
2731 * AddPrinterW [WINSPOOL.@]
2733 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2735 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2739 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2741 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2742 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2743 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2744 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2745 statusW
[] = {'S','t','a','t','u','s',0},
2746 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2748 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2751 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2752 SetLastError(ERROR_INVALID_PARAMETER
);
2756 ERR("Level = %d, unsupported!\n", Level
);
2757 SetLastError(ERROR_INVALID_LEVEL
);
2761 SetLastError(ERROR_INVALID_PARAMETER
);
2764 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2766 ERR("Can't create Printers key\n");
2769 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2770 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2771 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2772 RegCloseKey(hkeyPrinter
);
2773 RegCloseKey(hkeyPrinters
);
2776 RegCloseKey(hkeyPrinter
);
2778 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2780 ERR("Can't create Drivers key\n");
2781 RegCloseKey(hkeyPrinters
);
2784 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2786 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2787 RegCloseKey(hkeyPrinters
);
2788 RegCloseKey(hkeyDrivers
);
2789 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2792 RegCloseKey(hkeyDriver
);
2793 RegCloseKey(hkeyDrivers
);
2795 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2796 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2797 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2798 RegCloseKey(hkeyPrinters
);
2802 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2804 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2805 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2806 RegCloseKey(hkeyPrinters
);
2809 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2810 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2811 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2813 /* See if we can load the driver. We may need the devmode structure anyway
2816 * Note that DocumentPropertiesW will briefly try to open the printer we
2817 * just create to find a DEVMODEA struct (it will use the WINEPS default
2818 * one in case it is not there, so we are ok).
2820 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2823 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2824 size
= sizeof(DEVMODEW
);
2830 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2832 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2834 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2835 HeapFree(GetProcessHeap(),0,dmW
);
2840 /* set devmode to printer name */
2841 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2845 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2846 and we support these drivers. NT writes DEVMODEW so somehow
2847 we'll need to distinguish between these when we support NT
2851 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2852 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2853 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2854 HeapFree(GetProcessHeap(), 0, dmA
);
2856 HeapFree(GetProcessHeap(), 0, dmW
);
2858 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2859 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2860 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2861 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2863 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2864 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2865 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2866 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2867 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2868 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2869 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2870 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2871 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2872 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2873 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2874 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2875 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2877 RegCloseKey(hkeyPrinter
);
2878 RegCloseKey(hkeyPrinters
);
2879 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2880 ERR("OpenPrinter failing\n");
2886 /*****************************************************************************
2887 * AddPrinterA [WINSPOOL.@]
2889 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2891 UNICODE_STRING pNameW
;
2893 PRINTER_INFO_2W
*piW
;
2894 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2897 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2899 ERR("Level = %d, unsupported!\n", Level
);
2900 SetLastError(ERROR_INVALID_LEVEL
);
2903 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2904 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2906 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2908 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2909 RtlFreeUnicodeString(&pNameW
);
2914 /*****************************************************************************
2915 * ClosePrinter [WINSPOOL.@]
2917 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2919 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2920 opened_printer_t
*printer
= NULL
;
2923 TRACE("(%p)\n", hPrinter
);
2925 EnterCriticalSection(&printer_handles_cs
);
2927 if ((i
> 0) && (i
<= nb_printer_handles
))
2928 printer
= printer_handles
[i
- 1];
2933 struct list
*cursor
, *cursor2
;
2935 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2936 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2937 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2940 EndDocPrinter(hPrinter
);
2942 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2944 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2946 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2947 ScheduleJob(hPrinter
, job
->job_id
);
2949 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2951 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2952 monitor_unload(printer
->pm
);
2953 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2954 HeapFree(GetProcessHeap(), 0, printer
->name
);
2955 HeapFree(GetProcessHeap(), 0, printer
);
2956 printer_handles
[i
- 1] = NULL
;
2959 LeaveCriticalSection(&printer_handles_cs
);
2963 /*****************************************************************************
2964 * DeleteFormA [WINSPOOL.@]
2966 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2968 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2972 /*****************************************************************************
2973 * DeleteFormW [WINSPOOL.@]
2975 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2977 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2981 /*****************************************************************************
2982 * DeletePrinter [WINSPOOL.@]
2984 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2986 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2987 HKEY hkeyPrinters
, hkey
;
2990 SetLastError(ERROR_INVALID_HANDLE
);
2993 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2994 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2995 RegCloseKey(hkeyPrinters
);
2997 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2998 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2999 RegDeleteValueW(hkey
, lpNameW
);
3005 /*****************************************************************************
3006 * SetPrinterA [WINSPOOL.@]
3008 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3011 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3015 /*****************************************************************************
3016 * SetJobA [WINSPOOL.@]
3018 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3019 LPBYTE pJob
, DWORD Command
)
3023 UNICODE_STRING usBuffer
;
3025 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3027 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3028 are all ignored by SetJob, so we don't bother copying them */
3036 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3037 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3039 JobW
= (LPBYTE
)info1W
;
3040 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3041 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3042 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3043 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3044 info1W
->Status
= info1A
->Status
;
3045 info1W
->Priority
= info1A
->Priority
;
3046 info1W
->Position
= info1A
->Position
;
3047 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3052 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3053 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3055 JobW
= (LPBYTE
)info2W
;
3056 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3057 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3058 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3059 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3060 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3061 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3062 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3063 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3064 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3065 info2W
->Status
= info2A
->Status
;
3066 info2W
->Priority
= info2A
->Priority
;
3067 info2W
->Position
= info2A
->Position
;
3068 info2W
->StartTime
= info2A
->StartTime
;
3069 info2W
->UntilTime
= info2A
->UntilTime
;
3070 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3074 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3075 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3078 SetLastError(ERROR_INVALID_LEVEL
);
3082 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3088 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3089 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3090 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3091 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3092 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3097 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3098 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3099 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3100 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3101 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3102 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3103 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3104 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3105 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3109 HeapFree(GetProcessHeap(), 0, JobW
);
3114 /*****************************************************************************
3115 * SetJobW [WINSPOOL.@]
3117 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3118 LPBYTE pJob
, DWORD Command
)
3123 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3124 FIXME("Ignoring everything other than document title\n");
3126 EnterCriticalSection(&printer_handles_cs
);
3127 job
= get_job(hPrinter
, JobId
);
3137 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3138 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3139 job
->document_title
= strdupW(info1
->pDocument
);
3144 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3145 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3146 job
->document_title
= strdupW(info2
->pDocument
);
3152 SetLastError(ERROR_INVALID_LEVEL
);
3157 LeaveCriticalSection(&printer_handles_cs
);
3161 /*****************************************************************************
3162 * EndDocPrinter [WINSPOOL.@]
3164 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3166 opened_printer_t
*printer
;
3168 TRACE("(%p)\n", hPrinter
);
3170 EnterCriticalSection(&printer_handles_cs
);
3172 printer
= get_opened_printer(hPrinter
);
3175 SetLastError(ERROR_INVALID_HANDLE
);
3181 SetLastError(ERROR_SPL_NO_STARTDOC
);
3185 CloseHandle(printer
->doc
->hf
);
3186 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3187 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3188 printer
->doc
= NULL
;
3191 LeaveCriticalSection(&printer_handles_cs
);
3195 /*****************************************************************************
3196 * EndPagePrinter [WINSPOOL.@]
3198 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3200 FIXME("(%p): stub\n", hPrinter
);
3204 /*****************************************************************************
3205 * StartDocPrinterA [WINSPOOL.@]
3207 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3209 UNICODE_STRING usBuffer
;
3211 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3214 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3215 or one (DOC_INFO_3) extra DWORDs */
3219 doc2W
.JobId
= doc2
->JobId
;
3222 doc2W
.dwMode
= doc2
->dwMode
;
3225 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3226 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3227 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3231 SetLastError(ERROR_INVALID_LEVEL
);
3235 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3237 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3238 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3239 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3244 /*****************************************************************************
3245 * StartDocPrinterW [WINSPOOL.@]
3247 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3249 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3250 opened_printer_t
*printer
;
3251 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3252 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3253 JOB_INFO_1W job_info
;
3254 DWORD needed
, ret
= 0;
3258 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3259 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3260 debugstr_w(doc
->pDatatype
));
3262 if(Level
< 1 || Level
> 3)
3264 SetLastError(ERROR_INVALID_LEVEL
);
3268 EnterCriticalSection(&printer_handles_cs
);
3269 printer
= get_opened_printer(hPrinter
);
3272 SetLastError(ERROR_INVALID_HANDLE
);
3278 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3282 /* Even if we're printing to a file we still add a print job, we'll
3283 just ignore the spool file name */
3285 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3287 ERR("AddJob failed gle %u\n", GetLastError());
3291 if(doc
->pOutputFile
)
3292 filename
= doc
->pOutputFile
;
3294 filename
= addjob
->Path
;
3296 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3297 if(hf
== INVALID_HANDLE_VALUE
)
3300 memset(&job_info
, 0, sizeof(job_info
));
3301 job_info
.pDocument
= doc
->pDocName
;
3302 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3304 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3305 printer
->doc
->hf
= hf
;
3306 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3308 LeaveCriticalSection(&printer_handles_cs
);
3313 /*****************************************************************************
3314 * StartPagePrinter [WINSPOOL.@]
3316 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3318 FIXME("(%p): stub\n", hPrinter
);
3322 /*****************************************************************************
3323 * GetFormA [WINSPOOL.@]
3325 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3326 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3328 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3329 Level
,pForm
,cbBuf
,pcbNeeded
);
3333 /*****************************************************************************
3334 * GetFormW [WINSPOOL.@]
3336 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3337 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3339 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3340 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3344 /*****************************************************************************
3345 * SetFormA [WINSPOOL.@]
3347 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3350 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3354 /*****************************************************************************
3355 * SetFormW [WINSPOOL.@]
3357 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3360 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3364 /*****************************************************************************
3365 * ReadPrinter [WINSPOOL.@]
3367 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3368 LPDWORD pNoBytesRead
)
3370 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3374 /*****************************************************************************
3375 * ResetPrinterA [WINSPOOL.@]
3377 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3379 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3383 /*****************************************************************************
3384 * ResetPrinterW [WINSPOOL.@]
3386 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3388 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3392 /*****************************************************************************
3393 * WINSPOOL_GetDWORDFromReg
3395 * Return DWORD associated with ValueName from hkey.
3397 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3399 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3402 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3404 if(ret
!= ERROR_SUCCESS
) {
3405 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3408 if(type
!= REG_DWORD
) {
3409 ERR("Got type %d\n", type
);
3415 /*****************************************************************************
3416 * WINSPOOL_GetStringFromReg
3418 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3419 * String is stored either as unicode or ascii.
3420 * Bit of a hack here to get the ValueName if we want ascii.
3422 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3423 DWORD buflen
, DWORD
*needed
,
3426 DWORD sz
= buflen
, type
;
3430 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3432 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3433 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3434 HeapFree(GetProcessHeap(),0,ValueNameA
);
3436 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3437 WARN("Got ret = %d\n", ret
);
3441 /* add space for terminating '\0' */
3442 sz
+= unicode
? sizeof(WCHAR
) : 1;
3446 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3451 /*****************************************************************************
3452 * WINSPOOL_GetDefaultDevMode
3454 * Get a default DevMode values for wineps.
3458 static void WINSPOOL_GetDefaultDevMode(
3460 DWORD buflen
, DWORD
*needed
,
3464 static const char szwps
[] = "wineps.drv";
3466 /* fill default DEVMODE - should be read from ppd... */
3467 ZeroMemory( &dm
, sizeof(dm
) );
3468 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3469 dm
.dmSpecVersion
= DM_SPECVERSION
;
3470 dm
.dmDriverVersion
= 1;
3471 dm
.dmSize
= sizeof(DEVMODEA
);
3472 dm
.dmDriverExtra
= 0;
3474 DM_ORIENTATION
| DM_PAPERSIZE
|
3475 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3478 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3479 DM_YRESOLUTION
| DM_TTOPTION
;
3481 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3482 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3483 dm
.u1
.s1
.dmPaperLength
= 2970;
3484 dm
.u1
.s1
.dmPaperWidth
= 2100;
3488 dm
.dmDefaultSource
= DMBIN_AUTO
;
3489 dm
.dmPrintQuality
= DMRES_MEDIUM
;
3492 dm
.dmYResolution
= 300; /* 300dpi */
3493 dm
.dmTTOption
= DMTT_BITMAP
;
3496 /* dm.dmLogPixels */
3497 /* dm.dmBitsPerPel */
3498 /* dm.dmPelsWidth */
3499 /* dm.dmPelsHeight */
3500 /* dm.dmDisplayFlags */
3501 /* dm.dmDisplayFrequency */
3502 /* dm.dmICMMethod */
3503 /* dm.dmICMIntent */
3504 /* dm.dmMediaType */
3505 /* dm.dmDitherType */
3506 /* dm.dmReserved1 */
3507 /* dm.dmReserved2 */
3508 /* dm.dmPanningWidth */
3509 /* dm.dmPanningHeight */
3512 if(buflen
>= sizeof(DEVMODEW
)) {
3513 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3514 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3515 HeapFree(GetProcessHeap(),0,pdmW
);
3517 *needed
= sizeof(DEVMODEW
);
3521 if(buflen
>= sizeof(DEVMODEA
)) {
3522 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3524 *needed
= sizeof(DEVMODEA
);
3528 /*****************************************************************************
3529 * WINSPOOL_GetDevModeFromReg
3531 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3532 * DevMode is stored either as unicode or ascii.
3534 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3536 DWORD buflen
, DWORD
*needed
,
3539 DWORD sz
= buflen
, type
;
3542 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3543 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3544 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3545 if (sz
< sizeof(DEVMODEA
))
3547 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3550 /* ensures that dmSize is not erratically bogus if registry is invalid */
3551 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3552 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3554 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3556 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3557 memcpy(ptr
, dmW
, sz
);
3558 HeapFree(GetProcessHeap(),0,dmW
);
3565 /*********************************************************************
3566 * WINSPOOL_GetPrinter_1
3568 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3569 * The strings are either stored as unicode or ascii.
3571 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3572 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3575 DWORD size
, left
= cbBuf
;
3576 BOOL space
= (cbBuf
> 0);
3581 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3583 if(space
&& size
<= left
) {
3584 pi1
->pName
= (LPWSTR
)ptr
;
3592 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3593 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3595 if(space
&& size
<= left
) {
3596 pi1
->pDescription
= (LPWSTR
)ptr
;
3604 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3606 if(space
&& size
<= left
) {
3607 pi1
->pComment
= (LPWSTR
)ptr
;
3615 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3617 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3618 memset(pi1
, 0, sizeof(*pi1
));
3622 /*********************************************************************
3623 * WINSPOOL_GetPrinter_2
3625 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3626 * The strings are either stored as unicode or ascii.
3628 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3629 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3632 DWORD size
, left
= cbBuf
;
3633 BOOL space
= (cbBuf
> 0);
3638 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3640 if(space
&& size
<= left
) {
3641 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3648 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3650 if(space
&& size
<= left
) {
3651 pi2
->pShareName
= (LPWSTR
)ptr
;
3658 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3660 if(space
&& size
<= left
) {
3661 pi2
->pPortName
= (LPWSTR
)ptr
;
3668 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3670 if(space
&& size
<= left
) {
3671 pi2
->pDriverName
= (LPWSTR
)ptr
;
3678 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3680 if(space
&& size
<= left
) {
3681 pi2
->pComment
= (LPWSTR
)ptr
;
3688 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3690 if(space
&& size
<= left
) {
3691 pi2
->pLocation
= (LPWSTR
)ptr
;
3698 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3700 if(space
&& size
<= left
) {
3701 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3710 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3711 if(space
&& size
<= left
) {
3712 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3719 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3721 if(space
&& size
<= left
) {
3722 pi2
->pSepFile
= (LPWSTR
)ptr
;
3729 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3731 if(space
&& size
<= left
) {
3732 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3739 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3741 if(space
&& size
<= left
) {
3742 pi2
->pDatatype
= (LPWSTR
)ptr
;
3749 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3751 if(space
&& size
<= left
) {
3752 pi2
->pParameters
= (LPWSTR
)ptr
;
3760 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3761 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3762 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3763 "Default Priority");
3764 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3765 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3768 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3769 memset(pi2
, 0, sizeof(*pi2
));
3774 /*********************************************************************
3775 * WINSPOOL_GetPrinter_4
3777 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3779 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3780 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3783 DWORD size
, left
= cbBuf
;
3784 BOOL space
= (cbBuf
> 0);
3789 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3791 if(space
&& size
<= left
) {
3792 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3800 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3803 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3804 memset(pi4
, 0, sizeof(*pi4
));
3809 /*********************************************************************
3810 * WINSPOOL_GetPrinter_5
3812 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3814 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3815 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3818 DWORD size
, left
= cbBuf
;
3819 BOOL space
= (cbBuf
> 0);
3824 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3826 if(space
&& size
<= left
) {
3827 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3834 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3836 if(space
&& size
<= left
) {
3837 pi5
->pPortName
= (LPWSTR
)ptr
;
3845 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3846 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3848 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3852 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3853 memset(pi5
, 0, sizeof(*pi5
));
3858 /*****************************************************************************
3859 * WINSPOOL_GetPrinter
3861 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3862 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3863 * just a collection of pointers to strings.
3865 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3866 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3869 DWORD size
, needed
= 0;
3871 HKEY hkeyPrinter
, hkeyPrinters
;
3874 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3876 if (!(name
= get_opened_printer_name(hPrinter
))) {
3877 SetLastError(ERROR_INVALID_HANDLE
);
3881 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3883 ERR("Can't create Printers key\n");
3886 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3888 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3889 RegCloseKey(hkeyPrinters
);
3890 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3897 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3899 size
= sizeof(PRINTER_INFO_2W
);
3901 ptr
= pPrinter
+ size
;
3903 memset(pPrinter
, 0, size
);
3908 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
3916 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3918 size
= sizeof(PRINTER_INFO_4W
);
3920 ptr
= pPrinter
+ size
;
3922 memset(pPrinter
, 0, size
);
3927 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
3936 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3938 size
= sizeof(PRINTER_INFO_5W
);
3940 ptr
= pPrinter
+ size
;
3942 memset(pPrinter
, 0, size
);
3948 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
3955 FIXME("Unimplemented level %d\n", Level
);
3956 SetLastError(ERROR_INVALID_LEVEL
);
3957 RegCloseKey(hkeyPrinters
);
3958 RegCloseKey(hkeyPrinter
);
3962 RegCloseKey(hkeyPrinter
);
3963 RegCloseKey(hkeyPrinters
);
3965 TRACE("returning %d needed = %d\n", ret
, needed
);
3966 if(pcbNeeded
) *pcbNeeded
= needed
;
3968 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3972 /*****************************************************************************
3973 * GetPrinterW [WINSPOOL.@]
3975 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3976 DWORD cbBuf
, LPDWORD pcbNeeded
)
3978 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3982 /*****************************************************************************
3983 * GetPrinterA [WINSPOOL.@]
3985 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3986 DWORD cbBuf
, LPDWORD pcbNeeded
)
3988 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3992 /*****************************************************************************
3993 * WINSPOOL_EnumPrinters
3995 * Implementation of EnumPrintersA|W
3997 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
3998 DWORD dwLevel
, LPBYTE lpbPrinters
,
3999 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4000 LPDWORD lpdwReturned
, BOOL unicode
)
4003 HKEY hkeyPrinters
, hkeyPrinter
;
4004 WCHAR PrinterName
[255];
4005 DWORD needed
= 0, number
= 0;
4006 DWORD used
, i
, left
;
4010 memset(lpbPrinters
, 0, cbBuf
);
4016 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4017 if(dwType
== PRINTER_ENUM_DEFAULT
)
4020 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4021 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4022 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4024 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4032 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4033 FIXME("dwType = %08x\n", dwType
);
4034 SetLastError(ERROR_INVALID_FLAGS
);
4038 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4040 ERR("Can't create Printers key\n");
4044 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4045 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4046 RegCloseKey(hkeyPrinters
);
4047 ERR("Can't query Printers key\n");
4050 TRACE("Found %d printers\n", number
);
4054 used
= number
* sizeof(PRINTER_INFO_1W
);
4057 used
= number
* sizeof(PRINTER_INFO_2W
);
4060 used
= number
* sizeof(PRINTER_INFO_4W
);
4063 used
= number
* sizeof(PRINTER_INFO_5W
);
4067 SetLastError(ERROR_INVALID_LEVEL
);
4068 RegCloseKey(hkeyPrinters
);
4071 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4073 for(i
= 0; i
< number
; i
++) {
4074 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
4076 ERR("Can't enum key number %d\n", i
);
4077 RegCloseKey(hkeyPrinters
);
4080 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4081 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4083 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4084 RegCloseKey(hkeyPrinters
);
4089 buf
= lpbPrinters
+ used
;
4090 left
= cbBuf
- used
;
4098 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4099 left
, &needed
, unicode
);
4101 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4104 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4105 left
, &needed
, unicode
);
4107 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4110 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4111 left
, &needed
, unicode
);
4113 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4116 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4117 left
, &needed
, unicode
);
4119 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4122 ERR("Shouldn't be here!\n");
4123 RegCloseKey(hkeyPrinter
);
4124 RegCloseKey(hkeyPrinters
);
4127 RegCloseKey(hkeyPrinter
);
4129 RegCloseKey(hkeyPrinters
);
4136 memset(lpbPrinters
, 0, cbBuf
);
4137 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4141 *lpdwReturned
= number
;
4142 SetLastError(ERROR_SUCCESS
);
4147 /******************************************************************
4148 * EnumPrintersW [WINSPOOL.@]
4150 * Enumerates the available printers, print servers and print
4151 * providers, depending on the specified flags, name and level.
4155 * If level is set to 1:
4156 * Returns an array of PRINTER_INFO_1 data structures in the
4157 * lpbPrinters buffer.
4159 * If level is set to 2:
4160 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4161 * Returns an array of PRINTER_INFO_2 data structures in the
4162 * lpbPrinters buffer. Note that according to MSDN also an
4163 * OpenPrinter should be performed on every remote printer.
4165 * If level is set to 4 (officially WinNT only):
4166 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4167 * Fast: Only the registry is queried to retrieve printer names,
4168 * no connection to the driver is made.
4169 * Returns an array of PRINTER_INFO_4 data structures in the
4170 * lpbPrinters buffer.
4172 * If level is set to 5 (officially WinNT4/Win9x only):
4173 * Fast: Only the registry is queried to retrieve printer names,
4174 * no connection to the driver is made.
4175 * Returns an array of PRINTER_INFO_5 data structures in the
4176 * lpbPrinters buffer.
4178 * If level set to 3 or 6+:
4179 * returns zero (failure!)
4181 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4185 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4186 * - Only levels 2, 4 and 5 are implemented at the moment.
4187 * - 16-bit printer drivers are not enumerated.
4188 * - Returned amount of bytes used/needed does not match the real Windoze
4189 * implementation (as in this implementation, all strings are part
4190 * of the buffer, whereas Win32 keeps them somewhere else)
4191 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4194 * - In a regular Wine installation, no registry settings for printers
4195 * exist, which makes this function return an empty list.
4197 BOOL WINAPI
EnumPrintersW(
4198 DWORD dwType
, /* [in] Types of print objects to enumerate */
4199 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4200 DWORD dwLevel
, /* [in] type of printer info structure */
4201 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4202 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4203 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4204 LPDWORD lpdwReturned
/* [out] number of entries returned */
4207 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4208 lpdwNeeded
, lpdwReturned
, TRUE
);
4211 /******************************************************************
4212 * EnumPrintersA [WINSPOOL.@]
4215 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4216 DWORD dwLevel
, LPBYTE lpbPrinters
,
4217 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4218 LPDWORD lpdwReturned
)
4220 BOOL ret
, unicode
= FALSE
;
4221 UNICODE_STRING lpszNameW
;
4224 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4225 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4226 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4227 lpdwNeeded
, lpdwReturned
, unicode
);
4228 RtlFreeUnicodeString(&lpszNameW
);
4232 /*****************************************************************************
4233 * WINSPOOL_GetDriverInfoFromReg [internal]
4235 * Enters the information from the registry into the DRIVER_INFO struct
4238 * zero if the printer driver does not exist in the registry
4239 * (only if Level > 1) otherwise nonzero
4241 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4244 LPCWSTR pEnvironment
,
4246 LPBYTE ptr
, /* DRIVER_INFO */
4247 LPBYTE pDriverStrings
, /* strings buffer */
4248 DWORD cbBuf
, /* size of string buffer */
4249 LPDWORD pcbNeeded
, /* space needed for str. */
4250 BOOL unicode
) /* type of strings */
4254 LPBYTE strPtr
= pDriverStrings
;
4256 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4257 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
4258 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
4261 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4262 if (*pcbNeeded
<= cbBuf
)
4263 strcpyW((LPWSTR
)strPtr
, DriverName
);
4265 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
4267 if(*pcbNeeded
<= cbBuf
)
4268 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
4269 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4273 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
4277 ((PDRIVER_INFO_2W
) ptr
)->pName
= (LPWSTR
) strPtr
;
4278 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4281 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4282 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4283 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4288 ((PDRIVER_INFO_2A
) ptr
)->cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4291 pEnvironment
= DefaultEnvironmentW
;
4293 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
4295 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
4298 if(*pcbNeeded
<= cbBuf
) {
4300 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
4302 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
4303 (LPSTR
)strPtr
, size
, NULL
, NULL
);
4305 ((PDRIVER_INFO_2W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
4306 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4309 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
4312 if(*pcbNeeded
<= cbBuf
)
4313 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
4316 ((PDRIVER_INFO_2W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
4317 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4320 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
4323 if(*pcbNeeded
<= cbBuf
)
4324 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
4327 ((PDRIVER_INFO_2W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
4328 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4331 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4332 0, &size
, unicode
)) {
4334 if(*pcbNeeded
<= cbBuf
)
4335 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4336 size
, &tmp
, unicode
);
4338 ((PDRIVER_INFO_2W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
4339 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4343 RegCloseKey(hkeyDriver
);
4344 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4348 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
4351 if(*pcbNeeded
<= cbBuf
)
4352 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
4353 size
, &tmp
, unicode
);
4355 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
4356 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4359 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
4362 if(*pcbNeeded
<= cbBuf
)
4363 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
4364 size
, &tmp
, unicode
);
4366 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
4367 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4370 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
4373 if(*pcbNeeded
<= cbBuf
)
4374 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
4375 size
, &tmp
, unicode
);
4377 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
4378 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4381 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
4384 if(*pcbNeeded
<= cbBuf
)
4385 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
4386 size
, &tmp
, unicode
);
4388 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
4389 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4392 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4393 RegCloseKey(hkeyDriver
);
4397 /*****************************************************************************
4398 * WINSPOOL_GetPrinterDriver
4400 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4401 DWORD Level
, LPBYTE pDriverInfo
,
4402 DWORD cbBuf
, LPDWORD pcbNeeded
,
4406 WCHAR DriverName
[100];
4407 DWORD ret
, type
, size
, needed
= 0;
4409 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4411 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4412 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4414 ZeroMemory(pDriverInfo
, cbBuf
);
4416 if (!(name
= get_opened_printer_name(hPrinter
))) {
4417 SetLastError(ERROR_INVALID_HANDLE
);
4420 if(Level
< 1 || Level
> 6) {
4421 SetLastError(ERROR_INVALID_LEVEL
);
4424 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4426 ERR("Can't create Printers key\n");
4429 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4431 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4432 RegCloseKey(hkeyPrinters
);
4433 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4436 size
= sizeof(DriverName
);
4438 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4439 (LPBYTE
)DriverName
, &size
);
4440 RegCloseKey(hkeyPrinter
);
4441 RegCloseKey(hkeyPrinters
);
4442 if(ret
!= ERROR_SUCCESS
) {
4443 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4447 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4449 ERR("Can't create Drivers key\n");
4455 size
= sizeof(DRIVER_INFO_1W
);
4458 size
= sizeof(DRIVER_INFO_2W
);
4461 size
= sizeof(DRIVER_INFO_3W
);
4464 size
= sizeof(DRIVER_INFO_4W
);
4467 size
= sizeof(DRIVER_INFO_5W
);
4470 size
= sizeof(DRIVER_INFO_6W
);
4473 ERR("Invalid level\n");
4478 ptr
= pDriverInfo
+ size
;
4480 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4481 pEnvironment
, Level
, pDriverInfo
,
4482 (cbBuf
< size
) ? NULL
: ptr
,
4483 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4484 &needed
, unicode
)) {
4485 RegCloseKey(hkeyDrivers
);
4489 RegCloseKey(hkeyDrivers
);
4491 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4492 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4493 if(cbBuf
>= needed
) return TRUE
;
4494 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4498 /*****************************************************************************
4499 * GetPrinterDriverA [WINSPOOL.@]
4501 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4502 DWORD Level
, LPBYTE pDriverInfo
,
4503 DWORD cbBuf
, LPDWORD pcbNeeded
)
4506 UNICODE_STRING pEnvW
;
4509 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4510 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4511 cbBuf
, pcbNeeded
, FALSE
);
4512 RtlFreeUnicodeString(&pEnvW
);
4515 /*****************************************************************************
4516 * GetPrinterDriverW [WINSPOOL.@]
4518 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4519 DWORD Level
, LPBYTE pDriverInfo
,
4520 DWORD cbBuf
, LPDWORD pcbNeeded
)
4522 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4523 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4526 /*****************************************************************************
4527 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4529 * Return the PATH for the Printer-Drivers (UNICODE)
4532 * pName [I] Servername (NT only) or NULL (local Computer)
4533 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4534 * Level [I] Structure-Level (must be 1)
4535 * pDriverDirectory [O] PTR to Buffer that receives the Result
4536 * cbBuf [I] Size of Buffer at pDriverDirectory
4537 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4538 * required for pDriverDirectory
4541 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4542 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4543 * if cbBuf is too small
4545 * Native Values returned in pDriverDirectory on Success:
4546 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4547 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4548 *| win9x(Windows 4.0): "%winsysdir%"
4550 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4553 *- Only NULL or "" is supported for pName
4556 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4557 DWORD Level
, LPBYTE pDriverDirectory
,
4558 DWORD cbBuf
, LPDWORD pcbNeeded
)
4561 const printenv_t
* env
;
4563 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4564 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4565 if(pName
!= NULL
&& pName
[0]) {
4566 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
4567 SetLastError(ERROR_INVALID_PARAMETER
);
4571 env
= validate_envW(pEnvironment
);
4572 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
4575 WARN("(Level: %d) is ignored in win9x\n", Level
);
4576 SetLastError(ERROR_INVALID_LEVEL
);
4580 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4581 needed
= GetSystemDirectoryW(NULL
, 0);
4582 /* add the Size for the Subdirectories */
4583 needed
+= lstrlenW(spooldriversW
);
4584 needed
+= lstrlenW(env
->subdir
);
4585 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
4588 *pcbNeeded
= needed
;
4589 TRACE("required: 0x%x/%d\n", needed
, needed
);
4590 if(needed
> cbBuf
) {
4591 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4594 if(pcbNeeded
== NULL
) {
4595 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4596 SetLastError(RPC_X_NULL_REF_POINTER
);
4599 if(pDriverDirectory
== NULL
) {
4600 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4601 SetLastError(ERROR_INVALID_USER_BUFFER
);
4605 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
4606 /* add the Subdirectories */
4607 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
4608 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
4609 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
4614 /*****************************************************************************
4615 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4617 * Return the PATH for the Printer-Drivers (ANSI)
4619 * See GetPrinterDriverDirectoryW.
4622 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4625 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4626 DWORD Level
, LPBYTE pDriverDirectory
,
4627 DWORD cbBuf
, LPDWORD pcbNeeded
)
4629 UNICODE_STRING nameW
, environmentW
;
4632 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4633 WCHAR
*driverDirectoryW
= NULL
;
4635 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4636 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4638 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4640 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4641 else nameW
.Buffer
= NULL
;
4642 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4643 else environmentW
.Buffer
= NULL
;
4645 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4646 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4649 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4650 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4652 *pcbNeeded
= needed
;
4653 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4655 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4657 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4659 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4660 RtlFreeUnicodeString(&environmentW
);
4661 RtlFreeUnicodeString(&nameW
);
4666 /*****************************************************************************
4667 * AddPrinterDriverA [WINSPOOL.@]
4669 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4672 HKEY hkeyDrivers
, hkeyName
;
4673 static CHAR empty
[] = "",
4676 TRACE("(%s,%d,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
4678 if(level
!= 2 && level
!= 3) {
4679 SetLastError(ERROR_INVALID_LEVEL
);
4682 if ((pName
) && (pName
[0])) {
4683 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
4684 SetLastError(ERROR_INVALID_PARAMETER
);
4688 WARN("pDriverInfo == NULL\n");
4689 SetLastError(ERROR_INVALID_PARAMETER
);
4694 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
4696 memset(&di3
, 0, sizeof(di3
));
4697 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
4700 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
4702 SetLastError(ERROR_INVALID_PARAMETER
);
4706 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= empty
;
4707 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= nullnull
;
4708 if(!di3
.pHelpFile
) di3
.pHelpFile
= empty
;
4709 if(!di3
.pMonitorName
) di3
.pMonitorName
= empty
;
4711 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
4714 ERR("Can't create Drivers key\n");
4718 if(level
== 2) { /* apparently can't overwrite with level2 */
4719 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
4720 RegCloseKey(hkeyName
);
4721 RegCloseKey(hkeyDrivers
);
4722 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
4723 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
4727 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
4728 RegCloseKey(hkeyDrivers
);
4729 ERR("Can't create Name key\n");
4732 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
4733 lstrlenA(di3
.pConfigFile
) + 1);
4734 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, lstrlenA(di3
.pDataFile
) + 1);
4735 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, lstrlenA(di3
.pDriverPath
) + 1);
4736 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
4738 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, lstrlenA(di3
.pDefaultDataType
));
4739 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
4740 (LPBYTE
) di3
.pDependentFiles
, multi_sz_lenA(di3
.pDependentFiles
));
4741 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, lstrlenA(di3
.pHelpFile
) + 1);
4742 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, lstrlenA(di3
.pMonitorName
) + 1);
4743 RegCloseKey(hkeyName
);
4744 RegCloseKey(hkeyDrivers
);
4749 /*****************************************************************************
4750 * AddPrinterDriverW [WINSPOOL.@]
4752 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
4755 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName
),
4760 /*****************************************************************************
4761 * AddPrintProcessorA [WINSPOOL.@]
4763 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4764 LPSTR pPrintProcessorName
)
4766 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4767 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4771 /*****************************************************************************
4772 * AddPrintProcessorW [WINSPOOL.@]
4774 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4775 LPWSTR pPrintProcessorName
)
4777 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4778 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4782 /*****************************************************************************
4783 * AddPrintProvidorA [WINSPOOL.@]
4785 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4787 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4791 /*****************************************************************************
4792 * AddPrintProvidorW [WINSPOOL.@]
4794 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4796 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4800 /*****************************************************************************
4801 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4803 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4804 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4806 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4807 pDevModeOutput
, pDevModeInput
);
4811 /*****************************************************************************
4812 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4814 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4815 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4817 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4818 pDevModeOutput
, pDevModeInput
);
4822 /*****************************************************************************
4823 * PrinterProperties [WINSPOOL.@]
4825 * Displays a dialog to set the properties of the printer.
4828 * nonzero on success or zero on failure
4831 * implemented as stub only
4833 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4834 HANDLE hPrinter
/* [in] handle to printer object */
4836 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4837 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4841 /*****************************************************************************
4842 * EnumJobsA [WINSPOOL.@]
4845 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4846 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4849 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4850 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4852 if(pcbNeeded
) *pcbNeeded
= 0;
4853 if(pcReturned
) *pcReturned
= 0;
4858 /*****************************************************************************
4859 * EnumJobsW [WINSPOOL.@]
4862 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4863 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4866 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4867 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4869 if(pcbNeeded
) *pcbNeeded
= 0;
4870 if(pcReturned
) *pcReturned
= 0;
4874 /*****************************************************************************
4875 * WINSPOOL_EnumPrinterDrivers [internal]
4877 * Delivers information about all printer drivers installed on the
4878 * localhost or a given server
4881 * nonzero on success or zero on failure. If the buffer for the returned
4882 * information is too small the function will return an error
4885 * - only implemented for localhost, foreign hosts will return an error
4887 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4888 DWORD Level
, LPBYTE pDriverInfo
,
4889 DWORD cbBuf
, LPDWORD pcbNeeded
,
4890 LPDWORD pcReturned
, BOOL unicode
)
4893 DWORD i
, needed
, number
= 0, size
= 0;
4894 WCHAR DriverNameW
[255];
4897 TRACE("%s,%s,%d,%p,%d,%d\n",
4898 debugstr_w(pName
), debugstr_w(pEnvironment
),
4899 Level
, pDriverInfo
, cbBuf
, unicode
);
4901 /* check for local drivers */
4902 if((pName
) && (pName
[0])) {
4903 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4904 SetLastError(ERROR_ACCESS_DENIED
);
4908 /* check input parameter */
4909 if((Level
< 1) || (Level
> 3)) {
4910 ERR("unsupported level %d\n", Level
);
4911 SetLastError(ERROR_INVALID_LEVEL
);
4915 /* initialize return values */
4917 memset( pDriverInfo
, 0, cbBuf
);
4921 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
4923 ERR("Can't open Drivers key\n");
4927 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4928 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4929 RegCloseKey(hkeyDrivers
);
4930 ERR("Can't query Drivers key\n");
4933 TRACE("Found %d Drivers\n", number
);
4935 /* get size of single struct
4936 * unicode and ascii structure have the same size
4940 size
= sizeof(DRIVER_INFO_1A
);
4943 size
= sizeof(DRIVER_INFO_2A
);
4946 size
= sizeof(DRIVER_INFO_3A
);
4950 /* calculate required buffer size */
4951 *pcbNeeded
= size
* number
;
4953 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
4955 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
4956 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
4958 ERR("Can't enum key number %d\n", i
);
4959 RegCloseKey(hkeyDrivers
);
4962 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4963 pEnvironment
, Level
, ptr
,
4964 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
4965 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4966 &needed
, unicode
)) {
4967 RegCloseKey(hkeyDrivers
);
4970 (*pcbNeeded
) += needed
;
4973 RegCloseKey(hkeyDrivers
);
4975 if(cbBuf
< *pcbNeeded
){
4976 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4980 *pcReturned
= number
;
4984 /*****************************************************************************
4985 * EnumPrinterDriversW [WINSPOOL.@]
4987 * see function EnumPrinterDrivers for RETURNS, BUGS
4989 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4990 LPBYTE pDriverInfo
, DWORD cbBuf
,
4991 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4993 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4994 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
4997 /*****************************************************************************
4998 * EnumPrinterDriversA [WINSPOOL.@]
5000 * see function EnumPrinterDrivers for RETURNS, BUGS
5002 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5003 LPBYTE pDriverInfo
, DWORD cbBuf
,
5004 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5006 UNICODE_STRING pNameW
, pEnvironmentW
;
5007 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5009 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5010 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5012 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5013 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5015 RtlFreeUnicodeString(&pNameW
);
5016 RtlFreeUnicodeString(&pEnvironmentW
);
5021 /******************************************************************************
5022 * EnumPortsA (WINSPOOL.@)
5027 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5028 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5031 LPBYTE bufferW
= NULL
;
5032 LPWSTR nameW
= NULL
;
5034 DWORD numentries
= 0;
5037 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5038 cbBuf
, pcbNeeded
, pcReturned
);
5040 /* convert servername to unicode */
5042 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5043 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5044 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5046 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5047 needed
= cbBuf
* sizeof(WCHAR
);
5048 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5049 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5051 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5052 if (pcbNeeded
) needed
= *pcbNeeded
;
5053 /* HeapReAlloc return NULL, when bufferW was NULL */
5054 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5055 HeapAlloc(GetProcessHeap(), 0, needed
);
5057 /* Try again with the large Buffer */
5058 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5060 needed
= pcbNeeded
? *pcbNeeded
: 0;
5061 numentries
= pcReturned
? *pcReturned
: 0;
5064 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5065 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5068 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5069 DWORD entrysize
= 0;
5072 LPPORT_INFO_2W pi2w
;
5073 LPPORT_INFO_2A pi2a
;
5076 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5078 /* First pass: calculate the size for all Entries */
5079 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5080 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5082 while (index
< numentries
) {
5084 needed
+= entrysize
; /* PORT_INFO_?A */
5085 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5087 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5088 NULL
, 0, NULL
, NULL
);
5090 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5091 NULL
, 0, NULL
, NULL
);
5092 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5093 NULL
, 0, NULL
, NULL
);
5095 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5096 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5097 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5100 /* check for errors and quit on failure */
5101 if (cbBuf
< needed
) {
5102 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5106 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5107 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5108 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5109 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5110 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5112 /* Second Pass: Fill the User Buffer (if we have one) */
5113 while ((index
< numentries
) && pPorts
) {
5115 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5116 pi2a
->pPortName
= ptr
;
5117 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5118 ptr
, cbBuf
, NULL
, NULL
);
5122 pi2a
->pMonitorName
= ptr
;
5123 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5124 ptr
, cbBuf
, NULL
, NULL
);
5128 pi2a
->pDescription
= ptr
;
5129 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5130 ptr
, cbBuf
, NULL
, NULL
);
5134 pi2a
->fPortType
= pi2w
->fPortType
;
5135 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5138 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5139 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5140 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5145 if (pcbNeeded
) *pcbNeeded
= needed
;
5146 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5148 HeapFree(GetProcessHeap(), 0, nameW
);
5149 HeapFree(GetProcessHeap(), 0, bufferW
);
5151 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5152 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5158 /******************************************************************************
5159 * EnumPortsW (WINSPOOL.@)
5161 * Enumerate available Ports
5164 * name [I] Servername or NULL (local Computer)
5165 * level [I] Structure-Level (1 or 2)
5166 * buffer [O] PTR to Buffer that receives the Result
5167 * bufsize [I] Size of Buffer at buffer
5168 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5169 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5173 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5177 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5180 DWORD numentries
= 0;
5183 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5184 cbBuf
, pcbNeeded
, pcReturned
);
5186 if (pName
&& (pName
[0])) {
5187 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5188 SetLastError(ERROR_ACCESS_DENIED
);
5192 /* Level is not checked in win9x */
5193 if (!Level
|| (Level
> 2)) {
5194 WARN("level (%d) is ignored in win9x\n", Level
);
5195 SetLastError(ERROR_INVALID_LEVEL
);
5199 SetLastError(RPC_X_NULL_REF_POINTER
);
5203 EnterCriticalSection(&monitor_handles_cs
);
5206 /* Scan all local Ports */
5208 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5210 /* we calculated the needed buffersize. now do the error-checks */
5211 if (cbBuf
< needed
) {
5212 monitor_unloadall();
5213 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5214 goto emP_cleanup_cs
;
5216 else if (!pPorts
|| !pcReturned
) {
5217 monitor_unloadall();
5218 SetLastError(RPC_X_NULL_REF_POINTER
);
5219 goto emP_cleanup_cs
;
5222 /* Fill the Buffer */
5223 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5225 monitor_unloadall();
5228 LeaveCriticalSection(&monitor_handles_cs
);
5231 if (pcbNeeded
) *pcbNeeded
= needed
;
5232 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5234 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5235 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5240 /******************************************************************************
5241 * GetDefaultPrinterW (WINSPOOL.@)
5244 * This function must read the value from data 'device' of key
5245 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5247 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5251 WCHAR
*buffer
, *ptr
;
5255 SetLastError(ERROR_INVALID_PARAMETER
);
5259 /* make the buffer big enough for the stuff from the profile/registry,
5260 * the content must fit into the local buffer to compute the correct
5261 * size even if the extern buffer is too small or not given.
5262 * (20 for ,driver,port) */
5264 len
= max(100, (insize
+ 20));
5265 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5267 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5269 SetLastError (ERROR_FILE_NOT_FOUND
);
5273 TRACE("%s\n", debugstr_w(buffer
));
5275 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5277 SetLastError(ERROR_INVALID_NAME
);
5283 *namesize
= strlenW(buffer
) + 1;
5284 if(!name
|| (*namesize
> insize
))
5286 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5290 strcpyW(name
, buffer
);
5293 HeapFree( GetProcessHeap(), 0, buffer
);
5298 /******************************************************************************
5299 * GetDefaultPrinterA (WINSPOOL.@)
5301 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5305 WCHAR
*bufferW
= NULL
;
5309 SetLastError(ERROR_INVALID_PARAMETER
);
5313 if(name
&& *namesize
) {
5315 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5318 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5323 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5327 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5330 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5333 HeapFree( GetProcessHeap(), 0, bufferW
);
5338 /******************************************************************************
5339 * SetDefaultPrinterW (WINSPOOL.204)
5341 * Set the Name of the Default Printer
5344 * pszPrinter [I] Name of the Printer or NULL
5351 * When the Parameter is NULL or points to an Empty String and
5352 * a Default Printer was already present, then this Function changes nothing.
5353 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5354 * the First enumerated local Printer is used.
5357 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5360 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5362 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5366 /******************************************************************************
5367 * SetDefaultPrinterA (WINSPOOL.202)
5369 * See SetDefaultPrinterW.
5372 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5375 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5377 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5382 /******************************************************************************
5383 * SetPrinterDataExA (WINSPOOL.@)
5385 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5386 LPCSTR pValueName
, DWORD Type
,
5387 LPBYTE pData
, DWORD cbData
)
5389 HKEY hkeyPrinter
, hkeySubkey
;
5392 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5393 debugstr_a(pValueName
), Type
, pData
, cbData
);
5395 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5399 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5401 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5402 RegCloseKey(hkeyPrinter
);
5405 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5406 RegCloseKey(hkeySubkey
);
5407 RegCloseKey(hkeyPrinter
);
5411 /******************************************************************************
5412 * SetPrinterDataExW (WINSPOOL.@)
5414 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5415 LPCWSTR pValueName
, DWORD Type
,
5416 LPBYTE pData
, DWORD cbData
)
5418 HKEY hkeyPrinter
, hkeySubkey
;
5421 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5422 debugstr_w(pValueName
), Type
, pData
, cbData
);
5424 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5428 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5430 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5431 RegCloseKey(hkeyPrinter
);
5434 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5435 RegCloseKey(hkeySubkey
);
5436 RegCloseKey(hkeyPrinter
);
5440 /******************************************************************************
5441 * SetPrinterDataA (WINSPOOL.@)
5443 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5444 LPBYTE pData
, DWORD cbData
)
5446 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5450 /******************************************************************************
5451 * SetPrinterDataW (WINSPOOL.@)
5453 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5454 LPBYTE pData
, DWORD cbData
)
5456 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5460 /******************************************************************************
5461 * GetPrinterDataExA (WINSPOOL.@)
5463 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5464 LPCSTR pValueName
, LPDWORD pType
,
5465 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5467 HKEY hkeyPrinter
, hkeySubkey
;
5470 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5471 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5474 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5478 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5480 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5481 RegCloseKey(hkeyPrinter
);
5485 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5486 RegCloseKey(hkeySubkey
);
5487 RegCloseKey(hkeyPrinter
);
5491 /******************************************************************************
5492 * GetPrinterDataExW (WINSPOOL.@)
5494 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5495 LPCWSTR pValueName
, LPDWORD pType
,
5496 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5498 HKEY hkeyPrinter
, hkeySubkey
;
5501 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5502 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5505 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5509 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5511 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5512 RegCloseKey(hkeyPrinter
);
5516 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5517 RegCloseKey(hkeySubkey
);
5518 RegCloseKey(hkeyPrinter
);
5522 /******************************************************************************
5523 * GetPrinterDataA (WINSPOOL.@)
5525 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5526 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5528 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5529 pData
, nSize
, pcbNeeded
);
5532 /******************************************************************************
5533 * GetPrinterDataW (WINSPOOL.@)
5535 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5536 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5538 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5539 pData
, nSize
, pcbNeeded
);
5542 /*******************************************************************************
5543 * EnumPrinterDataExW [WINSPOOL.@]
5545 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5546 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5547 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5549 HKEY hkPrinter
, hkSubKey
;
5550 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5551 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5556 PPRINTER_ENUM_VALUESW ppev
;
5558 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5560 if (pKeyName
== NULL
|| *pKeyName
== 0)
5561 return ERROR_INVALID_PARAMETER
;
5563 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5564 if (ret
!= ERROR_SUCCESS
)
5566 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5571 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5572 if (ret
!= ERROR_SUCCESS
)
5574 r
= RegCloseKey (hkPrinter
);
5575 if (r
!= ERROR_SUCCESS
)
5576 WARN ("RegCloseKey returned %i\n", r
);
5577 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5578 debugstr_w (pKeyName
), ret
);
5582 ret
= RegCloseKey (hkPrinter
);
5583 if (ret
!= ERROR_SUCCESS
)
5585 ERR ("RegCloseKey returned %i\n", ret
);
5586 r
= RegCloseKey (hkSubKey
);
5587 if (r
!= ERROR_SUCCESS
)
5588 WARN ("RegCloseKey returned %i\n", r
);
5592 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5593 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5594 if (ret
!= ERROR_SUCCESS
)
5596 r
= RegCloseKey (hkSubKey
);
5597 if (r
!= ERROR_SUCCESS
)
5598 WARN ("RegCloseKey returned %i\n", r
);
5599 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5603 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5604 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5606 if (cValues
== 0) /* empty key */
5608 r
= RegCloseKey (hkSubKey
);
5609 if (r
!= ERROR_SUCCESS
)
5610 WARN ("RegCloseKey returned %i\n", r
);
5611 *pcbEnumValues
= *pnEnumValues
= 0;
5612 return ERROR_SUCCESS
;
5615 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5617 hHeap
= GetProcessHeap ();
5620 ERR ("GetProcessHeap failed\n");
5621 r
= RegCloseKey (hkSubKey
);
5622 if (r
!= ERROR_SUCCESS
)
5623 WARN ("RegCloseKey returned %i\n", r
);
5624 return ERROR_OUTOFMEMORY
;
5627 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5628 if (lpValueName
== NULL
)
5630 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5631 r
= RegCloseKey (hkSubKey
);
5632 if (r
!= ERROR_SUCCESS
)
5633 WARN ("RegCloseKey returned %i\n", r
);
5634 return ERROR_OUTOFMEMORY
;
5637 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5638 if (lpValue
== NULL
)
5640 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5641 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5642 WARN ("HeapFree failed with code %i\n", GetLastError ());
5643 r
= RegCloseKey (hkSubKey
);
5644 if (r
!= ERROR_SUCCESS
)
5645 WARN ("RegCloseKey returned %i\n", r
);
5646 return ERROR_OUTOFMEMORY
;
5649 TRACE ("pass 1: calculating buffer required for all names and values\n");
5651 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5653 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5655 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5657 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5658 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5659 NULL
, NULL
, lpValue
, &cbValueLen
);
5660 if (ret
!= ERROR_SUCCESS
)
5662 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5663 WARN ("HeapFree failed with code %i\n", GetLastError ());
5664 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5665 WARN ("HeapFree failed with code %i\n", GetLastError ());
5666 r
= RegCloseKey (hkSubKey
);
5667 if (r
!= ERROR_SUCCESS
)
5668 WARN ("RegCloseKey returned %i\n", r
);
5669 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5673 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5674 debugstr_w (lpValueName
), dwIndex
,
5675 cbValueNameLen
+ 1, cbValueLen
);
5677 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5678 cbBufSize
+= cbValueLen
;
5681 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5683 *pcbEnumValues
= cbBufSize
;
5684 *pnEnumValues
= cValues
;
5686 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5688 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5689 WARN ("HeapFree failed with code %i\n", GetLastError ());
5690 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5691 WARN ("HeapFree failed with code %i\n", GetLastError ());
5692 r
= RegCloseKey (hkSubKey
);
5693 if (r
!= ERROR_SUCCESS
)
5694 WARN ("RegCloseKey returned %i\n", r
);
5695 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5696 return ERROR_MORE_DATA
;
5699 TRACE ("pass 2: copying all names and values to buffer\n");
5701 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5702 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5704 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5706 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5707 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5708 NULL
, &dwType
, lpValue
, &cbValueLen
);
5709 if (ret
!= ERROR_SUCCESS
)
5711 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5712 WARN ("HeapFree failed with code %i\n", GetLastError ());
5713 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5714 WARN ("HeapFree failed with code %i\n", GetLastError ());
5715 r
= RegCloseKey (hkSubKey
);
5716 if (r
!= ERROR_SUCCESS
)
5717 WARN ("RegCloseKey returned %i\n", r
);
5718 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5722 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5723 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5724 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5725 pEnumValues
+= cbValueNameLen
;
5727 /* return # of *bytes* (including trailing \0), not # of chars */
5728 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5730 ppev
[dwIndex
].dwType
= dwType
;
5732 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5733 ppev
[dwIndex
].pData
= pEnumValues
;
5734 pEnumValues
+= cbValueLen
;
5736 ppev
[dwIndex
].cbData
= cbValueLen
;
5738 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5739 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5742 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5744 ret
= GetLastError ();
5745 ERR ("HeapFree failed with code %i\n", ret
);
5746 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5747 WARN ("HeapFree failed with code %i\n", GetLastError ());
5748 r
= RegCloseKey (hkSubKey
);
5749 if (r
!= ERROR_SUCCESS
)
5750 WARN ("RegCloseKey returned %i\n", r
);
5754 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5756 ret
= GetLastError ();
5757 ERR ("HeapFree failed with code %i\n", ret
);
5758 r
= RegCloseKey (hkSubKey
);
5759 if (r
!= ERROR_SUCCESS
)
5760 WARN ("RegCloseKey returned %i\n", r
);
5764 ret
= RegCloseKey (hkSubKey
);
5765 if (ret
!= ERROR_SUCCESS
)
5767 ERR ("RegCloseKey returned %i\n", ret
);
5771 return ERROR_SUCCESS
;
5774 /*******************************************************************************
5775 * EnumPrinterDataExA [WINSPOOL.@]
5777 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5778 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5779 * what Windows 2000 SP1 does.
5782 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5783 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5784 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5788 DWORD ret
, dwIndex
, dwBufSize
;
5792 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5794 if (pKeyName
== NULL
|| *pKeyName
== 0)
5795 return ERROR_INVALID_PARAMETER
;
5797 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5800 ret
= GetLastError ();
5801 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5805 hHeap
= GetProcessHeap ();
5808 ERR ("GetProcessHeap failed\n");
5809 return ERROR_OUTOFMEMORY
;
5812 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5813 if (pKeyNameW
== NULL
)
5815 ERR ("Failed to allocate %i bytes from process heap\n",
5816 (LONG
)(len
* sizeof (WCHAR
)));
5817 return ERROR_OUTOFMEMORY
;
5820 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5822 ret
= GetLastError ();
5823 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5824 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5829 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5830 pcbEnumValues
, pnEnumValues
);
5831 if (ret
!= ERROR_SUCCESS
)
5833 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5834 WARN ("HeapFree failed with code %i\n", GetLastError ());
5835 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5839 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5841 ret
= GetLastError ();
5842 ERR ("HeapFree failed with code %i\n", ret
);
5846 if (*pnEnumValues
== 0) /* empty key */
5847 return ERROR_SUCCESS
;
5850 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5852 PPRINTER_ENUM_VALUESW ppev
=
5853 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5855 if (dwBufSize
< ppev
->cbValueName
)
5856 dwBufSize
= ppev
->cbValueName
;
5858 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5859 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5860 dwBufSize
= ppev
->cbData
;
5863 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5865 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5866 if (pBuffer
== NULL
)
5868 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5869 return ERROR_OUTOFMEMORY
;
5872 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5874 PPRINTER_ENUM_VALUESW ppev
=
5875 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5877 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5878 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5882 ret
= GetLastError ();
5883 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5884 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5885 WARN ("HeapFree failed with code %i\n", GetLastError ());
5889 memcpy (ppev
->pValueName
, pBuffer
, len
);
5891 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5893 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5894 ppev
->dwType
!= REG_MULTI_SZ
)
5897 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5898 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5901 ret
= GetLastError ();
5902 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5903 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5904 WARN ("HeapFree failed with code %i\n", GetLastError ());
5908 memcpy (ppev
->pData
, pBuffer
, len
);
5910 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5911 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5914 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5916 ret
= GetLastError ();
5917 ERR ("HeapFree failed with code %i\n", ret
);
5921 return ERROR_SUCCESS
;
5924 /******************************************************************************
5925 * AbortPrinter (WINSPOOL.@)
5927 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5929 FIXME("(%p), stub!\n", hPrinter
);
5933 /******************************************************************************
5934 * AddPortA (WINSPOOL.@)
5939 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5941 LPWSTR nameW
= NULL
;
5942 LPWSTR monitorW
= NULL
;
5946 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
5949 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5950 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5951 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5955 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5956 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5957 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5959 res
= AddPortW(nameW
, hWnd
, monitorW
);
5960 HeapFree(GetProcessHeap(), 0, nameW
);
5961 HeapFree(GetProcessHeap(), 0, monitorW
);
5965 /******************************************************************************
5966 * AddPortW (WINSPOOL.@)
5968 * Add a Port for a specific Monitor
5971 * pName [I] Servername or NULL (local Computer)
5972 * hWnd [I] Handle to parent Window for the Dialog-Box
5973 * pMonitorName [I] Name of the Monitor that manage the Port
5980 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
5986 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
5988 if (pName
&& pName
[0]) {
5989 SetLastError(ERROR_INVALID_PARAMETER
);
5993 if (!pMonitorName
) {
5994 SetLastError(RPC_X_NULL_REF_POINTER
);
5998 /* an empty Monitorname is Invalid */
5999 if (!pMonitorName
[0]) {
6000 SetLastError(ERROR_NOT_SUPPORTED
);
6004 pm
= monitor_load(pMonitorName
, NULL
);
6005 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6006 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6007 TRACE("got %d with %u\n", res
, GetLastError());
6012 pui
= monitor_loadui(pm
);
6013 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6014 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6015 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6016 TRACE("got %d with %u\n", res
, GetLastError());
6021 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6022 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6024 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6025 SetLastError(ERROR_NOT_SUPPORTED
);
6028 monitor_unload(pui
);
6031 TRACE("returning %d with %u\n", res
, GetLastError());
6035 /******************************************************************************
6036 * AddPortExA (WINSPOOL.@)
6041 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6044 PORT_INFO_2A
* pi2A
;
6045 LPWSTR nameW
= NULL
;
6046 LPWSTR monitorW
= NULL
;
6050 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6052 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6053 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6055 if ((level
< 1) || (level
> 2)) {
6056 SetLastError(ERROR_INVALID_LEVEL
);
6061 SetLastError(ERROR_INVALID_PARAMETER
);
6066 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6067 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6068 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6072 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6073 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6074 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6077 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6079 if (pi2A
->pPortName
) {
6080 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6081 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6082 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6086 if (pi2A
->pMonitorName
) {
6087 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6088 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6089 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6092 if (pi2A
->pDescription
) {
6093 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6094 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6095 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6097 pi2W
.fPortType
= pi2A
->fPortType
;
6098 pi2W
.Reserved
= pi2A
->Reserved
;
6101 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6103 HeapFree(GetProcessHeap(), 0, nameW
);
6104 HeapFree(GetProcessHeap(), 0, monitorW
);
6105 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6106 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6107 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6112 /******************************************************************************
6113 * AddPortExW (WINSPOOL.@)
6115 * Add a Port for a specific Monitor, without presenting a user interface
6118 * pName [I] Servername or NULL (local Computer)
6119 * level [I] Structure-Level (1 or 2) for pBuffer
6120 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6121 * pMonitorName [I] Name of the Monitor that manage the Port
6128 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6134 pi2
= (PORT_INFO_2W
*) pBuffer
;
6136 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6137 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6138 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6139 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6142 if ((level
< 1) || (level
> 2)) {
6143 SetLastError(ERROR_INVALID_LEVEL
);
6148 SetLastError(ERROR_INVALID_PARAMETER
);
6152 /* we need a valid Monitorname */
6153 if (!pMonitorName
) {
6154 SetLastError(RPC_X_NULL_REF_POINTER
);
6157 if (!pMonitorName
[0]) {
6158 SetLastError(ERROR_NOT_SUPPORTED
);
6162 /* load the Monitor */
6163 pm
= monitor_load(pMonitorName
, NULL
);
6164 if (!pm
) return FALSE
;
6166 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6167 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6168 TRACE("got %u with %u\n", res
, GetLastError());
6174 /******************************************************************************
6175 * AddPrinterConnectionA (WINSPOOL.@)
6177 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6179 FIXME("%s\n", debugstr_a(pName
));
6183 /******************************************************************************
6184 * AddPrinterConnectionW (WINSPOOL.@)
6186 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6188 FIXME("%s\n", debugstr_w(pName
));
6192 /******************************************************************************
6193 * AddPrinterDriverExW (WINSPOOL.@)
6195 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
6196 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6198 FIXME("%s %d %p %d\n", debugstr_w(pName
),
6199 Level
, pDriverInfo
, dwFileCopyFlags
);
6200 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6204 /******************************************************************************
6205 * AddPrinterDriverExA (WINSPOOL.@)
6207 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
6208 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6210 FIXME("%s %d %p %d\n", debugstr_a(pName
),
6211 Level
, pDriverInfo
, dwFileCopyFlags
);
6212 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6216 /******************************************************************************
6217 * ConfigurePortA (WINSPOOL.@)
6219 * See ConfigurePortW.
6222 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6224 LPWSTR nameW
= NULL
;
6225 LPWSTR portW
= NULL
;
6229 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6231 /* convert servername to unicode */
6233 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6234 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6235 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6238 /* convert portname to unicode */
6240 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6241 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6242 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6245 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6246 HeapFree(GetProcessHeap(), 0, nameW
);
6247 HeapFree(GetProcessHeap(), 0, portW
);
6251 /******************************************************************************
6252 * ConfigurePortW (WINSPOOL.@)
6254 * Display the Configuration-Dialog for a specific Port
6257 * pName [I] Servername or NULL (local Computer)
6258 * hWnd [I] Handle to parent Window for the Dialog-Box
6259 * pPortName [I] Name of the Port, that should be configured
6266 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6272 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6274 if (pName
&& pName
[0]) {
6275 SetLastError(ERROR_INVALID_PARAMETER
);
6280 SetLastError(RPC_X_NULL_REF_POINTER
);
6284 /* an empty Portname is Invalid, but can popup a Dialog */
6285 if (!pPortName
[0]) {
6286 SetLastError(ERROR_NOT_SUPPORTED
);
6290 pm
= monitor_load_by_port(pPortName
);
6291 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6292 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6293 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6294 TRACE("got %d with %u\n", res
, GetLastError());
6298 pui
= monitor_loadui(pm
);
6299 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6300 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6301 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6302 TRACE("got %d with %u\n", res
, GetLastError());
6306 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6307 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6309 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6310 SetLastError(ERROR_NOT_SUPPORTED
);
6313 monitor_unload(pui
);
6317 TRACE("returning %d with %u\n", res
, GetLastError());
6321 /******************************************************************************
6322 * ConnectToPrinterDlg (WINSPOOL.@)
6324 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6326 FIXME("%p %x\n", hWnd
, Flags
);
6330 /******************************************************************************
6331 * DeletePrinterConnectionA (WINSPOOL.@)
6333 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6335 FIXME("%s\n", debugstr_a(pName
));
6339 /******************************************************************************
6340 * DeletePrinterConnectionW (WINSPOOL.@)
6342 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6344 FIXME("%s\n", debugstr_w(pName
));
6348 /******************************************************************************
6349 * DeletePrinterDriverExW (WINSPOOL.@)
6351 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6352 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6357 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6358 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6360 if(pName
&& pName
[0])
6362 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6363 SetLastError(ERROR_INVALID_PARAMETER
);
6369 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6370 SetLastError(ERROR_INVALID_PARAMETER
);
6374 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6378 ERR("Can't open drivers key\n");
6382 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6385 RegCloseKey(hkey_drivers
);
6390 /******************************************************************************
6391 * DeletePrinterDriverExA (WINSPOOL.@)
6393 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6394 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6396 UNICODE_STRING NameW
, EnvW
, DriverW
;
6399 asciitounicode(&NameW
, pName
);
6400 asciitounicode(&EnvW
, pEnvironment
);
6401 asciitounicode(&DriverW
, pDriverName
);
6403 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6405 RtlFreeUnicodeString(&DriverW
);
6406 RtlFreeUnicodeString(&EnvW
);
6407 RtlFreeUnicodeString(&NameW
);
6412 /******************************************************************************
6413 * DeletePrinterDataExW (WINSPOOL.@)
6415 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6418 FIXME("%p %s %s\n", hPrinter
,
6419 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6420 return ERROR_INVALID_PARAMETER
;
6423 /******************************************************************************
6424 * DeletePrinterDataExA (WINSPOOL.@)
6426 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6429 FIXME("%p %s %s\n", hPrinter
,
6430 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6431 return ERROR_INVALID_PARAMETER
;
6434 /******************************************************************************
6435 * DeletePrintProcessorA (WINSPOOL.@)
6437 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6439 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6440 debugstr_a(pPrintProcessorName
));
6444 /******************************************************************************
6445 * DeletePrintProcessorW (WINSPOOL.@)
6447 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6449 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6450 debugstr_w(pPrintProcessorName
));
6454 /******************************************************************************
6455 * DeletePrintProvidorA (WINSPOOL.@)
6457 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6459 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6460 debugstr_a(pPrintProviderName
));
6464 /******************************************************************************
6465 * DeletePrintProvidorW (WINSPOOL.@)
6467 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6469 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6470 debugstr_w(pPrintProviderName
));
6474 /******************************************************************************
6475 * EnumFormsA (WINSPOOL.@)
6477 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6478 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6480 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6485 /******************************************************************************
6486 * EnumFormsW (WINSPOOL.@)
6488 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6489 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6491 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6492 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6496 /*****************************************************************************
6497 * EnumMonitorsA [WINSPOOL.@]
6499 * See EnumMonitorsW.
6502 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6503 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6506 LPBYTE bufferW
= NULL
;
6507 LPWSTR nameW
= NULL
;
6509 DWORD numentries
= 0;
6512 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6513 cbBuf
, pcbNeeded
, pcReturned
);
6515 /* convert servername to unicode */
6517 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6518 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6519 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6521 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6522 needed
= cbBuf
* sizeof(WCHAR
);
6523 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6524 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6526 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6527 if (pcbNeeded
) needed
= *pcbNeeded
;
6528 /* HeapReAlloc return NULL, when bufferW was NULL */
6529 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6530 HeapAlloc(GetProcessHeap(), 0, needed
);
6532 /* Try again with the large Buffer */
6533 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6535 numentries
= pcReturned
? *pcReturned
: 0;
6538 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6539 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6542 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6543 DWORD entrysize
= 0;
6546 LPMONITOR_INFO_2W mi2w
;
6547 LPMONITOR_INFO_2A mi2a
;
6549 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6550 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6552 /* First pass: calculate the size for all Entries */
6553 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6554 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6556 while (index
< numentries
) {
6558 needed
+= entrysize
; /* MONITOR_INFO_?A */
6559 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6561 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6562 NULL
, 0, NULL
, NULL
);
6564 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6565 NULL
, 0, NULL
, NULL
);
6566 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6567 NULL
, 0, NULL
, NULL
);
6569 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6570 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6571 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6574 /* check for errors and quit on failure */
6575 if (cbBuf
< needed
) {
6576 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6580 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6581 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6582 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6583 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6584 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6586 /* Second Pass: Fill the User Buffer (if we have one) */
6587 while ((index
< numentries
) && pMonitors
) {
6589 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6591 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6592 ptr
, cbBuf
, NULL
, NULL
);
6596 mi2a
->pEnvironment
= ptr
;
6597 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6598 ptr
, cbBuf
, NULL
, NULL
);
6602 mi2a
->pDLLName
= ptr
;
6603 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6604 ptr
, cbBuf
, NULL
, NULL
);
6608 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6609 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6610 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6614 if (pcbNeeded
) *pcbNeeded
= needed
;
6615 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6617 HeapFree(GetProcessHeap(), 0, nameW
);
6618 HeapFree(GetProcessHeap(), 0, bufferW
);
6620 TRACE("returning %d with %d (%d byte for %d entries)\n",
6621 (res
), GetLastError(), needed
, numentries
);
6627 /*****************************************************************************
6628 * EnumMonitorsW [WINSPOOL.@]
6630 * Enumerate available Port-Monitors
6633 * pName [I] Servername or NULL (local Computer)
6634 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6635 * pMonitors [O] PTR to Buffer that receives the Result
6636 * cbBuf [I] Size of Buffer at pMonitors
6637 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6638 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6642 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6645 * Windows reads the Registry once and cache the Results.
6647 *| Language-Monitors are also installed in the same Registry-Location but
6648 *| they are filtered in Windows (not returned by EnumMonitors).
6649 *| We do no filtering to simplify our Code.
6652 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6653 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6656 DWORD numentries
= 0;
6659 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6660 cbBuf
, pcbNeeded
, pcReturned
);
6662 if (pName
&& (lstrlenW(pName
))) {
6663 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
6664 SetLastError(ERROR_ACCESS_DENIED
);
6668 /* Level is not checked in win9x */
6669 if (!Level
|| (Level
> 2)) {
6670 WARN("level (%d) is ignored in win9x\n", Level
);
6671 SetLastError(ERROR_INVALID_LEVEL
);
6675 SetLastError(RPC_X_NULL_REF_POINTER
);
6679 /* Scan all Monitor-Keys */
6681 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
6683 /* we calculated the needed buffersize. now do the error-checks */
6684 if (cbBuf
< needed
) {
6685 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6688 else if (!pMonitors
|| !pcReturned
) {
6689 SetLastError(RPC_X_NULL_REF_POINTER
);
6693 /* fill the Buffer with the Monitor-Keys */
6694 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
6698 if (pcbNeeded
) *pcbNeeded
= needed
;
6699 if (pcReturned
) *pcReturned
= numentries
;
6701 TRACE("returning %d with %d (%d byte for %d entries)\n",
6702 res
, GetLastError(), needed
, numentries
);
6707 /******************************************************************************
6708 * XcvDataW (WINSPOOL.@)
6710 * Execute commands in the Printmonitor DLL
6713 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6714 * pszDataName [i] Name of the command to execute
6715 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6716 * cbInputData [i] Size in Bytes of Buffer at pInputData
6717 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6718 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6719 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6720 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6727 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6728 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6730 * Minimal List of commands, that a Printmonitor DLL should support:
6732 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6733 *| "AddPort" : Add a Port
6734 *| "DeletePort": Delete a Port
6736 * Many Printmonitors support additional commands. Examples for localspl.dll:
6737 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6738 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6741 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6742 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6743 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6745 opened_printer_t
*printer
;
6747 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6748 pInputData
, cbInputData
, pOutputData
,
6749 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6751 printer
= get_opened_printer(hXcv
);
6752 if (!printer
|| (!printer
->hXcv
)) {
6753 SetLastError(ERROR_INVALID_HANDLE
);
6757 if (!pcbOutputNeeded
) {
6758 SetLastError(ERROR_INVALID_PARAMETER
);
6762 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6763 SetLastError(RPC_X_NULL_REF_POINTER
);
6767 *pcbOutputNeeded
= 0;
6769 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
6770 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
6775 /*****************************************************************************
6776 * EnumPrinterDataA [WINSPOOL.@]
6779 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6780 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6781 DWORD cbData
, LPDWORD pcbData
)
6783 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6784 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6785 return ERROR_NO_MORE_ITEMS
;
6788 /*****************************************************************************
6789 * EnumPrinterDataW [WINSPOOL.@]
6792 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6793 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6794 DWORD cbData
, LPDWORD pcbData
)
6796 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6797 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6798 return ERROR_NO_MORE_ITEMS
;
6801 /*****************************************************************************
6802 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6805 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6806 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6807 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6809 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6810 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6811 pcbNeeded
, pcReturned
);
6815 /*****************************************************************************
6816 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6819 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6820 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6821 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6823 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6824 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6825 pcbNeeded
, pcReturned
);
6829 /*****************************************************************************
6830 * EnumPrintProcessorsA [WINSPOOL.@]
6833 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6834 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6836 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
6837 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
6841 /*****************************************************************************
6842 * EnumPrintProcessorsW [WINSPOOL.@]
6845 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6846 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6848 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6849 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
6850 cbBuf
, pcbNeeded
, pcbReturned
);
6854 /*****************************************************************************
6855 * ExtDeviceMode [WINSPOOL.@]
6858 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6859 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6862 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6863 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6864 debugstr_a(pProfile
), fMode
);
6868 /*****************************************************************************
6869 * FindClosePrinterChangeNotification [WINSPOOL.@]
6872 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6874 FIXME("Stub: %p\n", hChange
);
6878 /*****************************************************************************
6879 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6882 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6883 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6885 FIXME("Stub: %p %x %x %p\n",
6886 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6887 return INVALID_HANDLE_VALUE
;
6890 /*****************************************************************************
6891 * FindNextPrinterChangeNotification [WINSPOOL.@]
6894 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6895 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6897 FIXME("Stub: %p %p %p %p\n",
6898 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
6902 /*****************************************************************************
6903 * FreePrinterNotifyInfo [WINSPOOL.@]
6906 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
6908 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
6912 /*****************************************************************************
6915 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6916 * ansi depending on the unicode parameter.
6918 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
6928 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
6931 memcpy(ptr
, str
, *size
);
6938 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
6941 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
6948 /*****************************************************************************
6951 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
6952 LPDWORD pcbNeeded
, BOOL unicode
)
6954 DWORD size
, left
= cbBuf
;
6955 BOOL space
= (cbBuf
> 0);
6962 ji1
->JobId
= job
->job_id
;
6965 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6966 if(space
&& size
<= left
)
6968 ji1
->pDocument
= (LPWSTR
)ptr
;
6979 /*****************************************************************************
6982 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
6983 LPDWORD pcbNeeded
, BOOL unicode
)
6985 DWORD size
, left
= cbBuf
;
6986 BOOL space
= (cbBuf
> 0);
6993 ji2
->JobId
= job
->job_id
;
6996 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6997 if(space
&& size
<= left
)
6999 ji2
->pDocument
= (LPWSTR
)ptr
;
7010 /*****************************************************************************
7013 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7014 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7017 DWORD needed
= 0, size
;
7021 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7023 EnterCriticalSection(&printer_handles_cs
);
7024 job
= get_job(hPrinter
, JobId
);
7031 size
= sizeof(JOB_INFO_1W
);
7036 memset(pJob
, 0, size
);
7040 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7045 size
= sizeof(JOB_INFO_2W
);
7050 memset(pJob
, 0, size
);
7054 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7059 size
= sizeof(JOB_INFO_3
);
7063 memset(pJob
, 0, size
);
7072 SetLastError(ERROR_INVALID_LEVEL
);
7076 *pcbNeeded
= needed
;
7078 LeaveCriticalSection(&printer_handles_cs
);
7082 /*****************************************************************************
7083 * GetJobA [WINSPOOL.@]
7086 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7087 DWORD cbBuf
, LPDWORD pcbNeeded
)
7089 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7092 /*****************************************************************************
7093 * GetJobW [WINSPOOL.@]
7096 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7097 DWORD cbBuf
, LPDWORD pcbNeeded
)
7099 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7102 /*****************************************************************************
7105 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7107 char *unixname
, *queue
, *cmd
;
7108 char fmt
[] = "lpr -P%s %s";
7111 if(!(unixname
= wine_get_unix_file_name(filename
)))
7114 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7115 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7116 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7118 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7119 sprintf(cmd
, fmt
, queue
, unixname
);
7121 TRACE("printing with: %s\n", cmd
);
7124 HeapFree(GetProcessHeap(), 0, cmd
);
7125 HeapFree(GetProcessHeap(), 0, queue
);
7126 HeapFree(GetProcessHeap(), 0, unixname
);
7130 /*****************************************************************************
7133 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7135 #if HAVE_CUPS_CUPS_H
7138 char *unixname
, *queue
, *doc_titleA
;
7142 if(!(unixname
= wine_get_unix_file_name(filename
)))
7145 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7146 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7147 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7149 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7150 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7151 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7153 TRACE("printing via cups\n");
7154 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7155 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7156 HeapFree(GetProcessHeap(), 0, queue
);
7157 HeapFree(GetProcessHeap(), 0, unixname
);
7163 return schedule_lpr(printer_name
, filename
);
7167 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7174 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7178 if(HIWORD(wparam
) == BN_CLICKED
)
7180 if(LOWORD(wparam
) == IDOK
)
7183 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7186 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7187 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7189 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7191 WCHAR caption
[200], message
[200];
7194 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7195 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7196 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7197 if(mb_ret
== IDCANCEL
)
7199 HeapFree(GetProcessHeap(), 0, filename
);
7203 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7204 if(hf
== INVALID_HANDLE_VALUE
)
7206 WCHAR caption
[200], message
[200];
7208 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7209 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7210 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7211 HeapFree(GetProcessHeap(), 0, filename
);
7215 DeleteFileW(filename
);
7216 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7218 EndDialog(hwnd
, IDOK
);
7221 if(LOWORD(wparam
) == IDCANCEL
)
7223 EndDialog(hwnd
, IDCANCEL
);
7232 /*****************************************************************************
7235 static BOOL
get_filename(LPWSTR
*filename
)
7237 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7238 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7241 /*****************************************************************************
7244 static BOOL
schedule_file(LPCWSTR filename
)
7246 LPWSTR output
= NULL
;
7248 if(get_filename(&output
))
7250 TRACE("copy to %s\n", debugstr_w(output
));
7251 CopyFileW(filename
, output
, FALSE
);
7252 HeapFree(GetProcessHeap(), 0, output
);
7258 /*****************************************************************************
7261 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7264 char *unixname
, *cmdA
;
7266 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7270 if(!(unixname
= wine_get_unix_file_name(filename
)))
7273 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7274 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7275 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7277 TRACE("printing with: %s\n", cmdA
);
7279 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7284 ERR("pipe() failed!\n");
7294 /* reset signals that we previously set to SIG_IGN */
7295 signal(SIGPIPE
, SIG_DFL
);
7296 signal(SIGCHLD
, SIG_DFL
);
7298 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7302 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7303 write(fds
[1], buf
, no_read
);
7308 if(file_fd
!= -1) close(file_fd
);
7309 if(fds
[0] != -1) close(fds
[0]);
7310 if(fds
[1] != -1) close(fds
[1]);
7312 HeapFree(GetProcessHeap(), 0, cmdA
);
7313 HeapFree(GetProcessHeap(), 0, unixname
);
7320 /*****************************************************************************
7323 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7325 int in_fd
, out_fd
, no_read
;
7328 char *unixname
, *outputA
;
7331 if(!(unixname
= wine_get_unix_file_name(filename
)))
7334 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7335 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7336 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7338 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7339 in_fd
= open(unixname
, O_RDONLY
);
7340 if(out_fd
== -1 || in_fd
== -1)
7343 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7344 write(out_fd
, buf
, no_read
);
7348 if(in_fd
!= -1) close(in_fd
);
7349 if(out_fd
!= -1) close(out_fd
);
7350 HeapFree(GetProcessHeap(), 0, outputA
);
7351 HeapFree(GetProcessHeap(), 0, unixname
);
7355 /*****************************************************************************
7356 * ScheduleJob [WINSPOOL.@]
7359 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7361 opened_printer_t
*printer
;
7363 struct list
*cursor
, *cursor2
;
7365 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7366 EnterCriticalSection(&printer_handles_cs
);
7367 printer
= get_opened_printer(hPrinter
);
7371 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7373 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7376 if(job
->job_id
!= dwJobID
) continue;
7378 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7379 if(hf
!= INVALID_HANDLE_VALUE
)
7381 PRINTER_INFO_5W
*pi5
;
7385 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7386 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7388 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7389 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7390 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7391 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7392 debugstr_w(pi5
->pPortName
));
7396 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7397 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7399 DWORD type
, count
= sizeof(output
);
7400 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7403 if(output
[0] == '|')
7405 schedule_pipe(output
+ 1, job
->filename
);
7409 schedule_unixfile(output
, job
->filename
);
7411 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7413 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7415 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7417 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7419 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7421 schedule_file(job
->filename
);
7425 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7427 HeapFree(GetProcessHeap(), 0, pi5
);
7429 DeleteFileW(job
->filename
);
7431 list_remove(cursor
);
7432 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7433 HeapFree(GetProcessHeap(), 0, job
->filename
);
7434 HeapFree(GetProcessHeap(), 0, job
);
7439 LeaveCriticalSection(&printer_handles_cs
);
7443 /*****************************************************************************
7444 * StartDocDlgA [WINSPOOL.@]
7446 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7448 UNICODE_STRING usBuffer
;
7451 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7454 docW
.cbSize
= sizeof(docW
);
7455 if (doc
->lpszDocName
)
7457 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7458 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7460 if (doc
->lpszOutput
)
7462 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7463 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7465 if (doc
->lpszDatatype
)
7467 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7468 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7470 docW
.fwType
= doc
->fwType
;
7472 retW
= StartDocDlgW(hPrinter
, &docW
);
7476 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7477 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7478 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7479 HeapFree(GetProcessHeap(), 0, retW
);
7482 HeapFree(GetProcessHeap(), 0, datatypeW
);
7483 HeapFree(GetProcessHeap(), 0, outputW
);
7484 HeapFree(GetProcessHeap(), 0, docnameW
);
7489 /*****************************************************************************
7490 * StartDocDlgW [WINSPOOL.@]
7492 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7493 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7494 * port is "FILE:". Also returns the full path if passed a relative path.
7496 * The caller should free the returned string from the process heap.
7498 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7503 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7505 PRINTER_INFO_5W
*pi5
;
7506 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7507 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7509 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7510 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7511 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7513 HeapFree(GetProcessHeap(), 0, pi5
);
7516 HeapFree(GetProcessHeap(), 0, pi5
);
7519 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7523 if (get_filename(&name
))
7525 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7527 HeapFree(GetProcessHeap(), 0, name
);
7530 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7531 GetFullPathNameW(name
, len
, ret
, NULL
);
7532 HeapFree(GetProcessHeap(), 0, name
);
7537 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7540 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7541 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7543 attr
= GetFileAttributesW(ret
);
7544 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7546 HeapFree(GetProcessHeap(), 0, ret
);