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 /* ############################### */
100 LPPORT_INFO_2W cache
; /* cached PORT_INFO_2W data */
101 DWORD pi1_needed
; /* size for PORT_INFO_1W */
102 DWORD pi2_needed
; /* size for PORT_INFO_2W */
103 DWORD returned
; /* number of cached PORT_INFO_2W - entries */
129 WCHAR
*document_title
;
137 LPCWSTR versionregpath
;
138 LPCWSTR versionsubdir
;
141 /* ############################### */
143 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
144 static monitor_t
* pm_localport
;
146 static opened_printer_t
**printer_handles
;
147 static int nb_printer_handles
;
148 static LONG next_job_id
= 1;
150 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
151 WORD fwCapability
, LPSTR lpszOutput
,
153 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
154 LPSTR lpszDevice
, LPSTR lpszPort
,
155 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
158 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'c','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
163 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
165 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
166 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
167 'C','o','n','t','r','o','l','\\',
168 'P','r','i','n','t','\\',
169 'M','o','n','i','t','o','r','s','\\',0};
171 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
172 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
173 'C','o','n','t','r','o','l','\\',
174 'P','r','i','n','t','\\',
175 'P','r','i','n','t','e','r','s',0};
177 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
179 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
180 'M','i','c','r','o','s','o','f','t','\\',
181 'W','i','n','d','o','w','s',' ','N','T','\\',
182 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
183 'W','i','n','d','o','w','s',0};
185 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
186 'M','i','c','r','o','s','o','f','t','\\',
187 'W','i','n','d','o','w','s',' ','N','T','\\',
188 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
189 'D','e','v','i','c','e','s',0};
191 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
192 'M','i','c','r','o','s','o','f','t','\\',
193 'W','i','n','d','o','w','s',' ','N','T','\\',
194 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
195 'P','o','r','t','s',0};
197 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
198 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
199 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
200 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
201 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
202 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
203 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
205 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
206 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
208 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
209 'i','o','n',' ','F','i','l','e',0};
210 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
211 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
212 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v',
214 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F',
216 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
218 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
219 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
220 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
221 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
222 static const WCHAR NameW
[] = {'N','a','m','e',0};
223 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
224 static const WCHAR PortW
[] = {'P','o','r','t',0};
225 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
226 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e',
228 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i',
230 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i',
231 'v','e','r','D','a','t','a',0};
232 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F',
234 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
235 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
236 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
237 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
238 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
239 static const WCHAR emptyStringW
[] = {0};
240 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
241 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
243 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
245 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
246 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
247 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
249 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
250 'D','o','c','u','m','e','n','t',0};
252 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
);
253 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
254 DWORD Level
, LPBYTE pDriverInfo
,
255 DWORD cbBuf
, LPDWORD pcbNeeded
,
257 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
);
258 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
);
260 /******************************************************************
261 * validate the user-supplied printing-environment [internal]
264 * env [I] PTR to Environment-String or NULL
268 * Success: PTR to printenv_t
271 * An empty string is handled the same way as NULL.
272 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
276 static const printenv_t
* validate_envW(LPCWSTR env
)
278 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
279 3, Version3_RegPathW
, Version3_SubdirW
};
280 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
281 0, emptyStringW
, emptyStringW
};
282 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
284 const printenv_t
*result
= NULL
;
287 TRACE("testing %s\n", debugstr_w(env
));
290 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
292 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
294 result
= all_printenv
[i
];
299 if (result
== NULL
) {
300 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
301 SetLastError(ERROR_INVALID_ENVIRONMENT
);
303 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
307 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
309 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
315 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
316 if passed a NULL string. This returns NULLs to the result.
318 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
322 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
323 return usBufferPtr
->Buffer
;
325 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
329 static LPWSTR
strdupW(LPCWSTR p
)
335 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
336 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
341 static LPSTR
strdupWtoA( LPCWSTR str
)
346 if (!str
) return NULL
;
347 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
348 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
349 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
353 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
354 The result includes all \0s (specifically the last two). */
355 static int multi_sz_lenA(const char *str
)
357 const char *ptr
= str
;
361 ptr
+= lstrlenA(ptr
) + 1;
364 return ptr
- str
+ 1;
368 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
,BOOL force
) {
371 /* If forcing, or no profile string entry for device yet, set the entry
373 * The always change entry if not WINEPS yet is discussable.
376 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
378 !strstr(qbuf
,"WINEPS.DRV")
380 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
383 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
384 WriteProfileStringA("windows","device",buf
);
385 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
386 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
389 HeapFree(GetProcessHeap(),0,buf
);
393 static BOOL
add_printer_driver(char *name
)
397 static char driver_path
[] = "wineps16",
398 data_file
[] = "<datafile?>",
399 config_file
[] = "wineps16",
400 help_file
[] = "<helpfile?>",
401 dep_file
[] = "<dependent files?>\0",
402 monitor_name
[] = "<monitor name?>",
403 default_data_type
[] = "RAW";
405 di3a
.cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
406 di3a
.pName
= (char *)name
;
407 di3a
.pEnvironment
= NULL
; /* NULL means auto */
408 di3a
.pDriverPath
= driver_path
;
409 di3a
.pDataFile
= data_file
;
410 di3a
.pConfigFile
= config_file
;
411 di3a
.pHelpFile
= help_file
;
412 di3a
.pDependentFiles
= dep_file
;
413 di3a
.pMonitorName
= monitor_name
;
414 di3a
.pDefaultDataType
= default_data_type
;
416 if (!AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
))
418 ERR("Failed adding driver (%d)\n", GetLastError());
424 #ifdef HAVE_CUPS_CUPS_H
425 static typeof(cupsGetDests
) *pcupsGetDests
;
426 static typeof(cupsGetPPD
) *pcupsGetPPD
;
427 static typeof(cupsPrintFile
) *pcupsPrintFile
;
428 static void *cupshandle
;
430 static BOOL
CUPS_LoadPrinters(void)
433 BOOL hadprinter
= FALSE
;
435 PRINTER_INFO_2A pinfo2a
;
437 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
439 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, NULL
, 0);
442 TRACE("loaded %s\n", SONAME_LIBCUPS
);
445 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
446 if (!p##x) return FALSE;
449 DYNCUPS(cupsGetDests
);
450 DYNCUPS(cupsPrintFile
);
453 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
455 ERR("Can't create Printers key\n");
459 nrofdests
= pcupsGetDests(&dests
);
460 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
461 for (i
=0;i
<nrofdests
;i
++) {
462 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
463 sprintf(port
,"LPR:%s",dests
[i
].name
);
464 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
465 sprintf(devline
,"WINEPS.DRV,%s",port
);
466 WriteProfileStringA("devices",dests
[i
].name
,devline
);
467 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
468 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
471 HeapFree(GetProcessHeap(),0,devline
);
473 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
474 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
475 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
477 TRACE("Printer already exists\n");
478 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
479 RegCloseKey(hkeyPrinter
);
481 static CHAR data_type
[] = "RAW",
482 print_proc
[] = "WinPrint",
483 comment
[] = "WINEPS Printer using CUPS",
484 location
[] = "<physical location of printer>",
485 params
[] = "<parameters?>",
486 share_name
[] = "<share name?>",
487 sep_file
[] = "<sep file?>";
489 add_printer_driver(dests
[i
].name
);
491 memset(&pinfo2a
,0,sizeof(pinfo2a
));
492 pinfo2a
.pPrinterName
= dests
[i
].name
;
493 pinfo2a
.pDatatype
= data_type
;
494 pinfo2a
.pPrintProcessor
= print_proc
;
495 pinfo2a
.pDriverName
= dests
[i
].name
;
496 pinfo2a
.pComment
= comment
;
497 pinfo2a
.pLocation
= location
;
498 pinfo2a
.pPortName
= port
;
499 pinfo2a
.pParameters
= params
;
500 pinfo2a
.pShareName
= share_name
;
501 pinfo2a
.pSepFile
= sep_file
;
503 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
504 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
505 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
508 HeapFree(GetProcessHeap(),0,port
);
511 if (dests
[i
].is_default
)
512 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
514 RegCloseKey(hkeyPrinters
);
520 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
521 PRINTER_INFO_2A pinfo2a
;
522 char *e
,*s
,*name
,*prettyname
,*devname
;
523 BOOL ret
= FALSE
, set_default
= FALSE
;
524 char *port
,*devline
,*env_default
;
525 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
527 while (isspace(*pent
)) pent
++;
528 s
= strchr(pent
,':');
530 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
538 TRACE("name=%s entry=%s\n",name
, pent
);
540 if(ispunct(*name
)) { /* a tc entry, not a real printer */
541 TRACE("skipping tc entry\n");
545 if(strstr(pent
,":server")) { /* server only version so skip */
546 TRACE("skipping server entry\n");
550 /* Determine whether this is a postscript printer. */
553 env_default
= getenv("PRINTER");
555 /* Get longest name, usually the one at the right for later display. */
556 while((s
=strchr(prettyname
,'|'))) {
559 while(isspace(*--e
)) *e
= '\0';
560 TRACE("\t%s\n", debugstr_a(prettyname
));
561 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
562 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
565 e
= prettyname
+ strlen(prettyname
);
566 while(isspace(*--e
)) *e
= '\0';
567 TRACE("\t%s\n", debugstr_a(prettyname
));
568 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
570 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
571 * if it is too long, we use it as comment below. */
572 devname
= prettyname
;
573 if (strlen(devname
)>=CCHDEVICENAME
-1)
575 if (strlen(devname
)>=CCHDEVICENAME
-1) {
580 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
581 sprintf(port
,"LPR:%s",name
);
583 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
584 sprintf(devline
,"WINEPS.DRV,%s",port
);
585 WriteProfileStringA("devices",devname
,devline
);
586 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
587 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
590 HeapFree(GetProcessHeap(),0,devline
);
592 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
594 ERR("Can't create Printers key\n");
598 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
599 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
601 TRACE("Printer already exists\n");
602 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
603 RegCloseKey(hkeyPrinter
);
605 static CHAR data_type
[] = "RAW",
606 print_proc
[] = "WinPrint",
607 comment
[] = "WINEPS Printer using LPR",
608 params
[] = "<parameters?>",
609 share_name
[] = "<share name?>",
610 sep_file
[] = "<sep file?>";
612 add_printer_driver(devname
);
614 memset(&pinfo2a
,0,sizeof(pinfo2a
));
615 pinfo2a
.pPrinterName
= devname
;
616 pinfo2a
.pDatatype
= data_type
;
617 pinfo2a
.pPrintProcessor
= print_proc
;
618 pinfo2a
.pDriverName
= devname
;
619 pinfo2a
.pComment
= comment
;
620 pinfo2a
.pLocation
= prettyname
;
621 pinfo2a
.pPortName
= port
;
622 pinfo2a
.pParameters
= params
;
623 pinfo2a
.pShareName
= share_name
;
624 pinfo2a
.pSepFile
= sep_file
;
626 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
627 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
628 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
631 RegCloseKey(hkeyPrinters
);
633 if (isfirst
|| set_default
)
634 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
636 HeapFree(GetProcessHeap(), 0, port
);
638 HeapFree(GetProcessHeap(), 0, name
);
643 PRINTCAP_LoadPrinters(void) {
644 BOOL hadprinter
= FALSE
;
648 BOOL had_bash
= FALSE
;
650 f
= fopen("/etc/printcap","r");
654 while(fgets(buf
,sizeof(buf
),f
)) {
657 end
=strchr(buf
,'\n');
661 while(isspace(*start
)) start
++;
662 if(*start
== '#' || *start
== '\0')
665 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
666 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
667 HeapFree(GetProcessHeap(),0,pent
);
671 if (end
&& *--end
== '\\') {
678 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
681 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
687 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
688 HeapFree(GetProcessHeap(),0,pent
);
694 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
697 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
698 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
700 return ERROR_FILE_NOT_FOUND
;
703 void WINSPOOL_LoadSystemPrinters(void)
705 HKEY hkey
, hkeyPrinters
;
707 DWORD needed
, num
, i
;
708 WCHAR PrinterName
[256];
711 /* This ensures that all printer entries have a valid Name value. If causes
712 problems later if they don't. If one is found to be missed we create one
713 and set it equal to the name of the key */
714 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
715 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
716 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
717 for(i
= 0; i
< num
; i
++) {
718 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
719 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
720 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
721 set_reg_szW(hkey
, NameW
, PrinterName
);
728 RegCloseKey(hkeyPrinters
);
731 /* We want to avoid calling AddPrinter on printers as much as
732 possible, because on cups printers this will (eventually) lead
733 to a call to cupsGetPPD which takes forever, even with non-cups
734 printers AddPrinter takes a while. So we'll tag all printers that
735 were automatically added last time around, if they still exist
736 we'll leave them be otherwise we'll delete them. */
737 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
739 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
740 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
741 for(i
= 0; i
< num
; i
++) {
742 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
743 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
744 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
746 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
754 HeapFree(GetProcessHeap(), 0, pi
);
758 #ifdef HAVE_CUPS_CUPS_H
759 done
= CUPS_LoadPrinters();
762 if(!done
) { /* If we have any CUPS based printers, skip looking for printcap printers */
763 /* Check for [ppd] section in config file before parsing /etc/printcap */
764 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
765 if (RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Printing\\PPD Files",
766 &hkey
) == ERROR_SUCCESS
) {
768 PRINTCAP_LoadPrinters();
772 /* Now enumerate the list again and delete any printers that a still tagged */
773 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
775 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
776 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
777 for(i
= 0; i
< num
; i
++) {
778 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
779 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
780 BOOL delete_driver
= FALSE
;
781 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
782 DWORD dw
, type
, size
= sizeof(dw
);
783 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
784 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
786 delete_driver
= TRUE
;
792 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
797 HeapFree(GetProcessHeap(), 0, pi
);
804 /*****************************************************************************
805 * enumerate the local monitors (INTERNAL)
807 * returns the needed size (in bytes) for pMonitors
808 * and *lpreturned is set to number of entries returned in pMonitors
811 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
816 LPMONITOR_INFO_2W mi
;
817 WCHAR buffer
[MAX_PATH
];
818 WCHAR dllname
[MAX_PATH
];
826 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
828 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
829 len
= entrysize
* numentries
;
830 ptr
= (LPWSTR
) &pMonitors
[len
];
833 len
= sizeof(buffer
);
836 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
837 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
838 /* Scan all Monitor-Registry-Keys */
839 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
840 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
841 dllsize
= sizeof(dllname
);
844 /* The Monitor must have a Driver-DLL */
845 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
846 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
847 /* We found a valid DLL for this Monitor. */
848 TRACE("using Driver: %s\n", debugstr_w(dllname
));
853 /* Windows returns only Port-Monitors here, but to simplify our code,
854 we do no filtering for Language-Monitors */
858 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
860 /* we install and return only monitors for "Windows NT x86" */
861 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
865 /* required size is calculated. Now fill the user-buffer */
866 if (pMonitors
&& (cbBuf
>= needed
)){
867 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
868 pMonitors
+= entrysize
;
870 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
872 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
873 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
875 mi
->pEnvironment
= ptr
;
876 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
877 ptr
+= (lstrlenW(envname_x86W
)+1);
880 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
881 ptr
+= (dllsize
/ sizeof(WCHAR
));
886 len
= sizeof(buffer
);
891 *lpreturned
= numentries
;
892 TRACE("need %d byte for %d entries\n", needed
, numentries
);
896 /******************************************************************
897 * monitor_flush [internal]
899 * flush the cached PORT_INFO_2W - data
902 void monitor_flush(monitor_t
* pm
)
906 EnterCriticalSection(&monitor_handles_cs
);
908 TRACE("%p (%s) cache: %p (%d, %d)\n", pm
, debugstr_w(pm
->name
), pm
->cache
, pm
->pi1_needed
, pm
->pi2_needed
);
910 HeapFree(GetProcessHeap(), 0, pm
->cache
);
915 LeaveCriticalSection(&monitor_handles_cs
);
918 /******************************************************************
919 * monitor_unload [internal]
921 * release a printmonitor and unload it from memory, when needed
924 static void monitor_unload(monitor_t
* pm
)
926 if (pm
== NULL
) return;
927 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
929 EnterCriticalSection(&monitor_handles_cs
);
931 if (pm
->refcount
) pm
->refcount
--;
933 if (pm
->refcount
== 0) {
934 list_remove(&pm
->entry
);
935 FreeLibrary(pm
->hdll
);
936 HeapFree(GetProcessHeap(), 0, pm
->name
);
937 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
938 HeapFree(GetProcessHeap(), 0, pm
);
940 LeaveCriticalSection(&monitor_handles_cs
);
943 /******************************************************************
944 * monitor_unloadall [internal]
946 * release all printmonitors and unload them from memory, when needed
949 static void monitor_unloadall(void)
954 EnterCriticalSection(&monitor_handles_cs
);
955 /* iterate through the list, with safety against removal */
956 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
960 LeaveCriticalSection(&monitor_handles_cs
);
963 /******************************************************************
964 * monitor_load [internal]
966 * load a printmonitor, get the dllname from the registry, when needed
967 * initialize the monitor and dump found function-pointers
969 * On failure, SetLastError() is called and NULL is returned
972 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
974 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
975 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
976 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
977 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
978 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
980 monitor_t
* pm
= NULL
;
982 LPWSTR regroot
= NULL
;
983 LPWSTR driver
= dllname
;
985 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
986 /* Is the Monitor already loaded? */
987 EnterCriticalSection(&monitor_handles_cs
);
990 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
992 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
1000 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
1001 if (pm
== NULL
) goto cleanup
;
1002 list_add_tail(&monitor_handles
, &pm
->entry
);
1006 if (pm
->name
== NULL
) {
1007 /* Load the monitor */
1008 LPMONITOREX pmonitorEx
;
1012 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
1013 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1017 lstrcpyW(regroot
, MonitorsW
);
1018 lstrcatW(regroot
, name
);
1019 /* Get the Driver from the Registry */
1020 if (driver
== NULL
) {
1023 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
1024 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
1025 &namesize
) == ERROR_SUCCESS
) {
1026 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
1027 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
1034 pm
->name
= strdupW(name
);
1035 pm
->dllname
= strdupW(driver
);
1037 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
1039 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1044 pm
->hdll
= LoadLibraryW(driver
);
1045 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
1047 if (pm
->hdll
== NULL
) {
1049 SetLastError(ERROR_MOD_NOT_FOUND
);
1054 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
1055 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
1056 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
1057 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
1058 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
1061 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
1062 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
1063 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
1064 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
1065 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
1067 if (pInitializePrintMonitorUI
!= NULL
) {
1068 pm
->monitorUI
= pInitializePrintMonitorUI();
1069 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
1070 if (pm
->monitorUI
) {
1071 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1072 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
1077 if (pInitializePrintMonitor
&& regroot
) {
1078 pmonitorEx
= pInitializePrintMonitor(regroot
);
1079 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1080 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
1083 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
1084 pm
->monitor
= &(pmonitorEx
->Monitor
);
1089 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
1093 if (!pm
->monitor
&& regroot
) {
1094 if (pInitializePrintMonitor2
!= NULL
) {
1095 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
1097 if (pInitializeMonitorEx
!= NULL
) {
1098 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
1100 if (pInitializeMonitor
!= NULL
) {
1101 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
1104 if (!pm
->monitor
&& !pm
->monitorUI
) {
1106 SetLastError(ERROR_PROC_NOT_FOUND
);
1111 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
1115 LeaveCriticalSection(&monitor_handles_cs
);
1116 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
1117 HeapFree(GetProcessHeap(), 0, regroot
);
1118 TRACE("=> %p\n", pm
);
1122 /******************************************************************
1123 * monitor_loadall [internal]
1125 * Load all registered monitors
1128 static DWORD
monitor_loadall(void)
1131 DWORD registered
= 0;
1134 WCHAR buffer
[MAX_PATH
];
1137 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1138 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1139 NULL
, NULL
, NULL
, NULL
, NULL
);
1141 TRACE("%d monitors registered\n", registered
);
1143 EnterCriticalSection(&monitor_handles_cs
);
1144 while (id
< registered
) {
1146 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1147 pm
= monitor_load(buffer
, NULL
);
1151 LeaveCriticalSection(&monitor_handles_cs
);
1152 RegCloseKey(hmonitors
);
1154 TRACE("%d monitors loaded\n", loaded
);
1158 /******************************************************************
1159 * monitor_loadui [internal]
1161 * load the userinterface-dll for a given portmonitor
1163 * On failure, NULL is returned
1166 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1168 monitor_t
* pui
= NULL
;
1169 LPWSTR buffer
[MAX_PATH
];
1174 if (pm
== NULL
) return NULL
;
1175 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1177 /* Try the Portmonitor first; works for many monitors */
1178 if (pm
->monitorUI
) {
1179 EnterCriticalSection(&monitor_handles_cs
);
1181 LeaveCriticalSection(&monitor_handles_cs
);
1185 /* query the userinterface-dllname from the Portmonitor */
1186 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1187 /* building (",XcvMonitor %s",pm->name) not needed yet */
1188 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1189 TRACE("got %u with %p\n", res
, hXcv
);
1191 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1192 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1193 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1194 pm
->monitor
->pfnXcvClosePort(hXcv
);
1201 /******************************************************************
1202 * monitor_load_by_port [internal]
1204 * load a printmonitor for a given port
1206 * On failure, NULL is returned
1209 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1214 monitor_t
* pm
= NULL
;
1215 DWORD registered
= 0;
1219 TRACE("(%s)\n", debugstr_w(portname
));
1221 /* Try the Local Monitor first */
1222 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1223 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1224 /* found the portname */
1226 return monitor_load(LocalPortW
, NULL
);
1231 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1232 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1233 if (buffer
== NULL
) return NULL
;
1235 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1236 EnterCriticalSection(&monitor_handles_cs
);
1237 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1239 while ((pm
== NULL
) && (id
< registered
)) {
1241 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1242 TRACE("testing %s\n", debugstr_w(buffer
));
1243 len
= lstrlenW(buffer
);
1244 lstrcatW(buffer
, bs_Ports_bsW
);
1245 lstrcatW(buffer
, portname
);
1246 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1248 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1249 pm
= monitor_load(buffer
, NULL
);
1253 LeaveCriticalSection(&monitor_handles_cs
);
1256 HeapFree(GetProcessHeap(), 0, buffer
);
1260 /******************************************************************
1261 * enumerate the local Ports from all loaded monitors (internal)
1263 * returns the needed size (in bytes) for pPorts
1264 * and *lpreturned is set to number of entries returned in pPorts
1267 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1271 LPPORT_INFO_2W cache
;
1281 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1282 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1284 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1285 needed
= entrysize
* numentries
;
1286 ptr
= (LPWSTR
) &pPorts
[needed
];
1291 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1293 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1294 if (pm
->cache
== NULL
) {
1295 res
= pm
->monitor
->pfnEnumPorts(NULL
, 2, NULL
, 0, &(pm
->pi2_needed
), &(pm
->returned
));
1296 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1297 pm
->cache
= HeapAlloc(GetProcessHeap(), 0, (pm
->pi2_needed
));
1298 res
= pm
->monitor
->pfnEnumPorts(NULL
, 2, (LPBYTE
) pm
->cache
, pm
->pi2_needed
, &(pm
->pi2_needed
), &(pm
->returned
));
1300 TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
1301 debugstr_w(pm
->name
), res
, GetLastError(), pm
->pi2_needed
, pm
->returned
);
1304 if (pm
->cache
&& (level
== 1) && (pm
->pi1_needed
== 0) && (pm
->returned
> 0)) {
1307 while (cacheindex
< (pm
->returned
)) {
1308 pm
->pi1_needed
+= sizeof(PORT_INFO_1W
);
1309 pm
->pi1_needed
+= (lstrlenW(cache
->pPortName
) + 1) * sizeof(WCHAR
);
1313 TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
1314 pm
->pi1_needed
, cacheindex
, debugstr_w(pm
->name
));
1316 numentries
+= pm
->returned
;
1317 needed
+= (level
== 1) ? pm
->pi1_needed
: pm
->pi2_needed
;
1319 /* fill the buffer, if we have one */
1320 if (pPorts
&& (cbBuf
>= needed
)) {
1323 while (cacheindex
< pm
->returned
) {
1324 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1325 out
->pPortName
= ptr
;
1326 lstrcpyW(ptr
, cache
->pPortName
);
1327 ptr
+= (lstrlenW(ptr
)+1);
1329 out
->pMonitorName
= ptr
;
1330 lstrcpyW(ptr
, cache
->pMonitorName
);
1331 ptr
+= (lstrlenW(ptr
)+1);
1333 out
->pDescription
= ptr
;
1334 lstrcpyW(ptr
, cache
->pDescription
);
1335 ptr
+= (lstrlenW(ptr
)+1);
1336 out
->fPortType
= cache
->fPortType
;
1337 out
->Reserved
= cache
->Reserved
;
1347 *lpreturned
= numentries
;
1348 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1352 /******************************************************************
1353 * get_servername_from_name (internal)
1355 * for an external server, a copy of the serverpart from the full name is returned
1358 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1362 WCHAR buffer
[MAX_PATH
];
1365 if (name
== NULL
) return NULL
;
1366 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1368 server
= strdupW(&name
[2]); /* skip over both backslash */
1369 if (server
== NULL
) return NULL
;
1371 /* strip '\' and the printername */
1372 ptr
= strchrW(server
, '\\');
1373 if (ptr
) ptr
[0] = '\0';
1375 TRACE("found %s\n", debugstr_w(server
));
1377 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1378 if (GetComputerNameW(buffer
, &len
)) {
1379 if (lstrcmpW(buffer
, server
) == 0) {
1380 /* The requested Servername is our computername */
1381 HeapFree(GetProcessHeap(), 0, server
);
1388 /******************************************************************
1389 * get_basename_from_name (internal)
1391 * skip over the serverpart from the full name
1394 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1396 if (name
== NULL
) return NULL
;
1397 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1398 /* skip over the servername and search for the following '\' */
1399 name
= strchrW(&name
[2], '\\');
1400 if ((name
) && (name
[1])) {
1401 /* found a seperator ('\') followed by a name:
1402 skip over the seperator and return the rest */
1407 /* no basename present (we found only a servername) */
1414 /******************************************************************
1415 * get_opened_printer_entry
1416 * Get the first place empty in the opened printer table
1419 * - pDefault is ignored
1421 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1423 UINT_PTR handle
= nb_printer_handles
, i
;
1424 jobqueue_t
*queue
= NULL
;
1425 opened_printer_t
*printer
= NULL
;
1427 LPCWSTR printername
;
1432 servername
= get_servername_from_name(name
);
1434 FIXME("server %s not supported\n", debugstr_w(servername
));
1435 HeapFree(GetProcessHeap(), 0, servername
);
1436 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1440 printername
= get_basename_from_name(name
);
1441 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1443 /* an empty printername is invalid */
1444 if (printername
&& (!printername
[0])) {
1445 SetLastError(ERROR_INVALID_PARAMETER
);
1449 EnterCriticalSection(&printer_handles_cs
);
1451 for (i
= 0; i
< nb_printer_handles
; i
++)
1453 if (!printer_handles
[i
])
1455 if(handle
== nb_printer_handles
)
1460 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1461 queue
= printer_handles
[i
]->queue
;
1465 if (handle
>= nb_printer_handles
)
1467 opened_printer_t
**new_array
;
1468 if (printer_handles
)
1469 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1470 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1472 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1473 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1480 printer_handles
= new_array
;
1481 nb_printer_handles
+= 16;
1484 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1491 /* clone the base name. This is NULL for the printserver */
1492 printer
->printername
= strdupW(printername
);
1494 /* clone the full name */
1495 printer
->name
= strdupW(name
);
1496 if (name
&& (!printer
->name
)) {
1502 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1503 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1504 /* OpenPrinter(",XcvMonitor " detected */
1505 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1506 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1507 if (printer
->pm
== NULL
) {
1508 SetLastError(ERROR_INVALID_PARAMETER
);
1515 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1516 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1517 /* OpenPrinter(",XcvPort " detected */
1518 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1519 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1520 if (printer
->pm
== NULL
) {
1521 SetLastError(ERROR_INVALID_PARAMETER
);
1529 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1530 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
], pDefault
->DesiredAccess
, &printer
->hXcv
);
1532 if (printer
->hXcv
== NULL
) {
1533 SetLastError(ERROR_INVALID_PARAMETER
);
1540 /* Does the Printer exist? */
1541 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1542 ERR("Can't create Printers key\n");
1546 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1547 WARN("Printer not found in Registry: '%s'\n", debugstr_w(printername
));
1548 RegCloseKey(hkeyPrinters
);
1549 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1553 RegCloseKey(hkeyPrinter
);
1554 RegCloseKey(hkeyPrinters
);
1559 TRACE("using the local printserver\n");
1563 printer
->queue
= queue
;
1566 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1567 if (!printer
->queue
) {
1571 list_init(&printer
->queue
->jobs
);
1572 printer
->queue
->ref
= 0;
1574 InterlockedIncrement(&printer
->queue
->ref
);
1576 printer_handles
[handle
] = printer
;
1579 LeaveCriticalSection(&printer_handles_cs
);
1580 if (!handle
&& printer
) {
1581 /* Something failed: Free all resources */
1582 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1583 monitor_unload(printer
->pm
);
1584 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1585 HeapFree(GetProcessHeap(), 0, printer
->name
);
1586 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1587 HeapFree(GetProcessHeap(), 0, printer
);
1590 return (HANDLE
)handle
;
1593 /******************************************************************
1594 * get_opened_printer
1595 * Get the pointer to the opened printer referred by the handle
1597 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1599 UINT_PTR idx
= (UINT_PTR
)hprn
;
1600 opened_printer_t
*ret
= NULL
;
1602 EnterCriticalSection(&printer_handles_cs
);
1604 if ((idx
<= 0) || (idx
> nb_printer_handles
))
1607 ret
= printer_handles
[idx
- 1];
1609 LeaveCriticalSection(&printer_handles_cs
);
1613 /******************************************************************
1614 * get_opened_printer_name
1615 * Get the pointer to the opened printer name referred by the handle
1617 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1619 opened_printer_t
*printer
= get_opened_printer(hprn
);
1620 if(!printer
) return NULL
;
1621 return printer
->name
;
1624 /******************************************************************
1625 * WINSPOOL_GetOpenedPrinterRegKey
1628 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1630 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1634 if(!name
) return ERROR_INVALID_HANDLE
;
1636 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1640 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1642 ERR("Can't find opened printer %s in registry\n",
1644 RegCloseKey(hkeyPrinters
);
1645 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1647 RegCloseKey(hkeyPrinters
);
1648 return ERROR_SUCCESS
;
1651 /******************************************************************
1654 * Get the pointer to the specified job.
1655 * Should hold the printer_handles_cs before calling.
1657 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1659 opened_printer_t
*printer
= get_opened_printer(hprn
);
1662 if(!printer
) return NULL
;
1663 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1665 if(job
->job_id
== JobId
)
1671 /***********************************************************
1674 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1677 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1680 Formname
= (dmA
->dmSize
> off_formname
);
1681 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1682 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1683 dmW
->dmDeviceName
, CCHDEVICENAME
);
1685 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1686 dmA
->dmSize
- CCHDEVICENAME
);
1688 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1689 off_formname
- CCHDEVICENAME
);
1690 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1691 dmW
->dmFormName
, CCHFORMNAME
);
1692 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1693 (off_formname
+ CCHFORMNAME
));
1696 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1697 dmA
->dmDriverExtra
);
1701 /***********************************************************
1703 * Creates an ascii copy of supplied devmode on heap
1705 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1710 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1712 if(!dmW
) return NULL
;
1713 Formname
= (dmW
->dmSize
> off_formname
);
1714 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1715 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1716 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1717 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1719 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1720 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1722 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1723 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1724 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1725 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1726 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1727 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1730 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1731 dmW
->dmDriverExtra
);
1735 /***********************************************************
1736 * PRINTER_INFO_2AtoW
1737 * Creates a unicode copy of PRINTER_INFO_2A on heap
1739 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1741 LPPRINTER_INFO_2W piW
;
1742 UNICODE_STRING usBuffer
;
1744 if(!piA
) return NULL
;
1745 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1746 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1748 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1749 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1750 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1751 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1752 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1753 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1754 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1755 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1756 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1757 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1758 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1759 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1763 /***********************************************************
1764 * FREE_PRINTER_INFO_2W
1765 * Free PRINTER_INFO_2W and all strings
1767 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1771 HeapFree(heap
,0,piW
->pServerName
);
1772 HeapFree(heap
,0,piW
->pPrinterName
);
1773 HeapFree(heap
,0,piW
->pShareName
);
1774 HeapFree(heap
,0,piW
->pPortName
);
1775 HeapFree(heap
,0,piW
->pDriverName
);
1776 HeapFree(heap
,0,piW
->pComment
);
1777 HeapFree(heap
,0,piW
->pLocation
);
1778 HeapFree(heap
,0,piW
->pDevMode
);
1779 HeapFree(heap
,0,piW
->pSepFile
);
1780 HeapFree(heap
,0,piW
->pPrintProcessor
);
1781 HeapFree(heap
,0,piW
->pDatatype
);
1782 HeapFree(heap
,0,piW
->pParameters
);
1783 HeapFree(heap
,0,piW
);
1787 /******************************************************************
1788 * DeviceCapabilities [WINSPOOL.@]
1789 * DeviceCapabilitiesA [WINSPOOL.@]
1792 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1793 LPSTR pOutput
, LPDEVMODEA lpdm
)
1797 if (!GDI_CallDeviceCapabilities16
)
1799 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1801 if (!GDI_CallDeviceCapabilities16
) return -1;
1803 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1805 /* If DC_PAPERSIZE map POINT16s to POINTs */
1806 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1807 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1808 POINT
*pt
= (POINT
*)pOutput
;
1810 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1811 for(i
= 0; i
< ret
; i
++, pt
++)
1816 HeapFree( GetProcessHeap(), 0, tmp
);
1822 /*****************************************************************************
1823 * DeviceCapabilitiesW [WINSPOOL.@]
1825 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1828 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1829 WORD fwCapability
, LPWSTR pOutput
,
1830 const DEVMODEW
*pDevMode
)
1832 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1833 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1834 LPSTR pPortA
= strdupWtoA(pPort
);
1837 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1838 fwCapability
== DC_FILEDEPENDENCIES
||
1839 fwCapability
== DC_PAPERNAMES
)) {
1840 /* These need A -> W translation */
1843 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1847 switch(fwCapability
) {
1852 case DC_FILEDEPENDENCIES
:
1856 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1857 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1859 for(i
= 0; i
< ret
; i
++)
1860 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1861 pOutput
+ (i
* size
), size
);
1862 HeapFree(GetProcessHeap(), 0, pOutputA
);
1864 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1865 (LPSTR
)pOutput
, dmA
);
1867 HeapFree(GetProcessHeap(),0,pPortA
);
1868 HeapFree(GetProcessHeap(),0,pDeviceA
);
1869 HeapFree(GetProcessHeap(),0,dmA
);
1873 /******************************************************************
1874 * DocumentPropertiesA [WINSPOOL.@]
1876 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1878 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1879 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1880 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1882 LPSTR lpName
= pDeviceName
;
1883 static CHAR port
[] = "LPT1:";
1886 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1887 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1891 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1893 ERR("no name from hPrinter?\n");
1894 SetLastError(ERROR_INVALID_HANDLE
);
1897 lpName
= strdupWtoA(lpNameW
);
1900 if (!GDI_CallExtDeviceMode16
)
1902 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1904 if (!GDI_CallExtDeviceMode16
) {
1905 ERR("No CallExtDeviceMode16?\n");
1909 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1910 pDevModeInput
, NULL
, fMode
);
1913 HeapFree(GetProcessHeap(),0,lpName
);
1918 /*****************************************************************************
1919 * DocumentPropertiesW (WINSPOOL.@)
1921 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1923 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1925 LPDEVMODEW pDevModeOutput
,
1926 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1929 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1930 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1931 LPDEVMODEA pDevModeOutputA
= NULL
;
1934 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1935 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1937 if(pDevModeOutput
) {
1938 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1939 if(ret
< 0) return ret
;
1940 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1942 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1943 pDevModeInputA
, fMode
);
1944 if(pDevModeOutput
) {
1945 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1946 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1948 if(fMode
== 0 && ret
> 0)
1949 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1950 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1951 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1955 /******************************************************************
1956 * OpenPrinterA [WINSPOOL.@]
1961 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1962 LPPRINTER_DEFAULTSA pDefault
)
1964 UNICODE_STRING lpPrinterNameW
;
1965 UNICODE_STRING usBuffer
;
1966 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1967 PWSTR pwstrPrinterNameW
;
1970 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1973 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1974 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1975 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1976 pDefaultW
= &DefaultW
;
1978 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1980 RtlFreeUnicodeString(&usBuffer
);
1981 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1983 RtlFreeUnicodeString(&lpPrinterNameW
);
1987 /******************************************************************
1988 * OpenPrinterW [WINSPOOL.@]
1990 * Open a Printer / Printserver or a Printer-Object
1993 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1994 * phPrinter [O] The resulting Handle is stored here
1995 * pDefault [I] PTR to Default Printer Settings or NULL
2002 * lpPrinterName is one of:
2003 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2004 *| Printer: "PrinterName"
2005 *| Printer-Object: "PrinterName,Job xxx"
2006 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2007 *| XcvPort: "Servername,XcvPort PortName"
2010 *| Printer-Object not supported
2011 *| pDefaults is ignored
2014 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2017 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2019 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2020 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2024 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2025 SetLastError(ERROR_INVALID_PARAMETER
);
2029 /* Get the unique handle of the printer or Printserver */
2030 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2031 TRACE("returning %d with 0x%x and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2032 return (*phPrinter
!= 0);
2035 /******************************************************************
2036 * AddMonitorA [WINSPOOL.@]
2041 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2043 LPWSTR nameW
= NULL
;
2046 LPMONITOR_INFO_2A mi2a
;
2047 MONITOR_INFO_2W mi2w
;
2049 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2050 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2051 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2052 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2053 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2056 SetLastError(ERROR_INVALID_LEVEL
);
2060 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2066 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2067 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2068 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2071 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2073 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2074 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2075 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2077 if (mi2a
->pEnvironment
) {
2078 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2079 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2080 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2082 if (mi2a
->pDLLName
) {
2083 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2084 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2085 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2088 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2090 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2091 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2092 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2094 HeapFree(GetProcessHeap(), 0, nameW
);
2098 /******************************************************************************
2099 * AddMonitorW [WINSPOOL.@]
2101 * Install a Printmonitor
2104 * pName [I] Servername or NULL (local Computer)
2105 * Level [I] Structure-Level (Must be 2)
2106 * pMonitors [I] PTR to MONITOR_INFO_2
2113 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2116 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2118 monitor_t
* pm
= NULL
;
2119 LPMONITOR_INFO_2W mi2w
;
2125 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2126 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2127 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2128 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2129 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2132 SetLastError(ERROR_INVALID_LEVEL
);
2136 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2141 if (pName
&& (pName
[0])) {
2142 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2143 SetLastError(ERROR_ACCESS_DENIED
);
2148 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2149 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2150 SetLastError(ERROR_INVALID_PARAMETER
);
2153 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2154 WARN("Environment %s requested (we support only %s)\n",
2155 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2156 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2160 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2161 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2162 SetLastError(ERROR_INVALID_PARAMETER
);
2166 /* Load and initialize the monitor. SetLastError() is called on failure */
2167 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2172 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2173 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2177 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2178 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2179 &disposition
) == ERROR_SUCCESS
) {
2181 /* Some installers set options for the port before calling AddMonitor.
2182 We query the "Driver" entry to verify that the monitor is installed,
2183 before we return an error.
2184 When a user installs two print monitors at the same time with the
2185 same name but with a different driver DLL and a task switch comes
2186 between RegQueryValueExW and RegSetValueExW, a race condition
2187 is possible but silently ignored. */
2191 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2192 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2193 &namesize
) == ERROR_SUCCESS
)) {
2194 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2195 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2196 9x: ERROR_ALREADY_EXISTS (183) */
2197 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2202 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2203 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2204 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2206 RegCloseKey(hentry
);
2213 /******************************************************************
2214 * DeletePrinterDriverA [WINSPOOL.@]
2217 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2219 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2222 /******************************************************************
2223 * DeletePrinterDriverW [WINSPOOL.@]
2226 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2228 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2231 /******************************************************************
2232 * DeleteMonitorA [WINSPOOL.@]
2234 * See DeleteMonitorW.
2237 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2239 LPWSTR nameW
= NULL
;
2240 LPWSTR EnvironmentW
= NULL
;
2241 LPWSTR MonitorNameW
= NULL
;
2246 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2247 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2248 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2252 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2253 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2254 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2257 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2258 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2259 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2262 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2264 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2265 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2266 HeapFree(GetProcessHeap(), 0, nameW
);
2270 /******************************************************************
2271 * DeleteMonitorW [WINSPOOL.@]
2273 * Delete a specific Printmonitor from a Printing-Environment
2276 * pName [I] Servername or NULL (local Computer)
2277 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2278 * pMonitorName [I] Name of the Monitor, that should be deleted
2285 * pEnvironment is ignored in Windows for the local Computer.
2289 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2293 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2294 debugstr_w(pMonitorName
));
2296 if (pName
&& (pName
[0])) {
2297 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2298 SetLastError(ERROR_ACCESS_DENIED
);
2302 /* pEnvironment is ignored in Windows for the local Computer */
2304 if (!pMonitorName
|| !pMonitorName
[0]) {
2305 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2306 SetLastError(ERROR_INVALID_PARAMETER
);
2310 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2311 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2315 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2316 if(WINSPOOL_SHDeleteKeyW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2317 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2322 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName
));
2325 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2326 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2330 /******************************************************************
2331 * DeletePortA [WINSPOOL.@]
2336 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2338 LPWSTR nameW
= NULL
;
2339 LPWSTR portW
= NULL
;
2343 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2345 /* convert servername to unicode */
2347 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2348 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2349 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2352 /* convert portname to unicode */
2354 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2355 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2356 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2359 res
= DeletePortW(nameW
, hWnd
, portW
);
2360 HeapFree(GetProcessHeap(), 0, nameW
);
2361 HeapFree(GetProcessHeap(), 0, portW
);
2365 /******************************************************************
2366 * DeletePortW [WINSPOOL.@]
2368 * Delete a specific Port
2371 * pName [I] Servername or NULL (local Computer)
2372 * hWnd [I] Handle to parent Window for the Dialog-Box
2373 * pPortName [I] Name of the Port, that should be deleted
2380 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2386 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2388 if (pName
&& pName
[0]) {
2389 SetLastError(ERROR_INVALID_PARAMETER
);
2394 SetLastError(RPC_X_NULL_REF_POINTER
);
2398 /* an empty Portname is Invalid */
2399 if (!pPortName
[0]) {
2400 SetLastError(ERROR_NOT_SUPPORTED
);
2404 pm
= monitor_load_by_port(pPortName
);
2405 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2406 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2407 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2408 TRACE("got %d with %u\n", res
, GetLastError());
2412 pui
= monitor_loadui(pm
);
2413 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2414 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2415 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2416 TRACE("got %d with %u\n", res
, GetLastError());
2420 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2421 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2423 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2424 SetLastError(ERROR_NOT_SUPPORTED
);
2427 monitor_unload(pui
);
2429 /* always invalidate cached PORT_INFO_2W */
2434 TRACE("returning %d with %u\n", res
, GetLastError());
2438 /******************************************************************************
2439 * SetPrinterW [WINSPOOL.@]
2441 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2443 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2444 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2448 /******************************************************************************
2449 * WritePrinter [WINSPOOL.@]
2451 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2453 opened_printer_t
*printer
;
2456 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2458 EnterCriticalSection(&printer_handles_cs
);
2459 printer
= get_opened_printer(hPrinter
);
2462 SetLastError(ERROR_INVALID_HANDLE
);
2468 SetLastError(ERROR_SPL_NO_STARTDOC
);
2472 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2474 LeaveCriticalSection(&printer_handles_cs
);
2478 /*****************************************************************************
2479 * AddFormA [WINSPOOL.@]
2481 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2483 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2487 /*****************************************************************************
2488 * AddFormW [WINSPOOL.@]
2490 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2492 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2496 /*****************************************************************************
2497 * AddJobA [WINSPOOL.@]
2499 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2502 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2506 SetLastError(ERROR_INVALID_LEVEL
);
2510 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2513 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2514 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2515 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2516 if(*pcbNeeded
> cbBuf
) {
2517 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2520 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2521 addjobA
->JobId
= addjobW
->JobId
;
2522 addjobA
->Path
= (char *)(addjobA
+ 1);
2523 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2529 /*****************************************************************************
2530 * AddJobW [WINSPOOL.@]
2532 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2534 opened_printer_t
*printer
;
2537 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2538 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2539 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2541 ADDJOB_INFO_1W
*addjob
;
2543 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2545 EnterCriticalSection(&printer_handles_cs
);
2547 printer
= get_opened_printer(hPrinter
);
2550 SetLastError(ERROR_INVALID_HANDLE
);
2555 SetLastError(ERROR_INVALID_LEVEL
);
2559 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2563 job
->job_id
= InterlockedIncrement(&next_job_id
);
2565 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2566 if(path
[len
- 1] != '\\')
2568 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2569 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2571 len
= strlenW(filename
);
2572 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2573 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2574 job
->document_title
= strdupW(default_doc_title
);
2575 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2577 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2578 if(*pcbNeeded
<= cbBuf
) {
2579 addjob
= (ADDJOB_INFO_1W
*)pData
;
2580 addjob
->JobId
= job
->job_id
;
2581 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2582 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2585 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2588 LeaveCriticalSection(&printer_handles_cs
);
2592 /*****************************************************************************
2593 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2595 * Return the PATH for the Print-Processors
2597 * See GetPrintProcessorDirectoryW.
2601 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2602 DWORD level
, LPBYTE Info
,
2603 DWORD cbBuf
, LPDWORD pcbNeeded
)
2605 LPWSTR serverW
= NULL
;
2610 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2611 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2615 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2616 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2617 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2621 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2622 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2623 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2626 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2627 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2629 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2632 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2633 cbBuf
, NULL
, NULL
) > 0;
2636 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2637 HeapFree(GetProcessHeap(), 0, envW
);
2638 HeapFree(GetProcessHeap(), 0, serverW
);
2642 /*****************************************************************************
2643 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2645 * Return the PATH for the Print-Processors
2648 * server [I] Servername (NT only) or NULL (local Computer)
2649 * env [I] Printing-Environment (see below) or NULL (Default)
2650 * level [I] Structure-Level (must be 1)
2651 * Info [O] PTR to Buffer that receives the Result
2652 * cbBuf [I] Size of Buffer at "Info"
2653 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2654 * required for the Buffer at "Info"
2657 * Success: TRUE and in pcbNeeded the Bytes used in Info
2658 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2659 * if cbBuf is too small
2661 * Native Values returned in Info on Success:
2662 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2663 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2664 *| win9x(Windows 4.0): "%winsysdir%"
2666 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2669 * Only NULL or "" is supported for server
2672 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2673 DWORD level
, LPBYTE Info
,
2674 DWORD cbBuf
, LPDWORD pcbNeeded
)
2677 const printenv_t
* env_t
;
2679 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2680 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2682 if(server
!= NULL
&& server
[0]) {
2683 FIXME("server not supported: %s\n", debugstr_w(server
));
2684 SetLastError(ERROR_INVALID_PARAMETER
);
2688 env_t
= validate_envW(env
);
2689 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2692 WARN("(Level: %d) is ignored in win9x\n", level
);
2693 SetLastError(ERROR_INVALID_LEVEL
);
2697 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2698 needed
= GetSystemDirectoryW(NULL
, 0);
2699 /* add the Size for the Subdirectories */
2700 needed
+= lstrlenW(spoolprtprocsW
);
2701 needed
+= lstrlenW(env_t
->subdir
);
2702 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2704 if(pcbNeeded
) *pcbNeeded
= needed
;
2705 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2706 if (needed
> cbBuf
) {
2707 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2710 if(pcbNeeded
== NULL
) {
2711 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2712 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2713 SetLastError(RPC_X_NULL_REF_POINTER
);
2717 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2718 SetLastError(RPC_X_NULL_REF_POINTER
);
2722 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2723 /* add the Subdirectories */
2724 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2725 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2726 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2730 /*****************************************************************************
2731 * WINSPOOL_OpenDriverReg [internal]
2733 * opens the registry for the printer drivers depending on the given input
2734 * variable pEnvironment
2737 * the opened hkey on success
2740 static HKEY
WINSPOOL_OpenDriverReg( LPVOID pEnvironment
, BOOL unicode
)
2744 const printenv_t
* env
;
2747 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2749 if (!pEnvironment
|| unicode
) {
2750 /* pEnvironment was NULL or an Unicode-String: use it direct */
2751 env
= validate_envW(pEnvironment
);
2755 /* pEnvironment was an ANSI-String: convert to unicode first */
2757 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2758 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2759 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2760 env
= validate_envW(buffer
);
2761 HeapFree(GetProcessHeap(), 0, buffer
);
2763 if (!env
) return NULL
;
2765 buffer
= HeapAlloc( GetProcessHeap(), 0,
2766 (strlenW(DriversW
) + strlenW(env
->envname
) +
2767 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2769 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2770 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2771 HeapFree(GetProcessHeap(), 0, buffer
);
2776 /*****************************************************************************
2777 * AddPrinterW [WINSPOOL.@]
2779 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2781 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2785 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2788 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2791 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2792 SetLastError(ERROR_INVALID_PARAMETER
);
2796 ERR("Level = %d, unsupported!\n", Level
);
2797 SetLastError(ERROR_INVALID_LEVEL
);
2801 SetLastError(ERROR_INVALID_PARAMETER
);
2804 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2806 ERR("Can't create Printers key\n");
2809 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2810 if (!RegQueryValueA(hkeyPrinter
,"Attributes",NULL
,NULL
)) {
2811 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2812 RegCloseKey(hkeyPrinter
);
2813 RegCloseKey(hkeyPrinters
);
2816 RegCloseKey(hkeyPrinter
);
2818 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2820 ERR("Can't create Drivers key\n");
2821 RegCloseKey(hkeyPrinters
);
2824 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2826 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2827 RegCloseKey(hkeyPrinters
);
2828 RegCloseKey(hkeyDrivers
);
2829 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2832 RegCloseKey(hkeyDriver
);
2833 RegCloseKey(hkeyDrivers
);
2835 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2836 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2837 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2838 RegCloseKey(hkeyPrinters
);
2842 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2844 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2845 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2846 RegCloseKey(hkeyPrinters
);
2849 RegSetValueExA(hkeyPrinter
, "Attributes", 0, REG_DWORD
,
2850 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2851 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2853 /* See if we can load the driver. We may need the devmode structure anyway
2856 * Note that DocumentPropertiesW will briefly try to open the printer we
2857 * just create to find a DEVMODEA struct (it will use the WINEPS default
2858 * one in case it is not there, so we are ok).
2860 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2863 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi
->pPrinterName
));
2864 size
= sizeof(DEVMODEW
);
2870 dmW
= HeapAlloc(GetProcessHeap(), 0, size
);
2871 ZeroMemory(dmW
,size
);
2873 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2875 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi
->pPrinterName
));
2876 HeapFree(GetProcessHeap(),0,dmW
);
2881 /* set devmode to printer name */
2882 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2886 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2887 and we support these drivers. NT writes DEVMODEW so somehow
2888 we'll need to distinguish between these when we support NT
2892 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2893 RegSetValueExA(hkeyPrinter
, "Default DevMode", 0, REG_BINARY
,
2894 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2895 HeapFree(GetProcessHeap(), 0, dmA
);
2897 HeapFree(GetProcessHeap(), 0, dmW
);
2899 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2900 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2901 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2902 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2904 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2905 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2906 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2907 RegSetValueExA(hkeyPrinter
, "Priority", 0, REG_DWORD
,
2908 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2909 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2910 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2911 RegSetValueExA(hkeyPrinter
, "StartTime", 0, REG_DWORD
,
2912 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2913 RegSetValueExA(hkeyPrinter
, "Status", 0, REG_DWORD
,
2914 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2915 RegSetValueExA(hkeyPrinter
, "UntilTime", 0, REG_DWORD
,
2916 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2918 RegCloseKey(hkeyPrinter
);
2919 RegCloseKey(hkeyPrinters
);
2920 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2921 ERR("OpenPrinter failing\n");
2927 /*****************************************************************************
2928 * AddPrinterA [WINSPOOL.@]
2930 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2932 UNICODE_STRING pNameW
;
2934 PRINTER_INFO_2W
*piW
;
2935 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2938 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2940 ERR("Level = %d, unsupported!\n", Level
);
2941 SetLastError(ERROR_INVALID_LEVEL
);
2944 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2945 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2947 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2949 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2950 RtlFreeUnicodeString(&pNameW
);
2955 /*****************************************************************************
2956 * ClosePrinter [WINSPOOL.@]
2958 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2960 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2961 opened_printer_t
*printer
= NULL
;
2964 TRACE("(%p)\n", hPrinter
);
2966 EnterCriticalSection(&printer_handles_cs
);
2968 if ((i
> 0) && (i
<= nb_printer_handles
))
2969 printer
= printer_handles
[i
- 1];
2974 struct list
*cursor
, *cursor2
;
2976 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
2977 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
2978 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
2981 EndDocPrinter(hPrinter
);
2983 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2985 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2987 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2988 ScheduleJob(hPrinter
, job
->job_id
);
2990 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2992 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
2993 monitor_unload(printer
->pm
);
2994 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2995 HeapFree(GetProcessHeap(), 0, printer
->name
);
2996 HeapFree(GetProcessHeap(), 0, printer
);
2997 printer_handles
[i
- 1] = NULL
;
3000 LeaveCriticalSection(&printer_handles_cs
);
3004 /*****************************************************************************
3005 * DeleteFormA [WINSPOOL.@]
3007 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3009 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3013 /*****************************************************************************
3014 * DeleteFormW [WINSPOOL.@]
3016 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3018 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3022 /*****************************************************************************
3023 * WINSPOOL_SHRegDeleteKey
3025 * Recursively delete subkeys.
3026 * Cut & paste from shlwapi.
3029 static DWORD
WINSPOOL_SHDeleteKeyW(HKEY hKey
, LPCWSTR lpszSubKey
)
3031 DWORD dwRet
, dwKeyCount
= 0, dwMaxSubkeyLen
= 0, dwSize
, i
;
3032 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
3035 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
3038 /* Find how many subkeys there are */
3039 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, &dwKeyCount
,
3040 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
3044 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
3045 /* Name too big: alloc a buffer for it */
3046 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
3049 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
3052 /* Recursively delete all the subkeys */
3053 for(i
= 0; i
< dwKeyCount
&& !dwRet
; i
++)
3055 dwSize
= dwMaxSubkeyLen
;
3056 dwRet
= RegEnumKeyExW(hSubKey
, i
, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
3058 dwRet
= WINSPOOL_SHDeleteKeyW(hSubKey
, lpszName
);
3061 if (lpszName
!= szNameBuf
)
3062 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
3066 RegCloseKey(hSubKey
);
3068 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
3073 /*****************************************************************************
3074 * DeletePrinter [WINSPOOL.@]
3076 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3078 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3079 HKEY hkeyPrinters
, hkey
;
3082 SetLastError(ERROR_INVALID_HANDLE
);
3085 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3086 WINSPOOL_SHDeleteKeyW(hkeyPrinters
, lpNameW
);
3087 RegCloseKey(hkeyPrinters
);
3089 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3090 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3091 RegDeleteValueW(hkey
, lpNameW
);
3097 /*****************************************************************************
3098 * SetPrinterA [WINSPOOL.@]
3100 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3103 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3107 /*****************************************************************************
3108 * SetJobA [WINSPOOL.@]
3110 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3111 LPBYTE pJob
, DWORD Command
)
3115 UNICODE_STRING usBuffer
;
3117 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3119 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3120 are all ignored by SetJob, so we don't bother copying them */
3128 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3129 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3131 JobW
= (LPBYTE
)info1W
;
3132 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3133 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3134 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3135 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3136 info1W
->Status
= info1A
->Status
;
3137 info1W
->Priority
= info1A
->Priority
;
3138 info1W
->Position
= info1A
->Position
;
3139 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3144 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3145 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3147 JobW
= (LPBYTE
)info2W
;
3148 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3149 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3150 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3151 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3152 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3153 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3154 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3155 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3156 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3157 info2W
->Status
= info2A
->Status
;
3158 info2W
->Priority
= info2A
->Priority
;
3159 info2W
->Position
= info2A
->Position
;
3160 info2W
->StartTime
= info2A
->StartTime
;
3161 info2W
->UntilTime
= info2A
->UntilTime
;
3162 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3166 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3167 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3170 SetLastError(ERROR_INVALID_LEVEL
);
3174 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3180 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3181 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3182 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3183 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3184 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3189 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3190 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3191 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3192 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3193 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3194 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3195 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3196 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3197 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3201 HeapFree(GetProcessHeap(), 0, JobW
);
3206 /*****************************************************************************
3207 * SetJobW [WINSPOOL.@]
3209 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3210 LPBYTE pJob
, DWORD Command
)
3215 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3216 FIXME("Ignoring everything other than document title\n");
3218 EnterCriticalSection(&printer_handles_cs
);
3219 job
= get_job(hPrinter
, JobId
);
3229 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3230 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3231 job
->document_title
= strdupW(info1
->pDocument
);
3236 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3237 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3238 job
->document_title
= strdupW(info2
->pDocument
);
3244 SetLastError(ERROR_INVALID_LEVEL
);
3249 LeaveCriticalSection(&printer_handles_cs
);
3253 /*****************************************************************************
3254 * EndDocPrinter [WINSPOOL.@]
3256 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3258 opened_printer_t
*printer
;
3260 TRACE("(%p)\n", hPrinter
);
3262 EnterCriticalSection(&printer_handles_cs
);
3264 printer
= get_opened_printer(hPrinter
);
3267 SetLastError(ERROR_INVALID_HANDLE
);
3273 SetLastError(ERROR_SPL_NO_STARTDOC
);
3277 CloseHandle(printer
->doc
->hf
);
3278 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3279 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3280 printer
->doc
= NULL
;
3283 LeaveCriticalSection(&printer_handles_cs
);
3287 /*****************************************************************************
3288 * EndPagePrinter [WINSPOOL.@]
3290 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3292 FIXME("(%p): stub\n", hPrinter
);
3296 /*****************************************************************************
3297 * StartDocPrinterA [WINSPOOL.@]
3299 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3301 UNICODE_STRING usBuffer
;
3303 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3306 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3307 or one (DOC_INFO_3) extra DWORDs */
3311 doc2W
.JobId
= doc2
->JobId
;
3314 doc2W
.dwMode
= doc2
->dwMode
;
3317 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3318 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3319 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3323 SetLastError(ERROR_INVALID_LEVEL
);
3327 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3329 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3330 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3331 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3336 /*****************************************************************************
3337 * StartDocPrinterW [WINSPOOL.@]
3339 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3341 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3342 opened_printer_t
*printer
;
3343 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3344 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3345 JOB_INFO_1W job_info
;
3346 DWORD needed
, ret
= 0;
3350 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3351 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3352 debugstr_w(doc
->pDatatype
));
3354 if(Level
< 1 || Level
> 3)
3356 SetLastError(ERROR_INVALID_LEVEL
);
3360 EnterCriticalSection(&printer_handles_cs
);
3361 printer
= get_opened_printer(hPrinter
);
3364 SetLastError(ERROR_INVALID_HANDLE
);
3370 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3374 /* Even if we're printing to a file we still add a print job, we'll
3375 just ignore the spool file name */
3377 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3379 ERR("AddJob failed gle %08x\n", GetLastError());
3383 if(doc
->pOutputFile
)
3384 filename
= doc
->pOutputFile
;
3386 filename
= addjob
->Path
;
3388 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3389 if(hf
== INVALID_HANDLE_VALUE
)
3392 memset(&job_info
, 0, sizeof(job_info
));
3393 job_info
.pDocument
= doc
->pDocName
;
3394 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3396 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3397 printer
->doc
->hf
= hf
;
3398 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3400 LeaveCriticalSection(&printer_handles_cs
);
3405 /*****************************************************************************
3406 * StartPagePrinter [WINSPOOL.@]
3408 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3410 FIXME("(%p): stub\n", hPrinter
);
3414 /*****************************************************************************
3415 * GetFormA [WINSPOOL.@]
3417 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3418 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3420 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3421 Level
,pForm
,cbBuf
,pcbNeeded
);
3425 /*****************************************************************************
3426 * GetFormW [WINSPOOL.@]
3428 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3429 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3431 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3432 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3436 /*****************************************************************************
3437 * SetFormA [WINSPOOL.@]
3439 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3442 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3446 /*****************************************************************************
3447 * SetFormW [WINSPOOL.@]
3449 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3452 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3456 /*****************************************************************************
3457 * ReadPrinter [WINSPOOL.@]
3459 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3460 LPDWORD pNoBytesRead
)
3462 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3466 /*****************************************************************************
3467 * ResetPrinterA [WINSPOOL.@]
3469 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3471 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3475 /*****************************************************************************
3476 * ResetPrinterW [WINSPOOL.@]
3478 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3480 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3484 /*****************************************************************************
3485 * WINSPOOL_GetDWORDFromReg
3487 * Return DWORD associated with ValueName from hkey.
3489 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3491 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3494 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3496 if(ret
!= ERROR_SUCCESS
) {
3497 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3500 if(type
!= REG_DWORD
) {
3501 ERR("Got type %d\n", type
);
3507 /*****************************************************************************
3508 * WINSPOOL_GetStringFromReg
3510 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3511 * String is stored either as unicode or ascii.
3512 * Bit of a hack here to get the ValueName if we want ascii.
3514 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3515 DWORD buflen
, DWORD
*needed
,
3518 DWORD sz
= buflen
, type
;
3522 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3524 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3525 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3526 HeapFree(GetProcessHeap(),0,ValueNameA
);
3528 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3529 WARN("Got ret = %d\n", ret
);
3533 /* add space for terminating '\0' */
3534 sz
+= unicode
? sizeof(WCHAR
) : 1;
3538 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3543 /*****************************************************************************
3544 * WINSPOOL_GetDefaultDevMode
3546 * Get a default DevMode values for wineps.
3550 static void WINSPOOL_GetDefaultDevMode(
3552 DWORD buflen
, DWORD
*needed
,
3556 static const char szwps
[] = "wineps.drv";
3558 /* fill default DEVMODE - should be read from ppd... */
3559 ZeroMemory( &dm
, sizeof(dm
) );
3560 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3561 dm
.dmSpecVersion
= DM_SPECVERSION
;
3562 dm
.dmDriverVersion
= 1;
3563 dm
.dmSize
= sizeof(DEVMODEA
);
3564 dm
.dmDriverExtra
= 0;
3566 DM_ORIENTATION
| DM_PAPERSIZE
|
3567 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3570 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3571 DM_YRESOLUTION
| DM_TTOPTION
;
3573 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3574 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3575 dm
.u1
.s1
.dmPaperLength
= 2970;
3576 dm
.u1
.s1
.dmPaperWidth
= 2100;
3580 dm
.dmDefaultSource
= DMBIN_AUTO
;
3581 dm
.dmPrintQuality
= DMRES_MEDIUM
;
3584 dm
.dmYResolution
= 300; /* 300dpi */
3585 dm
.dmTTOption
= DMTT_BITMAP
;
3588 /* dm.dmLogPixels */
3589 /* dm.dmBitsPerPel */
3590 /* dm.dmPelsWidth */
3591 /* dm.dmPelsHeight */
3592 /* dm.dmDisplayFlags */
3593 /* dm.dmDisplayFrequency */
3594 /* dm.dmICMMethod */
3595 /* dm.dmICMIntent */
3596 /* dm.dmMediaType */
3597 /* dm.dmDitherType */
3598 /* dm.dmReserved1 */
3599 /* dm.dmReserved2 */
3600 /* dm.dmPanningWidth */
3601 /* dm.dmPanningHeight */
3604 if(buflen
>= sizeof(DEVMODEW
)) {
3605 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3606 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3607 HeapFree(GetProcessHeap(),0,pdmW
);
3609 *needed
= sizeof(DEVMODEW
);
3613 if(buflen
>= sizeof(DEVMODEA
)) {
3614 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3616 *needed
= sizeof(DEVMODEA
);
3620 /*****************************************************************************
3621 * WINSPOOL_GetDevModeFromReg
3623 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3624 * DevMode is stored either as unicode or ascii.
3626 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3628 DWORD buflen
, DWORD
*needed
,
3631 DWORD sz
= buflen
, type
;
3634 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3635 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3636 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3637 if (sz
< sizeof(DEVMODEA
))
3639 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3642 /* ensures that dmSize is not erratically bogus if registry is invalid */
3643 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3644 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3646 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3648 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3649 memcpy(ptr
, dmW
, sz
);
3650 HeapFree(GetProcessHeap(),0,dmW
);
3657 /*********************************************************************
3658 * WINSPOOL_GetPrinter_2
3660 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3661 * The strings are either stored as unicode or ascii.
3663 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3664 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3667 DWORD size
, left
= cbBuf
;
3668 BOOL space
= (cbBuf
> 0);
3673 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3675 if(space
&& size
<= left
) {
3676 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3683 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3685 if(space
&& size
<= left
) {
3686 pi2
->pShareName
= (LPWSTR
)ptr
;
3693 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3695 if(space
&& size
<= left
) {
3696 pi2
->pPortName
= (LPWSTR
)ptr
;
3703 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3705 if(space
&& size
<= left
) {
3706 pi2
->pDriverName
= (LPWSTR
)ptr
;
3713 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3715 if(space
&& size
<= left
) {
3716 pi2
->pComment
= (LPWSTR
)ptr
;
3723 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3725 if(space
&& size
<= left
) {
3726 pi2
->pLocation
= (LPWSTR
)ptr
;
3733 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3735 if(space
&& size
<= left
) {
3736 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3745 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3746 if(space
&& size
<= left
) {
3747 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3754 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3756 if(space
&& size
<= left
) {
3757 pi2
->pSepFile
= (LPWSTR
)ptr
;
3764 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3766 if(space
&& size
<= left
) {
3767 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3774 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3776 if(space
&& size
<= left
) {
3777 pi2
->pDatatype
= (LPWSTR
)ptr
;
3784 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3786 if(space
&& size
<= left
) {
3787 pi2
->pParameters
= (LPWSTR
)ptr
;
3795 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3796 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3797 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3798 "Default Priority");
3799 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3800 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3803 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3804 memset(pi2
, 0, sizeof(*pi2
));
3809 /*********************************************************************
3810 * WINSPOOL_GetPrinter_4
3812 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3814 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
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 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3835 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3838 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3839 memset(pi4
, 0, sizeof(*pi4
));
3844 /*********************************************************************
3845 * WINSPOOL_GetPrinter_5
3847 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3849 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3850 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3853 DWORD size
, left
= cbBuf
;
3854 BOOL space
= (cbBuf
> 0);
3859 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3861 if(space
&& size
<= left
) {
3862 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3869 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3871 if(space
&& size
<= left
) {
3872 pi5
->pPortName
= (LPWSTR
)ptr
;
3880 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3881 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3883 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3887 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3888 memset(pi5
, 0, sizeof(*pi5
));
3893 /*****************************************************************************
3894 * WINSPOOL_GetPrinter
3896 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3897 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3898 * just a collection of pointers to strings.
3900 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3901 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3904 DWORD size
, needed
= 0;
3906 HKEY hkeyPrinter
, hkeyPrinters
;
3909 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3911 if (!(name
= get_opened_printer_name(hPrinter
))) {
3912 SetLastError(ERROR_INVALID_HANDLE
);
3916 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3918 ERR("Can't create Printers key\n");
3921 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3923 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3924 RegCloseKey(hkeyPrinters
);
3925 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3932 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3934 size
= sizeof(PRINTER_INFO_2W
);
3936 ptr
= pPrinter
+ size
;
3938 memset(pPrinter
, 0, size
);
3943 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
3951 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3953 size
= sizeof(PRINTER_INFO_4W
);
3955 ptr
= pPrinter
+ size
;
3957 memset(pPrinter
, 0, size
);
3962 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
3971 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3973 size
= sizeof(PRINTER_INFO_5W
);
3975 ptr
= pPrinter
+ size
;
3977 memset(pPrinter
, 0, size
);
3983 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
3990 FIXME("Unimplemented level %d\n", Level
);
3991 SetLastError(ERROR_INVALID_LEVEL
);
3992 RegCloseKey(hkeyPrinters
);
3993 RegCloseKey(hkeyPrinter
);
3997 RegCloseKey(hkeyPrinter
);
3998 RegCloseKey(hkeyPrinters
);
4000 TRACE("returning %d needed = %d\n", ret
, needed
);
4001 if(pcbNeeded
) *pcbNeeded
= needed
;
4003 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4007 /*****************************************************************************
4008 * GetPrinterW [WINSPOOL.@]
4010 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4011 DWORD cbBuf
, LPDWORD pcbNeeded
)
4013 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4017 /*****************************************************************************
4018 * GetPrinterA [WINSPOOL.@]
4020 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4021 DWORD cbBuf
, LPDWORD pcbNeeded
)
4023 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4027 /*****************************************************************************
4028 * WINSPOOL_EnumPrinters
4030 * Implementation of EnumPrintersA|W
4032 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4033 DWORD dwLevel
, LPBYTE lpbPrinters
,
4034 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4035 LPDWORD lpdwReturned
, BOOL unicode
)
4038 HKEY hkeyPrinters
, hkeyPrinter
;
4039 WCHAR PrinterName
[255];
4040 DWORD needed
= 0, number
= 0;
4041 DWORD used
, i
, left
;
4045 memset(lpbPrinters
, 0, cbBuf
);
4051 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4052 if(dwType
== PRINTER_ENUM_DEFAULT
)
4055 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4056 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4057 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4058 if(!dwType
) return TRUE
;
4061 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4062 FIXME("dwType = %08x\n", dwType
);
4063 SetLastError(ERROR_INVALID_FLAGS
);
4067 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4069 ERR("Can't create Printers key\n");
4073 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4074 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4075 RegCloseKey(hkeyPrinters
);
4076 ERR("Can't query Printers key\n");
4079 TRACE("Found %d printers\n", number
);
4083 RegCloseKey(hkeyPrinters
);
4085 *lpdwReturned
= number
;
4089 used
= number
* sizeof(PRINTER_INFO_2W
);
4092 used
= number
* sizeof(PRINTER_INFO_4W
);
4095 used
= number
* sizeof(PRINTER_INFO_5W
);
4099 SetLastError(ERROR_INVALID_LEVEL
);
4100 RegCloseKey(hkeyPrinters
);
4103 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4105 for(i
= 0; i
< number
; i
++) {
4106 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
4108 ERR("Can't enum key number %d\n", i
);
4109 RegCloseKey(hkeyPrinters
);
4112 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4113 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4115 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4116 RegCloseKey(hkeyPrinters
);
4121 buf
= lpbPrinters
+ used
;
4122 left
= cbBuf
- used
;
4130 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4131 left
, &needed
, unicode
);
4133 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4136 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4137 left
, &needed
, unicode
);
4139 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4142 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4143 left
, &needed
, unicode
);
4145 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4148 ERR("Shouldn't be here!\n");
4149 RegCloseKey(hkeyPrinter
);
4150 RegCloseKey(hkeyPrinters
);
4153 RegCloseKey(hkeyPrinter
);
4155 RegCloseKey(hkeyPrinters
);
4162 memset(lpbPrinters
, 0, cbBuf
);
4163 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4167 *lpdwReturned
= number
;
4168 SetLastError(ERROR_SUCCESS
);
4173 /******************************************************************
4174 * EnumPrintersW [WINSPOOL.@]
4176 * Enumerates the available printers, print servers and print
4177 * providers, depending on the specified flags, name and level.
4181 * If level is set to 1:
4182 * Not implemented yet!
4183 * Returns TRUE with an empty list.
4185 * If level is set to 2:
4186 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4187 * Returns an array of PRINTER_INFO_2 data structures in the
4188 * lpbPrinters buffer. Note that according to MSDN also an
4189 * OpenPrinter should be performed on every remote printer.
4191 * If level is set to 4 (officially WinNT only):
4192 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4193 * Fast: Only the registry is queried to retrieve printer names,
4194 * no connection to the driver is made.
4195 * Returns an array of PRINTER_INFO_4 data structures in the
4196 * lpbPrinters buffer.
4198 * If level is set to 5 (officially WinNT4/Win9x only):
4199 * Fast: Only the registry is queried to retrieve printer names,
4200 * no connection to the driver is made.
4201 * Returns an array of PRINTER_INFO_5 data structures in the
4202 * lpbPrinters buffer.
4204 * If level set to 3 or 6+:
4205 * returns zero (failure!)
4207 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4211 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4212 * - Only levels 2, 4 and 5 are implemented at the moment.
4213 * - 16-bit printer drivers are not enumerated.
4214 * - Returned amount of bytes used/needed does not match the real Windoze
4215 * implementation (as in this implementation, all strings are part
4216 * of the buffer, whereas Win32 keeps them somewhere else)
4217 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4220 * - In a regular Wine installation, no registry settings for printers
4221 * exist, which makes this function return an empty list.
4223 BOOL WINAPI
EnumPrintersW(
4224 DWORD dwType
, /* [in] Types of print objects to enumerate */
4225 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4226 DWORD dwLevel
, /* [in] type of printer info structure */
4227 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4228 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4229 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4230 LPDWORD lpdwReturned
/* [out] number of entries returned */
4233 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4234 lpdwNeeded
, lpdwReturned
, TRUE
);
4237 /******************************************************************
4238 * EnumPrintersA [WINSPOOL.@]
4241 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4242 DWORD dwLevel
, LPBYTE lpbPrinters
,
4243 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4244 LPDWORD lpdwReturned
)
4246 BOOL ret
, unicode
= FALSE
;
4247 UNICODE_STRING lpszNameW
;
4250 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4251 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4252 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4253 lpdwNeeded
, lpdwReturned
, unicode
);
4254 RtlFreeUnicodeString(&lpszNameW
);
4258 /*****************************************************************************
4259 * WINSPOOL_GetDriverInfoFromReg [internal]
4261 * Enters the information from the registry into the DRIVER_INFO struct
4264 * zero if the printer driver does not exist in the registry
4265 * (only if Level > 1) otherwise nonzero
4267 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4270 LPCWSTR pEnvironment
,
4272 LPBYTE ptr
, /* DRIVER_INFO */
4273 LPBYTE pDriverStrings
, /* strings buffer */
4274 DWORD cbBuf
, /* size of string buffer */
4275 LPDWORD pcbNeeded
, /* space needed for str. */
4276 BOOL unicode
) /* type of strings */
4280 LPBYTE strPtr
= pDriverStrings
;
4282 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4283 debugstr_w(DriverName
), debugstr_w(pEnvironment
),
4284 Level
, ptr
, pDriverStrings
, cbBuf
, unicode
);
4287 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4288 if (*pcbNeeded
<= cbBuf
)
4289 strcpyW((LPWSTR
)strPtr
, DriverName
);
4291 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0,
4293 if(*pcbNeeded
<= cbBuf
)
4294 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1,
4295 (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4299 ((PDRIVER_INFO_1W
) ptr
)->pName
= (LPWSTR
) strPtr
;
4303 ((PDRIVER_INFO_2W
) ptr
)->pName
= (LPWSTR
) strPtr
;
4304 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4307 if(!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4308 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName
));
4309 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4314 ((PDRIVER_INFO_2A
) ptr
)->cVersion
= (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4317 pEnvironment
= DefaultEnvironmentW
;
4319 size
= (lstrlenW(pEnvironment
) + 1) * sizeof(WCHAR
);
4321 size
= WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0,
4324 if(*pcbNeeded
<= cbBuf
) {
4326 strcpyW((LPWSTR
)strPtr
, pEnvironment
);
4328 WideCharToMultiByte(CP_ACP
, 0, pEnvironment
, -1,
4329 (LPSTR
)strPtr
, size
, NULL
, NULL
);
4331 ((PDRIVER_INFO_2W
) ptr
)->pEnvironment
= (LPWSTR
)strPtr
;
4332 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4335 if(WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, 0, &size
,
4338 if(*pcbNeeded
<= cbBuf
)
4339 WINSPOOL_GetStringFromReg(hkeyDriver
, DriverW
, strPtr
, size
, &tmp
,
4342 ((PDRIVER_INFO_2W
) ptr
)->pDriverPath
= (LPWSTR
)strPtr
;
4343 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4346 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, 0, &size
,
4349 if(*pcbNeeded
<= cbBuf
)
4350 WINSPOOL_GetStringFromReg(hkeyDriver
, Data_FileW
, strPtr
, size
,
4353 ((PDRIVER_INFO_2W
) ptr
)->pDataFile
= (LPWSTR
)strPtr
;
4354 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4357 if(WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4358 0, &size
, unicode
)) {
4360 if(*pcbNeeded
<= cbBuf
)
4361 WINSPOOL_GetStringFromReg(hkeyDriver
, Configuration_FileW
, strPtr
,
4362 size
, &tmp
, unicode
);
4364 ((PDRIVER_INFO_2W
) ptr
)->pConfigFile
= (LPWSTR
)strPtr
;
4365 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4369 RegCloseKey(hkeyDriver
);
4370 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4374 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
, 0, &size
,
4377 if(*pcbNeeded
<= cbBuf
)
4378 WINSPOOL_GetStringFromReg(hkeyDriver
, Help_FileW
, strPtr
,
4379 size
, &tmp
, unicode
);
4381 ((PDRIVER_INFO_3W
) ptr
)->pHelpFile
= (LPWSTR
)strPtr
;
4382 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4385 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
, 0,
4388 if(*pcbNeeded
<= cbBuf
)
4389 WINSPOOL_GetStringFromReg(hkeyDriver
, Dependent_FilesW
, strPtr
,
4390 size
, &tmp
, unicode
);
4392 ((PDRIVER_INFO_3W
) ptr
)->pDependentFiles
= (LPWSTR
)strPtr
;
4393 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4396 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
,
4399 if(*pcbNeeded
<= cbBuf
)
4400 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
,
4401 size
, &tmp
, unicode
);
4403 ((PDRIVER_INFO_3W
) ptr
)->pMonitorName
= (LPWSTR
)strPtr
;
4404 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4407 if (Level
!= 5 && WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
,
4410 if(*pcbNeeded
<= cbBuf
)
4411 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
,
4412 size
, &tmp
, unicode
);
4414 ((PDRIVER_INFO_3W
) ptr
)->pDefaultDataType
= (LPWSTR
)strPtr
;
4415 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4418 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4419 RegCloseKey(hkeyDriver
);
4423 /*****************************************************************************
4424 * WINSPOOL_GetPrinterDriver
4426 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPWSTR pEnvironment
,
4427 DWORD Level
, LPBYTE pDriverInfo
,
4428 DWORD cbBuf
, LPDWORD pcbNeeded
,
4432 WCHAR DriverName
[100];
4433 DWORD ret
, type
, size
, needed
= 0;
4435 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4437 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4438 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4440 ZeroMemory(pDriverInfo
, cbBuf
);
4442 if (!(name
= get_opened_printer_name(hPrinter
))) {
4443 SetLastError(ERROR_INVALID_HANDLE
);
4446 if(Level
< 1 || Level
> 6) {
4447 SetLastError(ERROR_INVALID_LEVEL
);
4450 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4452 ERR("Can't create Printers key\n");
4455 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4457 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4458 RegCloseKey(hkeyPrinters
);
4459 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4462 size
= sizeof(DriverName
);
4464 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4465 (LPBYTE
)DriverName
, &size
);
4466 RegCloseKey(hkeyPrinter
);
4467 RegCloseKey(hkeyPrinters
);
4468 if(ret
!= ERROR_SUCCESS
) {
4469 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4473 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4475 ERR("Can't create Drivers key\n");
4481 size
= sizeof(DRIVER_INFO_1W
);
4484 size
= sizeof(DRIVER_INFO_2W
);
4487 size
= sizeof(DRIVER_INFO_3W
);
4490 size
= sizeof(DRIVER_INFO_4W
);
4493 size
= sizeof(DRIVER_INFO_5W
);
4496 size
= sizeof(DRIVER_INFO_6W
);
4499 ERR("Invalid level\n");
4504 ptr
= pDriverInfo
+ size
;
4506 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4507 pEnvironment
, Level
, pDriverInfo
,
4508 (cbBuf
< size
) ? NULL
: ptr
,
4509 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4510 &needed
, unicode
)) {
4511 RegCloseKey(hkeyDrivers
);
4515 RegCloseKey(hkeyDrivers
);
4517 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4518 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4519 if(cbBuf
>= needed
) return TRUE
;
4520 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4524 /*****************************************************************************
4525 * GetPrinterDriverA [WINSPOOL.@]
4527 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4528 DWORD Level
, LPBYTE pDriverInfo
,
4529 DWORD cbBuf
, LPDWORD pcbNeeded
)
4532 UNICODE_STRING pEnvW
;
4535 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4536 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4537 cbBuf
, pcbNeeded
, FALSE
);
4538 RtlFreeUnicodeString(&pEnvW
);
4541 /*****************************************************************************
4542 * GetPrinterDriverW [WINSPOOL.@]
4544 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4545 DWORD Level
, LPBYTE pDriverInfo
,
4546 DWORD cbBuf
, LPDWORD pcbNeeded
)
4548 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4549 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4552 /*****************************************************************************
4553 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4555 * Return the PATH for the Printer-Drivers (UNICODE)
4558 * pName [I] Servername (NT only) or NULL (local Computer)
4559 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4560 * Level [I] Structure-Level (must be 1)
4561 * pDriverDirectory [O] PTR to Buffer that receives the Result
4562 * cbBuf [I] Size of Buffer at pDriverDirectory
4563 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4564 * required for pDriverDirectory
4567 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4568 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4569 * if cbBuf is too small
4571 * Native Values returned in pDriverDirectory on Success:
4572 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4573 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4574 *| win9x(Windows 4.0): "%winsysdir%"
4576 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4579 *- Only NULL or "" is supported for pName
4582 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4583 DWORD Level
, LPBYTE pDriverDirectory
,
4584 DWORD cbBuf
, LPDWORD pcbNeeded
)
4587 const printenv_t
* env
;
4589 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4590 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4591 if(pName
!= NULL
&& pName
[0]) {
4592 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
4593 SetLastError(ERROR_INVALID_PARAMETER
);
4597 env
= validate_envW(pEnvironment
);
4598 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
4601 WARN("(Level: %d) is ignored in win9x\n", Level
);
4602 SetLastError(ERROR_INVALID_LEVEL
);
4606 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4607 needed
= GetSystemDirectoryW(NULL
, 0);
4608 /* add the Size for the Subdirectories */
4609 needed
+= lstrlenW(spooldriversW
);
4610 needed
+= lstrlenW(env
->subdir
);
4611 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
4614 *pcbNeeded
= needed
;
4615 TRACE("required: 0x%x/%d\n", needed
, needed
);
4616 if(needed
> cbBuf
) {
4617 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4620 if(pcbNeeded
== NULL
) {
4621 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4622 SetLastError(RPC_X_NULL_REF_POINTER
);
4625 if(pDriverDirectory
== NULL
) {
4626 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4627 SetLastError(ERROR_INVALID_USER_BUFFER
);
4631 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
4632 /* add the Subdirectories */
4633 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
4634 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
4635 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
4640 /*****************************************************************************
4641 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4643 * Return the PATH for the Printer-Drivers (ANSI)
4645 * See GetPrinterDriverDirectoryW.
4648 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4651 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4652 DWORD Level
, LPBYTE pDriverDirectory
,
4653 DWORD cbBuf
, LPDWORD pcbNeeded
)
4655 UNICODE_STRING nameW
, environmentW
;
4658 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4659 WCHAR
*driverDirectoryW
= NULL
;
4661 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4662 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4664 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4666 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4667 else nameW
.Buffer
= NULL
;
4668 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4669 else environmentW
.Buffer
= NULL
;
4671 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4672 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4675 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4676 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4678 *pcbNeeded
= needed
;
4679 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4681 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4683 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4685 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4686 RtlFreeUnicodeString(&environmentW
);
4687 RtlFreeUnicodeString(&nameW
);
4692 /*****************************************************************************
4693 * AddPrinterDriverA [WINSPOOL.@]
4695 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4698 HKEY hkeyDrivers
, hkeyName
;
4699 static CHAR empty
[] = "",
4702 TRACE("(%s,%d,%p)\n",debugstr_a(pName
),level
,pDriverInfo
);
4704 if(level
!= 2 && level
!= 3) {
4705 SetLastError(ERROR_INVALID_LEVEL
);
4708 if ((pName
) && (pName
[0])) {
4709 FIXME("pName= %s - unsupported\n", debugstr_a(pName
));
4710 SetLastError(ERROR_INVALID_PARAMETER
);
4714 WARN("pDriverInfo == NULL\n");
4715 SetLastError(ERROR_INVALID_PARAMETER
);
4720 di3
= *(DRIVER_INFO_3A
*)pDriverInfo
;
4722 memset(&di3
, 0, sizeof(di3
));
4723 memcpy(&di3
, pDriverInfo
, sizeof(DRIVER_INFO_2A
));
4726 if(!di3
.pName
|| !di3
.pDriverPath
|| !di3
.pConfigFile
||
4728 SetLastError(ERROR_INVALID_PARAMETER
);
4732 if(!di3
.pDefaultDataType
) di3
.pDefaultDataType
= empty
;
4733 if(!di3
.pDependentFiles
) di3
.pDependentFiles
= nullnull
;
4734 if(!di3
.pHelpFile
) di3
.pHelpFile
= empty
;
4735 if(!di3
.pMonitorName
) di3
.pMonitorName
= empty
;
4737 hkeyDrivers
= WINSPOOL_OpenDriverReg(di3
.pEnvironment
, FALSE
);
4740 ERR("Can't create Drivers key\n");
4744 if(level
== 2) { /* apparently can't overwrite with level2 */
4745 if(RegOpenKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) == ERROR_SUCCESS
) {
4746 RegCloseKey(hkeyName
);
4747 RegCloseKey(hkeyDrivers
);
4748 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3
.pName
));
4749 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
4753 if(RegCreateKeyA(hkeyDrivers
, di3
.pName
, &hkeyName
) != ERROR_SUCCESS
) {
4754 RegCloseKey(hkeyDrivers
);
4755 ERR("Can't create Name key\n");
4758 RegSetValueExA(hkeyName
, "Configuration File", 0, REG_SZ
, (LPBYTE
) di3
.pConfigFile
,
4759 lstrlenA(di3
.pConfigFile
) + 1);
4760 RegSetValueExA(hkeyName
, "Data File", 0, REG_SZ
, (LPBYTE
) di3
.pDataFile
, lstrlenA(di3
.pDataFile
) + 1);
4761 RegSetValueExA(hkeyName
, "Driver", 0, REG_SZ
, (LPBYTE
) di3
.pDriverPath
, lstrlenA(di3
.pDriverPath
) + 1);
4762 RegSetValueExA(hkeyName
, "Version", 0, REG_DWORD
, (LPBYTE
) &di3
.cVersion
,
4764 RegSetValueExA(hkeyName
, "Datatype", 0, REG_SZ
, (LPBYTE
) di3
.pDefaultDataType
, lstrlenA(di3
.pDefaultDataType
));
4765 RegSetValueExA(hkeyName
, "Dependent Files", 0, REG_MULTI_SZ
,
4766 (LPBYTE
) di3
.pDependentFiles
, multi_sz_lenA(di3
.pDependentFiles
));
4767 RegSetValueExA(hkeyName
, "Help File", 0, REG_SZ
, (LPBYTE
) di3
.pHelpFile
, lstrlenA(di3
.pHelpFile
) + 1);
4768 RegSetValueExA(hkeyName
, "Monitor", 0, REG_SZ
, (LPBYTE
) di3
.pMonitorName
, lstrlenA(di3
.pMonitorName
) + 1);
4769 RegCloseKey(hkeyName
);
4770 RegCloseKey(hkeyDrivers
);
4775 /*****************************************************************************
4776 * AddPrinterDriverW [WINSPOOL.@]
4778 BOOL WINAPI
AddPrinterDriverW(LPWSTR printerName
,DWORD level
,
4781 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName
),
4786 /*****************************************************************************
4787 * AddPrintProcessorA [WINSPOOL.@]
4789 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4790 LPSTR pPrintProcessorName
)
4792 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4793 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4797 /*****************************************************************************
4798 * AddPrintProcessorW [WINSPOOL.@]
4800 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4801 LPWSTR pPrintProcessorName
)
4803 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4804 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4808 /*****************************************************************************
4809 * AddPrintProvidorA [WINSPOOL.@]
4811 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4813 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4817 /*****************************************************************************
4818 * AddPrintProvidorW [WINSPOOL.@]
4820 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4822 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4826 /*****************************************************************************
4827 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4829 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4830 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4832 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4833 pDevModeOutput
, pDevModeInput
);
4837 /*****************************************************************************
4838 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4840 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4841 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4843 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4844 pDevModeOutput
, pDevModeInput
);
4848 /*****************************************************************************
4849 * PrinterProperties [WINSPOOL.@]
4851 * Displays a dialog to set the properties of the printer.
4854 * nonzero on success or zero on failure
4857 * implemented as stub only
4859 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4860 HANDLE hPrinter
/* [in] handle to printer object */
4862 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4863 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4867 /*****************************************************************************
4868 * EnumJobsA [WINSPOOL.@]
4871 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4872 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4875 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4876 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4878 if(pcbNeeded
) *pcbNeeded
= 0;
4879 if(pcReturned
) *pcReturned
= 0;
4884 /*****************************************************************************
4885 * EnumJobsW [WINSPOOL.@]
4888 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4889 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4892 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4893 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4895 if(pcbNeeded
) *pcbNeeded
= 0;
4896 if(pcReturned
) *pcReturned
= 0;
4900 /*****************************************************************************
4901 * WINSPOOL_EnumPrinterDrivers [internal]
4903 * Delivers information about all printer drivers installed on the
4904 * localhost or a given server
4907 * nonzero on success or zero on failure. If the buffer for the returned
4908 * information is too small the function will return an error
4911 * - only implemented for localhost, foreign hosts will return an error
4913 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPWSTR pEnvironment
,
4914 DWORD Level
, LPBYTE pDriverInfo
,
4915 DWORD cbBuf
, LPDWORD pcbNeeded
,
4916 LPDWORD pcReturned
, BOOL unicode
)
4919 DWORD i
, needed
, number
= 0, size
= 0;
4920 WCHAR DriverNameW
[255];
4923 TRACE("%s,%s,%d,%p,%d,%d\n",
4924 debugstr_w(pName
), debugstr_w(pEnvironment
),
4925 Level
, pDriverInfo
, cbBuf
, unicode
);
4927 /* check for local drivers */
4928 if((pName
) && (pName
[0])) {
4929 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4930 SetLastError(ERROR_ACCESS_DENIED
);
4934 /* check input parameter */
4935 if((Level
< 1) || (Level
> 3)) {
4936 ERR("unsupported level %d\n", Level
);
4937 SetLastError(ERROR_INVALID_LEVEL
);
4941 /* initialize return values */
4943 memset( pDriverInfo
, 0, cbBuf
);
4947 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
4949 ERR("Can't open Drivers key\n");
4953 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4954 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4955 RegCloseKey(hkeyDrivers
);
4956 ERR("Can't query Drivers key\n");
4959 TRACE("Found %d Drivers\n", number
);
4961 /* get size of single struct
4962 * unicode and ascii structure have the same size
4966 size
= sizeof(DRIVER_INFO_1A
);
4969 size
= sizeof(DRIVER_INFO_2A
);
4972 size
= sizeof(DRIVER_INFO_3A
);
4976 /* calculate required buffer size */
4977 *pcbNeeded
= size
* number
;
4979 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
4981 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
4982 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
4984 ERR("Can't enum key number %d\n", i
);
4985 RegCloseKey(hkeyDrivers
);
4988 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4989 pEnvironment
, Level
, ptr
,
4990 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
4991 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4992 &needed
, unicode
)) {
4993 RegCloseKey(hkeyDrivers
);
4996 (*pcbNeeded
) += needed
;
4999 RegCloseKey(hkeyDrivers
);
5001 if(cbBuf
< *pcbNeeded
){
5002 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5006 *pcReturned
= number
;
5010 /*****************************************************************************
5011 * EnumPrinterDriversW [WINSPOOL.@]
5013 * see function EnumPrinterDrivers for RETURNS, BUGS
5015 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5016 LPBYTE pDriverInfo
, DWORD cbBuf
,
5017 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5019 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5020 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5023 /*****************************************************************************
5024 * EnumPrinterDriversA [WINSPOOL.@]
5026 * see function EnumPrinterDrivers for RETURNS, BUGS
5028 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5029 LPBYTE pDriverInfo
, DWORD cbBuf
,
5030 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5032 UNICODE_STRING pNameW
, pEnvironmentW
;
5033 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5035 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5036 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5038 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5039 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5041 RtlFreeUnicodeString(&pNameW
);
5042 RtlFreeUnicodeString(&pEnvironmentW
);
5047 /******************************************************************************
5048 * EnumPortsA (WINSPOOL.@)
5053 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5054 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5057 LPBYTE bufferW
= NULL
;
5058 LPWSTR nameW
= NULL
;
5060 DWORD numentries
= 0;
5063 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5064 cbBuf
, pcbNeeded
, pcReturned
);
5066 /* convert servername to unicode */
5068 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5069 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5070 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5072 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5073 needed
= cbBuf
* sizeof(WCHAR
);
5074 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5075 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5077 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5078 if (pcbNeeded
) needed
= *pcbNeeded
;
5079 /* HeapReAlloc return NULL, when bufferW was NULL */
5080 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5081 HeapAlloc(GetProcessHeap(), 0, needed
);
5083 /* Try again with the large Buffer */
5084 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5086 needed
= pcbNeeded
? *pcbNeeded
: 0;
5087 numentries
= pcReturned
? *pcReturned
: 0;
5090 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5091 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5094 /* EnumPortsW collected all Data. Parse them to caclulate ANSI-Size */
5095 DWORD entrysize
= 0;
5098 LPPORT_INFO_2W pi2w
;
5099 LPPORT_INFO_2A pi2a
;
5102 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5104 /* First pass: calculate the size for all Entries */
5105 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5106 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5108 while (index
< numentries
) {
5110 needed
+= entrysize
; /* PORT_INFO_?A */
5111 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5113 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5114 NULL
, 0, NULL
, NULL
);
5116 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5117 NULL
, 0, NULL
, NULL
);
5118 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5119 NULL
, 0, NULL
, NULL
);
5121 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5122 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5123 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5126 /* check for errors and quit on failure */
5127 if (cbBuf
< needed
) {
5128 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5132 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5133 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5134 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5135 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5136 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5138 /* Second Pass: Fill the User Buffer (if we have one) */
5139 while ((index
< numentries
) && pPorts
) {
5141 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5142 pi2a
->pPortName
= ptr
;
5143 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5144 ptr
, cbBuf
, NULL
, NULL
);
5148 pi2a
->pMonitorName
= ptr
;
5149 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5150 ptr
, cbBuf
, NULL
, NULL
);
5154 pi2a
->pDescription
= ptr
;
5155 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5156 ptr
, cbBuf
, NULL
, NULL
);
5160 pi2a
->fPortType
= pi2w
->fPortType
;
5161 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5164 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5165 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5166 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5171 if (pcbNeeded
) *pcbNeeded
= needed
;
5172 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5174 HeapFree(GetProcessHeap(), 0, nameW
);
5175 HeapFree(GetProcessHeap(), 0, bufferW
);
5177 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5178 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5184 /******************************************************************************
5185 * EnumPortsW (WINSPOOL.@)
5187 * Enumerate available Ports
5190 * name [I] Servername or NULL (local Computer)
5191 * level [I] Structure-Level (1 or 2)
5192 * buffer [O] PTR to Buffer that receives the Result
5193 * bufsize [I] Size of Buffer at buffer
5194 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5195 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5199 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5203 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5206 DWORD numentries
= 0;
5209 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5210 cbBuf
, pcbNeeded
, pcReturned
);
5212 if (pName
&& (pName
[0])) {
5213 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5214 SetLastError(ERROR_ACCESS_DENIED
);
5218 /* Level is not checked in win9x */
5219 if (!Level
|| (Level
> 2)) {
5220 WARN("level (%d) is ignored in win9x\n", Level
);
5221 SetLastError(ERROR_INVALID_LEVEL
);
5225 SetLastError(RPC_X_NULL_REF_POINTER
);
5229 EnterCriticalSection(&monitor_handles_cs
);
5232 /* Scan all local Ports */
5234 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5236 /* we calculated the needed buffersize. now do the error-checks */
5237 if (cbBuf
< needed
) {
5238 monitor_unloadall();
5239 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5240 goto emP_cleanup_cs
;
5242 else if (!pPorts
|| !pcReturned
) {
5243 monitor_unloadall();
5244 SetLastError(RPC_X_NULL_REF_POINTER
);
5245 goto emP_cleanup_cs
;
5248 /* Fill the Buffer */
5249 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5251 monitor_unloadall();
5254 LeaveCriticalSection(&monitor_handles_cs
);
5257 if (pcbNeeded
) *pcbNeeded
= needed
;
5258 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5260 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5261 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5266 /******************************************************************************
5267 * GetDefaultPrinterW (WINSPOOL.@)
5270 * This function must read the value from data 'device' of key
5271 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5273 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5277 WCHAR
*buffer
, *ptr
;
5281 SetLastError(ERROR_INVALID_PARAMETER
);
5285 /* make the buffer big enough for the stuff from the profile/registry,
5286 * the content must fit into the local buffer to compute the correct
5287 * size even if the extern buffer is too small or not given.
5288 * (20 for ,driver,port) */
5290 len
= max(100, (insize
+ 20));
5291 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5293 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5295 SetLastError (ERROR_FILE_NOT_FOUND
);
5299 TRACE("%s\n", debugstr_w(buffer
));
5301 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5303 SetLastError(ERROR_INVALID_NAME
);
5309 *namesize
= strlenW(buffer
) + 1;
5310 if(!name
|| (*namesize
> insize
))
5312 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5316 strcpyW(name
, buffer
);
5319 HeapFree( GetProcessHeap(), 0, buffer
);
5324 /******************************************************************************
5325 * GetDefaultPrinterA (WINSPOOL.@)
5327 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5331 WCHAR
*bufferW
= NULL
;
5335 SetLastError(ERROR_INVALID_PARAMETER
);
5339 if(name
&& *namesize
) {
5341 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5344 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5349 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5353 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5356 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5359 HeapFree( GetProcessHeap(), 0, bufferW
);
5364 /******************************************************************************
5365 * SetDefaultPrinterW (WINSPOOL.204)
5367 * Set the Name of the Default Printer
5370 * pszPrinter [I] Name of the Printer or NULL
5377 * When the Parameter is NULL or points to an Empty String and
5378 * a Default Printer was already present, then this Function changes nothing.
5379 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5380 * the First enumerated local Printer is used.
5383 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5386 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5388 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5392 /******************************************************************************
5393 * SetDefaultPrinterA (WINSPOOL.202)
5395 * See SetDefaultPrinterW.
5398 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5401 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5403 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5408 /******************************************************************************
5409 * SetPrinterDataExA (WINSPOOL.@)
5411 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5412 LPCSTR pValueName
, DWORD Type
,
5413 LPBYTE pData
, DWORD cbData
)
5415 HKEY hkeyPrinter
, hkeySubkey
;
5418 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5419 debugstr_a(pValueName
), Type
, pData
, cbData
);
5421 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5425 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5427 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5428 RegCloseKey(hkeyPrinter
);
5431 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5432 RegCloseKey(hkeySubkey
);
5433 RegCloseKey(hkeyPrinter
);
5437 /******************************************************************************
5438 * SetPrinterDataExW (WINSPOOL.@)
5440 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5441 LPCWSTR pValueName
, DWORD Type
,
5442 LPBYTE pData
, DWORD cbData
)
5444 HKEY hkeyPrinter
, hkeySubkey
;
5447 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5448 debugstr_w(pValueName
), Type
, pData
, cbData
);
5450 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5454 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5456 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5457 RegCloseKey(hkeyPrinter
);
5460 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5461 RegCloseKey(hkeySubkey
);
5462 RegCloseKey(hkeyPrinter
);
5466 /******************************************************************************
5467 * SetPrinterDataA (WINSPOOL.@)
5469 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5470 LPBYTE pData
, DWORD cbData
)
5472 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5476 /******************************************************************************
5477 * SetPrinterDataW (WINSPOOL.@)
5479 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5480 LPBYTE pData
, DWORD cbData
)
5482 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5486 /******************************************************************************
5487 * GetPrinterDataExA (WINSPOOL.@)
5489 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5490 LPCSTR pValueName
, LPDWORD pType
,
5491 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5493 HKEY hkeyPrinter
, hkeySubkey
;
5496 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5497 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5500 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5504 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5506 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5507 RegCloseKey(hkeyPrinter
);
5511 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5512 RegCloseKey(hkeySubkey
);
5513 RegCloseKey(hkeyPrinter
);
5517 /******************************************************************************
5518 * GetPrinterDataExW (WINSPOOL.@)
5520 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5521 LPCWSTR pValueName
, LPDWORD pType
,
5522 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5524 HKEY hkeyPrinter
, hkeySubkey
;
5527 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5528 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5531 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5535 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5537 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5538 RegCloseKey(hkeyPrinter
);
5542 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5543 RegCloseKey(hkeySubkey
);
5544 RegCloseKey(hkeyPrinter
);
5548 /******************************************************************************
5549 * GetPrinterDataA (WINSPOOL.@)
5551 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5552 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5554 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5555 pData
, nSize
, pcbNeeded
);
5558 /******************************************************************************
5559 * GetPrinterDataW (WINSPOOL.@)
5561 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5562 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5564 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5565 pData
, nSize
, pcbNeeded
);
5568 /*******************************************************************************
5569 * EnumPrinterDataExW [WINSPOOL.@]
5571 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5572 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5573 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5575 HKEY hkPrinter
, hkSubKey
;
5576 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5577 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5582 PPRINTER_ENUM_VALUESW ppev
;
5584 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5586 if (pKeyName
== NULL
|| *pKeyName
== 0)
5587 return ERROR_INVALID_PARAMETER
;
5589 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5590 if (ret
!= ERROR_SUCCESS
)
5592 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5597 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5598 if (ret
!= ERROR_SUCCESS
)
5600 r
= RegCloseKey (hkPrinter
);
5601 if (r
!= ERROR_SUCCESS
)
5602 WARN ("RegCloseKey returned %i\n", r
);
5603 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5604 debugstr_w (pKeyName
), ret
);
5608 ret
= RegCloseKey (hkPrinter
);
5609 if (ret
!= ERROR_SUCCESS
)
5611 ERR ("RegCloseKey returned %i\n", ret
);
5612 r
= RegCloseKey (hkSubKey
);
5613 if (r
!= ERROR_SUCCESS
)
5614 WARN ("RegCloseKey returned %i\n", r
);
5618 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5619 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5620 if (ret
!= ERROR_SUCCESS
)
5622 r
= RegCloseKey (hkSubKey
);
5623 if (r
!= ERROR_SUCCESS
)
5624 WARN ("RegCloseKey returned %i\n", r
);
5625 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5629 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5630 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5632 if (cValues
== 0) /* empty key */
5634 r
= RegCloseKey (hkSubKey
);
5635 if (r
!= ERROR_SUCCESS
)
5636 WARN ("RegCloseKey returned %i\n", r
);
5637 *pcbEnumValues
= *pnEnumValues
= 0;
5638 return ERROR_SUCCESS
;
5641 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5643 hHeap
= GetProcessHeap ();
5646 ERR ("GetProcessHeap failed\n");
5647 r
= RegCloseKey (hkSubKey
);
5648 if (r
!= ERROR_SUCCESS
)
5649 WARN ("RegCloseKey returned %i\n", r
);
5650 return ERROR_OUTOFMEMORY
;
5653 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5654 if (lpValueName
== NULL
)
5656 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5657 r
= RegCloseKey (hkSubKey
);
5658 if (r
!= ERROR_SUCCESS
)
5659 WARN ("RegCloseKey returned %i\n", r
);
5660 return ERROR_OUTOFMEMORY
;
5663 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5664 if (lpValue
== NULL
)
5666 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5667 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5668 WARN ("HeapFree failed with code %i\n", GetLastError ());
5669 r
= RegCloseKey (hkSubKey
);
5670 if (r
!= ERROR_SUCCESS
)
5671 WARN ("RegCloseKey returned %i\n", r
);
5672 return ERROR_OUTOFMEMORY
;
5675 TRACE ("pass 1: calculating buffer required for all names and values\n");
5677 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5679 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5681 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5683 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5684 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5685 NULL
, NULL
, lpValue
, &cbValueLen
);
5686 if (ret
!= ERROR_SUCCESS
)
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 ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5699 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5700 debugstr_w (lpValueName
), dwIndex
,
5701 cbValueNameLen
+ 1, cbValueLen
);
5703 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5704 cbBufSize
+= cbValueLen
;
5707 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5709 *pcbEnumValues
= cbBufSize
;
5710 *pnEnumValues
= cValues
;
5712 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5714 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5715 WARN ("HeapFree failed with code %i\n", GetLastError ());
5716 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5717 WARN ("HeapFree failed with code %i\n", GetLastError ());
5718 r
= RegCloseKey (hkSubKey
);
5719 if (r
!= ERROR_SUCCESS
)
5720 WARN ("RegCloseKey returned %i\n", r
);
5721 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5722 return ERROR_MORE_DATA
;
5725 TRACE ("pass 2: copying all names and values to buffer\n");
5727 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5728 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5730 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5732 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5733 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5734 NULL
, &dwType
, lpValue
, &cbValueLen
);
5735 if (ret
!= ERROR_SUCCESS
)
5737 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5738 WARN ("HeapFree failed with code %i\n", GetLastError ());
5739 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5740 WARN ("HeapFree failed with code %i\n", GetLastError ());
5741 r
= RegCloseKey (hkSubKey
);
5742 if (r
!= ERROR_SUCCESS
)
5743 WARN ("RegCloseKey returned %i\n", r
);
5744 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5748 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5749 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5750 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5751 pEnumValues
+= cbValueNameLen
;
5753 /* return # of *bytes* (including trailing \0), not # of chars */
5754 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5756 ppev
[dwIndex
].dwType
= dwType
;
5758 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5759 ppev
[dwIndex
].pData
= pEnumValues
;
5760 pEnumValues
+= cbValueLen
;
5762 ppev
[dwIndex
].cbData
= cbValueLen
;
5764 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5765 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5768 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5770 ret
= GetLastError ();
5771 ERR ("HeapFree failed with code %i\n", ret
);
5772 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5773 WARN ("HeapFree failed with code %i\n", GetLastError ());
5774 r
= RegCloseKey (hkSubKey
);
5775 if (r
!= ERROR_SUCCESS
)
5776 WARN ("RegCloseKey returned %i\n", r
);
5780 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5782 ret
= GetLastError ();
5783 ERR ("HeapFree failed with code %i\n", ret
);
5784 r
= RegCloseKey (hkSubKey
);
5785 if (r
!= ERROR_SUCCESS
)
5786 WARN ("RegCloseKey returned %i\n", r
);
5790 ret
= RegCloseKey (hkSubKey
);
5791 if (ret
!= ERROR_SUCCESS
)
5793 ERR ("RegCloseKey returned %i\n", ret
);
5797 return ERROR_SUCCESS
;
5800 /*******************************************************************************
5801 * EnumPrinterDataExA [WINSPOOL.@]
5803 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5804 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5805 * what Windows 2000 SP1 does.
5808 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5809 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5810 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5814 DWORD ret
, dwIndex
, dwBufSize
;
5818 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5820 if (pKeyName
== NULL
|| *pKeyName
== 0)
5821 return ERROR_INVALID_PARAMETER
;
5823 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5826 ret
= GetLastError ();
5827 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5831 hHeap
= GetProcessHeap ();
5834 ERR ("GetProcessHeap failed\n");
5835 return ERROR_OUTOFMEMORY
;
5838 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5839 if (pKeyNameW
== NULL
)
5841 ERR ("Failed to allocate %i bytes from process heap\n",
5842 (LONG
)(len
* sizeof (WCHAR
)));
5843 return ERROR_OUTOFMEMORY
;
5846 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5848 ret
= GetLastError ();
5849 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5850 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5855 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5856 pcbEnumValues
, pnEnumValues
);
5857 if (ret
!= ERROR_SUCCESS
)
5859 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5860 WARN ("HeapFree failed with code %i\n", GetLastError ());
5861 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5865 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5867 ret
= GetLastError ();
5868 ERR ("HeapFree failed with code %i\n", ret
);
5872 if (*pnEnumValues
== 0) /* empty key */
5873 return ERROR_SUCCESS
;
5876 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5878 PPRINTER_ENUM_VALUESW ppev
=
5879 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5881 if (dwBufSize
< ppev
->cbValueName
)
5882 dwBufSize
= ppev
->cbValueName
;
5884 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5885 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5886 dwBufSize
= ppev
->cbData
;
5889 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5891 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5892 if (pBuffer
== NULL
)
5894 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5895 return ERROR_OUTOFMEMORY
;
5898 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5900 PPRINTER_ENUM_VALUESW ppev
=
5901 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5903 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5904 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5908 ret
= GetLastError ();
5909 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5910 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5911 WARN ("HeapFree failed with code %i\n", GetLastError ());
5915 memcpy (ppev
->pValueName
, pBuffer
, len
);
5917 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5919 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5920 ppev
->dwType
!= REG_MULTI_SZ
)
5923 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5924 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5927 ret
= GetLastError ();
5928 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5929 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5930 WARN ("HeapFree failed with code %i\n", GetLastError ());
5934 memcpy (ppev
->pData
, pBuffer
, len
);
5936 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5937 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5940 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5942 ret
= GetLastError ();
5943 ERR ("HeapFree failed with code %i\n", ret
);
5947 return ERROR_SUCCESS
;
5950 /******************************************************************************
5951 * AbortPrinter (WINSPOOL.@)
5953 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5955 FIXME("(%p), stub!\n", hPrinter
);
5959 /******************************************************************************
5960 * AddPortA (WINSPOOL.@)
5965 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5967 LPWSTR nameW
= NULL
;
5968 LPWSTR monitorW
= NULL
;
5972 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
5975 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5976 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5977 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5981 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5982 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5983 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5985 res
= AddPortW(nameW
, hWnd
, monitorW
);
5986 HeapFree(GetProcessHeap(), 0, nameW
);
5987 HeapFree(GetProcessHeap(), 0, monitorW
);
5991 /******************************************************************************
5992 * AddPortW (WINSPOOL.@)
5994 * Add a Port for a specific Monitor
5997 * pName [I] Servername or NULL (local Computer)
5998 * hWnd [I] Handle to parent Window for the Dialog-Box
5999 * pMonitorName [I] Name of the Monitor that manage the Port
6006 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6012 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6014 if (pName
&& pName
[0]) {
6015 SetLastError(ERROR_INVALID_PARAMETER
);
6019 if (!pMonitorName
) {
6020 SetLastError(RPC_X_NULL_REF_POINTER
);
6024 /* an empty Monitorname is Invalid */
6025 if (!pMonitorName
[0]) {
6026 SetLastError(ERROR_NOT_SUPPORTED
);
6030 pm
= monitor_load(pMonitorName
, NULL
);
6031 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6032 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6033 TRACE("got %d with %u\n", res
, GetLastError());
6038 pui
= monitor_loadui(pm
);
6039 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6040 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6041 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6042 TRACE("got %d with %u\n", res
, GetLastError());
6047 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6048 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6050 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6051 SetLastError(ERROR_NOT_SUPPORTED
);
6054 monitor_unload(pui
);
6056 /* invalidate cached PORT_INFO_2W */
6060 TRACE("returning %d with %u\n", res
, GetLastError());
6064 /******************************************************************************
6065 * AddPortExA (WINSPOOL.@)
6070 BOOL WINAPI
AddPortExA(HANDLE hMonitor
, LPSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPSTR lpMonitorName
)
6072 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor
, debugstr_a(pName
), Level
,
6073 lpBuffer
, debugstr_a(lpMonitorName
));
6077 /******************************************************************************
6078 * AddPortExW (WINSPOOL.@)
6080 * Add a Port for a specific Monitor, without presenting a user interface
6083 * hMonitor [I] Handle from InitializePrintMonitor2()
6084 * pName [I] Servername or NULL (local Computer)
6085 * Level [I] Structure-Level (1 or 2) for lpBuffer
6086 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6087 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
6097 BOOL WINAPI
AddPortExW(HANDLE hMonitor
, LPWSTR pName
, DWORD Level
, LPBYTE lpBuffer
, LPWSTR lpMonitorName
)
6099 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor
, debugstr_w(pName
), Level
,
6100 lpBuffer
, debugstr_w(lpMonitorName
));
6104 /******************************************************************************
6105 * AddPrinterConnectionA (WINSPOOL.@)
6107 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6109 FIXME("%s\n", debugstr_a(pName
));
6113 /******************************************************************************
6114 * AddPrinterConnectionW (WINSPOOL.@)
6116 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6118 FIXME("%s\n", debugstr_w(pName
));
6122 /******************************************************************************
6123 * AddPrinterDriverExW (WINSPOOL.@)
6125 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD Level
,
6126 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6128 FIXME("%s %d %p %d\n", debugstr_w(pName
),
6129 Level
, pDriverInfo
, dwFileCopyFlags
);
6130 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6134 /******************************************************************************
6135 * AddPrinterDriverExA (WINSPOOL.@)
6137 BOOL WINAPI
AddPrinterDriverExA( LPSTR pName
, DWORD Level
,
6138 LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6140 FIXME("%s %d %p %d\n", debugstr_a(pName
),
6141 Level
, pDriverInfo
, dwFileCopyFlags
);
6142 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED
);
6146 /******************************************************************************
6147 * ConfigurePortA (WINSPOOL.@)
6149 * See ConfigurePortW.
6152 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6154 LPWSTR nameW
= NULL
;
6155 LPWSTR portW
= NULL
;
6159 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6161 /* convert servername to unicode */
6163 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6164 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6165 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6168 /* convert portname to unicode */
6170 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6171 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6172 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6175 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6176 HeapFree(GetProcessHeap(), 0, nameW
);
6177 HeapFree(GetProcessHeap(), 0, portW
);
6181 /******************************************************************************
6182 * ConfigurePortW (WINSPOOL.@)
6184 * Display the Configuration-Dialog for a specific Port
6187 * pName [I] Servername or NULL (local Computer)
6188 * hWnd [I] Handle to parent Window for the Dialog-Box
6189 * pPortName [I] Name of the Port, that should be configured
6196 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6202 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6204 if (pName
&& pName
[0]) {
6205 SetLastError(ERROR_INVALID_PARAMETER
);
6210 SetLastError(RPC_X_NULL_REF_POINTER
);
6214 /* an empty Portname is Invalid, but can popup a Dialog */
6215 if (!pPortName
[0]) {
6216 SetLastError(ERROR_NOT_SUPPORTED
);
6220 pm
= monitor_load_by_port(pPortName
);
6221 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6222 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6223 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6224 TRACE("got %d with %u\n", res
, GetLastError());
6228 pui
= monitor_loadui(pm
);
6229 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6230 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6231 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6232 TRACE("got %d with %u\n", res
, GetLastError());
6236 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6237 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6239 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6240 SetLastError(ERROR_NOT_SUPPORTED
);
6243 monitor_unload(pui
);
6247 TRACE("returning %d with %u\n", res
, GetLastError());
6251 /******************************************************************************
6252 * ConnectToPrinterDlg (WINSPOOL.@)
6254 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6256 FIXME("%p %x\n", hWnd
, Flags
);
6260 /******************************************************************************
6261 * DeletePrinterConnectionA (WINSPOOL.@)
6263 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6265 FIXME("%s\n", debugstr_a(pName
));
6269 /******************************************************************************
6270 * DeletePrinterConnectionW (WINSPOOL.@)
6272 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6274 FIXME("%s\n", debugstr_w(pName
));
6278 /******************************************************************************
6279 * DeletePrinterDriverExW (WINSPOOL.@)
6281 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6282 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6287 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6288 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6290 if(pName
&& pName
[0])
6292 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6293 SetLastError(ERROR_INVALID_PARAMETER
);
6299 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6300 SetLastError(ERROR_INVALID_PARAMETER
);
6304 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6308 ERR("Can't open drivers key\n");
6312 if(WINSPOOL_SHDeleteKeyW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6315 RegCloseKey(hkey_drivers
);
6320 /******************************************************************************
6321 * DeletePrinterDriverExA (WINSPOOL.@)
6323 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6324 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6326 UNICODE_STRING NameW
, EnvW
, DriverW
;
6329 asciitounicode(&NameW
, pName
);
6330 asciitounicode(&EnvW
, pEnvironment
);
6331 asciitounicode(&DriverW
, pDriverName
);
6333 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6335 RtlFreeUnicodeString(&DriverW
);
6336 RtlFreeUnicodeString(&EnvW
);
6337 RtlFreeUnicodeString(&NameW
);
6342 /******************************************************************************
6343 * DeletePrinterDataExW (WINSPOOL.@)
6345 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6348 FIXME("%p %s %s\n", hPrinter
,
6349 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6350 return ERROR_INVALID_PARAMETER
;
6353 /******************************************************************************
6354 * DeletePrinterDataExA (WINSPOOL.@)
6356 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6359 FIXME("%p %s %s\n", hPrinter
,
6360 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6361 return ERROR_INVALID_PARAMETER
;
6364 /******************************************************************************
6365 * DeletePrintProcessorA (WINSPOOL.@)
6367 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6369 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6370 debugstr_a(pPrintProcessorName
));
6374 /******************************************************************************
6375 * DeletePrintProcessorW (WINSPOOL.@)
6377 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6379 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6380 debugstr_w(pPrintProcessorName
));
6384 /******************************************************************************
6385 * DeletePrintProvidorA (WINSPOOL.@)
6387 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6389 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6390 debugstr_a(pPrintProviderName
));
6394 /******************************************************************************
6395 * DeletePrintProvidorW (WINSPOOL.@)
6397 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6399 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6400 debugstr_w(pPrintProviderName
));
6404 /******************************************************************************
6405 * EnumFormsA (WINSPOOL.@)
6407 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6408 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6410 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6411 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6415 /******************************************************************************
6416 * EnumFormsW (WINSPOOL.@)
6418 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6419 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6421 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6422 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6426 /*****************************************************************************
6427 * EnumMonitorsA [WINSPOOL.@]
6429 * See EnumMonitorsW.
6432 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6433 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6436 LPBYTE bufferW
= NULL
;
6437 LPWSTR nameW
= NULL
;
6439 DWORD numentries
= 0;
6442 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6443 cbBuf
, pcbNeeded
, pcReturned
);
6445 /* convert servername to unicode */
6447 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6448 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6449 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6451 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6452 needed
= cbBuf
* sizeof(WCHAR
);
6453 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6454 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6456 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6457 if (pcbNeeded
) needed
= *pcbNeeded
;
6458 /* HeapReAlloc return NULL, when bufferW was NULL */
6459 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6460 HeapAlloc(GetProcessHeap(), 0, needed
);
6462 /* Try again with the large Buffer */
6463 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6465 numentries
= pcReturned
? *pcReturned
: 0;
6468 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6469 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6472 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
6473 DWORD entrysize
= 0;
6476 LPMONITOR_INFO_2W mi2w
;
6477 LPMONITOR_INFO_2A mi2a
;
6479 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6480 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6482 /* First pass: calculate the size for all Entries */
6483 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6484 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6486 while (index
< numentries
) {
6488 needed
+= entrysize
; /* MONITOR_INFO_?A */
6489 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6491 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6492 NULL
, 0, NULL
, NULL
);
6494 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6495 NULL
, 0, NULL
, NULL
);
6496 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6497 NULL
, 0, NULL
, NULL
);
6499 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6500 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6501 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6504 /* check for errors and quit on failure */
6505 if (cbBuf
< needed
) {
6506 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6510 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6511 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6512 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6513 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6514 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6516 /* Second Pass: Fill the User Buffer (if we have one) */
6517 while ((index
< numentries
) && pMonitors
) {
6519 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6521 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6522 ptr
, cbBuf
, NULL
, NULL
);
6526 mi2a
->pEnvironment
= ptr
;
6527 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6528 ptr
, cbBuf
, NULL
, NULL
);
6532 mi2a
->pDLLName
= ptr
;
6533 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6534 ptr
, cbBuf
, NULL
, NULL
);
6538 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6539 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6540 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6544 if (pcbNeeded
) *pcbNeeded
= needed
;
6545 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6547 HeapFree(GetProcessHeap(), 0, nameW
);
6548 HeapFree(GetProcessHeap(), 0, bufferW
);
6550 TRACE("returning %d with %d (%d byte for %d entries)\n",
6551 (res
), GetLastError(), needed
, numentries
);
6557 /*****************************************************************************
6558 * EnumMonitorsW [WINSPOOL.@]
6560 * Enumerate available Port-Monitors
6563 * pName [I] Servername or NULL (local Computer)
6564 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6565 * pMonitors [O] PTR to Buffer that receives the Result
6566 * cbBuf [I] Size of Buffer at pMonitors
6567 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6568 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6572 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6575 * Windows reads the Registry once and cache the Results.
6577 *| Language-Monitors are also installed in the same Registry-Location but
6578 *| they are filtered in Windows (not returned by EnumMonitors).
6579 *| We do no filtering to simplify our Code.
6582 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6583 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6586 DWORD numentries
= 0;
6589 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6590 cbBuf
, pcbNeeded
, pcReturned
);
6592 if (pName
&& (lstrlenW(pName
))) {
6593 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
6594 SetLastError(ERROR_ACCESS_DENIED
);
6598 /* Level is not checked in win9x */
6599 if (!Level
|| (Level
> 2)) {
6600 WARN("level (%d) is ignored in win9x\n", Level
);
6601 SetLastError(ERROR_INVALID_LEVEL
);
6605 SetLastError(RPC_X_NULL_REF_POINTER
);
6609 /* Scan all Monitor-Keys */
6611 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
6613 /* we calculated the needed buffersize. now do the error-checks */
6614 if (cbBuf
< needed
) {
6615 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6618 else if (!pMonitors
|| !pcReturned
) {
6619 SetLastError(RPC_X_NULL_REF_POINTER
);
6623 /* fill the Buffer with the Monitor-Keys */
6624 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
6628 if (pcbNeeded
) *pcbNeeded
= needed
;
6629 if (pcReturned
) *pcReturned
= numentries
;
6631 TRACE("returning %d with %d (%d byte for %d entries)\n",
6632 res
, GetLastError(), needed
, numentries
);
6637 /******************************************************************************
6638 * XcvDataW (WINSPOOL.@)
6640 * Execute commands in the Printmonitor DLL
6643 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6644 * pszDataName [i] Name of the command to execute
6645 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6646 * cbInputData [i] Size in Bytes of Buffer at pInputData
6647 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6648 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6649 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6650 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6657 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6658 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6660 * Minimal List of commands, that a Printmonitor DLL should support:
6662 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6663 *| "AddPort" : Add a Port
6664 *| "DeletePort": Delete a Port
6666 * Many Printmonitors support additional commands. Examples for localspl.dll:
6667 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6668 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6671 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6672 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6673 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6675 opened_printer_t
*printer
;
6677 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6678 pInputData
, cbInputData
, pOutputData
,
6679 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6681 printer
= get_opened_printer(hXcv
);
6682 if (!printer
|| (!printer
->hXcv
)) {
6683 SetLastError(ERROR_INVALID_HANDLE
);
6687 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
6688 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
6693 /*****************************************************************************
6694 * EnumPrinterDataA [WINSPOOL.@]
6697 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6698 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6699 DWORD cbData
, LPDWORD pcbData
)
6701 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6702 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6703 return ERROR_NO_MORE_ITEMS
;
6706 /*****************************************************************************
6707 * EnumPrinterDataW [WINSPOOL.@]
6710 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6711 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6712 DWORD cbData
, LPDWORD pcbData
)
6714 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6715 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6716 return ERROR_NO_MORE_ITEMS
;
6719 /*****************************************************************************
6720 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6723 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6724 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6725 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6727 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6728 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6729 pcbNeeded
, pcReturned
);
6733 /*****************************************************************************
6734 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6737 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6738 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6739 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6741 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6742 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6743 pcbNeeded
, pcReturned
);
6747 /*****************************************************************************
6748 * EnumPrintProcessorsA [WINSPOOL.@]
6751 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6752 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6754 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
6755 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
6759 /*****************************************************************************
6760 * EnumPrintProcessorsW [WINSPOOL.@]
6763 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6764 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6766 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6767 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
6768 cbBuf
, pcbNeeded
, pcbReturned
);
6772 /*****************************************************************************
6773 * ExtDeviceMode [WINSPOOL.@]
6776 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6777 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6780 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6781 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6782 debugstr_a(pProfile
), fMode
);
6786 /*****************************************************************************
6787 * FindClosePrinterChangeNotification [WINSPOOL.@]
6790 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6792 FIXME("Stub: %p\n", hChange
);
6796 /*****************************************************************************
6797 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6800 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6801 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6803 FIXME("Stub: %p %x %x %p\n",
6804 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6805 return INVALID_HANDLE_VALUE
;
6808 /*****************************************************************************
6809 * FindNextPrinterChangeNotification [WINSPOOL.@]
6812 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6813 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6815 FIXME("Stub: %p %p %p %p\n",
6816 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
6820 /*****************************************************************************
6821 * FreePrinterNotifyInfo [WINSPOOL.@]
6824 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
6826 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
6830 /*****************************************************************************
6833 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6834 * ansi depending on the unicode parameter.
6836 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
6846 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
6849 memcpy(ptr
, str
, *size
);
6856 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
6859 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
6866 /*****************************************************************************
6869 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
6870 LPDWORD pcbNeeded
, BOOL unicode
)
6872 DWORD size
, left
= cbBuf
;
6873 BOOL space
= (cbBuf
> 0);
6880 ji1
->JobId
= job
->job_id
;
6883 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6884 if(space
&& size
<= left
)
6886 ji1
->pDocument
= (LPWSTR
)ptr
;
6897 /*****************************************************************************
6900 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
6901 LPDWORD pcbNeeded
, BOOL unicode
)
6903 DWORD size
, left
= cbBuf
;
6904 BOOL space
= (cbBuf
> 0);
6911 ji2
->JobId
= job
->job_id
;
6914 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6915 if(space
&& size
<= left
)
6917 ji2
->pDocument
= (LPWSTR
)ptr
;
6928 /*****************************************************************************
6931 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
6932 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
6935 DWORD needed
= 0, size
;
6939 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
6941 EnterCriticalSection(&printer_handles_cs
);
6942 job
= get_job(hPrinter
, JobId
);
6949 size
= sizeof(JOB_INFO_1W
);
6954 memset(pJob
, 0, size
);
6958 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
6963 size
= sizeof(JOB_INFO_2W
);
6968 memset(pJob
, 0, size
);
6972 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
6977 size
= sizeof(JOB_INFO_3
);
6981 memset(pJob
, 0, size
);
6990 SetLastError(ERROR_INVALID_LEVEL
);
6994 *pcbNeeded
= needed
;
6996 LeaveCriticalSection(&printer_handles_cs
);
7000 /*****************************************************************************
7001 * GetJobA [WINSPOOL.@]
7004 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7005 DWORD cbBuf
, LPDWORD pcbNeeded
)
7007 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7010 /*****************************************************************************
7011 * GetJobW [WINSPOOL.@]
7014 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7015 DWORD cbBuf
, LPDWORD pcbNeeded
)
7017 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7020 /*****************************************************************************
7023 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7025 char *unixname
, *queue
, *cmd
;
7026 char fmt
[] = "lpr -P%s %s";
7029 if(!(unixname
= wine_get_unix_file_name(filename
)))
7032 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7033 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7034 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7036 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7037 sprintf(cmd
, fmt
, queue
, unixname
);
7039 TRACE("printing with: %s\n", cmd
);
7042 HeapFree(GetProcessHeap(), 0, cmd
);
7043 HeapFree(GetProcessHeap(), 0, queue
);
7044 HeapFree(GetProcessHeap(), 0, unixname
);
7048 /*****************************************************************************
7051 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7053 #if HAVE_CUPS_CUPS_H
7056 char *unixname
, *queue
, *doc_titleA
;
7060 if(!(unixname
= wine_get_unix_file_name(filename
)))
7063 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7064 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7065 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7067 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7068 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7069 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7071 TRACE("printing via cups\n");
7072 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7073 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7074 HeapFree(GetProcessHeap(), 0, queue
);
7075 HeapFree(GetProcessHeap(), 0, unixname
);
7081 return schedule_lpr(printer_name
, filename
);
7085 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7092 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7096 if(HIWORD(wparam
) == BN_CLICKED
)
7098 if(LOWORD(wparam
) == IDOK
)
7101 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7104 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7105 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7107 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7109 WCHAR caption
[200], message
[200];
7112 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7113 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7114 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7115 if(mb_ret
== IDCANCEL
)
7117 HeapFree(GetProcessHeap(), 0, filename
);
7121 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7122 if(hf
== INVALID_HANDLE_VALUE
)
7124 WCHAR caption
[200], message
[200];
7126 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7127 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7128 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7129 HeapFree(GetProcessHeap(), 0, filename
);
7133 DeleteFileW(filename
);
7134 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7136 EndDialog(hwnd
, IDOK
);
7139 if(LOWORD(wparam
) == IDCANCEL
)
7141 EndDialog(hwnd
, IDCANCEL
);
7150 /*****************************************************************************
7153 static BOOL
get_filename(LPWSTR
*filename
)
7155 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7156 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7159 /*****************************************************************************
7162 static BOOL
schedule_file(LPCWSTR filename
)
7164 LPWSTR output
= NULL
;
7166 if(get_filename(&output
))
7168 TRACE("copy to %s\n", debugstr_w(output
));
7169 CopyFileW(filename
, output
, FALSE
);
7170 HeapFree(GetProcessHeap(), 0, output
);
7176 /*****************************************************************************
7179 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7182 char *unixname
, *cmdA
;
7184 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7188 if(!(unixname
= wine_get_unix_file_name(filename
)))
7191 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7192 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7193 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7195 TRACE("printing with: %s\n", cmdA
);
7197 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7202 ERR("pipe() failed!\n");
7212 /* reset signals that we previously set to SIG_IGN */
7213 signal(SIGPIPE
, SIG_DFL
);
7214 signal(SIGCHLD
, SIG_DFL
);
7220 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7221 write(fds
[1], buf
, no_read
);
7226 if(file_fd
!= -1) close(file_fd
);
7227 if(fds
[0] != -1) close(fds
[0]);
7228 if(fds
[1] != -1) close(fds
[1]);
7230 HeapFree(GetProcessHeap(), 0, cmdA
);
7231 HeapFree(GetProcessHeap(), 0, unixname
);
7238 /*****************************************************************************
7241 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7243 int in_fd
, out_fd
, no_read
;
7246 char *unixname
, *outputA
;
7249 if(!(unixname
= wine_get_unix_file_name(filename
)))
7252 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7253 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7254 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7256 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7257 in_fd
= open(unixname
, O_RDONLY
);
7258 if(out_fd
== -1 || in_fd
== -1)
7261 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7262 write(out_fd
, buf
, no_read
);
7266 if(in_fd
!= -1) close(in_fd
);
7267 if(out_fd
!= -1) close(out_fd
);
7268 HeapFree(GetProcessHeap(), 0, outputA
);
7269 HeapFree(GetProcessHeap(), 0, unixname
);
7273 /*****************************************************************************
7274 * ScheduleJob [WINSPOOL.@]
7277 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7279 opened_printer_t
*printer
;
7281 struct list
*cursor
, *cursor2
;
7283 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7284 EnterCriticalSection(&printer_handles_cs
);
7285 printer
= get_opened_printer(hPrinter
);
7289 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7291 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7294 if(job
->job_id
!= dwJobID
) continue;
7296 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7297 if(hf
!= INVALID_HANDLE_VALUE
)
7299 PRINTER_INFO_5W
*pi5
;
7303 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7304 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7306 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7307 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7308 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7309 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7310 debugstr_w(pi5
->pPortName
));
7314 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7315 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7317 DWORD type
, count
= sizeof(output
);
7318 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7321 if(output
[0] == '|')
7323 schedule_pipe(output
+ 1, job
->filename
);
7327 schedule_unixfile(output
, job
->filename
);
7329 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7331 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7333 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7335 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7337 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7339 schedule_file(job
->filename
);
7343 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7345 HeapFree(GetProcessHeap(), 0, pi5
);
7347 DeleteFileW(job
->filename
);
7349 list_remove(cursor
);
7350 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7351 HeapFree(GetProcessHeap(), 0, job
->filename
);
7352 HeapFree(GetProcessHeap(), 0, job
);
7357 LeaveCriticalSection(&printer_handles_cs
);
7361 /*****************************************************************************
7362 * StartDocDlgA [WINSPOOL.@]
7364 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7366 UNICODE_STRING usBuffer
;
7369 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7372 docW
.cbSize
= sizeof(docW
);
7373 if (doc
->lpszDocName
)
7375 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7376 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7378 if (doc
->lpszOutput
)
7380 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7381 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7383 if (doc
->lpszDatatype
)
7385 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7386 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7388 docW
.fwType
= doc
->fwType
;
7390 retW
= StartDocDlgW(hPrinter
, &docW
);
7394 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7395 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7396 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7397 HeapFree(GetProcessHeap(), 0, retW
);
7400 HeapFree(GetProcessHeap(), 0, datatypeW
);
7401 HeapFree(GetProcessHeap(), 0, outputW
);
7402 HeapFree(GetProcessHeap(), 0, docnameW
);
7407 /*****************************************************************************
7408 * StartDocDlgW [WINSPOOL.@]
7410 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7411 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7412 * port is "FILE:". Also returns the full path if passed a relative path.
7414 * The caller should free the returned string from the process heap.
7416 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7421 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7423 PRINTER_INFO_5W
*pi5
;
7424 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7425 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7427 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7428 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7429 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7431 HeapFree(GetProcessHeap(), 0, pi5
);
7434 HeapFree(GetProcessHeap(), 0, pi5
);
7437 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7441 if (get_filename(&name
))
7443 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7445 HeapFree(GetProcessHeap(), 0, name
);
7448 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7449 GetFullPathNameW(name
, len
, ret
, NULL
);
7450 HeapFree(GetProcessHeap(), 0, name
);
7455 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7458 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7459 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7461 attr
= GetFileAttributesW(ret
);
7462 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7464 HeapFree(GetProcessHeap(), 0, ret
);