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-2009 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs
;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
70 0, 0, &monitor_handles_cs
,
71 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
72 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs
;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
80 0, 0, &printer_handles_cs
,
81 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
82 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
86 /* ############################### */
112 HANDLE backend_printer
;
121 WCHAR
*document_title
;
129 LPCWSTR versionregpath
;
130 LPCWSTR versionsubdir
;
133 /* ############################### */
135 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
136 static monitor_t
* pm_localport
;
138 static opened_printer_t
**printer_handles
;
139 static UINT nb_printer_handles
;
140 static LONG next_job_id
= 1;
142 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
143 WORD fwCapability
, LPSTR lpszOutput
,
145 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
146 LPSTR lpszDevice
, LPSTR lpszPort
,
147 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
150 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
151 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
152 'c','o','n','t','r','o','l','\\',
153 'P','r','i','n','t','\\',
154 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
155 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
157 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
158 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
159 'C','o','n','t','r','o','l','\\',
160 'P','r','i','n','t','\\',
161 'M','o','n','i','t','o','r','s','\\',0};
163 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
164 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
165 'C','o','n','t','r','o','l','\\',
166 'P','r','i','n','t','\\',
167 'P','r','i','n','t','e','r','s',0};
169 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
171 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
172 'M','i','c','r','o','s','o','f','t','\\',
173 'W','i','n','d','o','w','s',' ','N','T','\\',
174 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
175 'W','i','n','d','o','w','s',0};
177 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
178 'M','i','c','r','o','s','o','f','t','\\',
179 'W','i','n','d','o','w','s',' ','N','T','\\',
180 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
181 'D','e','v','i','c','e','s',0};
183 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
184 'M','i','c','r','o','s','o','f','t','\\',
185 'W','i','n','d','o','w','s',' ','N','T','\\',
186 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
187 'P','o','r','t','s',0};
189 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
190 'M','i','c','r','o','s','o','f','t','\\',
191 'W','i','n','d','o','w','s',' ','N','T','\\',
192 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
193 'P','r','i','n','t','e','r','P','o','r','t','s',0};
195 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
196 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
197 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
198 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
199 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
200 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
201 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
202 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
203 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
204 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
205 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
207 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
208 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
210 static const WCHAR backslashW
[] = {'\\',0};
211 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
212 'i','o','n',' ','F','i','l','e',0};
213 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
214 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
215 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
216 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
217 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
218 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
219 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
220 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
221 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
222 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
223 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
224 static const WCHAR NameW
[] = {'N','a','m','e',0};
225 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
226 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
227 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
228 static const WCHAR PortW
[] = {'P','o','r','t',0};
229 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
230 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
231 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
232 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
233 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
234 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
235 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW
[] = {0};
245 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
247 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
248 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
249 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
251 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
252 'D','o','c','u','m','e','n','t',0};
254 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
255 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
256 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
257 0, sizeof(DRIVER_INFO_8W
)};
260 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
261 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
262 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
263 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
264 sizeof(PRINTER_INFO_9W
)};
266 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
267 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
268 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
270 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
272 /******************************************************************
273 * validate the user-supplied printing-environment [internal]
276 * env [I] PTR to Environment-String or NULL
280 * Success: PTR to printenv_t
283 * An empty string is handled the same way as NULL.
284 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
288 static const printenv_t
* validate_envW(LPCWSTR env
)
290 const printenv_t
*result
= NULL
;
293 TRACE("testing %s\n", debugstr_w(env
));
296 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
298 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
300 result
= all_printenv
[i
];
305 if (result
== NULL
) {
306 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
307 SetLastError(ERROR_INVALID_ENVIRONMENT
);
309 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
313 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
315 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
321 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
322 if passed a NULL string. This returns NULLs to the result.
324 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
328 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
329 return usBufferPtr
->Buffer
;
331 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
335 static LPWSTR
strdupW(LPCWSTR p
)
341 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
342 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
347 static LPSTR
strdupWtoA( LPCWSTR str
)
352 if (!str
) return NULL
;
353 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
354 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
355 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
359 /******************************************************************
360 * Return the number of bytes for an multi_sz string.
361 * The result includes all \0s
362 * (specifically the extra \0, that is needed as multi_sz terminator).
365 static int multi_sz_lenW(const WCHAR
*str
)
367 const WCHAR
*ptr
= str
;
371 ptr
+= lstrlenW(ptr
) + 1;
374 return (ptr
- str
+ 1) * sizeof(WCHAR
);
377 /* ################################ */
379 static int multi_sz_lenA(const char *str
)
381 const char *ptr
= str
;
385 ptr
+= lstrlenA(ptr
) + 1;
388 return ptr
- str
+ 1;
392 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
395 /* If forcing, or no profile string entry for device yet, set the entry
397 * The always change entry if not WINEPS yet is discussable.
400 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
402 !strstr(qbuf
,"WINEPS.DRV")
404 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
407 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
408 WriteProfileStringA("windows","device",buf
);
409 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
410 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
413 HeapFree(GetProcessHeap(),0,buf
);
417 static BOOL
add_printer_driver(const char *name
)
421 static char driver_9x
[] = "wineps16.drv",
422 driver_nt
[] = "wineps.drv",
423 env_9x
[] = "Windows 4.0",
424 env_nt
[] = "Windows NT x86",
425 data_file
[] = "generic.ppd",
426 default_data_type
[] = "RAW";
428 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
430 di3a
.pName
= (char *)name
;
431 di3a
.pEnvironment
= env_nt
;
432 di3a
.pDriverPath
= driver_nt
;
433 di3a
.pDataFile
= data_file
;
434 di3a
.pConfigFile
= driver_nt
;
435 di3a
.pDefaultDataType
= default_data_type
;
437 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
438 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
441 di3a
.pEnvironment
= env_9x
;
442 di3a
.pDriverPath
= driver_9x
;
443 di3a
.pConfigFile
= driver_9x
;
444 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
445 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
450 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
451 debugstr_a(di3a
.pEnvironment
), GetLastError());
455 #ifdef SONAME_LIBCUPS
456 static typeof(cupsFreeDests
) *pcupsFreeDests
;
457 static typeof(cupsGetDests
) *pcupsGetDests
;
458 static typeof(cupsGetPPD
) *pcupsGetPPD
;
459 static typeof(cupsPrintFile
) *pcupsPrintFile
;
460 static void *cupshandle
;
462 static BOOL
CUPS_LoadPrinters(void)
465 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
467 PRINTER_INFO_2A pinfo2a
;
469 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
472 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
474 TRACE("%s\n", loaderror
);
477 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
480 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
481 if (!p##x) return FALSE;
483 DYNCUPS(cupsFreeDests
);
485 DYNCUPS(cupsGetDests
);
486 DYNCUPS(cupsPrintFile
);
489 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
491 ERR("Can't create Printers key\n");
495 nrofdests
= pcupsGetDests(&dests
);
496 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
497 for (i
=0;i
<nrofdests
;i
++) {
498 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
499 port
= HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests
[i
].name
)+1);
500 sprintf(port
,"LPR:%s", dests
[i
].name
);
501 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
502 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
503 sprintf(devline
, "WINEPS.DRV,%s", port
);
504 WriteProfileStringA("devices", dests
[i
].name
, devline
);
505 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
506 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
510 lstrcatA(devline
, ",15,45");
511 WriteProfileStringA("PrinterPorts", dests
[i
].name
, devline
);
512 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
513 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
517 HeapFree(GetProcessHeap(), 0, devline
);
519 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
520 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
521 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
523 TRACE("Printer already exists\n");
524 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
525 RegCloseKey(hkeyPrinter
);
527 static CHAR data_type
[] = "RAW",
528 print_proc
[] = "WinPrint",
529 comment
[] = "WINEPS Printer using CUPS",
530 location
[] = "<physical location of printer>",
531 params
[] = "<parameters?>",
532 share_name
[] = "<share name?>",
533 sep_file
[] = "<sep file?>";
535 add_printer_driver(dests
[i
].name
);
537 memset(&pinfo2a
,0,sizeof(pinfo2a
));
538 pinfo2a
.pPrinterName
= dests
[i
].name
;
539 pinfo2a
.pDatatype
= data_type
;
540 pinfo2a
.pPrintProcessor
= print_proc
;
541 pinfo2a
.pDriverName
= dests
[i
].name
;
542 pinfo2a
.pComment
= comment
;
543 pinfo2a
.pLocation
= location
;
544 pinfo2a
.pPortName
= port
;
545 pinfo2a
.pParameters
= params
;
546 pinfo2a
.pShareName
= share_name
;
547 pinfo2a
.pSepFile
= sep_file
;
549 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
550 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
551 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
554 HeapFree(GetProcessHeap(),0,port
);
557 if (dests
[i
].is_default
) {
558 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
562 if (hadprinter
& !haddefault
)
563 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
564 pcupsFreeDests(nrofdests
, dests
);
565 RegCloseKey(hkeyPrinters
);
571 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
572 PRINTER_INFO_2A pinfo2a
;
573 char *e
,*s
,*name
,*prettyname
,*devname
;
574 BOOL ret
= FALSE
, set_default
= FALSE
;
575 char *port
= NULL
, *devline
,*env_default
;
576 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
578 while (isspace(*pent
)) pent
++;
579 s
= strchr(pent
,':');
581 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
589 TRACE("name=%s entry=%s\n",name
, pent
);
591 if(ispunct(*name
)) { /* a tc entry, not a real printer */
592 TRACE("skipping tc entry\n");
596 if(strstr(pent
,":server")) { /* server only version so skip */
597 TRACE("skipping server entry\n");
601 /* Determine whether this is a postscript printer. */
604 env_default
= getenv("PRINTER");
606 /* Get longest name, usually the one at the right for later display. */
607 while((s
=strchr(prettyname
,'|'))) {
610 while(isspace(*--e
)) *e
= '\0';
611 TRACE("\t%s\n", debugstr_a(prettyname
));
612 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
613 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
616 e
= prettyname
+ strlen(prettyname
);
617 while(isspace(*--e
)) *e
= '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname
));
619 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
621 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
622 * if it is too long, we use it as comment below. */
623 devname
= prettyname
;
624 if (strlen(devname
)>=CCHDEVICENAME
-1)
626 if (strlen(devname
)>=CCHDEVICENAME
-1) {
631 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
632 sprintf(port
,"LPR:%s",name
);
634 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
635 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
636 sprintf(devline
, "WINEPS.DRV,%s", port
);
637 WriteProfileStringA("devices", devname
, devline
);
638 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
639 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
643 lstrcatA(devline
, ",15,45");
644 WriteProfileStringA("PrinterPorts", devname
, devline
);
645 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
646 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
650 HeapFree(GetProcessHeap(),0,devline
);
652 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
654 ERR("Can't create Printers key\n");
658 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
659 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
661 TRACE("Printer already exists\n");
662 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
663 RegCloseKey(hkeyPrinter
);
665 static CHAR data_type
[] = "RAW",
666 print_proc
[] = "WinPrint",
667 comment
[] = "WINEPS Printer using LPR",
668 params
[] = "<parameters?>",
669 share_name
[] = "<share name?>",
670 sep_file
[] = "<sep file?>";
672 add_printer_driver(devname
);
674 memset(&pinfo2a
,0,sizeof(pinfo2a
));
675 pinfo2a
.pPrinterName
= devname
;
676 pinfo2a
.pDatatype
= data_type
;
677 pinfo2a
.pPrintProcessor
= print_proc
;
678 pinfo2a
.pDriverName
= devname
;
679 pinfo2a
.pComment
= comment
;
680 pinfo2a
.pLocation
= prettyname
;
681 pinfo2a
.pPortName
= port
;
682 pinfo2a
.pParameters
= params
;
683 pinfo2a
.pShareName
= share_name
;
684 pinfo2a
.pSepFile
= sep_file
;
686 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
687 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
688 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
691 RegCloseKey(hkeyPrinters
);
693 if (isfirst
|| set_default
)
694 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
697 HeapFree(GetProcessHeap(), 0, port
);
698 HeapFree(GetProcessHeap(), 0, name
);
703 PRINTCAP_LoadPrinters(void) {
704 BOOL hadprinter
= FALSE
;
708 BOOL had_bash
= FALSE
;
710 f
= fopen("/etc/printcap","r");
714 while(fgets(buf
,sizeof(buf
),f
)) {
717 end
=strchr(buf
,'\n');
721 while(isspace(*start
)) start
++;
722 if(*start
== '#' || *start
== '\0')
725 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
726 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
727 HeapFree(GetProcessHeap(),0,pent
);
731 if (end
&& *--end
== '\\') {
738 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
741 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
747 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
748 HeapFree(GetProcessHeap(),0,pent
);
754 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
757 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
758 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
760 return ERROR_FILE_NOT_FOUND
;
763 /******************************************************************
764 * monitor_unload [internal]
766 * release a printmonitor and unload it from memory, when needed
769 static void monitor_unload(monitor_t
* pm
)
771 if (pm
== NULL
) return;
772 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
774 EnterCriticalSection(&monitor_handles_cs
);
776 if (pm
->refcount
) pm
->refcount
--;
778 if (pm
->refcount
== 0) {
779 list_remove(&pm
->entry
);
780 FreeLibrary(pm
->hdll
);
781 HeapFree(GetProcessHeap(), 0, pm
->name
);
782 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
783 HeapFree(GetProcessHeap(), 0, pm
);
785 LeaveCriticalSection(&monitor_handles_cs
);
788 /******************************************************************
789 * monitor_load [internal]
791 * load a printmonitor, get the dllname from the registry, when needed
792 * initialize the monitor and dump found function-pointers
794 * On failure, SetLastError() is called and NULL is returned
797 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
799 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
800 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
801 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
802 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
803 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
805 monitor_t
* pm
= NULL
;
807 LPWSTR regroot
= NULL
;
808 LPWSTR driver
= dllname
;
810 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
811 /* Is the Monitor already loaded? */
812 EnterCriticalSection(&monitor_handles_cs
);
815 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
817 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
825 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
826 if (pm
== NULL
) goto cleanup
;
827 list_add_tail(&monitor_handles
, &pm
->entry
);
831 if (pm
->name
== NULL
) {
832 /* Load the monitor */
833 LPMONITOREX pmonitorEx
;
837 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
838 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
842 lstrcpyW(regroot
, MonitorsW
);
843 lstrcatW(regroot
, name
);
844 /* Get the Driver from the Registry */
845 if (driver
== NULL
) {
848 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
849 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
850 &namesize
) == ERROR_SUCCESS
) {
851 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
852 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
859 pm
->name
= strdupW(name
);
860 pm
->dllname
= strdupW(driver
);
862 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
864 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
869 pm
->hdll
= LoadLibraryW(driver
);
870 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
872 if (pm
->hdll
== NULL
) {
874 SetLastError(ERROR_MOD_NOT_FOUND
);
879 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
880 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
881 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
882 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
883 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
886 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
887 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
888 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
889 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
890 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
892 if (pInitializePrintMonitorUI
!= NULL
) {
893 pm
->monitorUI
= pInitializePrintMonitorUI();
894 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
896 TRACE( "0x%08x: dwMonitorSize (%d)\n",
897 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
902 if (pInitializePrintMonitor
&& regroot
) {
903 pmonitorEx
= pInitializePrintMonitor(regroot
);
904 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
905 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
908 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
909 pm
->monitor
= &(pmonitorEx
->Monitor
);
914 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
918 if (!pm
->monitor
&& regroot
) {
919 if (pInitializePrintMonitor2
!= NULL
) {
920 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
922 if (pInitializeMonitorEx
!= NULL
) {
923 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
925 if (pInitializeMonitor
!= NULL
) {
926 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
929 if (!pm
->monitor
&& !pm
->monitorUI
) {
931 SetLastError(ERROR_PROC_NOT_FOUND
);
936 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
940 LeaveCriticalSection(&monitor_handles_cs
);
941 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
942 HeapFree(GetProcessHeap(), 0, regroot
);
943 TRACE("=> %p\n", pm
);
947 /******************************************************************
948 * get_servername_from_name (internal)
950 * for an external server, a copy of the serverpart from the full name is returned
953 static LPWSTR
get_servername_from_name(LPCWSTR name
)
957 WCHAR buffer
[MAX_PATH
];
960 if (name
== NULL
) return NULL
;
961 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
963 server
= strdupW(&name
[2]); /* skip over both backslash */
964 if (server
== NULL
) return NULL
;
966 /* strip '\' and the printername */
967 ptr
= strchrW(server
, '\\');
968 if (ptr
) ptr
[0] = '\0';
970 TRACE("found %s\n", debugstr_w(server
));
972 len
= sizeof(buffer
)/sizeof(buffer
[0]);
973 if (GetComputerNameW(buffer
, &len
)) {
974 if (lstrcmpW(buffer
, server
) == 0) {
975 /* The requested Servername is our computername */
976 HeapFree(GetProcessHeap(), 0, server
);
983 /******************************************************************
984 * get_basename_from_name (internal)
986 * skip over the serverpart from the full name
989 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
991 if (name
== NULL
) return NULL
;
992 if ((name
[0] == '\\') && (name
[1] == '\\')) {
993 /* skip over the servername and search for the following '\' */
994 name
= strchrW(&name
[2], '\\');
995 if ((name
) && (name
[1])) {
996 /* found a separator ('\') followed by a name:
997 skip over the separator and return the rest */
1002 /* no basename present (we found only a servername) */
1009 /******************************************************************
1010 * get_opened_printer_entry
1011 * Get the first place empty in the opened printer table
1014 * - pDefault is ignored
1016 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1018 UINT_PTR handle
= nb_printer_handles
, i
;
1019 jobqueue_t
*queue
= NULL
;
1020 opened_printer_t
*printer
= NULL
;
1022 LPCWSTR printername
;
1024 if ((backend
== NULL
) && !load_backend()) return NULL
;
1026 servername
= get_servername_from_name(name
);
1028 FIXME("server %s not supported\n", debugstr_w(servername
));
1029 HeapFree(GetProcessHeap(), 0, servername
);
1030 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1034 printername
= get_basename_from_name(name
);
1035 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1037 /* an empty printername is invalid */
1038 if (printername
&& (!printername
[0])) {
1039 SetLastError(ERROR_INVALID_PARAMETER
);
1043 EnterCriticalSection(&printer_handles_cs
);
1045 for (i
= 0; i
< nb_printer_handles
; i
++)
1047 if (!printer_handles
[i
])
1049 if(handle
== nb_printer_handles
)
1054 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1055 queue
= printer_handles
[i
]->queue
;
1059 if (handle
>= nb_printer_handles
)
1061 opened_printer_t
**new_array
;
1062 if (printer_handles
)
1063 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1064 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1066 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1067 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1074 printer_handles
= new_array
;
1075 nb_printer_handles
+= 16;
1078 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1084 /* get a printer handle from the backend */
1085 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
1090 /* clone the base name. This is NULL for the printserver */
1091 printer
->printername
= strdupW(printername
);
1093 /* clone the full name */
1094 printer
->name
= strdupW(name
);
1095 if (name
&& (!printer
->name
)) {
1101 printer
->queue
= queue
;
1104 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1105 if (!printer
->queue
) {
1109 list_init(&printer
->queue
->jobs
);
1110 printer
->queue
->ref
= 0;
1112 InterlockedIncrement(&printer
->queue
->ref
);
1114 printer_handles
[handle
] = printer
;
1117 LeaveCriticalSection(&printer_handles_cs
);
1118 if (!handle
&& printer
) {
1119 /* Something failed: Free all resources */
1120 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1121 HeapFree(GetProcessHeap(), 0, printer
->name
);
1122 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1123 HeapFree(GetProcessHeap(), 0, printer
);
1126 return (HANDLE
)handle
;
1129 /******************************************************************
1130 * get_opened_printer
1131 * Get the pointer to the opened printer referred by the handle
1133 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1135 UINT_PTR idx
= (UINT_PTR
)hprn
;
1136 opened_printer_t
*ret
= NULL
;
1138 EnterCriticalSection(&printer_handles_cs
);
1140 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
1141 ret
= printer_handles
[idx
- 1];
1143 LeaveCriticalSection(&printer_handles_cs
);
1147 /******************************************************************
1148 * get_opened_printer_name
1149 * Get the pointer to the opened printer name referred by the handle
1151 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1153 opened_printer_t
*printer
= get_opened_printer(hprn
);
1154 if(!printer
) return NULL
;
1155 return printer
->name
;
1158 /******************************************************************
1159 * WINSPOOL_GetOpenedPrinterRegKey
1162 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1164 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1168 if(!name
) return ERROR_INVALID_HANDLE
;
1170 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1174 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1176 ERR("Can't find opened printer %s in registry\n",
1178 RegCloseKey(hkeyPrinters
);
1179 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1181 RegCloseKey(hkeyPrinters
);
1182 return ERROR_SUCCESS
;
1185 void WINSPOOL_LoadSystemPrinters(void)
1187 HKEY hkey
, hkeyPrinters
;
1189 DWORD needed
, num
, i
;
1190 WCHAR PrinterName
[256];
1193 /* This ensures that all printer entries have a valid Name value. If causes
1194 problems later if they don't. If one is found to be missed we create one
1195 and set it equal to the name of the key */
1196 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1197 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1198 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1199 for(i
= 0; i
< num
; i
++) {
1200 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
1201 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1202 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1203 set_reg_szW(hkey
, NameW
, PrinterName
);
1210 RegCloseKey(hkeyPrinters
);
1213 /* We want to avoid calling AddPrinter on printers as much as
1214 possible, because on cups printers this will (eventually) lead
1215 to a call to cupsGetPPD which takes forever, even with non-cups
1216 printers AddPrinter takes a while. So we'll tag all printers that
1217 were automatically added last time around, if they still exist
1218 we'll leave them be otherwise we'll delete them. */
1219 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1221 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1222 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1223 for(i
= 0; i
< num
; i
++) {
1224 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1225 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1226 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1228 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1236 HeapFree(GetProcessHeap(), 0, pi
);
1240 #ifdef SONAME_LIBCUPS
1241 done
= CUPS_LoadPrinters();
1244 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1245 PRINTCAP_LoadPrinters();
1247 /* Now enumerate the list again and delete any printers that are still tagged */
1248 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1250 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1251 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1252 for(i
= 0; i
< num
; i
++) {
1253 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1254 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1255 BOOL delete_driver
= FALSE
;
1256 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1257 DWORD dw
, type
, size
= sizeof(dw
);
1258 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1259 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1260 DeletePrinter(hprn
);
1261 delete_driver
= TRUE
;
1267 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1272 HeapFree(GetProcessHeap(), 0, pi
);
1279 /******************************************************************
1282 * Get the pointer to the specified job.
1283 * Should hold the printer_handles_cs before calling.
1285 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1287 opened_printer_t
*printer
= get_opened_printer(hprn
);
1290 if(!printer
) return NULL
;
1291 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1293 if(job
->job_id
== JobId
)
1299 /***********************************************************
1302 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1305 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1308 Formname
= (dmA
->dmSize
> off_formname
);
1309 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1310 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1311 dmW
->dmDeviceName
, CCHDEVICENAME
);
1313 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1314 dmA
->dmSize
- CCHDEVICENAME
);
1316 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1317 off_formname
- CCHDEVICENAME
);
1318 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1319 dmW
->dmFormName
, CCHFORMNAME
);
1320 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1321 (off_formname
+ CCHFORMNAME
));
1324 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1325 dmA
->dmDriverExtra
);
1329 /***********************************************************
1331 * Creates an ansi copy of supplied devmode
1333 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1338 if (!dmW
) return NULL
;
1339 size
= dmW
->dmSize
- CCHDEVICENAME
-
1340 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1342 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1343 if (!dmA
) return NULL
;
1345 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1346 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1348 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1349 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1350 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1354 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1355 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1356 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1357 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1359 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1363 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1367 /******************************************************************
1368 * convert_printerinfo_W_to_A [internal]
1371 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1372 DWORD level
, DWORD outlen
, DWORD numentries
)
1378 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1380 len
= pi_sizeof
[level
] * numentries
;
1381 ptr
= (LPSTR
) out
+ len
;
1384 /* copy the numbers of all PRINTER_INFO_* first */
1385 memcpy(out
, pPrintersW
, len
);
1387 while (id
< numentries
) {
1391 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1392 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1394 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1395 if (piW
->pDescription
) {
1396 piA
->pDescription
= ptr
;
1397 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1398 ptr
, outlen
, NULL
, NULL
);
1404 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1405 ptr
, outlen
, NULL
, NULL
);
1409 if (piW
->pComment
) {
1410 piA
->pComment
= ptr
;
1411 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1412 ptr
, outlen
, NULL
, NULL
);
1421 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1422 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1425 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1426 if (piW
->pServerName
) {
1427 piA
->pServerName
= ptr
;
1428 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1429 ptr
, outlen
, NULL
, NULL
);
1433 if (piW
->pPrinterName
) {
1434 piA
->pPrinterName
= ptr
;
1435 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1436 ptr
, outlen
, NULL
, NULL
);
1440 if (piW
->pShareName
) {
1441 piA
->pShareName
= ptr
;
1442 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1443 ptr
, outlen
, NULL
, NULL
);
1447 if (piW
->pPortName
) {
1448 piA
->pPortName
= ptr
;
1449 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1450 ptr
, outlen
, NULL
, NULL
);
1454 if (piW
->pDriverName
) {
1455 piA
->pDriverName
= ptr
;
1456 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1457 ptr
, outlen
, NULL
, NULL
);
1461 if (piW
->pComment
) {
1462 piA
->pComment
= ptr
;
1463 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1464 ptr
, outlen
, NULL
, NULL
);
1468 if (piW
->pLocation
) {
1469 piA
->pLocation
= ptr
;
1470 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1471 ptr
, outlen
, NULL
, NULL
);
1476 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1478 /* align DEVMODEA to a DWORD boundary */
1479 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1483 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1484 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1485 memcpy(ptr
, dmA
, len
);
1486 HeapFree(GetProcessHeap(), 0, dmA
);
1492 if (piW
->pSepFile
) {
1493 piA
->pSepFile
= ptr
;
1494 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1495 ptr
, outlen
, NULL
, NULL
);
1499 if (piW
->pPrintProcessor
) {
1500 piA
->pPrintProcessor
= ptr
;
1501 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1502 ptr
, outlen
, NULL
, NULL
);
1506 if (piW
->pDatatype
) {
1507 piA
->pDatatype
= ptr
;
1508 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1509 ptr
, outlen
, NULL
, NULL
);
1513 if (piW
->pParameters
) {
1514 piA
->pParameters
= ptr
;
1515 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1516 ptr
, outlen
, NULL
, NULL
);
1520 if (piW
->pSecurityDescriptor
) {
1521 piA
->pSecurityDescriptor
= NULL
;
1522 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1529 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1530 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1532 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1534 if (piW
->pPrinterName
) {
1535 piA
->pPrinterName
= ptr
;
1536 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1537 ptr
, outlen
, NULL
, NULL
);
1541 if (piW
->pServerName
) {
1542 piA
->pServerName
= ptr
;
1543 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1544 ptr
, outlen
, NULL
, NULL
);
1553 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1554 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1556 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1558 if (piW
->pPrinterName
) {
1559 piA
->pPrinterName
= ptr
;
1560 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1561 ptr
, outlen
, NULL
, NULL
);
1565 if (piW
->pPortName
) {
1566 piA
->pPortName
= ptr
;
1567 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1568 ptr
, outlen
, NULL
, NULL
);
1576 FIXME("for level %u\n", level
);
1578 pPrintersW
+= pi_sizeof
[level
];
1579 out
+= pi_sizeof
[level
];
1584 /***********************************************************
1585 * PRINTER_INFO_2AtoW
1586 * Creates a unicode copy of PRINTER_INFO_2A on heap
1588 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1590 LPPRINTER_INFO_2W piW
;
1591 UNICODE_STRING usBuffer
;
1593 if(!piA
) return NULL
;
1594 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1595 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1597 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1598 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1599 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1600 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1601 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1602 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1603 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1604 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1605 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1606 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1607 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1608 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1612 /***********************************************************
1613 * FREE_PRINTER_INFO_2W
1614 * Free PRINTER_INFO_2W and all strings
1616 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1620 HeapFree(heap
,0,piW
->pServerName
);
1621 HeapFree(heap
,0,piW
->pPrinterName
);
1622 HeapFree(heap
,0,piW
->pShareName
);
1623 HeapFree(heap
,0,piW
->pPortName
);
1624 HeapFree(heap
,0,piW
->pDriverName
);
1625 HeapFree(heap
,0,piW
->pComment
);
1626 HeapFree(heap
,0,piW
->pLocation
);
1627 HeapFree(heap
,0,piW
->pDevMode
);
1628 HeapFree(heap
,0,piW
->pSepFile
);
1629 HeapFree(heap
,0,piW
->pPrintProcessor
);
1630 HeapFree(heap
,0,piW
->pDatatype
);
1631 HeapFree(heap
,0,piW
->pParameters
);
1632 HeapFree(heap
,0,piW
);
1636 /******************************************************************
1637 * DeviceCapabilities [WINSPOOL.@]
1638 * DeviceCapabilitiesA [WINSPOOL.@]
1641 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1642 LPSTR pOutput
, LPDEVMODEA lpdm
)
1646 if (!GDI_CallDeviceCapabilities16
)
1648 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1650 if (!GDI_CallDeviceCapabilities16
) return -1;
1652 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1654 /* If DC_PAPERSIZE map POINT16s to POINTs */
1655 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1656 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1657 POINT
*pt
= (POINT
*)pOutput
;
1659 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1660 for(i
= 0; i
< ret
; i
++, pt
++)
1665 HeapFree( GetProcessHeap(), 0, tmp
);
1671 /*****************************************************************************
1672 * DeviceCapabilitiesW [WINSPOOL.@]
1674 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1677 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1678 WORD fwCapability
, LPWSTR pOutput
,
1679 const DEVMODEW
*pDevMode
)
1681 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1682 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1683 LPSTR pPortA
= strdupWtoA(pPort
);
1686 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1687 fwCapability
== DC_FILEDEPENDENCIES
||
1688 fwCapability
== DC_PAPERNAMES
)) {
1689 /* These need A -> W translation */
1692 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1696 switch(fwCapability
) {
1701 case DC_FILEDEPENDENCIES
:
1705 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1706 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1708 for(i
= 0; i
< ret
; i
++)
1709 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1710 pOutput
+ (i
* size
), size
);
1711 HeapFree(GetProcessHeap(), 0, pOutputA
);
1713 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1714 (LPSTR
)pOutput
, dmA
);
1716 HeapFree(GetProcessHeap(),0,pPortA
);
1717 HeapFree(GetProcessHeap(),0,pDeviceA
);
1718 HeapFree(GetProcessHeap(),0,dmA
);
1722 /******************************************************************
1723 * DocumentPropertiesA [WINSPOOL.@]
1725 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1727 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1728 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1729 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1731 LPSTR lpName
= pDeviceName
;
1732 static CHAR port
[] = "LPT1:";
1735 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1736 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1740 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1742 ERR("no name from hPrinter?\n");
1743 SetLastError(ERROR_INVALID_HANDLE
);
1746 lpName
= strdupWtoA(lpNameW
);
1749 if (!GDI_CallExtDeviceMode16
)
1751 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1753 if (!GDI_CallExtDeviceMode16
) {
1754 ERR("No CallExtDeviceMode16?\n");
1758 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1759 pDevModeInput
, NULL
, fMode
);
1762 HeapFree(GetProcessHeap(),0,lpName
);
1767 /*****************************************************************************
1768 * DocumentPropertiesW (WINSPOOL.@)
1770 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1772 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1774 LPDEVMODEW pDevModeOutput
,
1775 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1778 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1779 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1780 LPDEVMODEA pDevModeOutputA
= NULL
;
1783 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1784 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1786 if(pDevModeOutput
) {
1787 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1788 if(ret
< 0) return ret
;
1789 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1791 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1792 pDevModeInputA
, fMode
);
1793 if(pDevModeOutput
) {
1794 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1795 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1797 if(fMode
== 0 && ret
> 0)
1798 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1799 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1800 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1804 /******************************************************************
1805 * OpenPrinterA [WINSPOOL.@]
1810 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1811 LPPRINTER_DEFAULTSA pDefault
)
1813 UNICODE_STRING lpPrinterNameW
;
1814 UNICODE_STRING usBuffer
;
1815 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1816 PWSTR pwstrPrinterNameW
;
1819 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1822 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1823 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1824 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1825 pDefaultW
= &DefaultW
;
1827 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1829 RtlFreeUnicodeString(&usBuffer
);
1830 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1832 RtlFreeUnicodeString(&lpPrinterNameW
);
1836 /******************************************************************
1837 * OpenPrinterW [WINSPOOL.@]
1839 * Open a Printer / Printserver or a Printer-Object
1842 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1843 * phPrinter [O] The resulting Handle is stored here
1844 * pDefault [I] PTR to Default Printer Settings or NULL
1851 * lpPrinterName is one of:
1852 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1853 *| Printer: "PrinterName"
1854 *| Printer-Object: "PrinterName,Job xxx"
1855 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1856 *| XcvPort: "Servername,XcvPort PortName"
1859 *| Printer-Object not supported
1860 *| pDefaults is ignored
1863 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1866 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1868 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1869 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1873 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1874 SetLastError(ERROR_INVALID_PARAMETER
);
1878 /* Get the unique handle of the printer or Printserver */
1879 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1880 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1881 return (*phPrinter
!= 0);
1884 /******************************************************************
1885 * AddMonitorA [WINSPOOL.@]
1890 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1892 LPWSTR nameW
= NULL
;
1895 LPMONITOR_INFO_2A mi2a
;
1896 MONITOR_INFO_2W mi2w
;
1898 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1899 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1900 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1901 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1902 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1905 SetLastError(ERROR_INVALID_LEVEL
);
1909 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1915 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1916 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1917 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1920 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1922 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1923 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1924 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1926 if (mi2a
->pEnvironment
) {
1927 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1928 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1929 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1931 if (mi2a
->pDLLName
) {
1932 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1933 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1934 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1937 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1939 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1940 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1941 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1943 HeapFree(GetProcessHeap(), 0, nameW
);
1947 /******************************************************************************
1948 * AddMonitorW [WINSPOOL.@]
1950 * Install a Printmonitor
1953 * pName [I] Servername or NULL (local Computer)
1954 * Level [I] Structure-Level (Must be 2)
1955 * pMonitors [I] PTR to MONITOR_INFO_2
1962 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1965 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1967 LPMONITOR_INFO_2W mi2w
;
1969 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1970 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1971 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1972 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1973 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1975 if ((backend
== NULL
) && !load_backend()) return FALSE
;
1978 SetLastError(ERROR_INVALID_LEVEL
);
1982 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1987 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
1990 /******************************************************************
1991 * DeletePrinterDriverA [WINSPOOL.@]
1994 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
1996 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
1999 /******************************************************************
2000 * DeletePrinterDriverW [WINSPOOL.@]
2003 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2005 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2008 /******************************************************************
2009 * DeleteMonitorA [WINSPOOL.@]
2011 * See DeleteMonitorW.
2014 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2016 LPWSTR nameW
= NULL
;
2017 LPWSTR EnvironmentW
= NULL
;
2018 LPWSTR MonitorNameW
= NULL
;
2023 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2024 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2025 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2029 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2030 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2031 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2034 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2035 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2036 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2039 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2041 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2042 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2043 HeapFree(GetProcessHeap(), 0, nameW
);
2047 /******************************************************************
2048 * DeleteMonitorW [WINSPOOL.@]
2050 * Delete a specific Printmonitor from a Printing-Environment
2053 * pName [I] Servername or NULL (local Computer)
2054 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2055 * pMonitorName [I] Name of the Monitor, that should be deleted
2062 * pEnvironment is ignored in Windows for the local Computer.
2065 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2068 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2069 debugstr_w(pMonitorName
));
2071 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2073 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2077 /******************************************************************
2078 * DeletePortA [WINSPOOL.@]
2083 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2085 LPWSTR nameW
= NULL
;
2086 LPWSTR portW
= NULL
;
2090 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2092 /* convert servername to unicode */
2094 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2095 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2096 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2099 /* convert portname to unicode */
2101 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2102 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2103 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2106 res
= DeletePortW(nameW
, hWnd
, portW
);
2107 HeapFree(GetProcessHeap(), 0, nameW
);
2108 HeapFree(GetProcessHeap(), 0, portW
);
2112 /******************************************************************
2113 * DeletePortW [WINSPOOL.@]
2115 * Delete a specific Port
2118 * pName [I] Servername or NULL (local Computer)
2119 * hWnd [I] Handle to parent Window for the Dialog-Box
2120 * pPortName [I] Name of the Port, that should be deleted
2127 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2129 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2131 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2134 SetLastError(RPC_X_NULL_REF_POINTER
);
2138 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2141 /******************************************************************************
2142 * SetPrinterW [WINSPOOL.@]
2144 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2146 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2147 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2151 /******************************************************************************
2152 * WritePrinter [WINSPOOL.@]
2154 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2156 opened_printer_t
*printer
;
2159 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2161 EnterCriticalSection(&printer_handles_cs
);
2162 printer
= get_opened_printer(hPrinter
);
2165 SetLastError(ERROR_INVALID_HANDLE
);
2171 SetLastError(ERROR_SPL_NO_STARTDOC
);
2175 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2177 LeaveCriticalSection(&printer_handles_cs
);
2181 /*****************************************************************************
2182 * AddFormA [WINSPOOL.@]
2184 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2186 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2190 /*****************************************************************************
2191 * AddFormW [WINSPOOL.@]
2193 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2195 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2199 /*****************************************************************************
2200 * AddJobA [WINSPOOL.@]
2202 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2205 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2209 SetLastError(ERROR_INVALID_LEVEL
);
2213 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2216 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2217 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2218 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2219 if(*pcbNeeded
> cbBuf
) {
2220 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2223 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2224 addjobA
->JobId
= addjobW
->JobId
;
2225 addjobA
->Path
= (char *)(addjobA
+ 1);
2226 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2232 /*****************************************************************************
2233 * AddJobW [WINSPOOL.@]
2235 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2237 opened_printer_t
*printer
;
2240 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2241 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2242 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2244 ADDJOB_INFO_1W
*addjob
;
2246 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2248 EnterCriticalSection(&printer_handles_cs
);
2250 printer
= get_opened_printer(hPrinter
);
2253 SetLastError(ERROR_INVALID_HANDLE
);
2258 SetLastError(ERROR_INVALID_LEVEL
);
2262 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2266 job
->job_id
= InterlockedIncrement(&next_job_id
);
2268 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2269 if(path
[len
- 1] != '\\')
2271 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2272 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2274 len
= strlenW(filename
);
2275 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2276 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2277 job
->document_title
= strdupW(default_doc_title
);
2278 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2280 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2281 if(*pcbNeeded
<= cbBuf
) {
2282 addjob
= (ADDJOB_INFO_1W
*)pData
;
2283 addjob
->JobId
= job
->job_id
;
2284 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2285 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2288 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2291 LeaveCriticalSection(&printer_handles_cs
);
2295 /*****************************************************************************
2296 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2298 * Return the PATH for the Print-Processors
2300 * See GetPrintProcessorDirectoryW.
2304 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2305 DWORD level
, LPBYTE Info
,
2306 DWORD cbBuf
, LPDWORD pcbNeeded
)
2308 LPWSTR serverW
= NULL
;
2313 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2314 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2318 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2319 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2320 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2324 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2325 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2326 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2329 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2330 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2332 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2335 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2336 cbBuf
, NULL
, NULL
) > 0;
2339 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2340 HeapFree(GetProcessHeap(), 0, envW
);
2341 HeapFree(GetProcessHeap(), 0, serverW
);
2345 /*****************************************************************************
2346 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2348 * Return the PATH for the Print-Processors
2351 * server [I] Servername (NT only) or NULL (local Computer)
2352 * env [I] Printing-Environment (see below) or NULL (Default)
2353 * level [I] Structure-Level (must be 1)
2354 * Info [O] PTR to Buffer that receives the Result
2355 * cbBuf [I] Size of Buffer at "Info"
2356 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2357 * required for the Buffer at "Info"
2360 * Success: TRUE and in pcbNeeded the Bytes used in Info
2361 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2362 * if cbBuf is too small
2364 * Native Values returned in Info on Success:
2365 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2366 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2367 *| win9x(Windows 4.0): "%winsysdir%"
2369 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2372 * Only NULL or "" is supported for server
2375 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2376 DWORD level
, LPBYTE Info
,
2377 DWORD cbBuf
, LPDWORD pcbNeeded
)
2380 const printenv_t
* env_t
;
2382 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2383 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2385 if(server
!= NULL
&& server
[0]) {
2386 FIXME("server not supported: %s\n", debugstr_w(server
));
2387 SetLastError(ERROR_INVALID_PARAMETER
);
2391 env_t
= validate_envW(env
);
2392 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2395 WARN("(Level: %d) is ignored in win9x\n", level
);
2396 SetLastError(ERROR_INVALID_LEVEL
);
2400 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2401 needed
= GetSystemDirectoryW(NULL
, 0);
2402 /* add the Size for the Subdirectories */
2403 needed
+= lstrlenW(spoolprtprocsW
);
2404 needed
+= lstrlenW(env_t
->subdir
);
2405 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2407 if(pcbNeeded
) *pcbNeeded
= needed
;
2408 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2409 if (needed
> cbBuf
) {
2410 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2413 if(pcbNeeded
== NULL
) {
2414 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2415 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2416 SetLastError(RPC_X_NULL_REF_POINTER
);
2420 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2421 SetLastError(RPC_X_NULL_REF_POINTER
);
2425 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2426 /* add the Subdirectories */
2427 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2428 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2429 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2433 /*****************************************************************************
2434 * WINSPOOL_OpenDriverReg [internal]
2436 * opens the registry for the printer drivers depending on the given input
2437 * variable pEnvironment
2440 * the opened hkey on success
2443 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2447 const printenv_t
* env
;
2450 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2452 if (!pEnvironment
|| unicode
) {
2453 /* pEnvironment was NULL or a Unicode-String: use it direct */
2454 env
= validate_envW(pEnvironment
);
2458 /* pEnvironment was an ANSI-String: convert to unicode first */
2460 INT len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2461 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2462 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, buffer
, len
);
2463 env
= validate_envW(buffer
);
2464 HeapFree(GetProcessHeap(), 0, buffer
);
2466 if (!env
) return NULL
;
2468 buffer
= HeapAlloc( GetProcessHeap(), 0,
2469 (strlenW(DriversW
) + strlenW(env
->envname
) +
2470 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2472 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2473 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2474 HeapFree(GetProcessHeap(), 0, buffer
);
2479 /*****************************************************************************
2480 * AddPrinterW [WINSPOOL.@]
2482 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2484 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2488 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2490 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2491 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2492 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2493 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2494 statusW
[] = {'S','t','a','t','u','s',0},
2495 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2497 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2500 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2501 SetLastError(ERROR_INVALID_PARAMETER
);
2505 ERR("Level = %d, unsupported!\n", Level
);
2506 SetLastError(ERROR_INVALID_LEVEL
);
2510 SetLastError(ERROR_INVALID_PARAMETER
);
2513 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2515 ERR("Can't create Printers key\n");
2518 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2519 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2520 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2521 RegCloseKey(hkeyPrinter
);
2522 RegCloseKey(hkeyPrinters
);
2525 RegCloseKey(hkeyPrinter
);
2527 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2529 ERR("Can't create Drivers key\n");
2530 RegCloseKey(hkeyPrinters
);
2533 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2535 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2536 RegCloseKey(hkeyPrinters
);
2537 RegCloseKey(hkeyDrivers
);
2538 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2541 RegCloseKey(hkeyDriver
);
2542 RegCloseKey(hkeyDrivers
);
2544 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2545 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2546 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2547 RegCloseKey(hkeyPrinters
);
2551 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2553 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2554 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2555 RegCloseKey(hkeyPrinters
);
2558 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2559 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2560 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2562 /* See if we can load the driver. We may need the devmode structure anyway
2565 * Note that DocumentPropertiesW will briefly try to open the printer we
2566 * just create to find a DEVMODEA struct (it will use the WINEPS default
2567 * one in case it is not there, so we are ok).
2569 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2572 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2573 size
= sizeof(DEVMODEW
);
2579 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2581 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2583 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2584 HeapFree(GetProcessHeap(),0,dmW
);
2589 /* set devmode to printer name */
2590 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2594 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2595 and we support these drivers. NT writes DEVMODEW so somehow
2596 we'll need to distinguish between these when we support NT
2600 dmA
= DEVMODEdupWtoA(dmW
);
2601 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2602 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2603 HeapFree(GetProcessHeap(), 0, dmA
);
2605 HeapFree(GetProcessHeap(), 0, dmW
);
2607 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2608 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2609 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2610 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2612 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2613 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2614 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2615 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2616 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2617 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2618 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2619 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2620 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2621 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2622 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2623 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2624 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2626 RegCloseKey(hkeyPrinter
);
2627 RegCloseKey(hkeyPrinters
);
2628 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2629 ERR("OpenPrinter failing\n");
2635 /*****************************************************************************
2636 * AddPrinterA [WINSPOOL.@]
2638 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2640 UNICODE_STRING pNameW
;
2642 PRINTER_INFO_2W
*piW
;
2643 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2646 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2648 ERR("Level = %d, unsupported!\n", Level
);
2649 SetLastError(ERROR_INVALID_LEVEL
);
2652 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2653 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2655 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2657 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2658 RtlFreeUnicodeString(&pNameW
);
2663 /*****************************************************************************
2664 * ClosePrinter [WINSPOOL.@]
2666 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2668 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2669 opened_printer_t
*printer
= NULL
;
2672 TRACE("(%p)\n", hPrinter
);
2674 EnterCriticalSection(&printer_handles_cs
);
2676 if ((i
> 0) && (i
<= nb_printer_handles
))
2677 printer
= printer_handles
[i
- 1];
2682 struct list
*cursor
, *cursor2
;
2684 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2686 if (printer
->backend_printer
) {
2687 backend
->fpClosePrinter(printer
->backend_printer
);
2691 EndDocPrinter(hPrinter
);
2693 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2695 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2697 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2698 ScheduleJob(hPrinter
, job
->job_id
);
2700 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2703 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2704 HeapFree(GetProcessHeap(), 0, printer
->name
);
2705 HeapFree(GetProcessHeap(), 0, printer
);
2706 printer_handles
[i
- 1] = NULL
;
2709 LeaveCriticalSection(&printer_handles_cs
);
2713 /*****************************************************************************
2714 * DeleteFormA [WINSPOOL.@]
2716 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2718 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2722 /*****************************************************************************
2723 * DeleteFormW [WINSPOOL.@]
2725 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2727 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2731 /*****************************************************************************
2732 * DeletePrinter [WINSPOOL.@]
2734 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2736 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2737 HKEY hkeyPrinters
, hkey
;
2740 SetLastError(ERROR_INVALID_HANDLE
);
2743 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2744 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2745 RegCloseKey(hkeyPrinters
);
2747 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2748 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2750 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2751 RegDeleteValueW(hkey
, lpNameW
);
2755 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2756 RegDeleteValueW(hkey
, lpNameW
);
2762 /*****************************************************************************
2763 * SetPrinterA [WINSPOOL.@]
2765 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2768 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2772 /*****************************************************************************
2773 * SetJobA [WINSPOOL.@]
2775 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2776 LPBYTE pJob
, DWORD Command
)
2780 UNICODE_STRING usBuffer
;
2782 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2784 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2785 are all ignored by SetJob, so we don't bother copying them */
2793 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2794 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2796 JobW
= (LPBYTE
)info1W
;
2797 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2798 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2799 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2800 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2801 info1W
->Status
= info1A
->Status
;
2802 info1W
->Priority
= info1A
->Priority
;
2803 info1W
->Position
= info1A
->Position
;
2804 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2809 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2810 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2812 JobW
= (LPBYTE
)info2W
;
2813 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2814 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2815 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2816 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2817 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2818 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2819 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2820 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2821 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2822 info2W
->Status
= info2A
->Status
;
2823 info2W
->Priority
= info2A
->Priority
;
2824 info2W
->Position
= info2A
->Position
;
2825 info2W
->StartTime
= info2A
->StartTime
;
2826 info2W
->UntilTime
= info2A
->UntilTime
;
2827 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2831 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2832 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2835 SetLastError(ERROR_INVALID_LEVEL
);
2839 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2845 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2846 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2847 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2848 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2849 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2854 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2855 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2856 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2857 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2858 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2859 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2860 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2861 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2862 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2866 HeapFree(GetProcessHeap(), 0, JobW
);
2871 /*****************************************************************************
2872 * SetJobW [WINSPOOL.@]
2874 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2875 LPBYTE pJob
, DWORD Command
)
2880 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2881 FIXME("Ignoring everything other than document title\n");
2883 EnterCriticalSection(&printer_handles_cs
);
2884 job
= get_job(hPrinter
, JobId
);
2894 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2895 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2896 job
->document_title
= strdupW(info1
->pDocument
);
2901 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2902 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2903 job
->document_title
= strdupW(info2
->pDocument
);
2909 SetLastError(ERROR_INVALID_LEVEL
);
2914 LeaveCriticalSection(&printer_handles_cs
);
2918 /*****************************************************************************
2919 * EndDocPrinter [WINSPOOL.@]
2921 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2923 opened_printer_t
*printer
;
2925 TRACE("(%p)\n", hPrinter
);
2927 EnterCriticalSection(&printer_handles_cs
);
2929 printer
= get_opened_printer(hPrinter
);
2932 SetLastError(ERROR_INVALID_HANDLE
);
2938 SetLastError(ERROR_SPL_NO_STARTDOC
);
2942 CloseHandle(printer
->doc
->hf
);
2943 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2944 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2945 printer
->doc
= NULL
;
2948 LeaveCriticalSection(&printer_handles_cs
);
2952 /*****************************************************************************
2953 * EndPagePrinter [WINSPOOL.@]
2955 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2957 FIXME("(%p): stub\n", hPrinter
);
2961 /*****************************************************************************
2962 * StartDocPrinterA [WINSPOOL.@]
2964 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2966 UNICODE_STRING usBuffer
;
2968 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2971 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2972 or one (DOC_INFO_3) extra DWORDs */
2976 doc2W
.JobId
= doc2
->JobId
;
2979 doc2W
.dwMode
= doc2
->dwMode
;
2982 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2983 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2984 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2988 SetLastError(ERROR_INVALID_LEVEL
);
2992 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2994 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2995 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2996 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3001 /*****************************************************************************
3002 * StartDocPrinterW [WINSPOOL.@]
3004 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3006 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3007 opened_printer_t
*printer
;
3008 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3009 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3010 JOB_INFO_1W job_info
;
3011 DWORD needed
, ret
= 0;
3015 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3016 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3017 debugstr_w(doc
->pDatatype
));
3019 if(Level
< 1 || Level
> 3)
3021 SetLastError(ERROR_INVALID_LEVEL
);
3025 EnterCriticalSection(&printer_handles_cs
);
3026 printer
= get_opened_printer(hPrinter
);
3029 SetLastError(ERROR_INVALID_HANDLE
);
3035 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3039 /* Even if we're printing to a file we still add a print job, we'll
3040 just ignore the spool file name */
3042 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3044 ERR("AddJob failed gle %u\n", GetLastError());
3048 if(doc
->pOutputFile
)
3049 filename
= doc
->pOutputFile
;
3051 filename
= addjob
->Path
;
3053 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3054 if(hf
== INVALID_HANDLE_VALUE
)
3057 memset(&job_info
, 0, sizeof(job_info
));
3058 job_info
.pDocument
= doc
->pDocName
;
3059 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3061 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3062 printer
->doc
->hf
= hf
;
3063 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3065 LeaveCriticalSection(&printer_handles_cs
);
3070 /*****************************************************************************
3071 * StartPagePrinter [WINSPOOL.@]
3073 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3075 FIXME("(%p): stub\n", hPrinter
);
3079 /*****************************************************************************
3080 * GetFormA [WINSPOOL.@]
3082 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3083 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3085 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3086 Level
,pForm
,cbBuf
,pcbNeeded
);
3090 /*****************************************************************************
3091 * GetFormW [WINSPOOL.@]
3093 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3094 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3096 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3097 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3101 /*****************************************************************************
3102 * SetFormA [WINSPOOL.@]
3104 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3107 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3111 /*****************************************************************************
3112 * SetFormW [WINSPOOL.@]
3114 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3117 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3121 /*****************************************************************************
3122 * ReadPrinter [WINSPOOL.@]
3124 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3125 LPDWORD pNoBytesRead
)
3127 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3131 /*****************************************************************************
3132 * ResetPrinterA [WINSPOOL.@]
3134 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3136 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3140 /*****************************************************************************
3141 * ResetPrinterW [WINSPOOL.@]
3143 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3145 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3149 /*****************************************************************************
3150 * WINSPOOL_GetDWORDFromReg
3152 * Return DWORD associated with ValueName from hkey.
3154 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3156 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3159 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3161 if(ret
!= ERROR_SUCCESS
) {
3162 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3165 if(type
!= REG_DWORD
) {
3166 ERR("Got type %d\n", type
);
3173 /*****************************************************************************
3174 * get_filename_from_reg [internal]
3176 * Get ValueName from hkey storing result in out
3177 * when the Value in the registry has only a filename, use driverdir as prefix
3178 * outlen is space left in out
3179 * String is stored either as unicode or ascii
3183 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3184 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3186 WCHAR filename
[MAX_PATH
];
3190 LPWSTR buffer
= filename
;
3194 size
= sizeof(filename
);
3196 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3197 if (ret
== ERROR_MORE_DATA
) {
3198 TRACE("need dynamic buffer: %u\n", size
);
3199 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3201 /* No Memory is bad */
3205 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3208 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3209 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3215 /* do we have a full path ? */
3216 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3217 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3220 /* we must build the full Path */
3222 if ((out
) && (outlen
> dirlen
)) {
3224 lstrcpyW((LPWSTR
)out
, driverdir
);
3228 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3237 /* write the filename */
3239 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3240 if ((out
) && (outlen
>= size
)) {
3241 lstrcpyW((LPWSTR
)out
, ptr
);
3250 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3251 if ((out
) && (outlen
>= size
)) {
3252 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3260 ptr
+= lstrlenW(ptr
)+1;
3261 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3264 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3266 /* write the multisz-termination */
3267 if (type
== REG_MULTI_SZ
) {
3268 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3271 if (out
&& (outlen
>= size
)) {
3272 memset (out
, 0, size
);
3278 /*****************************************************************************
3279 * WINSPOOL_GetStringFromReg
3281 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3282 * String is stored either as unicode or ascii.
3283 * Bit of a hack here to get the ValueName if we want ascii.
3285 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3286 DWORD buflen
, DWORD
*needed
,
3289 DWORD sz
= buflen
, type
;
3293 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3295 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3296 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3297 HeapFree(GetProcessHeap(),0,ValueNameA
);
3299 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3300 WARN("Got ret = %d\n", ret
);
3304 /* add space for terminating '\0' */
3305 sz
+= unicode
? sizeof(WCHAR
) : 1;
3309 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3314 /*****************************************************************************
3315 * WINSPOOL_GetDefaultDevMode
3317 * Get a default DevMode values for wineps.
3321 static void WINSPOOL_GetDefaultDevMode(
3323 DWORD buflen
, DWORD
*needed
,
3327 static const char szwps
[] = "wineps.drv";
3329 /* fill default DEVMODE - should be read from ppd... */
3330 ZeroMemory( &dm
, sizeof(dm
) );
3331 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3332 dm
.dmSpecVersion
= DM_SPECVERSION
;
3333 dm
.dmDriverVersion
= 1;
3334 dm
.dmSize
= sizeof(DEVMODEA
);
3335 dm
.dmDriverExtra
= 0;
3337 DM_ORIENTATION
| DM_PAPERSIZE
|
3338 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3341 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3342 DM_YRESOLUTION
| DM_TTOPTION
;
3344 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3345 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3346 dm
.u1
.s1
.dmPaperLength
= 2970;
3347 dm
.u1
.s1
.dmPaperWidth
= 2100;
3349 dm
.u1
.s1
.dmScale
= 100;
3350 dm
.u1
.s1
.dmCopies
= 1;
3351 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3352 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3355 dm
.dmYResolution
= 300; /* 300dpi */
3356 dm
.dmTTOption
= DMTT_BITMAP
;
3359 /* dm.dmLogPixels */
3360 /* dm.dmBitsPerPel */
3361 /* dm.dmPelsWidth */
3362 /* dm.dmPelsHeight */
3363 /* dm.u2.dmDisplayFlags */
3364 /* dm.dmDisplayFrequency */
3365 /* dm.dmICMMethod */
3366 /* dm.dmICMIntent */
3367 /* dm.dmMediaType */
3368 /* dm.dmDitherType */
3369 /* dm.dmReserved1 */
3370 /* dm.dmReserved2 */
3371 /* dm.dmPanningWidth */
3372 /* dm.dmPanningHeight */
3375 if(buflen
>= sizeof(DEVMODEW
)) {
3376 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3377 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3378 HeapFree(GetProcessHeap(),0,pdmW
);
3380 *needed
= sizeof(DEVMODEW
);
3384 if(buflen
>= sizeof(DEVMODEA
)) {
3385 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3387 *needed
= sizeof(DEVMODEA
);
3391 /*****************************************************************************
3392 * WINSPOOL_GetDevModeFromReg
3394 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3395 * DevMode is stored either as unicode or ascii.
3397 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3399 DWORD buflen
, DWORD
*needed
,
3402 DWORD sz
= buflen
, type
;
3405 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3406 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3407 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3408 if (sz
< sizeof(DEVMODEA
))
3410 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3413 /* ensures that dmSize is not erratically bogus if registry is invalid */
3414 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3415 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3417 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3419 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3420 memcpy(ptr
, dmW
, sz
);
3421 HeapFree(GetProcessHeap(),0,dmW
);
3428 /*********************************************************************
3429 * WINSPOOL_GetPrinter_1
3431 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3432 * The strings are either stored as unicode or ascii.
3434 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3435 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3438 DWORD size
, left
= cbBuf
;
3439 BOOL space
= (cbBuf
> 0);
3444 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3446 if(space
&& size
<= left
) {
3447 pi1
->pName
= (LPWSTR
)ptr
;
3455 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3456 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3458 if(space
&& size
<= left
) {
3459 pi1
->pDescription
= (LPWSTR
)ptr
;
3467 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3469 if(space
&& size
<= left
) {
3470 pi1
->pComment
= (LPWSTR
)ptr
;
3478 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3480 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3481 memset(pi1
, 0, sizeof(*pi1
));
3485 /*********************************************************************
3486 * WINSPOOL_GetPrinter_2
3488 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3489 * The strings are either stored as unicode or ascii.
3491 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3492 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3495 DWORD size
, left
= cbBuf
;
3496 BOOL space
= (cbBuf
> 0);
3501 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3503 if(space
&& size
<= left
) {
3504 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3511 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3513 if(space
&& size
<= left
) {
3514 pi2
->pShareName
= (LPWSTR
)ptr
;
3521 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3523 if(space
&& size
<= left
) {
3524 pi2
->pPortName
= (LPWSTR
)ptr
;
3531 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3533 if(space
&& size
<= left
) {
3534 pi2
->pDriverName
= (LPWSTR
)ptr
;
3541 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3543 if(space
&& size
<= left
) {
3544 pi2
->pComment
= (LPWSTR
)ptr
;
3551 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3553 if(space
&& size
<= left
) {
3554 pi2
->pLocation
= (LPWSTR
)ptr
;
3561 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3563 if(space
&& size
<= left
) {
3564 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3573 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3574 if(space
&& size
<= left
) {
3575 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3582 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3584 if(space
&& size
<= left
) {
3585 pi2
->pSepFile
= (LPWSTR
)ptr
;
3592 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3594 if(space
&& size
<= left
) {
3595 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3602 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3604 if(space
&& size
<= left
) {
3605 pi2
->pDatatype
= (LPWSTR
)ptr
;
3612 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3614 if(space
&& size
<= left
) {
3615 pi2
->pParameters
= (LPWSTR
)ptr
;
3623 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3624 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3625 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3626 "Default Priority");
3627 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3628 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3631 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3632 memset(pi2
, 0, sizeof(*pi2
));
3637 /*********************************************************************
3638 * WINSPOOL_GetPrinter_4
3640 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3642 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3643 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3646 DWORD size
, left
= cbBuf
;
3647 BOOL space
= (cbBuf
> 0);
3652 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3654 if(space
&& size
<= left
) {
3655 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3663 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3666 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3667 memset(pi4
, 0, sizeof(*pi4
));
3672 /*********************************************************************
3673 * WINSPOOL_GetPrinter_5
3675 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3677 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3678 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3681 DWORD size
, left
= cbBuf
;
3682 BOOL space
= (cbBuf
> 0);
3687 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3689 if(space
&& size
<= left
) {
3690 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3697 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3699 if(space
&& size
<= left
) {
3700 pi5
->pPortName
= (LPWSTR
)ptr
;
3708 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3709 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3711 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3715 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3716 memset(pi5
, 0, sizeof(*pi5
));
3721 /*********************************************************************
3722 * WINSPOOL_GetPrinter_7
3724 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3726 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3727 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3729 DWORD size
, left
= cbBuf
;
3730 BOOL space
= (cbBuf
> 0);
3735 if (WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
, unicode
))
3737 if (space
&& size
<= left
) {
3738 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3746 /* We do not have a Directory Service */
3747 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3750 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3751 memset(pi7
, 0, sizeof(*pi7
));
3756 /*********************************************************************
3757 * WINSPOOL_GetPrinter_9
3759 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3760 * The strings are either stored as unicode or ascii.
3762 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3763 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3766 BOOL space
= (cbBuf
> 0);
3770 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
, unicode
)) {
3771 if(space
&& size
<= cbBuf
) {
3772 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3779 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
, unicode
);
3780 if(space
&& size
<= cbBuf
) {
3781 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3787 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3788 memset(pi9
, 0, sizeof(*pi9
));
3793 /*****************************************************************************
3794 * WINSPOOL_GetPrinter
3796 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3797 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3798 * just a collection of pointers to strings.
3800 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3801 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3804 DWORD size
, needed
= 0;
3806 HKEY hkeyPrinter
, hkeyPrinters
;
3809 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3811 if (!(name
= get_opened_printer_name(hPrinter
))) {
3812 SetLastError(ERROR_INVALID_HANDLE
);
3816 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3818 ERR("Can't create Printers key\n");
3821 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3823 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3824 RegCloseKey(hkeyPrinters
);
3825 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3832 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3834 size
= sizeof(PRINTER_INFO_2W
);
3836 ptr
= pPrinter
+ size
;
3838 memset(pPrinter
, 0, size
);
3843 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
3851 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3853 size
= sizeof(PRINTER_INFO_4W
);
3855 ptr
= pPrinter
+ size
;
3857 memset(pPrinter
, 0, size
);
3862 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
3871 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3873 size
= sizeof(PRINTER_INFO_5W
);
3875 ptr
= pPrinter
+ size
;
3877 memset(pPrinter
, 0, size
);
3883 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
3892 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3894 size
= sizeof(PRINTER_INFO_6
);
3895 if (size
<= cbBuf
) {
3896 /* FIXME: We do not update the status yet */
3897 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3909 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3911 size
= sizeof(PRINTER_INFO_7W
);
3912 if (size
<= cbBuf
) {
3913 ptr
= pPrinter
+ size
;
3915 memset(pPrinter
, 0, size
);
3921 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
, unicode
);
3929 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3931 size
= sizeof(PRINTER_INFO_9W
);
3933 ptr
= pPrinter
+ size
;
3935 memset(pPrinter
, 0, size
);
3941 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
, unicode
);
3948 FIXME("Unimplemented level %d\n", Level
);
3949 SetLastError(ERROR_INVALID_LEVEL
);
3950 RegCloseKey(hkeyPrinters
);
3951 RegCloseKey(hkeyPrinter
);
3955 RegCloseKey(hkeyPrinter
);
3956 RegCloseKey(hkeyPrinters
);
3958 TRACE("returning %d needed = %d\n", ret
, needed
);
3959 if(pcbNeeded
) *pcbNeeded
= needed
;
3961 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3965 /*****************************************************************************
3966 * GetPrinterW [WINSPOOL.@]
3968 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3969 DWORD cbBuf
, LPDWORD pcbNeeded
)
3971 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3975 /*****************************************************************************
3976 * GetPrinterA [WINSPOOL.@]
3978 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3979 DWORD cbBuf
, LPDWORD pcbNeeded
)
3981 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3985 /*****************************************************************************
3986 * WINSPOOL_EnumPrinters
3988 * Implementation of EnumPrintersA|W
3990 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
3991 DWORD dwLevel
, LPBYTE lpbPrinters
,
3992 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3993 LPDWORD lpdwReturned
, BOOL unicode
)
3996 HKEY hkeyPrinters
, hkeyPrinter
;
3997 WCHAR PrinterName
[255];
3998 DWORD needed
= 0, number
= 0;
3999 DWORD used
, i
, left
;
4003 memset(lpbPrinters
, 0, cbBuf
);
4009 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4010 if(dwType
== PRINTER_ENUM_DEFAULT
)
4013 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4014 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4015 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4017 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4025 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4026 FIXME("dwType = %08x\n", dwType
);
4027 SetLastError(ERROR_INVALID_FLAGS
);
4031 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4033 ERR("Can't create Printers key\n");
4037 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4038 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4039 RegCloseKey(hkeyPrinters
);
4040 ERR("Can't query Printers key\n");
4043 TRACE("Found %d printers\n", number
);
4047 used
= number
* sizeof(PRINTER_INFO_1W
);
4050 used
= number
* sizeof(PRINTER_INFO_2W
);
4053 used
= number
* sizeof(PRINTER_INFO_4W
);
4056 used
= number
* sizeof(PRINTER_INFO_5W
);
4060 SetLastError(ERROR_INVALID_LEVEL
);
4061 RegCloseKey(hkeyPrinters
);
4064 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4066 for(i
= 0; i
< number
; i
++) {
4067 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
4069 ERR("Can't enum key number %d\n", i
);
4070 RegCloseKey(hkeyPrinters
);
4073 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4074 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4076 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4077 RegCloseKey(hkeyPrinters
);
4082 buf
= lpbPrinters
+ used
;
4083 left
= cbBuf
- used
;
4091 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4092 left
, &needed
, unicode
);
4094 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4097 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4098 left
, &needed
, unicode
);
4100 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4103 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4104 left
, &needed
, unicode
);
4106 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4109 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4110 left
, &needed
, unicode
);
4112 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4115 ERR("Shouldn't be here!\n");
4116 RegCloseKey(hkeyPrinter
);
4117 RegCloseKey(hkeyPrinters
);
4120 RegCloseKey(hkeyPrinter
);
4122 RegCloseKey(hkeyPrinters
);
4129 memset(lpbPrinters
, 0, cbBuf
);
4130 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4134 *lpdwReturned
= number
;
4135 SetLastError(ERROR_SUCCESS
);
4140 /******************************************************************
4141 * EnumPrintersW [WINSPOOL.@]
4143 * Enumerates the available printers, print servers and print
4144 * providers, depending on the specified flags, name and level.
4148 * If level is set to 1:
4149 * Returns an array of PRINTER_INFO_1 data structures in the
4150 * lpbPrinters buffer.
4152 * If level is set to 2:
4153 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4154 * Returns an array of PRINTER_INFO_2 data structures in the
4155 * lpbPrinters buffer. Note that according to MSDN also an
4156 * OpenPrinter should be performed on every remote printer.
4158 * If level is set to 4 (officially WinNT only):
4159 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4160 * Fast: Only the registry is queried to retrieve printer names,
4161 * no connection to the driver is made.
4162 * Returns an array of PRINTER_INFO_4 data structures in the
4163 * lpbPrinters buffer.
4165 * If level is set to 5 (officially WinNT4/Win9x only):
4166 * Fast: Only the registry is queried to retrieve printer names,
4167 * no connection to the driver is made.
4168 * Returns an array of PRINTER_INFO_5 data structures in the
4169 * lpbPrinters buffer.
4171 * If level set to 3 or 6+:
4172 * returns zero (failure!)
4174 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4178 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4179 * - Only levels 2, 4 and 5 are implemented at the moment.
4180 * - 16-bit printer drivers are not enumerated.
4181 * - Returned amount of bytes used/needed does not match the real Windoze
4182 * implementation (as in this implementation, all strings are part
4183 * of the buffer, whereas Win32 keeps them somewhere else)
4184 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4187 * - In a regular Wine installation, no registry settings for printers
4188 * exist, which makes this function return an empty list.
4190 BOOL WINAPI
EnumPrintersW(
4191 DWORD dwType
, /* [in] Types of print objects to enumerate */
4192 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4193 DWORD dwLevel
, /* [in] type of printer info structure */
4194 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4195 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4196 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4197 LPDWORD lpdwReturned
/* [out] number of entries returned */
4200 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4201 lpdwNeeded
, lpdwReturned
, TRUE
);
4204 /******************************************************************
4205 * EnumPrintersA [WINSPOOL.@]
4210 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4211 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4214 UNICODE_STRING pNameU
;
4218 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4219 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4221 pNameW
= asciitounicode(&pNameU
, pName
);
4223 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4224 MS Office need this */
4225 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4227 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4229 RtlFreeUnicodeString(&pNameU
);
4231 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4233 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4237 /*****************************************************************************
4238 * WINSPOOL_GetDriverInfoFromReg [internal]
4240 * Enters the information from the registry into the DRIVER_INFO struct
4243 * zero if the printer driver does not exist in the registry
4244 * (only if Level > 1) otherwise nonzero
4246 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4249 const printenv_t
* env
,
4251 LPBYTE ptr
, /* DRIVER_INFO */
4252 LPBYTE pDriverStrings
, /* strings buffer */
4253 DWORD cbBuf
, /* size of string buffer */
4254 LPDWORD pcbNeeded
, /* space needed for str. */
4255 BOOL unicode
) /* type of strings */
4259 WCHAR driverdir
[MAX_PATH
];
4261 LPBYTE strPtr
= pDriverStrings
;
4262 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4264 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4265 debugstr_w(DriverName
), env
,
4266 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4268 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4271 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4272 if (*pcbNeeded
<= cbBuf
)
4273 strcpyW((LPWSTR
)strPtr
, DriverName
);
4277 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4278 if (*pcbNeeded
<= cbBuf
)
4279 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4282 /* pName for level 1 has a different offset! */
4284 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4288 /* .cVersion and .pName for level > 1 */
4290 di
->cVersion
= env
->driverversion
;
4291 di
->pName
= (LPWSTR
) strPtr
;
4292 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4295 /* Reserve Space for the largest subdir and a Backslash*/
4296 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4297 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4298 /* Should never Fail */
4301 lstrcatW(driverdir
, env
->versionsubdir
);
4302 lstrcatW(driverdir
, backslashW
);
4304 /* dirlen must not include the terminating zero */
4305 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4306 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4308 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4309 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4310 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4316 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4318 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4321 if (*pcbNeeded
<= cbBuf
) {
4323 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4327 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4329 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4330 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4333 /* .pDriverPath is the Graphics rendering engine.
4334 The full Path is required to avoid a crash in some apps */
4335 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4337 if (*pcbNeeded
<= cbBuf
)
4338 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4340 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4341 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4344 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4345 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4347 if (*pcbNeeded
<= cbBuf
)
4348 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4350 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4351 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4354 /* .pConfigFile is the Driver user Interface */
4355 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4357 if (*pcbNeeded
<= cbBuf
)
4358 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4360 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4361 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4365 RegCloseKey(hkeyDriver
);
4366 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4371 RegCloseKey(hkeyDriver
);
4372 FIXME("level 5: incomplete\n");
4377 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4379 if (*pcbNeeded
<= cbBuf
)
4380 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4382 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4383 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4386 /* .pDependentFiles */
4387 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4389 if (*pcbNeeded
<= cbBuf
)
4390 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4392 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4393 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4395 else if (GetVersion() & 0x80000000) {
4396 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4397 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4399 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4401 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4402 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4405 /* .pMonitorName is the optional Language Monitor */
4406 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4408 if (*pcbNeeded
<= cbBuf
)
4409 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4411 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4412 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4415 /* .pDefaultDataType */
4416 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4418 if(*pcbNeeded
<= cbBuf
)
4419 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4421 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4422 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4426 RegCloseKey(hkeyDriver
);
4427 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4431 /* .pszzPreviousNames */
4432 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4434 if(*pcbNeeded
<= cbBuf
)
4435 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4437 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4438 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4442 RegCloseKey(hkeyDriver
);
4443 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4447 /* support is missing, but not important enough for a FIXME */
4448 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4451 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4453 if(*pcbNeeded
<= cbBuf
)
4454 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4456 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4457 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4461 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4463 if(*pcbNeeded
<= cbBuf
)
4464 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4466 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4467 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4470 /* .pszHardwareID */
4471 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4473 if(*pcbNeeded
<= cbBuf
)
4474 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4476 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4477 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4481 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4483 if(*pcbNeeded
<= cbBuf
)
4484 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4486 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4487 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4491 RegCloseKey(hkeyDriver
);
4495 /* support is missing, but not important enough for a FIXME */
4496 TRACE("level 8: incomplete\n");
4498 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4499 RegCloseKey(hkeyDriver
);
4503 /*****************************************************************************
4504 * WINSPOOL_GetPrinterDriver
4506 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4507 DWORD Level
, LPBYTE pDriverInfo
,
4508 DWORD cbBuf
, LPDWORD pcbNeeded
,
4512 WCHAR DriverName
[100];
4513 DWORD ret
, type
, size
, needed
= 0;
4515 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4516 const printenv_t
* env
;
4518 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4519 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4522 if (!(name
= get_opened_printer_name(hPrinter
))) {
4523 SetLastError(ERROR_INVALID_HANDLE
);
4527 if (Level
< 1 || Level
== 7 || Level
> 8) {
4528 SetLastError(ERROR_INVALID_LEVEL
);
4532 env
= validate_envW(pEnvironment
);
4533 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4535 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4537 ERR("Can't create Printers key\n");
4540 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4542 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4543 RegCloseKey(hkeyPrinters
);
4544 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4547 size
= sizeof(DriverName
);
4549 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4550 (LPBYTE
)DriverName
, &size
);
4551 RegCloseKey(hkeyPrinter
);
4552 RegCloseKey(hkeyPrinters
);
4553 if(ret
!= ERROR_SUCCESS
) {
4554 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4558 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4560 ERR("Can't create Drivers key\n");
4564 size
= di_sizeof
[Level
];
4565 if ((size
<= cbBuf
) && pDriverInfo
)
4566 ptr
= pDriverInfo
+ size
;
4568 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4569 env
, Level
, pDriverInfo
, ptr
,
4570 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4571 &needed
, unicode
)) {
4572 RegCloseKey(hkeyDrivers
);
4576 RegCloseKey(hkeyDrivers
);
4578 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4579 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4580 if(cbBuf
>= needed
) return TRUE
;
4581 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4585 /*****************************************************************************
4586 * GetPrinterDriverA [WINSPOOL.@]
4588 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4589 DWORD Level
, LPBYTE pDriverInfo
,
4590 DWORD cbBuf
, LPDWORD pcbNeeded
)
4593 UNICODE_STRING pEnvW
;
4596 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4597 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4598 cbBuf
, pcbNeeded
, FALSE
);
4599 RtlFreeUnicodeString(&pEnvW
);
4602 /*****************************************************************************
4603 * GetPrinterDriverW [WINSPOOL.@]
4605 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4606 DWORD Level
, LPBYTE pDriverInfo
,
4607 DWORD cbBuf
, LPDWORD pcbNeeded
)
4609 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4610 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4613 /*****************************************************************************
4614 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4616 * Return the PATH for the Printer-Drivers (UNICODE)
4619 * pName [I] Servername (NT only) or NULL (local Computer)
4620 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4621 * Level [I] Structure-Level (must be 1)
4622 * pDriverDirectory [O] PTR to Buffer that receives the Result
4623 * cbBuf [I] Size of Buffer at pDriverDirectory
4624 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4625 * required for pDriverDirectory
4628 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4629 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4630 * if cbBuf is too small
4632 * Native Values returned in pDriverDirectory on Success:
4633 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4634 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4635 *| win9x(Windows 4.0): "%winsysdir%"
4637 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4640 *- Only NULL or "" is supported for pName
4643 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4644 DWORD Level
, LPBYTE pDriverDirectory
,
4645 DWORD cbBuf
, LPDWORD pcbNeeded
)
4647 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4648 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4650 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4653 /* (Level != 1) is ignored in win9x */
4654 SetLastError(ERROR_INVALID_LEVEL
);
4657 if (pcbNeeded
== NULL
) {
4658 /* (pcbNeeded == NULL) is ignored in win9x */
4659 SetLastError(RPC_X_NULL_REF_POINTER
);
4663 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4664 pDriverDirectory
, cbBuf
, pcbNeeded
);
4669 /*****************************************************************************
4670 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4672 * Return the PATH for the Printer-Drivers (ANSI)
4674 * See GetPrinterDriverDirectoryW.
4677 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4680 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4681 DWORD Level
, LPBYTE pDriverDirectory
,
4682 DWORD cbBuf
, LPDWORD pcbNeeded
)
4684 UNICODE_STRING nameW
, environmentW
;
4687 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4688 WCHAR
*driverDirectoryW
= NULL
;
4690 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4691 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4693 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4695 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4696 else nameW
.Buffer
= NULL
;
4697 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4698 else environmentW
.Buffer
= NULL
;
4700 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4701 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4704 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4705 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4707 *pcbNeeded
= needed
;
4708 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4710 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4712 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4714 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4715 RtlFreeUnicodeString(&environmentW
);
4716 RtlFreeUnicodeString(&nameW
);
4721 /*****************************************************************************
4722 * AddPrinterDriverA [WINSPOOL.@]
4724 * See AddPrinterDriverW.
4727 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4729 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4730 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4733 /******************************************************************************
4734 * AddPrinterDriverW (WINSPOOL.@)
4736 * Install a Printer Driver
4739 * pName [I] Servername or NULL (local Computer)
4740 * level [I] Level for the supplied DRIVER_INFO_*W struct
4741 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4748 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4750 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4751 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4754 /*****************************************************************************
4755 * AddPrintProcessorA [WINSPOOL.@]
4757 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4758 LPSTR pPrintProcessorName
)
4760 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4761 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4765 /*****************************************************************************
4766 * AddPrintProcessorW [WINSPOOL.@]
4768 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4769 LPWSTR pPrintProcessorName
)
4771 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4772 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4776 /*****************************************************************************
4777 * AddPrintProvidorA [WINSPOOL.@]
4779 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4781 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4785 /*****************************************************************************
4786 * AddPrintProvidorW [WINSPOOL.@]
4788 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4790 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4794 /*****************************************************************************
4795 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4797 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4798 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4800 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4801 pDevModeOutput
, pDevModeInput
);
4805 /*****************************************************************************
4806 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4808 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4809 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4811 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4812 pDevModeOutput
, pDevModeInput
);
4816 /*****************************************************************************
4817 * PrinterProperties [WINSPOOL.@]
4819 * Displays a dialog to set the properties of the printer.
4822 * nonzero on success or zero on failure
4825 * implemented as stub only
4827 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4828 HANDLE hPrinter
/* [in] handle to printer object */
4830 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4831 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4835 /*****************************************************************************
4836 * EnumJobsA [WINSPOOL.@]
4839 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4840 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4843 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4844 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4846 if(pcbNeeded
) *pcbNeeded
= 0;
4847 if(pcReturned
) *pcReturned
= 0;
4852 /*****************************************************************************
4853 * EnumJobsW [WINSPOOL.@]
4856 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4857 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4860 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4861 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4863 if(pcbNeeded
) *pcbNeeded
= 0;
4864 if(pcReturned
) *pcReturned
= 0;
4868 /*****************************************************************************
4869 * WINSPOOL_EnumPrinterDrivers [internal]
4871 * Delivers information about all printer drivers installed on the
4872 * localhost or a given server
4875 * nonzero on success or zero on failure. If the buffer for the returned
4876 * information is too small the function will return an error
4879 * - only implemented for localhost, foreign hosts will return an error
4881 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4882 DWORD Level
, LPBYTE pDriverInfo
,
4883 DWORD cbBuf
, LPDWORD pcbNeeded
,
4884 LPDWORD pcReturned
, BOOL unicode
)
4887 DWORD i
, needed
, number
= 0, size
= 0;
4888 WCHAR DriverNameW
[255];
4890 const printenv_t
* env
;
4892 TRACE("%s,%s,%d,%p,%d,%d\n",
4893 debugstr_w(pName
), debugstr_w(pEnvironment
),
4894 Level
, pDriverInfo
, cbBuf
, unicode
);
4896 /* check for local drivers */
4897 if((pName
) && (pName
[0])) {
4898 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4899 SetLastError(ERROR_ACCESS_DENIED
);
4903 env
= validate_envW(pEnvironment
);
4904 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4906 /* check input parameter */
4907 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4908 SetLastError(ERROR_INVALID_LEVEL
);
4912 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
4913 SetLastError(RPC_X_NULL_REF_POINTER
);
4917 /* initialize return values */
4919 memset( pDriverInfo
, 0, cbBuf
);
4923 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
4925 ERR("Can't open Drivers key\n");
4929 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4930 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4931 RegCloseKey(hkeyDrivers
);
4932 ERR("Can't query Drivers key\n");
4935 TRACE("Found %d Drivers\n", number
);
4937 /* get size of single struct
4938 * unicode and ascii structure have the same size
4940 size
= di_sizeof
[Level
];
4942 /* calculate required buffer size */
4943 *pcbNeeded
= size
* number
;
4945 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
4947 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
4948 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4950 ERR("Can't enum key number %d\n", i
);
4951 RegCloseKey(hkeyDrivers
);
4954 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4956 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
4957 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4958 &needed
, unicode
)) {
4959 RegCloseKey(hkeyDrivers
);
4962 *pcbNeeded
+= needed
;
4965 RegCloseKey(hkeyDrivers
);
4967 if(cbBuf
< *pcbNeeded
){
4968 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4972 *pcReturned
= number
;
4976 /*****************************************************************************
4977 * EnumPrinterDriversW [WINSPOOL.@]
4979 * see function EnumPrinterDrivers for RETURNS, BUGS
4981 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4982 LPBYTE pDriverInfo
, DWORD cbBuf
,
4983 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4985 static const WCHAR allW
[] = {'a','l','l',0};
4987 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4990 DWORD i
, needed
, returned
, bufsize
= cbBuf
;
4992 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4994 needed
= returned
= 0;
4995 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4996 pDriverInfo
, bufsize
, &needed
, &returned
, TRUE
);
4997 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
5001 if (pDriverInfo
) pDriverInfo
+= needed
;
5002 if (pcReturned
) *pcReturned
+= returned
;
5004 if (pcbNeeded
) *pcbNeeded
+= needed
;
5008 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5009 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5012 /*****************************************************************************
5013 * EnumPrinterDriversA [WINSPOOL.@]
5015 * see function EnumPrinterDrivers for RETURNS, BUGS
5017 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5018 LPBYTE pDriverInfo
, DWORD cbBuf
,
5019 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5022 UNICODE_STRING pNameW
, pEnvironmentW
;
5023 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5025 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5026 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5028 if (pEnvironment
&& !strcmp(pEnvironment
, "all"))
5030 DWORD i
, needed
, returned
, bufsize
= cbBuf
;
5032 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
5034 needed
= returned
= 0;
5035 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, all_printenv
[i
]->envname
, Level
,
5036 pDriverInfo
, bufsize
, &needed
, &returned
, FALSE
);
5037 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) break;
5041 if (pDriverInfo
) pDriverInfo
+= needed
;
5042 if (pcReturned
) *pcReturned
+= returned
;
5044 if (pcbNeeded
) *pcbNeeded
+= needed
;
5047 else ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5048 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5050 RtlFreeUnicodeString(&pNameW
);
5051 RtlFreeUnicodeString(&pEnvironmentW
);
5056 /******************************************************************************
5057 * EnumPortsA (WINSPOOL.@)
5062 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5063 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5066 LPBYTE bufferW
= NULL
;
5067 LPWSTR nameW
= NULL
;
5069 DWORD numentries
= 0;
5072 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5073 cbBuf
, pcbNeeded
, pcReturned
);
5075 /* convert servername to unicode */
5077 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5078 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5079 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5081 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5082 needed
= cbBuf
* sizeof(WCHAR
);
5083 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5084 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5086 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5087 if (pcbNeeded
) needed
= *pcbNeeded
;
5088 /* HeapReAlloc return NULL, when bufferW was NULL */
5089 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5090 HeapAlloc(GetProcessHeap(), 0, needed
);
5092 /* Try again with the large Buffer */
5093 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5095 needed
= pcbNeeded
? *pcbNeeded
: 0;
5096 numentries
= pcReturned
? *pcReturned
: 0;
5099 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5100 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5103 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5104 DWORD entrysize
= 0;
5107 LPPORT_INFO_2W pi2w
;
5108 LPPORT_INFO_2A pi2a
;
5111 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5113 /* First pass: calculate the size for all Entries */
5114 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5115 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5117 while (index
< numentries
) {
5119 needed
+= entrysize
; /* PORT_INFO_?A */
5120 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5122 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5123 NULL
, 0, NULL
, NULL
);
5125 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5126 NULL
, 0, NULL
, NULL
);
5127 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5128 NULL
, 0, NULL
, NULL
);
5130 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5131 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5132 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5135 /* check for errors and quit on failure */
5136 if (cbBuf
< needed
) {
5137 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5141 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5142 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5143 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5144 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5145 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5147 /* Second Pass: Fill the User Buffer (if we have one) */
5148 while ((index
< numentries
) && pPorts
) {
5150 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5151 pi2a
->pPortName
= ptr
;
5152 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5153 ptr
, cbBuf
, NULL
, NULL
);
5157 pi2a
->pMonitorName
= ptr
;
5158 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5159 ptr
, cbBuf
, NULL
, NULL
);
5163 pi2a
->pDescription
= ptr
;
5164 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5165 ptr
, cbBuf
, NULL
, NULL
);
5169 pi2a
->fPortType
= pi2w
->fPortType
;
5170 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5173 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5174 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5175 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5180 if (pcbNeeded
) *pcbNeeded
= needed
;
5181 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5183 HeapFree(GetProcessHeap(), 0, nameW
);
5184 HeapFree(GetProcessHeap(), 0, bufferW
);
5186 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5187 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5193 /******************************************************************************
5194 * EnumPortsW (WINSPOOL.@)
5196 * Enumerate available Ports
5199 * pName [I] Servername or NULL (local Computer)
5200 * Level [I] Structure-Level (1 or 2)
5201 * pPorts [O] PTR to Buffer that receives the Result
5202 * cbBuf [I] Size of Buffer at pPorts
5203 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5204 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5208 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5211 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5214 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5215 cbBuf
, pcbNeeded
, pcReturned
);
5217 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5219 /* Level is not checked in win9x */
5220 if (!Level
|| (Level
> 2)) {
5221 WARN("level (%d) is ignored in win9x\n", Level
);
5222 SetLastError(ERROR_INVALID_LEVEL
);
5225 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5226 SetLastError(RPC_X_NULL_REF_POINTER
);
5230 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5233 /******************************************************************************
5234 * GetDefaultPrinterW (WINSPOOL.@)
5237 * This function must read the value from data 'device' of key
5238 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5240 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5244 WCHAR
*buffer
, *ptr
;
5248 SetLastError(ERROR_INVALID_PARAMETER
);
5252 /* make the buffer big enough for the stuff from the profile/registry,
5253 * the content must fit into the local buffer to compute the correct
5254 * size even if the extern buffer is too small or not given.
5255 * (20 for ,driver,port) */
5257 len
= max(100, (insize
+ 20));
5258 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5260 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5262 SetLastError (ERROR_FILE_NOT_FOUND
);
5266 TRACE("%s\n", debugstr_w(buffer
));
5268 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5270 SetLastError(ERROR_INVALID_NAME
);
5276 *namesize
= strlenW(buffer
) + 1;
5277 if(!name
|| (*namesize
> insize
))
5279 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5283 strcpyW(name
, buffer
);
5286 HeapFree( GetProcessHeap(), 0, buffer
);
5291 /******************************************************************************
5292 * GetDefaultPrinterA (WINSPOOL.@)
5294 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5298 WCHAR
*bufferW
= NULL
;
5302 SetLastError(ERROR_INVALID_PARAMETER
);
5306 if(name
&& *namesize
) {
5308 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5311 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5316 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5320 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5323 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5326 HeapFree( GetProcessHeap(), 0, bufferW
);
5331 /******************************************************************************
5332 * SetDefaultPrinterW (WINSPOOL.204)
5334 * Set the Name of the Default Printer
5337 * pszPrinter [I] Name of the Printer or NULL
5344 * When the Parameter is NULL or points to an Empty String and
5345 * a Default Printer was already present, then this Function changes nothing.
5346 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5347 * the First enumerated local Printer is used.
5350 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5353 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5355 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5359 /******************************************************************************
5360 * SetDefaultPrinterA (WINSPOOL.202)
5362 * See SetDefaultPrinterW.
5365 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5368 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5370 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5375 /******************************************************************************
5376 * SetPrinterDataExA (WINSPOOL.@)
5378 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5379 LPCSTR pValueName
, DWORD Type
,
5380 LPBYTE pData
, DWORD cbData
)
5382 HKEY hkeyPrinter
, hkeySubkey
;
5385 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5386 debugstr_a(pValueName
), Type
, pData
, cbData
);
5388 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5392 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5394 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5395 RegCloseKey(hkeyPrinter
);
5398 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5399 RegCloseKey(hkeySubkey
);
5400 RegCloseKey(hkeyPrinter
);
5404 /******************************************************************************
5405 * SetPrinterDataExW (WINSPOOL.@)
5407 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5408 LPCWSTR pValueName
, DWORD Type
,
5409 LPBYTE pData
, DWORD cbData
)
5411 HKEY hkeyPrinter
, hkeySubkey
;
5414 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5415 debugstr_w(pValueName
), Type
, pData
, cbData
);
5417 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5421 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5423 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5424 RegCloseKey(hkeyPrinter
);
5427 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5428 RegCloseKey(hkeySubkey
);
5429 RegCloseKey(hkeyPrinter
);
5433 /******************************************************************************
5434 * SetPrinterDataA (WINSPOOL.@)
5436 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5437 LPBYTE pData
, DWORD cbData
)
5439 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5443 /******************************************************************************
5444 * SetPrinterDataW (WINSPOOL.@)
5446 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5447 LPBYTE pData
, DWORD cbData
)
5449 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5453 /******************************************************************************
5454 * GetPrinterDataExA (WINSPOOL.@)
5456 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5457 LPCSTR pValueName
, LPDWORD pType
,
5458 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5460 HKEY hkeyPrinter
, hkeySubkey
;
5463 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5464 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5467 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5471 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5473 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5474 RegCloseKey(hkeyPrinter
);
5478 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5479 RegCloseKey(hkeySubkey
);
5480 RegCloseKey(hkeyPrinter
);
5484 /******************************************************************************
5485 * GetPrinterDataExW (WINSPOOL.@)
5487 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5488 LPCWSTR pValueName
, LPDWORD pType
,
5489 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5491 HKEY hkeyPrinter
, hkeySubkey
;
5494 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5495 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5498 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5502 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5504 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5505 RegCloseKey(hkeyPrinter
);
5509 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5510 RegCloseKey(hkeySubkey
);
5511 RegCloseKey(hkeyPrinter
);
5515 /******************************************************************************
5516 * GetPrinterDataA (WINSPOOL.@)
5518 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5519 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5521 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5522 pData
, nSize
, pcbNeeded
);
5525 /******************************************************************************
5526 * GetPrinterDataW (WINSPOOL.@)
5528 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5529 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5531 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5532 pData
, nSize
, pcbNeeded
);
5535 /*******************************************************************************
5536 * EnumPrinterDataExW [WINSPOOL.@]
5538 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5539 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5540 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5542 HKEY hkPrinter
, hkSubKey
;
5543 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5544 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5549 PPRINTER_ENUM_VALUESW ppev
;
5551 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5553 if (pKeyName
== NULL
|| *pKeyName
== 0)
5554 return ERROR_INVALID_PARAMETER
;
5556 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5557 if (ret
!= ERROR_SUCCESS
)
5559 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5564 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5565 if (ret
!= ERROR_SUCCESS
)
5567 r
= RegCloseKey (hkPrinter
);
5568 if (r
!= ERROR_SUCCESS
)
5569 WARN ("RegCloseKey returned %i\n", r
);
5570 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5571 debugstr_w (pKeyName
), ret
);
5575 ret
= RegCloseKey (hkPrinter
);
5576 if (ret
!= ERROR_SUCCESS
)
5578 ERR ("RegCloseKey returned %i\n", ret
);
5579 r
= RegCloseKey (hkSubKey
);
5580 if (r
!= ERROR_SUCCESS
)
5581 WARN ("RegCloseKey returned %i\n", r
);
5585 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5586 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5587 if (ret
!= ERROR_SUCCESS
)
5589 r
= RegCloseKey (hkSubKey
);
5590 if (r
!= ERROR_SUCCESS
)
5591 WARN ("RegCloseKey returned %i\n", r
);
5592 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5596 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5597 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5599 if (cValues
== 0) /* empty key */
5601 r
= RegCloseKey (hkSubKey
);
5602 if (r
!= ERROR_SUCCESS
)
5603 WARN ("RegCloseKey returned %i\n", r
);
5604 *pcbEnumValues
= *pnEnumValues
= 0;
5605 return ERROR_SUCCESS
;
5608 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5610 hHeap
= GetProcessHeap ();
5613 ERR ("GetProcessHeap failed\n");
5614 r
= RegCloseKey (hkSubKey
);
5615 if (r
!= ERROR_SUCCESS
)
5616 WARN ("RegCloseKey returned %i\n", r
);
5617 return ERROR_OUTOFMEMORY
;
5620 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5621 if (lpValueName
== NULL
)
5623 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5624 r
= RegCloseKey (hkSubKey
);
5625 if (r
!= ERROR_SUCCESS
)
5626 WARN ("RegCloseKey returned %i\n", r
);
5627 return ERROR_OUTOFMEMORY
;
5630 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5631 if (lpValue
== NULL
)
5633 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5634 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5635 WARN ("HeapFree failed with code %i\n", GetLastError ());
5636 r
= RegCloseKey (hkSubKey
);
5637 if (r
!= ERROR_SUCCESS
)
5638 WARN ("RegCloseKey returned %i\n", r
);
5639 return ERROR_OUTOFMEMORY
;
5642 TRACE ("pass 1: calculating buffer required for all names and values\n");
5644 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5646 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5648 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5650 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5651 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5652 NULL
, NULL
, lpValue
, &cbValueLen
);
5653 if (ret
!= ERROR_SUCCESS
)
5655 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5656 WARN ("HeapFree failed with code %i\n", GetLastError ());
5657 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5658 WARN ("HeapFree failed with code %i\n", GetLastError ());
5659 r
= RegCloseKey (hkSubKey
);
5660 if (r
!= ERROR_SUCCESS
)
5661 WARN ("RegCloseKey returned %i\n", r
);
5662 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5666 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5667 debugstr_w (lpValueName
), dwIndex
,
5668 cbValueNameLen
+ 1, cbValueLen
);
5670 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5671 cbBufSize
+= cbValueLen
;
5674 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5676 *pcbEnumValues
= cbBufSize
;
5677 *pnEnumValues
= cValues
;
5679 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5681 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5682 WARN ("HeapFree failed with code %i\n", GetLastError ());
5683 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5684 WARN ("HeapFree failed with code %i\n", GetLastError ());
5685 r
= RegCloseKey (hkSubKey
);
5686 if (r
!= ERROR_SUCCESS
)
5687 WARN ("RegCloseKey returned %i\n", r
);
5688 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5689 return ERROR_MORE_DATA
;
5692 TRACE ("pass 2: copying all names and values to buffer\n");
5694 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5695 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5697 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5699 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5700 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5701 NULL
, &dwType
, lpValue
, &cbValueLen
);
5702 if (ret
!= ERROR_SUCCESS
)
5704 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5705 WARN ("HeapFree failed with code %i\n", GetLastError ());
5706 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5707 WARN ("HeapFree failed with code %i\n", GetLastError ());
5708 r
= RegCloseKey (hkSubKey
);
5709 if (r
!= ERROR_SUCCESS
)
5710 WARN ("RegCloseKey returned %i\n", r
);
5711 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5715 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5716 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5717 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5718 pEnumValues
+= cbValueNameLen
;
5720 /* return # of *bytes* (including trailing \0), not # of chars */
5721 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5723 ppev
[dwIndex
].dwType
= dwType
;
5725 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5726 ppev
[dwIndex
].pData
= pEnumValues
;
5727 pEnumValues
+= cbValueLen
;
5729 ppev
[dwIndex
].cbData
= cbValueLen
;
5731 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5732 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5735 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5737 ret
= GetLastError ();
5738 ERR ("HeapFree failed with code %i\n", ret
);
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
);
5747 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5749 ret
= GetLastError ();
5750 ERR ("HeapFree failed with code %i\n", ret
);
5751 r
= RegCloseKey (hkSubKey
);
5752 if (r
!= ERROR_SUCCESS
)
5753 WARN ("RegCloseKey returned %i\n", r
);
5757 ret
= RegCloseKey (hkSubKey
);
5758 if (ret
!= ERROR_SUCCESS
)
5760 ERR ("RegCloseKey returned %i\n", ret
);
5764 return ERROR_SUCCESS
;
5767 /*******************************************************************************
5768 * EnumPrinterDataExA [WINSPOOL.@]
5770 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5771 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5772 * what Windows 2000 SP1 does.
5775 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5776 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5777 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5781 DWORD ret
, dwIndex
, dwBufSize
;
5785 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5787 if (pKeyName
== NULL
|| *pKeyName
== 0)
5788 return ERROR_INVALID_PARAMETER
;
5790 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5793 ret
= GetLastError ();
5794 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5798 hHeap
= GetProcessHeap ();
5801 ERR ("GetProcessHeap failed\n");
5802 return ERROR_OUTOFMEMORY
;
5805 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5806 if (pKeyNameW
== NULL
)
5808 ERR ("Failed to allocate %i bytes from process heap\n",
5809 (LONG
)(len
* sizeof (WCHAR
)));
5810 return ERROR_OUTOFMEMORY
;
5813 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5815 ret
= GetLastError ();
5816 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5817 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5818 WARN ("HeapFree failed with code %i\n", GetLastError ());
5822 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5823 pcbEnumValues
, pnEnumValues
);
5824 if (ret
!= ERROR_SUCCESS
)
5826 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5827 WARN ("HeapFree failed with code %i\n", GetLastError ());
5828 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5832 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5834 ret
= GetLastError ();
5835 ERR ("HeapFree failed with code %i\n", ret
);
5839 if (*pnEnumValues
== 0) /* empty key */
5840 return ERROR_SUCCESS
;
5843 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5845 PPRINTER_ENUM_VALUESW ppev
=
5846 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5848 if (dwBufSize
< ppev
->cbValueName
)
5849 dwBufSize
= ppev
->cbValueName
;
5851 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5852 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5853 dwBufSize
= ppev
->cbData
;
5856 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5858 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5859 if (pBuffer
== NULL
)
5861 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5862 return ERROR_OUTOFMEMORY
;
5865 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5867 PPRINTER_ENUM_VALUESW ppev
=
5868 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5870 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5871 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5875 ret
= GetLastError ();
5876 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5877 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5878 WARN ("HeapFree failed with code %i\n", GetLastError ());
5882 memcpy (ppev
->pValueName
, pBuffer
, len
);
5884 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5886 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5887 ppev
->dwType
!= REG_MULTI_SZ
)
5890 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5891 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5894 ret
= GetLastError ();
5895 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5896 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5897 WARN ("HeapFree failed with code %i\n", GetLastError ());
5901 memcpy (ppev
->pData
, pBuffer
, len
);
5903 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5904 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5907 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5909 ret
= GetLastError ();
5910 ERR ("HeapFree failed with code %i\n", ret
);
5914 return ERROR_SUCCESS
;
5917 /******************************************************************************
5918 * AbortPrinter (WINSPOOL.@)
5920 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5922 FIXME("(%p), stub!\n", hPrinter
);
5926 /******************************************************************************
5927 * AddPortA (WINSPOOL.@)
5932 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5934 LPWSTR nameW
= NULL
;
5935 LPWSTR monitorW
= NULL
;
5939 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
5942 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5943 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5944 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5948 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5949 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5950 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5952 res
= AddPortW(nameW
, hWnd
, monitorW
);
5953 HeapFree(GetProcessHeap(), 0, nameW
);
5954 HeapFree(GetProcessHeap(), 0, monitorW
);
5958 /******************************************************************************
5959 * AddPortW (WINSPOOL.@)
5961 * Add a Port for a specific Monitor
5964 * pName [I] Servername or NULL (local Computer)
5965 * hWnd [I] Handle to parent Window for the Dialog-Box
5966 * pMonitorName [I] Name of the Monitor that manage the Port
5973 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
5975 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
5977 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5979 if (!pMonitorName
) {
5980 SetLastError(RPC_X_NULL_REF_POINTER
);
5984 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
5987 /******************************************************************************
5988 * AddPortExA (WINSPOOL.@)
5993 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
5996 PORT_INFO_2A
* pi2A
;
5997 LPWSTR nameW
= NULL
;
5998 LPWSTR monitorW
= NULL
;
6002 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6004 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6005 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6007 if ((level
< 1) || (level
> 2)) {
6008 SetLastError(ERROR_INVALID_LEVEL
);
6013 SetLastError(ERROR_INVALID_PARAMETER
);
6018 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6019 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6020 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6024 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6025 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6026 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6029 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6031 if (pi2A
->pPortName
) {
6032 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6033 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6034 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6038 if (pi2A
->pMonitorName
) {
6039 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6040 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6041 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6044 if (pi2A
->pDescription
) {
6045 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6046 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6047 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6049 pi2W
.fPortType
= pi2A
->fPortType
;
6050 pi2W
.Reserved
= pi2A
->Reserved
;
6053 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6055 HeapFree(GetProcessHeap(), 0, nameW
);
6056 HeapFree(GetProcessHeap(), 0, monitorW
);
6057 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6058 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6059 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6064 /******************************************************************************
6065 * AddPortExW (WINSPOOL.@)
6067 * Add a Port for a specific Monitor, without presenting a user interface
6070 * pName [I] Servername or NULL (local Computer)
6071 * level [I] Structure-Level (1 or 2) for pBuffer
6072 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6073 * pMonitorName [I] Name of the Monitor that manage the Port
6080 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6086 pi2
= (PORT_INFO_2W
*) pBuffer
;
6088 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6089 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6090 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6091 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6094 if ((level
< 1) || (level
> 2)) {
6095 SetLastError(ERROR_INVALID_LEVEL
);
6099 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6100 SetLastError(ERROR_INVALID_PARAMETER
);
6104 /* load the Monitor */
6105 pm
= monitor_load(pMonitorName
, NULL
);
6107 SetLastError(ERROR_INVALID_PARAMETER
);
6111 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6112 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6113 TRACE("got %u with %u\n", res
, GetLastError());
6117 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6123 /******************************************************************************
6124 * AddPrinterConnectionA (WINSPOOL.@)
6126 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6128 FIXME("%s\n", debugstr_a(pName
));
6132 /******************************************************************************
6133 * AddPrinterConnectionW (WINSPOOL.@)
6135 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6137 FIXME("%s\n", debugstr_w(pName
));
6141 /******************************************************************************
6142 * AddPrinterDriverExW (WINSPOOL.@)
6144 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6147 * pName [I] Servername or NULL (local Computer)
6148 * level [I] Level for the supplied DRIVER_INFO_*W struct
6149 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6150 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6157 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6159 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6161 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6163 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6164 SetLastError(ERROR_INVALID_LEVEL
);
6169 SetLastError(ERROR_INVALID_PARAMETER
);
6173 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6176 /******************************************************************************
6177 * AddPrinterDriverExA (WINSPOOL.@)
6179 * See AddPrinterDriverExW.
6182 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6184 DRIVER_INFO_8A
*diA
;
6186 LPWSTR nameW
= NULL
;
6191 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6193 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6194 ZeroMemory(&diW
, sizeof(diW
));
6196 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6197 SetLastError(ERROR_INVALID_LEVEL
);
6202 SetLastError(ERROR_INVALID_PARAMETER
);
6206 /* convert servername to unicode */
6208 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6209 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6210 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6214 diW
.cVersion
= diA
->cVersion
;
6217 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6218 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6219 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6222 if (diA
->pEnvironment
) {
6223 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6224 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6225 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6228 if (diA
->pDriverPath
) {
6229 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6230 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6231 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6234 if (diA
->pDataFile
) {
6235 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6236 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6237 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6240 if (diA
->pConfigFile
) {
6241 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6242 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6243 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6246 if ((Level
> 2) && diA
->pDependentFiles
) {
6247 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6248 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6249 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6250 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6253 if ((Level
> 2) && diA
->pMonitorName
) {
6254 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6255 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6256 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6259 if ((Level
> 3) && diA
->pDefaultDataType
) {
6260 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6261 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6262 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6265 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6266 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6267 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6268 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6269 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6272 if ((Level
> 5) && diA
->pszMfgName
) {
6273 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6274 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6275 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6278 if ((Level
> 5) && diA
->pszOEMUrl
) {
6279 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6280 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6281 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6284 if ((Level
> 5) && diA
->pszHardwareID
) {
6285 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6286 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6287 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6290 if ((Level
> 5) && diA
->pszProvider
) {
6291 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6292 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6293 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6297 FIXME("level %u is incomplete\n", Level
);
6300 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6301 TRACE("got %u with %u\n", res
, GetLastError());
6302 HeapFree(GetProcessHeap(), 0, nameW
);
6303 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6304 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6305 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6306 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6307 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6308 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6309 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6310 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6311 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6312 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6313 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6314 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6315 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6317 TRACE("=> %u with %u\n", res
, GetLastError());
6321 /******************************************************************************
6322 * ConfigurePortA (WINSPOOL.@)
6324 * See ConfigurePortW.
6327 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6329 LPWSTR nameW
= NULL
;
6330 LPWSTR portW
= NULL
;
6334 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6336 /* convert servername to unicode */
6338 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6339 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6340 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6343 /* convert portname to unicode */
6345 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6346 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6347 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6350 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6351 HeapFree(GetProcessHeap(), 0, nameW
);
6352 HeapFree(GetProcessHeap(), 0, portW
);
6356 /******************************************************************************
6357 * ConfigurePortW (WINSPOOL.@)
6359 * Display the Configuration-Dialog for a specific Port
6362 * pName [I] Servername or NULL (local Computer)
6363 * hWnd [I] Handle to parent Window for the Dialog-Box
6364 * pPortName [I] Name of the Port, that should be configured
6371 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6374 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6376 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6379 SetLastError(RPC_X_NULL_REF_POINTER
);
6383 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6386 /******************************************************************************
6387 * ConnectToPrinterDlg (WINSPOOL.@)
6389 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6391 FIXME("%p %x\n", hWnd
, Flags
);
6395 /******************************************************************************
6396 * DeletePrinterConnectionA (WINSPOOL.@)
6398 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6400 FIXME("%s\n", debugstr_a(pName
));
6404 /******************************************************************************
6405 * DeletePrinterConnectionW (WINSPOOL.@)
6407 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6409 FIXME("%s\n", debugstr_w(pName
));
6413 /******************************************************************************
6414 * DeletePrinterDriverExW (WINSPOOL.@)
6416 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6417 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6422 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6423 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6425 if(pName
&& pName
[0])
6427 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6428 SetLastError(ERROR_INVALID_PARAMETER
);
6434 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6435 SetLastError(ERROR_INVALID_PARAMETER
);
6439 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6443 ERR("Can't open drivers key\n");
6447 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6450 RegCloseKey(hkey_drivers
);
6455 /******************************************************************************
6456 * DeletePrinterDriverExA (WINSPOOL.@)
6458 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6459 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6461 UNICODE_STRING NameW
, EnvW
, DriverW
;
6464 asciitounicode(&NameW
, pName
);
6465 asciitounicode(&EnvW
, pEnvironment
);
6466 asciitounicode(&DriverW
, pDriverName
);
6468 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6470 RtlFreeUnicodeString(&DriverW
);
6471 RtlFreeUnicodeString(&EnvW
);
6472 RtlFreeUnicodeString(&NameW
);
6477 /******************************************************************************
6478 * DeletePrinterDataExW (WINSPOOL.@)
6480 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6483 FIXME("%p %s %s\n", hPrinter
,
6484 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6485 return ERROR_INVALID_PARAMETER
;
6488 /******************************************************************************
6489 * DeletePrinterDataExA (WINSPOOL.@)
6491 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6494 FIXME("%p %s %s\n", hPrinter
,
6495 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6496 return ERROR_INVALID_PARAMETER
;
6499 /******************************************************************************
6500 * DeletePrintProcessorA (WINSPOOL.@)
6502 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6504 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6505 debugstr_a(pPrintProcessorName
));
6509 /******************************************************************************
6510 * DeletePrintProcessorW (WINSPOOL.@)
6512 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6514 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6515 debugstr_w(pPrintProcessorName
));
6519 /******************************************************************************
6520 * DeletePrintProvidorA (WINSPOOL.@)
6522 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6524 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6525 debugstr_a(pPrintProviderName
));
6529 /******************************************************************************
6530 * DeletePrintProvidorW (WINSPOOL.@)
6532 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6534 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6535 debugstr_w(pPrintProviderName
));
6539 /******************************************************************************
6540 * EnumFormsA (WINSPOOL.@)
6542 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6543 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6545 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6546 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6550 /******************************************************************************
6551 * EnumFormsW (WINSPOOL.@)
6553 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6554 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6556 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6557 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6561 /*****************************************************************************
6562 * EnumMonitorsA [WINSPOOL.@]
6564 * See EnumMonitorsW.
6567 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6568 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6571 LPBYTE bufferW
= NULL
;
6572 LPWSTR nameW
= NULL
;
6574 DWORD numentries
= 0;
6577 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6578 cbBuf
, pcbNeeded
, pcReturned
);
6580 /* convert servername to unicode */
6582 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6583 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6584 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6586 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6587 needed
= cbBuf
* sizeof(WCHAR
);
6588 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6589 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6591 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6592 if (pcbNeeded
) needed
= *pcbNeeded
;
6593 /* HeapReAlloc return NULL, when bufferW was NULL */
6594 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6595 HeapAlloc(GetProcessHeap(), 0, needed
);
6597 /* Try again with the large Buffer */
6598 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6600 numentries
= pcReturned
? *pcReturned
: 0;
6603 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6604 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6607 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6608 DWORD entrysize
= 0;
6611 LPMONITOR_INFO_2W mi2w
;
6612 LPMONITOR_INFO_2A mi2a
;
6614 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6615 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6617 /* First pass: calculate the size for all Entries */
6618 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6619 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6621 while (index
< numentries
) {
6623 needed
+= entrysize
; /* MONITOR_INFO_?A */
6624 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6626 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6627 NULL
, 0, NULL
, NULL
);
6629 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6630 NULL
, 0, NULL
, NULL
);
6631 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6632 NULL
, 0, NULL
, NULL
);
6634 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6635 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6636 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6639 /* check for errors and quit on failure */
6640 if (cbBuf
< needed
) {
6641 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6645 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6646 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6647 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6648 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6649 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6651 /* Second Pass: Fill the User Buffer (if we have one) */
6652 while ((index
< numentries
) && pMonitors
) {
6654 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6656 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6657 ptr
, cbBuf
, NULL
, NULL
);
6661 mi2a
->pEnvironment
= ptr
;
6662 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6663 ptr
, cbBuf
, NULL
, NULL
);
6667 mi2a
->pDLLName
= ptr
;
6668 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6669 ptr
, cbBuf
, NULL
, NULL
);
6673 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6674 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6675 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6679 if (pcbNeeded
) *pcbNeeded
= needed
;
6680 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6682 HeapFree(GetProcessHeap(), 0, nameW
);
6683 HeapFree(GetProcessHeap(), 0, bufferW
);
6685 TRACE("returning %d with %d (%d byte for %d entries)\n",
6686 (res
), GetLastError(), needed
, numentries
);
6692 /*****************************************************************************
6693 * EnumMonitorsW [WINSPOOL.@]
6695 * Enumerate available Port-Monitors
6698 * pName [I] Servername or NULL (local Computer)
6699 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6700 * pMonitors [O] PTR to Buffer that receives the Result
6701 * cbBuf [I] Size of Buffer at pMonitors
6702 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6703 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6707 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6710 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6711 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6714 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6715 cbBuf
, pcbNeeded
, pcReturned
);
6717 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6719 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6720 SetLastError(RPC_X_NULL_REF_POINTER
);
6724 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6727 /******************************************************************************
6728 * SpoolerInit (WINSPOOL.@)
6730 * Initialize the Spooler
6737 * The function fails on windows, when the spooler service is not running
6740 BOOL WINAPI
SpoolerInit(void)
6743 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6747 /******************************************************************************
6748 * XcvDataW (WINSPOOL.@)
6750 * Execute commands in the Printmonitor DLL
6753 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6754 * pszDataName [i] Name of the command to execute
6755 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6756 * cbInputData [i] Size in Bytes of Buffer at pInputData
6757 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6758 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6759 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6760 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6767 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6768 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6770 * Minimal List of commands, that a Printmonitor DLL should support:
6772 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6773 *| "AddPort" : Add a Port
6774 *| "DeletePort": Delete a Port
6776 * Many Printmonitors support additional commands. Examples for localspl.dll:
6777 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6778 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6781 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6782 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6783 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6785 opened_printer_t
*printer
;
6787 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6788 pInputData
, cbInputData
, pOutputData
,
6789 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6791 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6793 printer
= get_opened_printer(hXcv
);
6794 if (!printer
|| (!printer
->backend_printer
)) {
6795 SetLastError(ERROR_INVALID_HANDLE
);
6799 if (!pcbOutputNeeded
) {
6800 SetLastError(ERROR_INVALID_PARAMETER
);
6804 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6805 SetLastError(RPC_X_NULL_REF_POINTER
);
6809 *pcbOutputNeeded
= 0;
6811 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6812 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6816 /*****************************************************************************
6817 * EnumPrinterDataA [WINSPOOL.@]
6820 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6821 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6822 DWORD cbData
, LPDWORD pcbData
)
6824 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6825 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6826 return ERROR_NO_MORE_ITEMS
;
6829 /*****************************************************************************
6830 * EnumPrinterDataW [WINSPOOL.@]
6833 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6834 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6835 DWORD cbData
, LPDWORD pcbData
)
6837 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6838 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6839 return ERROR_NO_MORE_ITEMS
;
6842 /*****************************************************************************
6843 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6846 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6847 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6848 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6850 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6851 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6852 pcbNeeded
, pcReturned
);
6856 /*****************************************************************************
6857 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6860 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6861 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6862 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6864 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6865 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6866 pcbNeeded
, pcReturned
);
6870 /*****************************************************************************
6871 * EnumPrintProcessorsA [WINSPOOL.@]
6874 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6875 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6877 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
6878 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
6882 /*****************************************************************************
6883 * EnumPrintProcessorsW [WINSPOOL.@]
6886 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6887 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6889 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6890 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
6891 cbBuf
, pcbNeeded
, pcbReturned
);
6895 /*****************************************************************************
6896 * ExtDeviceMode [WINSPOOL.@]
6899 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6900 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6903 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6904 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6905 debugstr_a(pProfile
), fMode
);
6909 /*****************************************************************************
6910 * FindClosePrinterChangeNotification [WINSPOOL.@]
6913 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6915 FIXME("Stub: %p\n", hChange
);
6919 /*****************************************************************************
6920 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6923 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6924 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6926 FIXME("Stub: %p %x %x %p\n",
6927 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6928 return INVALID_HANDLE_VALUE
;
6931 /*****************************************************************************
6932 * FindNextPrinterChangeNotification [WINSPOOL.@]
6935 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6936 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6938 FIXME("Stub: %p %p %p %p\n",
6939 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
6943 /*****************************************************************************
6944 * FreePrinterNotifyInfo [WINSPOOL.@]
6947 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
6949 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
6953 /*****************************************************************************
6956 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6957 * ansi depending on the unicode parameter.
6959 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
6969 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
6972 memcpy(ptr
, str
, *size
);
6979 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
6982 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
6989 /*****************************************************************************
6992 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
6993 LPDWORD pcbNeeded
, BOOL unicode
)
6995 DWORD size
, left
= cbBuf
;
6996 BOOL space
= (cbBuf
> 0);
7003 ji1
->JobId
= job
->job_id
;
7006 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7007 if(space
&& size
<= left
)
7009 ji1
->pDocument
= (LPWSTR
)ptr
;
7020 /*****************************************************************************
7023 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7024 LPDWORD pcbNeeded
, BOOL unicode
)
7026 DWORD size
, left
= cbBuf
;
7027 BOOL space
= (cbBuf
> 0);
7034 ji2
->JobId
= job
->job_id
;
7037 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7038 if(space
&& size
<= left
)
7040 ji2
->pDocument
= (LPWSTR
)ptr
;
7051 /*****************************************************************************
7054 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7055 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7058 DWORD needed
= 0, size
;
7062 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7064 EnterCriticalSection(&printer_handles_cs
);
7065 job
= get_job(hPrinter
, JobId
);
7072 size
= sizeof(JOB_INFO_1W
);
7077 memset(pJob
, 0, size
);
7081 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7086 size
= sizeof(JOB_INFO_2W
);
7091 memset(pJob
, 0, size
);
7095 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7100 size
= sizeof(JOB_INFO_3
);
7104 memset(pJob
, 0, size
);
7113 SetLastError(ERROR_INVALID_LEVEL
);
7117 *pcbNeeded
= needed
;
7119 LeaveCriticalSection(&printer_handles_cs
);
7123 /*****************************************************************************
7124 * GetJobA [WINSPOOL.@]
7127 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7128 DWORD cbBuf
, LPDWORD pcbNeeded
)
7130 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7133 /*****************************************************************************
7134 * GetJobW [WINSPOOL.@]
7137 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7138 DWORD cbBuf
, LPDWORD pcbNeeded
)
7140 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7143 /*****************************************************************************
7146 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7148 char *unixname
, *queue
, *cmd
;
7149 char fmt
[] = "lpr -P%s %s";
7153 if(!(unixname
= wine_get_unix_file_name(filename
)))
7156 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7157 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7158 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7160 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7161 sprintf(cmd
, fmt
, queue
, unixname
);
7163 TRACE("printing with: %s\n", cmd
);
7166 HeapFree(GetProcessHeap(), 0, cmd
);
7167 HeapFree(GetProcessHeap(), 0, queue
);
7168 HeapFree(GetProcessHeap(), 0, unixname
);
7172 /*****************************************************************************
7175 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7177 #ifdef SONAME_LIBCUPS
7180 char *unixname
, *queue
, *unix_doc_title
;
7184 if(!(unixname
= wine_get_unix_file_name(filename
)))
7187 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7188 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7189 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7191 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7192 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7193 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7195 TRACE("printing via cups\n");
7196 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7197 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7198 HeapFree(GetProcessHeap(), 0, queue
);
7199 HeapFree(GetProcessHeap(), 0, unixname
);
7205 return schedule_lpr(printer_name
, filename
);
7209 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7216 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7220 if(HIWORD(wparam
) == BN_CLICKED
)
7222 if(LOWORD(wparam
) == IDOK
)
7225 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7228 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7229 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7231 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7233 WCHAR caption
[200], message
[200];
7236 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7237 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7238 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7239 if(mb_ret
== IDCANCEL
)
7241 HeapFree(GetProcessHeap(), 0, filename
);
7245 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7246 if(hf
== INVALID_HANDLE_VALUE
)
7248 WCHAR caption
[200], message
[200];
7250 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7251 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7252 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7253 HeapFree(GetProcessHeap(), 0, filename
);
7257 DeleteFileW(filename
);
7258 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7260 EndDialog(hwnd
, IDOK
);
7263 if(LOWORD(wparam
) == IDCANCEL
)
7265 EndDialog(hwnd
, IDCANCEL
);
7274 /*****************************************************************************
7277 static BOOL
get_filename(LPWSTR
*filename
)
7279 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7280 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7283 /*****************************************************************************
7286 static BOOL
schedule_file(LPCWSTR filename
)
7288 LPWSTR output
= NULL
;
7290 if(get_filename(&output
))
7293 TRACE("copy to %s\n", debugstr_w(output
));
7294 r
= CopyFileW(filename
, output
, FALSE
);
7295 HeapFree(GetProcessHeap(), 0, output
);
7301 /*****************************************************************************
7304 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7307 char *unixname
, *cmdA
;
7309 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7313 if(!(unixname
= wine_get_unix_file_name(filename
)))
7316 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7317 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7318 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7320 TRACE("printing with: %s\n", cmdA
);
7322 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7327 ERR("pipe() failed!\n");
7337 /* reset signals that we previously set to SIG_IGN */
7338 signal(SIGPIPE
, SIG_DFL
);
7339 signal(SIGCHLD
, SIG_DFL
);
7341 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7345 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7346 write(fds
[1], buf
, no_read
);
7351 if(file_fd
!= -1) close(file_fd
);
7352 if(fds
[0] != -1) close(fds
[0]);
7353 if(fds
[1] != -1) close(fds
[1]);
7355 HeapFree(GetProcessHeap(), 0, cmdA
);
7356 HeapFree(GetProcessHeap(), 0, unixname
);
7363 /*****************************************************************************
7366 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7368 int in_fd
, out_fd
, no_read
;
7371 char *unixname
, *outputA
;
7374 if(!(unixname
= wine_get_unix_file_name(filename
)))
7377 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7378 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7379 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7381 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7382 in_fd
= open(unixname
, O_RDONLY
);
7383 if(out_fd
== -1 || in_fd
== -1)
7386 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7387 write(out_fd
, buf
, no_read
);
7391 if(in_fd
!= -1) close(in_fd
);
7392 if(out_fd
!= -1) close(out_fd
);
7393 HeapFree(GetProcessHeap(), 0, outputA
);
7394 HeapFree(GetProcessHeap(), 0, unixname
);
7398 /*****************************************************************************
7399 * ScheduleJob [WINSPOOL.@]
7402 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7404 opened_printer_t
*printer
;
7406 struct list
*cursor
, *cursor2
;
7408 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7409 EnterCriticalSection(&printer_handles_cs
);
7410 printer
= get_opened_printer(hPrinter
);
7414 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7416 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7419 if(job
->job_id
!= dwJobID
) continue;
7421 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7422 if(hf
!= INVALID_HANDLE_VALUE
)
7424 PRINTER_INFO_5W
*pi5
;
7428 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7429 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7431 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7432 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7433 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7434 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7435 debugstr_w(pi5
->pPortName
));
7439 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7440 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7442 DWORD type
, count
= sizeof(output
);
7443 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7446 if(output
[0] == '|')
7448 ret
= schedule_pipe(output
+ 1, job
->filename
);
7452 ret
= schedule_unixfile(output
, job
->filename
);
7454 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7456 ret
= schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7458 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7460 ret
= schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7462 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7464 ret
= schedule_file(job
->filename
);
7468 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7470 HeapFree(GetProcessHeap(), 0, pi5
);
7472 DeleteFileW(job
->filename
);
7474 list_remove(cursor
);
7475 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7476 HeapFree(GetProcessHeap(), 0, job
->filename
);
7477 HeapFree(GetProcessHeap(), 0, job
);
7481 LeaveCriticalSection(&printer_handles_cs
);
7485 /*****************************************************************************
7486 * StartDocDlgA [WINSPOOL.@]
7488 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7490 UNICODE_STRING usBuffer
;
7493 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7496 docW
.cbSize
= sizeof(docW
);
7497 if (doc
->lpszDocName
)
7499 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7500 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7502 if (doc
->lpszOutput
)
7504 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7505 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7507 if (doc
->lpszDatatype
)
7509 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7510 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7512 docW
.fwType
= doc
->fwType
;
7514 retW
= StartDocDlgW(hPrinter
, &docW
);
7518 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7519 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7520 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7521 HeapFree(GetProcessHeap(), 0, retW
);
7524 HeapFree(GetProcessHeap(), 0, datatypeW
);
7525 HeapFree(GetProcessHeap(), 0, outputW
);
7526 HeapFree(GetProcessHeap(), 0, docnameW
);
7531 /*****************************************************************************
7532 * StartDocDlgW [WINSPOOL.@]
7534 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7535 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7536 * port is "FILE:". Also returns the full path if passed a relative path.
7538 * The caller should free the returned string from the process heap.
7540 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7545 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7547 PRINTER_INFO_5W
*pi5
;
7548 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7549 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7551 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7552 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7553 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7555 HeapFree(GetProcessHeap(), 0, pi5
);
7558 HeapFree(GetProcessHeap(), 0, pi5
);
7561 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7565 if (get_filename(&name
))
7567 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7569 HeapFree(GetProcessHeap(), 0, name
);
7572 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7573 GetFullPathNameW(name
, len
, ret
, NULL
);
7574 HeapFree(GetProcessHeap(), 0, name
);
7579 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7582 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7583 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7585 attr
= GetFileAttributesW(ret
);
7586 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7588 HeapFree(GetProcessHeap(), 0, ret
);