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 printer_handles_cs
;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
70 0, 0, &printer_handles_cs
,
71 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
72 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
76 /* ############################### */
91 HANDLE backend_printer
;
100 WCHAR
*document_title
;
108 LPCWSTR versionregpath
;
109 LPCWSTR versionsubdir
;
112 /* ############################### */
114 static opened_printer_t
**printer_handles
;
115 static UINT nb_printer_handles
;
116 static LONG next_job_id
= 1;
118 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
119 WORD fwCapability
, LPSTR lpszOutput
,
121 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
122 LPSTR lpszDevice
, LPSTR lpszPort
,
123 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
126 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
127 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
128 'c','o','n','t','r','o','l','\\',
129 'P','r','i','n','t','\\',
130 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
131 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
133 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
134 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
135 'C','o','n','t','r','o','l','\\',
136 'P','r','i','n','t','\\',
137 'P','r','i','n','t','e','r','s',0};
139 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
141 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
142 'M','i','c','r','o','s','o','f','t','\\',
143 'W','i','n','d','o','w','s',' ','N','T','\\',
144 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
145 'W','i','n','d','o','w','s',0};
147 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
148 'M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s',' ','N','T','\\',
150 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
151 'D','e','v','i','c','e','s',0};
153 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
154 'M','i','c','r','o','s','o','f','t','\\',
155 'W','i','n','d','o','w','s',' ','N','T','\\',
156 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
157 'P','o','r','t','s',0};
159 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
160 'M','i','c','r','o','s','o','f','t','\\',
161 'W','i','n','d','o','w','s',' ','N','T','\\',
162 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
163 'P','r','i','n','t','e','r','P','o','r','t','s',0};
165 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
166 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
167 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
168 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
169 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
170 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
171 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
172 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
173 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
174 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
175 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
177 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
178 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
180 static const WCHAR backslashW
[] = {'\\',0};
181 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
182 'i','o','n',' ','F','i','l','e',0};
183 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
184 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
185 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
186 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
187 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
188 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
189 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
190 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
191 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
192 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
193 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
194 static const WCHAR NameW
[] = {'N','a','m','e',0};
195 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
196 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
197 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
198 static const WCHAR PortW
[] = {'P','o','r','t',0};
199 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
200 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
201 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
202 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
203 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
204 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
205 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
206 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
207 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
208 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
209 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
210 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
211 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
212 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
213 static const WCHAR emptyStringW
[] = {0};
215 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
217 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
218 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
219 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
221 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
222 'D','o','c','u','m','e','n','t',0};
224 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
225 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
226 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
227 0, sizeof(DRIVER_INFO_8W
)};
230 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
231 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
232 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
233 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
234 sizeof(PRINTER_INFO_9W
)};
236 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
237 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
238 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
240 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
242 /******************************************************************
243 * validate the user-supplied printing-environment [internal]
246 * env [I] PTR to Environment-String or NULL
250 * Success: PTR to printenv_t
253 * An empty string is handled the same way as NULL.
254 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
258 static const printenv_t
* validate_envW(LPCWSTR env
)
260 const printenv_t
*result
= NULL
;
263 TRACE("testing %s\n", debugstr_w(env
));
266 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
268 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
270 result
= all_printenv
[i
];
275 if (result
== NULL
) {
276 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
277 SetLastError(ERROR_INVALID_ENVIRONMENT
);
279 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
283 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
285 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
291 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
292 if passed a NULL string. This returns NULLs to the result.
294 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
298 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
299 return usBufferPtr
->Buffer
;
301 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
305 static LPWSTR
strdupW(LPCWSTR p
)
311 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
312 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
317 static LPSTR
strdupWtoA( LPCWSTR str
)
322 if (!str
) return NULL
;
323 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
324 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
325 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
329 /******************************************************************
330 * Return the number of bytes for an multi_sz string.
331 * The result includes all \0s
332 * (specifically the extra \0, that is needed as multi_sz terminator).
335 static int multi_sz_lenW(const WCHAR
*str
)
337 const WCHAR
*ptr
= str
;
341 ptr
+= lstrlenW(ptr
) + 1;
344 return (ptr
- str
+ 1) * sizeof(WCHAR
);
347 /* ################################ */
349 static int multi_sz_lenA(const char *str
)
351 const char *ptr
= str
;
355 ptr
+= lstrlenA(ptr
) + 1;
358 return ptr
- str
+ 1;
362 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
365 /* If forcing, or no profile string entry for device yet, set the entry
367 * The always change entry if not WINEPS yet is discussable.
370 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
372 !strstr(qbuf
,"WINEPS.DRV")
374 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
377 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
378 WriteProfileStringA("windows","device",buf
);
379 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
380 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
383 HeapFree(GetProcessHeap(),0,buf
);
387 static BOOL
add_printer_driver(const char *name
)
391 static char driver_9x
[] = "wineps16.drv",
392 driver_nt
[] = "wineps.drv",
393 env_9x
[] = "Windows 4.0",
394 env_nt
[] = "Windows NT x86",
395 data_file
[] = "generic.ppd",
396 default_data_type
[] = "RAW";
398 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
400 di3a
.pName
= (char *)name
;
401 di3a
.pEnvironment
= env_nt
;
402 di3a
.pDriverPath
= driver_nt
;
403 di3a
.pDataFile
= data_file
;
404 di3a
.pConfigFile
= driver_nt
;
405 di3a
.pDefaultDataType
= default_data_type
;
407 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
408 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
411 di3a
.pEnvironment
= env_9x
;
412 di3a
.pDriverPath
= driver_9x
;
413 di3a
.pConfigFile
= driver_9x
;
414 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
415 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
420 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
421 debugstr_a(di3a
.pEnvironment
), GetLastError());
425 #ifdef SONAME_LIBCUPS
426 static typeof(cupsFreeDests
) *pcupsFreeDests
;
427 static typeof(cupsGetDests
) *pcupsGetDests
;
428 static typeof(cupsGetPPD
) *pcupsGetPPD
;
429 static typeof(cupsPrintFile
) *pcupsPrintFile
;
430 static void *cupshandle
;
432 static BOOL
CUPS_LoadPrinters(void)
435 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
437 PRINTER_INFO_2A pinfo2a
;
439 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
442 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
444 TRACE("%s\n", loaderror
);
447 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
450 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
451 if (!p##x) return FALSE;
453 DYNCUPS(cupsFreeDests
);
455 DYNCUPS(cupsGetDests
);
456 DYNCUPS(cupsPrintFile
);
459 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
461 ERR("Can't create Printers key\n");
465 nrofdests
= pcupsGetDests(&dests
);
466 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
467 for (i
=0;i
<nrofdests
;i
++) {
468 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
469 port
= HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests
[i
].name
)+1);
470 sprintf(port
,"LPR:%s", dests
[i
].name
);
471 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
472 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
473 sprintf(devline
, "WINEPS.DRV,%s", port
);
474 WriteProfileStringA("devices", dests
[i
].name
, devline
);
475 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
476 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
480 lstrcatA(devline
, ",15,45");
481 WriteProfileStringA("PrinterPorts", dests
[i
].name
, devline
);
482 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
483 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
487 HeapFree(GetProcessHeap(), 0, devline
);
489 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
490 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
491 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
493 TRACE("Printer already exists\n");
494 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
495 RegCloseKey(hkeyPrinter
);
497 static CHAR data_type
[] = "RAW",
498 print_proc
[] = "WinPrint",
499 comment
[] = "WINEPS Printer using CUPS",
500 location
[] = "<physical location of printer>",
501 params
[] = "<parameters?>",
502 share_name
[] = "<share name?>",
503 sep_file
[] = "<sep file?>";
505 add_printer_driver(dests
[i
].name
);
507 memset(&pinfo2a
,0,sizeof(pinfo2a
));
508 pinfo2a
.pPrinterName
= dests
[i
].name
;
509 pinfo2a
.pDatatype
= data_type
;
510 pinfo2a
.pPrintProcessor
= print_proc
;
511 pinfo2a
.pDriverName
= dests
[i
].name
;
512 pinfo2a
.pComment
= comment
;
513 pinfo2a
.pLocation
= location
;
514 pinfo2a
.pPortName
= port
;
515 pinfo2a
.pParameters
= params
;
516 pinfo2a
.pShareName
= share_name
;
517 pinfo2a
.pSepFile
= sep_file
;
519 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
520 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
521 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
524 HeapFree(GetProcessHeap(),0,port
);
527 if (dests
[i
].is_default
) {
528 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
532 if (hadprinter
& !haddefault
)
533 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
534 pcupsFreeDests(nrofdests
, dests
);
535 RegCloseKey(hkeyPrinters
);
541 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
542 PRINTER_INFO_2A pinfo2a
;
543 char *e
,*s
,*name
,*prettyname
,*devname
;
544 BOOL ret
= FALSE
, set_default
= FALSE
;
545 char *port
= NULL
, *devline
,*env_default
;
546 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
548 while (isspace(*pent
)) pent
++;
549 s
= strchr(pent
,':');
551 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
559 TRACE("name=%s entry=%s\n",name
, pent
);
561 if(ispunct(*name
)) { /* a tc entry, not a real printer */
562 TRACE("skipping tc entry\n");
566 if(strstr(pent
,":server")) { /* server only version so skip */
567 TRACE("skipping server entry\n");
571 /* Determine whether this is a postscript printer. */
574 env_default
= getenv("PRINTER");
576 /* Get longest name, usually the one at the right for later display. */
577 while((s
=strchr(prettyname
,'|'))) {
580 while(isspace(*--e
)) *e
= '\0';
581 TRACE("\t%s\n", debugstr_a(prettyname
));
582 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
583 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
586 e
= prettyname
+ strlen(prettyname
);
587 while(isspace(*--e
)) *e
= '\0';
588 TRACE("\t%s\n", debugstr_a(prettyname
));
589 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
591 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
592 * if it is too long, we use it as comment below. */
593 devname
= prettyname
;
594 if (strlen(devname
)>=CCHDEVICENAME
-1)
596 if (strlen(devname
)>=CCHDEVICENAME
-1) {
601 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
602 sprintf(port
,"LPR:%s",name
);
604 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
605 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
606 sprintf(devline
, "WINEPS.DRV,%s", port
);
607 WriteProfileStringA("devices", devname
, devline
);
608 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
609 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
613 lstrcatA(devline
, ",15,45");
614 WriteProfileStringA("PrinterPorts", devname
, devline
);
615 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
616 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
620 HeapFree(GetProcessHeap(),0,devline
);
622 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
624 ERR("Can't create Printers key\n");
628 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
629 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
631 TRACE("Printer already exists\n");
632 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
633 RegCloseKey(hkeyPrinter
);
635 static CHAR data_type
[] = "RAW",
636 print_proc
[] = "WinPrint",
637 comment
[] = "WINEPS Printer using LPR",
638 params
[] = "<parameters?>",
639 share_name
[] = "<share name?>",
640 sep_file
[] = "<sep file?>";
642 add_printer_driver(devname
);
644 memset(&pinfo2a
,0,sizeof(pinfo2a
));
645 pinfo2a
.pPrinterName
= devname
;
646 pinfo2a
.pDatatype
= data_type
;
647 pinfo2a
.pPrintProcessor
= print_proc
;
648 pinfo2a
.pDriverName
= devname
;
649 pinfo2a
.pComment
= comment
;
650 pinfo2a
.pLocation
= prettyname
;
651 pinfo2a
.pPortName
= port
;
652 pinfo2a
.pParameters
= params
;
653 pinfo2a
.pShareName
= share_name
;
654 pinfo2a
.pSepFile
= sep_file
;
656 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
657 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
658 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
661 RegCloseKey(hkeyPrinters
);
663 if (isfirst
|| set_default
)
664 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
667 HeapFree(GetProcessHeap(), 0, port
);
668 HeapFree(GetProcessHeap(), 0, name
);
673 PRINTCAP_LoadPrinters(void) {
674 BOOL hadprinter
= FALSE
;
678 BOOL had_bash
= FALSE
;
680 f
= fopen("/etc/printcap","r");
684 while(fgets(buf
,sizeof(buf
),f
)) {
687 end
=strchr(buf
,'\n');
691 while(isspace(*start
)) start
++;
692 if(*start
== '#' || *start
== '\0')
695 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
696 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
697 HeapFree(GetProcessHeap(),0,pent
);
701 if (end
&& *--end
== '\\') {
708 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
711 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
717 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
718 HeapFree(GetProcessHeap(),0,pent
);
724 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
727 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
728 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
730 return ERROR_FILE_NOT_FOUND
;
733 /******************************************************************
734 * get_servername_from_name (internal)
736 * for an external server, a copy of the serverpart from the full name is returned
739 static LPWSTR
get_servername_from_name(LPCWSTR name
)
743 WCHAR buffer
[MAX_PATH
];
746 if (name
== NULL
) return NULL
;
747 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
749 server
= strdupW(&name
[2]); /* skip over both backslash */
750 if (server
== NULL
) return NULL
;
752 /* strip '\' and the printername */
753 ptr
= strchrW(server
, '\\');
754 if (ptr
) ptr
[0] = '\0';
756 TRACE("found %s\n", debugstr_w(server
));
758 len
= sizeof(buffer
)/sizeof(buffer
[0]);
759 if (GetComputerNameW(buffer
, &len
)) {
760 if (lstrcmpW(buffer
, server
) == 0) {
761 /* The requested Servername is our computername */
762 HeapFree(GetProcessHeap(), 0, server
);
769 /******************************************************************
770 * get_basename_from_name (internal)
772 * skip over the serverpart from the full name
775 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
777 if (name
== NULL
) return NULL
;
778 if ((name
[0] == '\\') && (name
[1] == '\\')) {
779 /* skip over the servername and search for the following '\' */
780 name
= strchrW(&name
[2], '\\');
781 if ((name
) && (name
[1])) {
782 /* found a separator ('\') followed by a name:
783 skip over the separator and return the rest */
788 /* no basename present (we found only a servername) */
795 /******************************************************************
796 * get_opened_printer_entry
797 * Get the first place empty in the opened printer table
800 * - pDefault is ignored
802 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
804 UINT_PTR handle
= nb_printer_handles
, i
;
805 jobqueue_t
*queue
= NULL
;
806 opened_printer_t
*printer
= NULL
;
810 if ((backend
== NULL
) && !load_backend()) return NULL
;
812 servername
= get_servername_from_name(name
);
814 FIXME("server %s not supported\n", debugstr_w(servername
));
815 HeapFree(GetProcessHeap(), 0, servername
);
816 SetLastError(ERROR_INVALID_PRINTER_NAME
);
820 printername
= get_basename_from_name(name
);
821 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
823 /* an empty printername is invalid */
824 if (printername
&& (!printername
[0])) {
825 SetLastError(ERROR_INVALID_PARAMETER
);
829 EnterCriticalSection(&printer_handles_cs
);
831 for (i
= 0; i
< nb_printer_handles
; i
++)
833 if (!printer_handles
[i
])
835 if(handle
== nb_printer_handles
)
840 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
841 queue
= printer_handles
[i
]->queue
;
845 if (handle
>= nb_printer_handles
)
847 opened_printer_t
**new_array
;
849 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
850 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
852 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
853 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
860 printer_handles
= new_array
;
861 nb_printer_handles
+= 16;
864 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
870 /* get a printer handle from the backend */
871 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
876 /* clone the base name. This is NULL for the printserver */
877 printer
->printername
= strdupW(printername
);
879 /* clone the full name */
880 printer
->name
= strdupW(name
);
881 if (name
&& (!printer
->name
)) {
887 printer
->queue
= queue
;
890 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
891 if (!printer
->queue
) {
895 list_init(&printer
->queue
->jobs
);
896 printer
->queue
->ref
= 0;
898 InterlockedIncrement(&printer
->queue
->ref
);
900 printer_handles
[handle
] = printer
;
903 LeaveCriticalSection(&printer_handles_cs
);
904 if (!handle
&& printer
) {
905 /* Something failed: Free all resources */
906 HeapFree(GetProcessHeap(), 0, printer
->printername
);
907 HeapFree(GetProcessHeap(), 0, printer
->name
);
908 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
909 HeapFree(GetProcessHeap(), 0, printer
);
912 return (HANDLE
)handle
;
915 /******************************************************************
917 * Get the pointer to the opened printer referred by the handle
919 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
921 UINT_PTR idx
= (UINT_PTR
)hprn
;
922 opened_printer_t
*ret
= NULL
;
924 EnterCriticalSection(&printer_handles_cs
);
926 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
927 ret
= printer_handles
[idx
- 1];
929 LeaveCriticalSection(&printer_handles_cs
);
933 /******************************************************************
934 * get_opened_printer_name
935 * Get the pointer to the opened printer name referred by the handle
937 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
939 opened_printer_t
*printer
= get_opened_printer(hprn
);
940 if(!printer
) return NULL
;
941 return printer
->name
;
944 /******************************************************************
945 * WINSPOOL_GetOpenedPrinterRegKey
948 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
950 LPCWSTR name
= get_opened_printer_name(hPrinter
);
954 if(!name
) return ERROR_INVALID_HANDLE
;
956 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
960 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
962 ERR("Can't find opened printer %s in registry\n",
964 RegCloseKey(hkeyPrinters
);
965 return ERROR_INVALID_PRINTER_NAME
; /* ? */
967 RegCloseKey(hkeyPrinters
);
968 return ERROR_SUCCESS
;
971 void WINSPOOL_LoadSystemPrinters(void)
973 HKEY hkey
, hkeyPrinters
;
975 DWORD needed
, num
, i
;
976 WCHAR PrinterName
[256];
979 /* This ensures that all printer entries have a valid Name value. If causes
980 problems later if they don't. If one is found to be missed we create one
981 and set it equal to the name of the key */
982 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
983 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
984 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
985 for(i
= 0; i
< num
; i
++) {
986 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
987 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
988 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
989 set_reg_szW(hkey
, NameW
, PrinterName
);
996 RegCloseKey(hkeyPrinters
);
999 /* We want to avoid calling AddPrinter on printers as much as
1000 possible, because on cups printers this will (eventually) lead
1001 to a call to cupsGetPPD which takes forever, even with non-cups
1002 printers AddPrinter takes a while. So we'll tag all printers that
1003 were automatically added last time around, if they still exist
1004 we'll leave them be otherwise we'll delete them. */
1005 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1007 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1008 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1009 for(i
= 0; i
< num
; i
++) {
1010 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1011 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1012 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1014 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1022 HeapFree(GetProcessHeap(), 0, pi
);
1026 #ifdef SONAME_LIBCUPS
1027 done
= CUPS_LoadPrinters();
1030 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1031 PRINTCAP_LoadPrinters();
1033 /* Now enumerate the list again and delete any printers that are still tagged */
1034 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1036 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1037 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1038 for(i
= 0; i
< num
; i
++) {
1039 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1040 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1041 BOOL delete_driver
= FALSE
;
1042 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1043 DWORD dw
, type
, size
= sizeof(dw
);
1044 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1045 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1046 DeletePrinter(hprn
);
1047 delete_driver
= TRUE
;
1053 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1058 HeapFree(GetProcessHeap(), 0, pi
);
1065 /******************************************************************
1068 * Get the pointer to the specified job.
1069 * Should hold the printer_handles_cs before calling.
1071 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1073 opened_printer_t
*printer
= get_opened_printer(hprn
);
1076 if(!printer
) return NULL
;
1077 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1079 if(job
->job_id
== JobId
)
1085 /***********************************************************
1088 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1091 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1094 Formname
= (dmA
->dmSize
> off_formname
);
1095 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1096 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1097 dmW
->dmDeviceName
, CCHDEVICENAME
);
1099 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1100 dmA
->dmSize
- CCHDEVICENAME
);
1102 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1103 off_formname
- CCHDEVICENAME
);
1104 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1105 dmW
->dmFormName
, CCHFORMNAME
);
1106 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1107 (off_formname
+ CCHFORMNAME
));
1110 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1111 dmA
->dmDriverExtra
);
1115 /***********************************************************
1117 * Creates an ansi copy of supplied devmode
1119 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1124 if (!dmW
) return NULL
;
1125 size
= dmW
->dmSize
- CCHDEVICENAME
-
1126 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1128 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1129 if (!dmA
) return NULL
;
1131 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1132 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1134 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1135 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1136 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1140 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1141 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1142 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1143 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1145 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1149 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1153 /******************************************************************
1154 * convert_printerinfo_W_to_A [internal]
1157 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1158 DWORD level
, DWORD outlen
, DWORD numentries
)
1164 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1166 len
= pi_sizeof
[level
] * numentries
;
1167 ptr
= (LPSTR
) out
+ len
;
1170 /* copy the numbers of all PRINTER_INFO_* first */
1171 memcpy(out
, pPrintersW
, len
);
1173 while (id
< numentries
) {
1177 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1178 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1180 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1181 if (piW
->pDescription
) {
1182 piA
->pDescription
= ptr
;
1183 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1184 ptr
, outlen
, NULL
, NULL
);
1190 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1191 ptr
, outlen
, NULL
, NULL
);
1195 if (piW
->pComment
) {
1196 piA
->pComment
= ptr
;
1197 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1198 ptr
, outlen
, NULL
, NULL
);
1207 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1208 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1211 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1212 if (piW
->pServerName
) {
1213 piA
->pServerName
= ptr
;
1214 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1215 ptr
, outlen
, NULL
, NULL
);
1219 if (piW
->pPrinterName
) {
1220 piA
->pPrinterName
= ptr
;
1221 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1222 ptr
, outlen
, NULL
, NULL
);
1226 if (piW
->pShareName
) {
1227 piA
->pShareName
= ptr
;
1228 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1229 ptr
, outlen
, NULL
, NULL
);
1233 if (piW
->pPortName
) {
1234 piA
->pPortName
= ptr
;
1235 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1236 ptr
, outlen
, NULL
, NULL
);
1240 if (piW
->pDriverName
) {
1241 piA
->pDriverName
= ptr
;
1242 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1243 ptr
, outlen
, NULL
, NULL
);
1247 if (piW
->pComment
) {
1248 piA
->pComment
= ptr
;
1249 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1250 ptr
, outlen
, NULL
, NULL
);
1254 if (piW
->pLocation
) {
1255 piA
->pLocation
= ptr
;
1256 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1257 ptr
, outlen
, NULL
, NULL
);
1262 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1264 /* align DEVMODEA to a DWORD boundary */
1265 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1269 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1270 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1271 memcpy(ptr
, dmA
, len
);
1272 HeapFree(GetProcessHeap(), 0, dmA
);
1278 if (piW
->pSepFile
) {
1279 piA
->pSepFile
= ptr
;
1280 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1281 ptr
, outlen
, NULL
, NULL
);
1285 if (piW
->pPrintProcessor
) {
1286 piA
->pPrintProcessor
= ptr
;
1287 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1288 ptr
, outlen
, NULL
, NULL
);
1292 if (piW
->pDatatype
) {
1293 piA
->pDatatype
= ptr
;
1294 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1295 ptr
, outlen
, NULL
, NULL
);
1299 if (piW
->pParameters
) {
1300 piA
->pParameters
= ptr
;
1301 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1302 ptr
, outlen
, NULL
, NULL
);
1306 if (piW
->pSecurityDescriptor
) {
1307 piA
->pSecurityDescriptor
= NULL
;
1308 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1315 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1316 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1318 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1320 if (piW
->pPrinterName
) {
1321 piA
->pPrinterName
= ptr
;
1322 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1323 ptr
, outlen
, NULL
, NULL
);
1327 if (piW
->pServerName
) {
1328 piA
->pServerName
= ptr
;
1329 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1330 ptr
, outlen
, NULL
, NULL
);
1339 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1340 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1342 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1344 if (piW
->pPrinterName
) {
1345 piA
->pPrinterName
= ptr
;
1346 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1347 ptr
, outlen
, NULL
, NULL
);
1351 if (piW
->pPortName
) {
1352 piA
->pPortName
= ptr
;
1353 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1354 ptr
, outlen
, NULL
, NULL
);
1362 FIXME("for level %u\n", level
);
1364 pPrintersW
+= pi_sizeof
[level
];
1365 out
+= pi_sizeof
[level
];
1370 /***********************************************************
1371 * PRINTER_INFO_2AtoW
1372 * Creates a unicode copy of PRINTER_INFO_2A on heap
1374 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1376 LPPRINTER_INFO_2W piW
;
1377 UNICODE_STRING usBuffer
;
1379 if(!piA
) return NULL
;
1380 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1381 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1383 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1384 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1385 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1386 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1387 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1388 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1389 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1390 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1391 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1392 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1393 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1394 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1398 /***********************************************************
1399 * FREE_PRINTER_INFO_2W
1400 * Free PRINTER_INFO_2W and all strings
1402 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1406 HeapFree(heap
,0,piW
->pServerName
);
1407 HeapFree(heap
,0,piW
->pPrinterName
);
1408 HeapFree(heap
,0,piW
->pShareName
);
1409 HeapFree(heap
,0,piW
->pPortName
);
1410 HeapFree(heap
,0,piW
->pDriverName
);
1411 HeapFree(heap
,0,piW
->pComment
);
1412 HeapFree(heap
,0,piW
->pLocation
);
1413 HeapFree(heap
,0,piW
->pDevMode
);
1414 HeapFree(heap
,0,piW
->pSepFile
);
1415 HeapFree(heap
,0,piW
->pPrintProcessor
);
1416 HeapFree(heap
,0,piW
->pDatatype
);
1417 HeapFree(heap
,0,piW
->pParameters
);
1418 HeapFree(heap
,0,piW
);
1422 /******************************************************************
1423 * DeviceCapabilities [WINSPOOL.@]
1424 * DeviceCapabilitiesA [WINSPOOL.@]
1427 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1428 LPSTR pOutput
, LPDEVMODEA lpdm
)
1432 if (!GDI_CallDeviceCapabilities16
)
1434 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1436 if (!GDI_CallDeviceCapabilities16
) return -1;
1438 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1440 /* If DC_PAPERSIZE map POINT16s to POINTs */
1441 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1442 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1443 POINT
*pt
= (POINT
*)pOutput
;
1445 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1446 for(i
= 0; i
< ret
; i
++, pt
++)
1451 HeapFree( GetProcessHeap(), 0, tmp
);
1457 /*****************************************************************************
1458 * DeviceCapabilitiesW [WINSPOOL.@]
1460 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1463 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1464 WORD fwCapability
, LPWSTR pOutput
,
1465 const DEVMODEW
*pDevMode
)
1467 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1468 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1469 LPSTR pPortA
= strdupWtoA(pPort
);
1472 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1473 fwCapability
== DC_FILEDEPENDENCIES
||
1474 fwCapability
== DC_PAPERNAMES
)) {
1475 /* These need A -> W translation */
1478 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1482 switch(fwCapability
) {
1487 case DC_FILEDEPENDENCIES
:
1491 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1492 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1494 for(i
= 0; i
< ret
; i
++)
1495 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1496 pOutput
+ (i
* size
), size
);
1497 HeapFree(GetProcessHeap(), 0, pOutputA
);
1499 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1500 (LPSTR
)pOutput
, dmA
);
1502 HeapFree(GetProcessHeap(),0,pPortA
);
1503 HeapFree(GetProcessHeap(),0,pDeviceA
);
1504 HeapFree(GetProcessHeap(),0,dmA
);
1508 /******************************************************************
1509 * DocumentPropertiesA [WINSPOOL.@]
1511 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1513 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1514 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1515 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1517 LPSTR lpName
= pDeviceName
;
1518 static CHAR port
[] = "LPT1:";
1521 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1522 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1526 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1528 ERR("no name from hPrinter?\n");
1529 SetLastError(ERROR_INVALID_HANDLE
);
1532 lpName
= strdupWtoA(lpNameW
);
1535 if (!GDI_CallExtDeviceMode16
)
1537 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1539 if (!GDI_CallExtDeviceMode16
) {
1540 ERR("No CallExtDeviceMode16?\n");
1544 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1545 pDevModeInput
, NULL
, fMode
);
1548 HeapFree(GetProcessHeap(),0,lpName
);
1553 /*****************************************************************************
1554 * DocumentPropertiesW (WINSPOOL.@)
1556 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1558 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1560 LPDEVMODEW pDevModeOutput
,
1561 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1564 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1565 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1566 LPDEVMODEA pDevModeOutputA
= NULL
;
1569 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1570 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1572 if(pDevModeOutput
) {
1573 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1574 if(ret
< 0) return ret
;
1575 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1577 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1578 pDevModeInputA
, fMode
);
1579 if(pDevModeOutput
) {
1580 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1581 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1583 if(fMode
== 0 && ret
> 0)
1584 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1585 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1586 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1590 /******************************************************************
1591 * OpenPrinterA [WINSPOOL.@]
1596 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1597 LPPRINTER_DEFAULTSA pDefault
)
1599 UNICODE_STRING lpPrinterNameW
;
1600 UNICODE_STRING usBuffer
;
1601 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1602 PWSTR pwstrPrinterNameW
;
1605 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1608 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1609 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1610 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1611 pDefaultW
= &DefaultW
;
1613 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1615 RtlFreeUnicodeString(&usBuffer
);
1616 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1618 RtlFreeUnicodeString(&lpPrinterNameW
);
1622 /******************************************************************
1623 * OpenPrinterW [WINSPOOL.@]
1625 * Open a Printer / Printserver or a Printer-Object
1628 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1629 * phPrinter [O] The resulting Handle is stored here
1630 * pDefault [I] PTR to Default Printer Settings or NULL
1637 * lpPrinterName is one of:
1638 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1639 *| Printer: "PrinterName"
1640 *| Printer-Object: "PrinterName,Job xxx"
1641 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1642 *| XcvPort: "Servername,XcvPort PortName"
1645 *| Printer-Object not supported
1646 *| pDefaults is ignored
1649 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1652 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1654 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1655 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1659 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1660 SetLastError(ERROR_INVALID_PARAMETER
);
1664 /* Get the unique handle of the printer or Printserver */
1665 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1666 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1667 return (*phPrinter
!= 0);
1670 /******************************************************************
1671 * AddMonitorA [WINSPOOL.@]
1676 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1678 LPWSTR nameW
= NULL
;
1681 LPMONITOR_INFO_2A mi2a
;
1682 MONITOR_INFO_2W mi2w
;
1684 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1685 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1686 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1687 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1688 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1691 SetLastError(ERROR_INVALID_LEVEL
);
1695 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1701 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1702 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1703 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1706 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1708 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1709 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1710 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1712 if (mi2a
->pEnvironment
) {
1713 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1714 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1715 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1717 if (mi2a
->pDLLName
) {
1718 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1719 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1720 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1723 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1725 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1726 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1727 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1729 HeapFree(GetProcessHeap(), 0, nameW
);
1733 /******************************************************************************
1734 * AddMonitorW [WINSPOOL.@]
1736 * Install a Printmonitor
1739 * pName [I] Servername or NULL (local Computer)
1740 * Level [I] Structure-Level (Must be 2)
1741 * pMonitors [I] PTR to MONITOR_INFO_2
1748 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1751 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1753 LPMONITOR_INFO_2W mi2w
;
1755 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1756 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1757 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1758 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1759 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1761 if ((backend
== NULL
) && !load_backend()) return FALSE
;
1764 SetLastError(ERROR_INVALID_LEVEL
);
1768 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1773 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
1776 /******************************************************************
1777 * DeletePrinterDriverA [WINSPOOL.@]
1780 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
1782 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
1785 /******************************************************************
1786 * DeletePrinterDriverW [WINSPOOL.@]
1789 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
1791 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
1794 /******************************************************************
1795 * DeleteMonitorA [WINSPOOL.@]
1797 * See DeleteMonitorW.
1800 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
1802 LPWSTR nameW
= NULL
;
1803 LPWSTR EnvironmentW
= NULL
;
1804 LPWSTR MonitorNameW
= NULL
;
1809 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1810 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1811 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1815 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
1816 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1817 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
1820 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
1821 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1822 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
1825 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
1827 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
1828 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
1829 HeapFree(GetProcessHeap(), 0, nameW
);
1833 /******************************************************************
1834 * DeleteMonitorW [WINSPOOL.@]
1836 * Delete a specific Printmonitor from a Printing-Environment
1839 * pName [I] Servername or NULL (local Computer)
1840 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1841 * pMonitorName [I] Name of the Monitor, that should be deleted
1848 * pEnvironment is ignored in Windows for the local Computer.
1851 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1854 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1855 debugstr_w(pMonitorName
));
1857 if ((backend
== NULL
) && !load_backend()) return FALSE
;
1859 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
1863 /******************************************************************
1864 * DeletePortA [WINSPOOL.@]
1869 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
1871 LPWSTR nameW
= NULL
;
1872 LPWSTR portW
= NULL
;
1876 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
1878 /* convert servername to unicode */
1880 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1881 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1882 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1885 /* convert portname to unicode */
1887 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
1888 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1889 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
1892 res
= DeletePortW(nameW
, hWnd
, portW
);
1893 HeapFree(GetProcessHeap(), 0, nameW
);
1894 HeapFree(GetProcessHeap(), 0, portW
);
1898 /******************************************************************
1899 * DeletePortW [WINSPOOL.@]
1901 * Delete a specific Port
1904 * pName [I] Servername or NULL (local Computer)
1905 * hWnd [I] Handle to parent Window for the Dialog-Box
1906 * pPortName [I] Name of the Port, that should be deleted
1913 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1915 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1917 if ((backend
== NULL
) && !load_backend()) return FALSE
;
1920 SetLastError(RPC_X_NULL_REF_POINTER
);
1924 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
1927 /******************************************************************************
1928 * SetPrinterW [WINSPOOL.@]
1930 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
1932 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
1933 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1937 /******************************************************************************
1938 * WritePrinter [WINSPOOL.@]
1940 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
1942 opened_printer_t
*printer
;
1945 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
1947 EnterCriticalSection(&printer_handles_cs
);
1948 printer
= get_opened_printer(hPrinter
);
1951 SetLastError(ERROR_INVALID_HANDLE
);
1957 SetLastError(ERROR_SPL_NO_STARTDOC
);
1961 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
1963 LeaveCriticalSection(&printer_handles_cs
);
1967 /*****************************************************************************
1968 * AddFormA [WINSPOOL.@]
1970 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1972 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
1976 /*****************************************************************************
1977 * AddFormW [WINSPOOL.@]
1979 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
1981 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
1985 /*****************************************************************************
1986 * AddJobA [WINSPOOL.@]
1988 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1991 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
1995 SetLastError(ERROR_INVALID_LEVEL
);
1999 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2002 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2003 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2004 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2005 if(*pcbNeeded
> cbBuf
) {
2006 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2009 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2010 addjobA
->JobId
= addjobW
->JobId
;
2011 addjobA
->Path
= (char *)(addjobA
+ 1);
2012 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2018 /*****************************************************************************
2019 * AddJobW [WINSPOOL.@]
2021 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2023 opened_printer_t
*printer
;
2026 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2027 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2028 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2030 ADDJOB_INFO_1W
*addjob
;
2032 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2034 EnterCriticalSection(&printer_handles_cs
);
2036 printer
= get_opened_printer(hPrinter
);
2039 SetLastError(ERROR_INVALID_HANDLE
);
2044 SetLastError(ERROR_INVALID_LEVEL
);
2048 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2052 job
->job_id
= InterlockedIncrement(&next_job_id
);
2054 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2055 if(path
[len
- 1] != '\\')
2057 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2058 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2060 len
= strlenW(filename
);
2061 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2062 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2063 job
->document_title
= strdupW(default_doc_title
);
2064 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2066 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2067 if(*pcbNeeded
<= cbBuf
) {
2068 addjob
= (ADDJOB_INFO_1W
*)pData
;
2069 addjob
->JobId
= job
->job_id
;
2070 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2071 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2074 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2077 LeaveCriticalSection(&printer_handles_cs
);
2081 /*****************************************************************************
2082 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2084 * Return the PATH for the Print-Processors
2086 * See GetPrintProcessorDirectoryW.
2090 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2091 DWORD level
, LPBYTE Info
,
2092 DWORD cbBuf
, LPDWORD pcbNeeded
)
2094 LPWSTR serverW
= NULL
;
2099 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2100 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2104 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2105 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2106 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2110 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2111 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2112 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2115 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2116 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2118 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2121 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2122 cbBuf
, NULL
, NULL
) > 0;
2125 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2126 HeapFree(GetProcessHeap(), 0, envW
);
2127 HeapFree(GetProcessHeap(), 0, serverW
);
2131 /*****************************************************************************
2132 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2134 * Return the PATH for the Print-Processors
2137 * server [I] Servername (NT only) or NULL (local Computer)
2138 * env [I] Printing-Environment (see below) or NULL (Default)
2139 * level [I] Structure-Level (must be 1)
2140 * Info [O] PTR to Buffer that receives the Result
2141 * cbBuf [I] Size of Buffer at "Info"
2142 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2143 * required for the Buffer at "Info"
2146 * Success: TRUE and in pcbNeeded the Bytes used in Info
2147 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2148 * if cbBuf is too small
2150 * Native Values returned in Info on Success:
2151 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2152 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2153 *| win9x(Windows 4.0): "%winsysdir%"
2155 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2158 * Only NULL or "" is supported for server
2161 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2162 DWORD level
, LPBYTE Info
,
2163 DWORD cbBuf
, LPDWORD pcbNeeded
)
2166 const printenv_t
* env_t
;
2168 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2169 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2171 if(server
!= NULL
&& server
[0]) {
2172 FIXME("server not supported: %s\n", debugstr_w(server
));
2173 SetLastError(ERROR_INVALID_PARAMETER
);
2177 env_t
= validate_envW(env
);
2178 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2181 WARN("(Level: %d) is ignored in win9x\n", level
);
2182 SetLastError(ERROR_INVALID_LEVEL
);
2186 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2187 needed
= GetSystemDirectoryW(NULL
, 0);
2188 /* add the Size for the Subdirectories */
2189 needed
+= lstrlenW(spoolprtprocsW
);
2190 needed
+= lstrlenW(env_t
->subdir
);
2191 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2193 if(pcbNeeded
) *pcbNeeded
= needed
;
2194 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2195 if (needed
> cbBuf
) {
2196 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2199 if(pcbNeeded
== NULL
) {
2200 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2201 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2202 SetLastError(RPC_X_NULL_REF_POINTER
);
2206 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2207 SetLastError(RPC_X_NULL_REF_POINTER
);
2211 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2212 /* add the Subdirectories */
2213 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2214 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2215 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2219 /*****************************************************************************
2220 * WINSPOOL_OpenDriverReg [internal]
2222 * opens the registry for the printer drivers depending on the given input
2223 * variable pEnvironment
2226 * the opened hkey on success
2229 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2233 const printenv_t
* env
;
2236 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2238 if (!pEnvironment
|| unicode
) {
2239 /* pEnvironment was NULL or a Unicode-String: use it direct */
2240 env
= validate_envW(pEnvironment
);
2244 /* pEnvironment was an ANSI-String: convert to unicode first */
2246 INT len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2247 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2248 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, buffer
, len
);
2249 env
= validate_envW(buffer
);
2250 HeapFree(GetProcessHeap(), 0, buffer
);
2252 if (!env
) return NULL
;
2254 buffer
= HeapAlloc( GetProcessHeap(), 0,
2255 (strlenW(DriversW
) + strlenW(env
->envname
) +
2256 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2258 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2259 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2260 HeapFree(GetProcessHeap(), 0, buffer
);
2265 /*****************************************************************************
2266 * AddPrinterW [WINSPOOL.@]
2268 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2270 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2274 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2276 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2277 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2278 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2279 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2280 statusW
[] = {'S','t','a','t','u','s',0},
2281 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2283 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2286 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2287 SetLastError(ERROR_INVALID_PARAMETER
);
2291 ERR("Level = %d, unsupported!\n", Level
);
2292 SetLastError(ERROR_INVALID_LEVEL
);
2296 SetLastError(ERROR_INVALID_PARAMETER
);
2299 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2301 ERR("Can't create Printers key\n");
2304 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2305 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2306 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2307 RegCloseKey(hkeyPrinter
);
2308 RegCloseKey(hkeyPrinters
);
2311 RegCloseKey(hkeyPrinter
);
2313 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2315 ERR("Can't create Drivers key\n");
2316 RegCloseKey(hkeyPrinters
);
2319 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2321 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2322 RegCloseKey(hkeyPrinters
);
2323 RegCloseKey(hkeyDrivers
);
2324 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2327 RegCloseKey(hkeyDriver
);
2328 RegCloseKey(hkeyDrivers
);
2330 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2331 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2332 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2333 RegCloseKey(hkeyPrinters
);
2337 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2339 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2340 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2341 RegCloseKey(hkeyPrinters
);
2344 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2345 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2346 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2348 /* See if we can load the driver. We may need the devmode structure anyway
2351 * Note that DocumentPropertiesW will briefly try to open the printer we
2352 * just create to find a DEVMODEA struct (it will use the WINEPS default
2353 * one in case it is not there, so we are ok).
2355 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2358 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2359 size
= sizeof(DEVMODEW
);
2365 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2367 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2369 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2370 HeapFree(GetProcessHeap(),0,dmW
);
2375 /* set devmode to printer name */
2376 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2380 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2381 and we support these drivers. NT writes DEVMODEW so somehow
2382 we'll need to distinguish between these when we support NT
2386 dmA
= DEVMODEdupWtoA(dmW
);
2387 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2388 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2389 HeapFree(GetProcessHeap(), 0, dmA
);
2391 HeapFree(GetProcessHeap(), 0, dmW
);
2393 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2394 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2395 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2396 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2398 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2399 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2400 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2401 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2402 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2403 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2404 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2405 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2406 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2407 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2408 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2409 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2410 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2412 RegCloseKey(hkeyPrinter
);
2413 RegCloseKey(hkeyPrinters
);
2414 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2415 ERR("OpenPrinter failing\n");
2421 /*****************************************************************************
2422 * AddPrinterA [WINSPOOL.@]
2424 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2426 UNICODE_STRING pNameW
;
2428 PRINTER_INFO_2W
*piW
;
2429 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2432 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2434 ERR("Level = %d, unsupported!\n", Level
);
2435 SetLastError(ERROR_INVALID_LEVEL
);
2438 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2439 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2441 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2443 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2444 RtlFreeUnicodeString(&pNameW
);
2449 /*****************************************************************************
2450 * ClosePrinter [WINSPOOL.@]
2452 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2454 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2455 opened_printer_t
*printer
= NULL
;
2458 TRACE("(%p)\n", hPrinter
);
2460 EnterCriticalSection(&printer_handles_cs
);
2462 if ((i
> 0) && (i
<= nb_printer_handles
))
2463 printer
= printer_handles
[i
- 1];
2468 struct list
*cursor
, *cursor2
;
2470 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2472 if (printer
->backend_printer
) {
2473 backend
->fpClosePrinter(printer
->backend_printer
);
2477 EndDocPrinter(hPrinter
);
2479 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2481 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2483 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2484 ScheduleJob(hPrinter
, job
->job_id
);
2486 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2489 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2490 HeapFree(GetProcessHeap(), 0, printer
->name
);
2491 HeapFree(GetProcessHeap(), 0, printer
);
2492 printer_handles
[i
- 1] = NULL
;
2495 LeaveCriticalSection(&printer_handles_cs
);
2499 /*****************************************************************************
2500 * DeleteFormA [WINSPOOL.@]
2502 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2504 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2508 /*****************************************************************************
2509 * DeleteFormW [WINSPOOL.@]
2511 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2513 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2517 /*****************************************************************************
2518 * DeletePrinter [WINSPOOL.@]
2520 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2522 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2523 HKEY hkeyPrinters
, hkey
;
2526 SetLastError(ERROR_INVALID_HANDLE
);
2529 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2530 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2531 RegCloseKey(hkeyPrinters
);
2533 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2534 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2536 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2537 RegDeleteValueW(hkey
, lpNameW
);
2541 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2542 RegDeleteValueW(hkey
, lpNameW
);
2548 /*****************************************************************************
2549 * SetPrinterA [WINSPOOL.@]
2551 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2554 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2558 /*****************************************************************************
2559 * SetJobA [WINSPOOL.@]
2561 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2562 LPBYTE pJob
, DWORD Command
)
2566 UNICODE_STRING usBuffer
;
2568 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2570 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2571 are all ignored by SetJob, so we don't bother copying them */
2579 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2580 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2582 JobW
= (LPBYTE
)info1W
;
2583 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2584 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2585 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2586 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2587 info1W
->Status
= info1A
->Status
;
2588 info1W
->Priority
= info1A
->Priority
;
2589 info1W
->Position
= info1A
->Position
;
2590 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2595 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2596 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2598 JobW
= (LPBYTE
)info2W
;
2599 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2600 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2601 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2602 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2603 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2604 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2605 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2606 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2607 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2608 info2W
->Status
= info2A
->Status
;
2609 info2W
->Priority
= info2A
->Priority
;
2610 info2W
->Position
= info2A
->Position
;
2611 info2W
->StartTime
= info2A
->StartTime
;
2612 info2W
->UntilTime
= info2A
->UntilTime
;
2613 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2617 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2618 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2621 SetLastError(ERROR_INVALID_LEVEL
);
2625 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2631 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2632 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2633 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2634 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2635 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2640 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2641 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2642 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2643 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2644 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2645 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2646 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2647 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2648 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2652 HeapFree(GetProcessHeap(), 0, JobW
);
2657 /*****************************************************************************
2658 * SetJobW [WINSPOOL.@]
2660 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2661 LPBYTE pJob
, DWORD Command
)
2666 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2667 FIXME("Ignoring everything other than document title\n");
2669 EnterCriticalSection(&printer_handles_cs
);
2670 job
= get_job(hPrinter
, JobId
);
2680 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2681 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2682 job
->document_title
= strdupW(info1
->pDocument
);
2687 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2688 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2689 job
->document_title
= strdupW(info2
->pDocument
);
2695 SetLastError(ERROR_INVALID_LEVEL
);
2700 LeaveCriticalSection(&printer_handles_cs
);
2704 /*****************************************************************************
2705 * EndDocPrinter [WINSPOOL.@]
2707 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2709 opened_printer_t
*printer
;
2711 TRACE("(%p)\n", hPrinter
);
2713 EnterCriticalSection(&printer_handles_cs
);
2715 printer
= get_opened_printer(hPrinter
);
2718 SetLastError(ERROR_INVALID_HANDLE
);
2724 SetLastError(ERROR_SPL_NO_STARTDOC
);
2728 CloseHandle(printer
->doc
->hf
);
2729 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2730 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2731 printer
->doc
= NULL
;
2734 LeaveCriticalSection(&printer_handles_cs
);
2738 /*****************************************************************************
2739 * EndPagePrinter [WINSPOOL.@]
2741 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2743 FIXME("(%p): stub\n", hPrinter
);
2747 /*****************************************************************************
2748 * StartDocPrinterA [WINSPOOL.@]
2750 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2752 UNICODE_STRING usBuffer
;
2754 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2757 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2758 or one (DOC_INFO_3) extra DWORDs */
2762 doc2W
.JobId
= doc2
->JobId
;
2765 doc2W
.dwMode
= doc2
->dwMode
;
2768 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2769 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2770 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2774 SetLastError(ERROR_INVALID_LEVEL
);
2778 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2780 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2781 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2782 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
2787 /*****************************************************************************
2788 * StartDocPrinterW [WINSPOOL.@]
2790 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2792 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
2793 opened_printer_t
*printer
;
2794 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2795 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
2796 JOB_INFO_1W job_info
;
2797 DWORD needed
, ret
= 0;
2801 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2802 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
2803 debugstr_w(doc
->pDatatype
));
2805 if(Level
< 1 || Level
> 3)
2807 SetLastError(ERROR_INVALID_LEVEL
);
2811 EnterCriticalSection(&printer_handles_cs
);
2812 printer
= get_opened_printer(hPrinter
);
2815 SetLastError(ERROR_INVALID_HANDLE
);
2821 SetLastError(ERROR_INVALID_PRINTER_STATE
);
2825 /* Even if we're printing to a file we still add a print job, we'll
2826 just ignore the spool file name */
2828 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
2830 ERR("AddJob failed gle %u\n", GetLastError());
2834 if(doc
->pOutputFile
)
2835 filename
= doc
->pOutputFile
;
2837 filename
= addjob
->Path
;
2839 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
2840 if(hf
== INVALID_HANDLE_VALUE
)
2843 memset(&job_info
, 0, sizeof(job_info
));
2844 job_info
.pDocument
= doc
->pDocName
;
2845 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
2847 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
2848 printer
->doc
->hf
= hf
;
2849 ret
= printer
->doc
->job_id
= addjob
->JobId
;
2851 LeaveCriticalSection(&printer_handles_cs
);
2856 /*****************************************************************************
2857 * StartPagePrinter [WINSPOOL.@]
2859 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
2861 FIXME("(%p): stub\n", hPrinter
);
2865 /*****************************************************************************
2866 * GetFormA [WINSPOOL.@]
2868 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2869 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2871 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
2872 Level
,pForm
,cbBuf
,pcbNeeded
);
2876 /*****************************************************************************
2877 * GetFormW [WINSPOOL.@]
2879 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2880 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2882 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
2883 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
2887 /*****************************************************************************
2888 * SetFormA [WINSPOOL.@]
2890 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
2893 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2897 /*****************************************************************************
2898 * SetFormW [WINSPOOL.@]
2900 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
2903 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
2907 /*****************************************************************************
2908 * ReadPrinter [WINSPOOL.@]
2910 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
2911 LPDWORD pNoBytesRead
)
2913 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
2917 /*****************************************************************************
2918 * ResetPrinterA [WINSPOOL.@]
2920 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
2922 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2926 /*****************************************************************************
2927 * ResetPrinterW [WINSPOOL.@]
2929 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2931 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
2935 /*****************************************************************************
2936 * WINSPOOL_GetDWORDFromReg
2938 * Return DWORD associated with ValueName from hkey.
2940 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
2942 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
2945 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
2947 if(ret
!= ERROR_SUCCESS
) {
2948 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
2951 if(type
!= REG_DWORD
) {
2952 ERR("Got type %d\n", type
);
2959 /*****************************************************************************
2960 * get_filename_from_reg [internal]
2962 * Get ValueName from hkey storing result in out
2963 * when the Value in the registry has only a filename, use driverdir as prefix
2964 * outlen is space left in out
2965 * String is stored either as unicode or ascii
2969 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
2970 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
2972 WCHAR filename
[MAX_PATH
];
2976 LPWSTR buffer
= filename
;
2980 size
= sizeof(filename
);
2982 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
2983 if (ret
== ERROR_MORE_DATA
) {
2984 TRACE("need dynamic buffer: %u\n", size
);
2985 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
2987 /* No Memory is bad */
2991 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
2994 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
2995 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3001 /* do we have a full path ? */
3002 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3003 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3006 /* we must build the full Path */
3008 if ((out
) && (outlen
> dirlen
)) {
3010 lstrcpyW((LPWSTR
)out
, driverdir
);
3014 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3023 /* write the filename */
3025 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3026 if ((out
) && (outlen
>= size
)) {
3027 lstrcpyW((LPWSTR
)out
, ptr
);
3036 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3037 if ((out
) && (outlen
>= size
)) {
3038 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3046 ptr
+= lstrlenW(ptr
)+1;
3047 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3050 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3052 /* write the multisz-termination */
3053 if (type
== REG_MULTI_SZ
) {
3054 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3057 if (out
&& (outlen
>= size
)) {
3058 memset (out
, 0, size
);
3064 /*****************************************************************************
3065 * WINSPOOL_GetStringFromReg
3067 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3068 * String is stored either as unicode or ascii.
3069 * Bit of a hack here to get the ValueName if we want ascii.
3071 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3072 DWORD buflen
, DWORD
*needed
,
3075 DWORD sz
= buflen
, type
;
3079 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3081 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3082 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3083 HeapFree(GetProcessHeap(),0,ValueNameA
);
3085 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3086 WARN("Got ret = %d\n", ret
);
3090 /* add space for terminating '\0' */
3091 sz
+= unicode
? sizeof(WCHAR
) : 1;
3095 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3100 /*****************************************************************************
3101 * WINSPOOL_GetDefaultDevMode
3103 * Get a default DevMode values for wineps.
3107 static void WINSPOOL_GetDefaultDevMode(
3109 DWORD buflen
, DWORD
*needed
,
3113 static const char szwps
[] = "wineps.drv";
3115 /* fill default DEVMODE - should be read from ppd... */
3116 ZeroMemory( &dm
, sizeof(dm
) );
3117 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3118 dm
.dmSpecVersion
= DM_SPECVERSION
;
3119 dm
.dmDriverVersion
= 1;
3120 dm
.dmSize
= sizeof(DEVMODEA
);
3121 dm
.dmDriverExtra
= 0;
3123 DM_ORIENTATION
| DM_PAPERSIZE
|
3124 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3127 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3128 DM_YRESOLUTION
| DM_TTOPTION
;
3130 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3131 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3132 dm
.u1
.s1
.dmPaperLength
= 2970;
3133 dm
.u1
.s1
.dmPaperWidth
= 2100;
3135 dm
.u1
.s1
.dmScale
= 100;
3136 dm
.u1
.s1
.dmCopies
= 1;
3137 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3138 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3141 dm
.dmYResolution
= 300; /* 300dpi */
3142 dm
.dmTTOption
= DMTT_BITMAP
;
3145 /* dm.dmLogPixels */
3146 /* dm.dmBitsPerPel */
3147 /* dm.dmPelsWidth */
3148 /* dm.dmPelsHeight */
3149 /* dm.u2.dmDisplayFlags */
3150 /* dm.dmDisplayFrequency */
3151 /* dm.dmICMMethod */
3152 /* dm.dmICMIntent */
3153 /* dm.dmMediaType */
3154 /* dm.dmDitherType */
3155 /* dm.dmReserved1 */
3156 /* dm.dmReserved2 */
3157 /* dm.dmPanningWidth */
3158 /* dm.dmPanningHeight */
3161 if(buflen
>= sizeof(DEVMODEW
)) {
3162 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3163 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3164 HeapFree(GetProcessHeap(),0,pdmW
);
3166 *needed
= sizeof(DEVMODEW
);
3170 if(buflen
>= sizeof(DEVMODEA
)) {
3171 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3173 *needed
= sizeof(DEVMODEA
);
3177 /*****************************************************************************
3178 * WINSPOOL_GetDevModeFromReg
3180 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3181 * DevMode is stored either as unicode or ascii.
3183 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3185 DWORD buflen
, DWORD
*needed
,
3188 DWORD sz
= buflen
, type
;
3191 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3192 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3193 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3194 if (sz
< sizeof(DEVMODEA
))
3196 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3199 /* ensures that dmSize is not erratically bogus if registry is invalid */
3200 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3201 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3203 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3205 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3206 memcpy(ptr
, dmW
, sz
);
3207 HeapFree(GetProcessHeap(),0,dmW
);
3214 /*********************************************************************
3215 * WINSPOOL_GetPrinter_1
3217 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3218 * The strings are either stored as unicode or ascii.
3220 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3221 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3224 DWORD size
, left
= cbBuf
;
3225 BOOL space
= (cbBuf
> 0);
3230 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3232 if(space
&& size
<= left
) {
3233 pi1
->pName
= (LPWSTR
)ptr
;
3241 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3242 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3244 if(space
&& size
<= left
) {
3245 pi1
->pDescription
= (LPWSTR
)ptr
;
3253 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3255 if(space
&& size
<= left
) {
3256 pi1
->pComment
= (LPWSTR
)ptr
;
3264 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3266 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3267 memset(pi1
, 0, sizeof(*pi1
));
3271 /*********************************************************************
3272 * WINSPOOL_GetPrinter_2
3274 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3275 * The strings are either stored as unicode or ascii.
3277 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3278 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3281 DWORD size
, left
= cbBuf
;
3282 BOOL space
= (cbBuf
> 0);
3287 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3289 if(space
&& size
<= left
) {
3290 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3297 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3299 if(space
&& size
<= left
) {
3300 pi2
->pShareName
= (LPWSTR
)ptr
;
3307 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3309 if(space
&& size
<= left
) {
3310 pi2
->pPortName
= (LPWSTR
)ptr
;
3317 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3319 if(space
&& size
<= left
) {
3320 pi2
->pDriverName
= (LPWSTR
)ptr
;
3327 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3329 if(space
&& size
<= left
) {
3330 pi2
->pComment
= (LPWSTR
)ptr
;
3337 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3339 if(space
&& size
<= left
) {
3340 pi2
->pLocation
= (LPWSTR
)ptr
;
3347 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3349 if(space
&& size
<= left
) {
3350 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3359 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3360 if(space
&& size
<= left
) {
3361 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3368 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3370 if(space
&& size
<= left
) {
3371 pi2
->pSepFile
= (LPWSTR
)ptr
;
3378 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3380 if(space
&& size
<= left
) {
3381 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3388 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3390 if(space
&& size
<= left
) {
3391 pi2
->pDatatype
= (LPWSTR
)ptr
;
3398 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3400 if(space
&& size
<= left
) {
3401 pi2
->pParameters
= (LPWSTR
)ptr
;
3409 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3410 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3411 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3412 "Default Priority");
3413 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3414 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3417 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3418 memset(pi2
, 0, sizeof(*pi2
));
3423 /*********************************************************************
3424 * WINSPOOL_GetPrinter_4
3426 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3428 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3429 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3432 DWORD size
, left
= cbBuf
;
3433 BOOL space
= (cbBuf
> 0);
3438 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3440 if(space
&& size
<= left
) {
3441 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3449 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3452 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3453 memset(pi4
, 0, sizeof(*pi4
));
3458 /*********************************************************************
3459 * WINSPOOL_GetPrinter_5
3461 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3463 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3464 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3467 DWORD size
, left
= cbBuf
;
3468 BOOL space
= (cbBuf
> 0);
3473 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3475 if(space
&& size
<= left
) {
3476 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3483 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3485 if(space
&& size
<= left
) {
3486 pi5
->pPortName
= (LPWSTR
)ptr
;
3494 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3495 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3497 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3501 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3502 memset(pi5
, 0, sizeof(*pi5
));
3507 /*********************************************************************
3508 * WINSPOOL_GetPrinter_7
3510 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3512 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3513 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3515 DWORD size
, left
= cbBuf
;
3516 BOOL space
= (cbBuf
> 0);
3521 if (WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
, unicode
))
3523 if (space
&& size
<= left
) {
3524 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3532 /* We do not have a Directory Service */
3533 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3536 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3537 memset(pi7
, 0, sizeof(*pi7
));
3542 /*********************************************************************
3543 * WINSPOOL_GetPrinter_9
3545 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3546 * The strings are either stored as unicode or ascii.
3548 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3549 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3552 BOOL space
= (cbBuf
> 0);
3556 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
, unicode
)) {
3557 if(space
&& size
<= cbBuf
) {
3558 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3565 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
, unicode
);
3566 if(space
&& size
<= cbBuf
) {
3567 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3573 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3574 memset(pi9
, 0, sizeof(*pi9
));
3579 /*****************************************************************************
3580 * WINSPOOL_GetPrinter
3582 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3583 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3584 * just a collection of pointers to strings.
3586 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3587 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
3590 DWORD size
, needed
= 0;
3592 HKEY hkeyPrinter
, hkeyPrinters
;
3595 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3597 if (!(name
= get_opened_printer_name(hPrinter
))) {
3598 SetLastError(ERROR_INVALID_HANDLE
);
3602 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3604 ERR("Can't create Printers key\n");
3607 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3609 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3610 RegCloseKey(hkeyPrinters
);
3611 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3618 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3620 size
= sizeof(PRINTER_INFO_2W
);
3622 ptr
= pPrinter
+ size
;
3624 memset(pPrinter
, 0, size
);
3629 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
3637 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3639 size
= sizeof(PRINTER_INFO_4W
);
3641 ptr
= pPrinter
+ size
;
3643 memset(pPrinter
, 0, size
);
3648 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
3657 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3659 size
= sizeof(PRINTER_INFO_5W
);
3661 ptr
= pPrinter
+ size
;
3663 memset(pPrinter
, 0, size
);
3669 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
3678 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3680 size
= sizeof(PRINTER_INFO_6
);
3681 if (size
<= cbBuf
) {
3682 /* FIXME: We do not update the status yet */
3683 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3695 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3697 size
= sizeof(PRINTER_INFO_7W
);
3698 if (size
<= cbBuf
) {
3699 ptr
= pPrinter
+ size
;
3701 memset(pPrinter
, 0, size
);
3707 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
, unicode
);
3715 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3717 size
= sizeof(PRINTER_INFO_9W
);
3719 ptr
= pPrinter
+ size
;
3721 memset(pPrinter
, 0, size
);
3727 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
, unicode
);
3734 FIXME("Unimplemented level %d\n", Level
);
3735 SetLastError(ERROR_INVALID_LEVEL
);
3736 RegCloseKey(hkeyPrinters
);
3737 RegCloseKey(hkeyPrinter
);
3741 RegCloseKey(hkeyPrinter
);
3742 RegCloseKey(hkeyPrinters
);
3744 TRACE("returning %d needed = %d\n", ret
, needed
);
3745 if(pcbNeeded
) *pcbNeeded
= needed
;
3747 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3751 /*****************************************************************************
3752 * GetPrinterW [WINSPOOL.@]
3754 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3755 DWORD cbBuf
, LPDWORD pcbNeeded
)
3757 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3761 /*****************************************************************************
3762 * GetPrinterA [WINSPOOL.@]
3764 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3765 DWORD cbBuf
, LPDWORD pcbNeeded
)
3767 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
3771 /*****************************************************************************
3772 * WINSPOOL_EnumPrinters
3774 * Implementation of EnumPrintersA|W
3776 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
3777 DWORD dwLevel
, LPBYTE lpbPrinters
,
3778 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3779 LPDWORD lpdwReturned
, BOOL unicode
)
3782 HKEY hkeyPrinters
, hkeyPrinter
;
3783 WCHAR PrinterName
[255];
3784 DWORD needed
= 0, number
= 0;
3785 DWORD used
, i
, left
;
3789 memset(lpbPrinters
, 0, cbBuf
);
3795 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3796 if(dwType
== PRINTER_ENUM_DEFAULT
)
3799 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3800 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3801 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3803 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3811 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3812 FIXME("dwType = %08x\n", dwType
);
3813 SetLastError(ERROR_INVALID_FLAGS
);
3817 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3819 ERR("Can't create Printers key\n");
3823 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3824 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3825 RegCloseKey(hkeyPrinters
);
3826 ERR("Can't query Printers key\n");
3829 TRACE("Found %d printers\n", number
);
3833 used
= number
* sizeof(PRINTER_INFO_1W
);
3836 used
= number
* sizeof(PRINTER_INFO_2W
);
3839 used
= number
* sizeof(PRINTER_INFO_4W
);
3842 used
= number
* sizeof(PRINTER_INFO_5W
);
3846 SetLastError(ERROR_INVALID_LEVEL
);
3847 RegCloseKey(hkeyPrinters
);
3850 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
3852 for(i
= 0; i
< number
; i
++) {
3853 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
3855 ERR("Can't enum key number %d\n", i
);
3856 RegCloseKey(hkeyPrinters
);
3859 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
3860 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
3862 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
3863 RegCloseKey(hkeyPrinters
);
3868 buf
= lpbPrinters
+ used
;
3869 left
= cbBuf
- used
;
3877 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
3878 left
, &needed
, unicode
);
3880 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
3883 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
3884 left
, &needed
, unicode
);
3886 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
3889 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
3890 left
, &needed
, unicode
);
3892 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
3895 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
3896 left
, &needed
, unicode
);
3898 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
3901 ERR("Shouldn't be here!\n");
3902 RegCloseKey(hkeyPrinter
);
3903 RegCloseKey(hkeyPrinters
);
3906 RegCloseKey(hkeyPrinter
);
3908 RegCloseKey(hkeyPrinters
);
3915 memset(lpbPrinters
, 0, cbBuf
);
3916 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3920 *lpdwReturned
= number
;
3921 SetLastError(ERROR_SUCCESS
);
3926 /******************************************************************
3927 * EnumPrintersW [WINSPOOL.@]
3929 * Enumerates the available printers, print servers and print
3930 * providers, depending on the specified flags, name and level.
3934 * If level is set to 1:
3935 * Returns an array of PRINTER_INFO_1 data structures in the
3936 * lpbPrinters buffer.
3938 * If level is set to 2:
3939 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3940 * Returns an array of PRINTER_INFO_2 data structures in the
3941 * lpbPrinters buffer. Note that according to MSDN also an
3942 * OpenPrinter should be performed on every remote printer.
3944 * If level is set to 4 (officially WinNT only):
3945 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3946 * Fast: Only the registry is queried to retrieve printer names,
3947 * no connection to the driver is made.
3948 * Returns an array of PRINTER_INFO_4 data structures in the
3949 * lpbPrinters buffer.
3951 * If level is set to 5 (officially WinNT4/Win9x only):
3952 * Fast: Only the registry is queried to retrieve printer names,
3953 * no connection to the driver is made.
3954 * Returns an array of PRINTER_INFO_5 data structures in the
3955 * lpbPrinters buffer.
3957 * If level set to 3 or 6+:
3958 * returns zero (failure!)
3960 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3964 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3965 * - Only levels 2, 4 and 5 are implemented at the moment.
3966 * - 16-bit printer drivers are not enumerated.
3967 * - Returned amount of bytes used/needed does not match the real Windoze
3968 * implementation (as in this implementation, all strings are part
3969 * of the buffer, whereas Win32 keeps them somewhere else)
3970 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3973 * - In a regular Wine installation, no registry settings for printers
3974 * exist, which makes this function return an empty list.
3976 BOOL WINAPI
EnumPrintersW(
3977 DWORD dwType
, /* [in] Types of print objects to enumerate */
3978 LPWSTR lpszName
, /* [in] name of objects to enumerate */
3979 DWORD dwLevel
, /* [in] type of printer info structure */
3980 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
3981 DWORD cbBuf
, /* [in] max size of buffer in bytes */
3982 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
3983 LPDWORD lpdwReturned
/* [out] number of entries returned */
3986 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
3987 lpdwNeeded
, lpdwReturned
, TRUE
);
3990 /******************************************************************
3991 * EnumPrintersA [WINSPOOL.@]
3996 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
3997 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4000 UNICODE_STRING pNameU
;
4004 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4005 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4007 pNameW
= asciitounicode(&pNameU
, pName
);
4009 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4010 MS Office need this */
4011 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4013 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4015 RtlFreeUnicodeString(&pNameU
);
4017 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4019 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4023 /*****************************************************************************
4024 * WINSPOOL_GetDriverInfoFromReg [internal]
4026 * Enters the information from the registry into the DRIVER_INFO struct
4029 * zero if the printer driver does not exist in the registry
4030 * (only if Level > 1) otherwise nonzero
4032 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4035 const printenv_t
* env
,
4037 LPBYTE ptr
, /* DRIVER_INFO */
4038 LPBYTE pDriverStrings
, /* strings buffer */
4039 DWORD cbBuf
, /* size of string buffer */
4040 LPDWORD pcbNeeded
, /* space needed for str. */
4041 BOOL unicode
) /* type of strings */
4045 WCHAR driverdir
[MAX_PATH
];
4047 LPBYTE strPtr
= pDriverStrings
;
4048 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4050 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4051 debugstr_w(DriverName
), env
,
4052 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4054 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4057 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4058 if (*pcbNeeded
<= cbBuf
)
4059 strcpyW((LPWSTR
)strPtr
, DriverName
);
4063 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4064 if (*pcbNeeded
<= cbBuf
)
4065 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4068 /* pName for level 1 has a different offset! */
4070 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4074 /* .cVersion and .pName for level > 1 */
4076 di
->cVersion
= env
->driverversion
;
4077 di
->pName
= (LPWSTR
) strPtr
;
4078 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4081 /* Reserve Space for the largest subdir and a Backslash*/
4082 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4083 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4084 /* Should never Fail */
4087 lstrcatW(driverdir
, env
->versionsubdir
);
4088 lstrcatW(driverdir
, backslashW
);
4090 /* dirlen must not include the terminating zero */
4091 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4092 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4094 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4095 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4096 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4102 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4104 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4107 if (*pcbNeeded
<= cbBuf
) {
4109 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4113 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4115 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4116 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4119 /* .pDriverPath is the Graphics rendering engine.
4120 The full Path is required to avoid a crash in some apps */
4121 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4123 if (*pcbNeeded
<= cbBuf
)
4124 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4126 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4127 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4130 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4131 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4133 if (*pcbNeeded
<= cbBuf
)
4134 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4136 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4137 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4140 /* .pConfigFile is the Driver user Interface */
4141 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4143 if (*pcbNeeded
<= cbBuf
)
4144 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4146 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4147 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4151 RegCloseKey(hkeyDriver
);
4152 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4157 RegCloseKey(hkeyDriver
);
4158 FIXME("level 5: incomplete\n");
4163 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4165 if (*pcbNeeded
<= cbBuf
)
4166 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4168 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4169 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4172 /* .pDependentFiles */
4173 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4175 if (*pcbNeeded
<= cbBuf
)
4176 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4178 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4179 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4181 else if (GetVersion() & 0x80000000) {
4182 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4183 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4185 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4187 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4188 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4191 /* .pMonitorName is the optional Language Monitor */
4192 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4194 if (*pcbNeeded
<= cbBuf
)
4195 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4197 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4198 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4201 /* .pDefaultDataType */
4202 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4204 if(*pcbNeeded
<= cbBuf
)
4205 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4207 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4208 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4212 RegCloseKey(hkeyDriver
);
4213 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4217 /* .pszzPreviousNames */
4218 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4220 if(*pcbNeeded
<= cbBuf
)
4221 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4223 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4224 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4228 RegCloseKey(hkeyDriver
);
4229 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4233 /* support is missing, but not important enough for a FIXME */
4234 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4237 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4239 if(*pcbNeeded
<= cbBuf
)
4240 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4242 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4243 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4247 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4249 if(*pcbNeeded
<= cbBuf
)
4250 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4252 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4253 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4256 /* .pszHardwareID */
4257 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4259 if(*pcbNeeded
<= cbBuf
)
4260 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4262 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4263 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4267 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4269 if(*pcbNeeded
<= cbBuf
)
4270 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4272 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4273 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4277 RegCloseKey(hkeyDriver
);
4281 /* support is missing, but not important enough for a FIXME */
4282 TRACE("level 8: incomplete\n");
4284 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4285 RegCloseKey(hkeyDriver
);
4289 /*****************************************************************************
4290 * WINSPOOL_GetPrinterDriver
4292 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4293 DWORD Level
, LPBYTE pDriverInfo
,
4294 DWORD cbBuf
, LPDWORD pcbNeeded
,
4298 WCHAR DriverName
[100];
4299 DWORD ret
, type
, size
, needed
= 0;
4301 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4302 const printenv_t
* env
;
4304 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4305 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4308 if (!(name
= get_opened_printer_name(hPrinter
))) {
4309 SetLastError(ERROR_INVALID_HANDLE
);
4313 if (Level
< 1 || Level
== 7 || Level
> 8) {
4314 SetLastError(ERROR_INVALID_LEVEL
);
4318 env
= validate_envW(pEnvironment
);
4319 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4321 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4323 ERR("Can't create Printers key\n");
4326 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4328 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4329 RegCloseKey(hkeyPrinters
);
4330 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4333 size
= sizeof(DriverName
);
4335 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4336 (LPBYTE
)DriverName
, &size
);
4337 RegCloseKey(hkeyPrinter
);
4338 RegCloseKey(hkeyPrinters
);
4339 if(ret
!= ERROR_SUCCESS
) {
4340 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4344 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4346 ERR("Can't create Drivers key\n");
4350 size
= di_sizeof
[Level
];
4351 if ((size
<= cbBuf
) && pDriverInfo
)
4352 ptr
= pDriverInfo
+ size
;
4354 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4355 env
, Level
, pDriverInfo
, ptr
,
4356 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4357 &needed
, unicode
)) {
4358 RegCloseKey(hkeyDrivers
);
4362 RegCloseKey(hkeyDrivers
);
4364 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4365 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4366 if(cbBuf
>= needed
) return TRUE
;
4367 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4371 /*****************************************************************************
4372 * GetPrinterDriverA [WINSPOOL.@]
4374 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4375 DWORD Level
, LPBYTE pDriverInfo
,
4376 DWORD cbBuf
, LPDWORD pcbNeeded
)
4379 UNICODE_STRING pEnvW
;
4382 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4383 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4384 cbBuf
, pcbNeeded
, FALSE
);
4385 RtlFreeUnicodeString(&pEnvW
);
4388 /*****************************************************************************
4389 * GetPrinterDriverW [WINSPOOL.@]
4391 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4392 DWORD Level
, LPBYTE pDriverInfo
,
4393 DWORD cbBuf
, LPDWORD pcbNeeded
)
4395 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4396 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4399 /*****************************************************************************
4400 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4402 * Return the PATH for the Printer-Drivers (UNICODE)
4405 * pName [I] Servername (NT only) or NULL (local Computer)
4406 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4407 * Level [I] Structure-Level (must be 1)
4408 * pDriverDirectory [O] PTR to Buffer that receives the Result
4409 * cbBuf [I] Size of Buffer at pDriverDirectory
4410 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4411 * required for pDriverDirectory
4414 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4415 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4416 * if cbBuf is too small
4418 * Native Values returned in pDriverDirectory on Success:
4419 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4420 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4421 *| win9x(Windows 4.0): "%winsysdir%"
4423 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4426 *- Only NULL or "" is supported for pName
4429 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4430 DWORD Level
, LPBYTE pDriverDirectory
,
4431 DWORD cbBuf
, LPDWORD pcbNeeded
)
4433 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4434 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4436 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4439 /* (Level != 1) is ignored in win9x */
4440 SetLastError(ERROR_INVALID_LEVEL
);
4443 if (pcbNeeded
== NULL
) {
4444 /* (pcbNeeded == NULL) is ignored in win9x */
4445 SetLastError(RPC_X_NULL_REF_POINTER
);
4449 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4450 pDriverDirectory
, cbBuf
, pcbNeeded
);
4455 /*****************************************************************************
4456 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4458 * Return the PATH for the Printer-Drivers (ANSI)
4460 * See GetPrinterDriverDirectoryW.
4463 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4466 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4467 DWORD Level
, LPBYTE pDriverDirectory
,
4468 DWORD cbBuf
, LPDWORD pcbNeeded
)
4470 UNICODE_STRING nameW
, environmentW
;
4473 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4474 WCHAR
*driverDirectoryW
= NULL
;
4476 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4477 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4479 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4481 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4482 else nameW
.Buffer
= NULL
;
4483 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4484 else environmentW
.Buffer
= NULL
;
4486 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4487 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4490 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4491 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4493 *pcbNeeded
= needed
;
4494 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4496 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4498 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4500 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4501 RtlFreeUnicodeString(&environmentW
);
4502 RtlFreeUnicodeString(&nameW
);
4507 /*****************************************************************************
4508 * AddPrinterDriverA [WINSPOOL.@]
4510 * See AddPrinterDriverW.
4513 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4515 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4516 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4519 /******************************************************************************
4520 * AddPrinterDriverW (WINSPOOL.@)
4522 * Install a Printer Driver
4525 * pName [I] Servername or NULL (local Computer)
4526 * level [I] Level for the supplied DRIVER_INFO_*W struct
4527 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4534 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4536 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4537 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4540 /*****************************************************************************
4541 * AddPrintProcessorA [WINSPOOL.@]
4543 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4544 LPSTR pPrintProcessorName
)
4546 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4547 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4551 /*****************************************************************************
4552 * AddPrintProcessorW [WINSPOOL.@]
4554 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4555 LPWSTR pPrintProcessorName
)
4557 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4558 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4562 /*****************************************************************************
4563 * AddPrintProvidorA [WINSPOOL.@]
4565 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4567 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4571 /*****************************************************************************
4572 * AddPrintProvidorW [WINSPOOL.@]
4574 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4576 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4580 /*****************************************************************************
4581 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4583 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4584 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4586 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4587 pDevModeOutput
, pDevModeInput
);
4591 /*****************************************************************************
4592 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4594 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4595 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4597 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4598 pDevModeOutput
, pDevModeInput
);
4602 /*****************************************************************************
4603 * PrinterProperties [WINSPOOL.@]
4605 * Displays a dialog to set the properties of the printer.
4608 * nonzero on success or zero on failure
4611 * implemented as stub only
4613 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4614 HANDLE hPrinter
/* [in] handle to printer object */
4616 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4617 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4621 /*****************************************************************************
4622 * EnumJobsA [WINSPOOL.@]
4625 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4626 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4629 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4630 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4632 if(pcbNeeded
) *pcbNeeded
= 0;
4633 if(pcReturned
) *pcReturned
= 0;
4638 /*****************************************************************************
4639 * EnumJobsW [WINSPOOL.@]
4642 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4643 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4646 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4647 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4649 if(pcbNeeded
) *pcbNeeded
= 0;
4650 if(pcReturned
) *pcReturned
= 0;
4654 /*****************************************************************************
4655 * WINSPOOL_EnumPrinterDrivers [internal]
4657 * Delivers information about all printer drivers installed on the
4658 * localhost or a given server
4661 * nonzero on success or zero on failure. If the buffer for the returned
4662 * information is too small the function will return an error
4665 * - only implemented for localhost, foreign hosts will return an error
4667 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4668 DWORD Level
, LPBYTE pDriverInfo
,
4669 DWORD cbBuf
, LPDWORD pcbNeeded
,
4670 LPDWORD pcReturned
, BOOL unicode
)
4673 DWORD i
, needed
, number
= 0, size
= 0;
4674 WCHAR DriverNameW
[255];
4676 const printenv_t
* env
;
4678 TRACE("%s,%s,%d,%p,%d,%d\n",
4679 debugstr_w(pName
), debugstr_w(pEnvironment
),
4680 Level
, pDriverInfo
, cbBuf
, unicode
);
4682 /* check for local drivers */
4683 if((pName
) && (pName
[0])) {
4684 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4685 SetLastError(ERROR_ACCESS_DENIED
);
4689 env
= validate_envW(pEnvironment
);
4690 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4692 /* check input parameter */
4693 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4694 SetLastError(ERROR_INVALID_LEVEL
);
4698 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
4699 SetLastError(RPC_X_NULL_REF_POINTER
);
4703 /* initialize return values */
4705 memset( pDriverInfo
, 0, cbBuf
);
4709 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
4711 ERR("Can't open Drivers key\n");
4715 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4716 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4717 RegCloseKey(hkeyDrivers
);
4718 ERR("Can't query Drivers key\n");
4721 TRACE("Found %d Drivers\n", number
);
4723 /* get size of single struct
4724 * unicode and ascii structure have the same size
4726 size
= di_sizeof
[Level
];
4728 /* calculate required buffer size */
4729 *pcbNeeded
= size
* number
;
4731 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
4733 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
4734 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4736 ERR("Can't enum key number %d\n", i
);
4737 RegCloseKey(hkeyDrivers
);
4740 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4742 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
4743 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4744 &needed
, unicode
)) {
4745 RegCloseKey(hkeyDrivers
);
4748 *pcbNeeded
+= needed
;
4751 RegCloseKey(hkeyDrivers
);
4753 if(cbBuf
< *pcbNeeded
){
4754 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4758 *pcReturned
= number
;
4762 /*****************************************************************************
4763 * EnumPrinterDriversW [WINSPOOL.@]
4765 * see function EnumPrinterDrivers for RETURNS, BUGS
4767 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4768 LPBYTE pDriverInfo
, DWORD cbBuf
,
4769 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4771 static const WCHAR allW
[] = {'a','l','l',0};
4773 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4776 DWORD i
, needed
, returned
, bufsize
= cbBuf
;
4778 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4780 needed
= returned
= 0;
4781 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4782 pDriverInfo
, bufsize
, &needed
, &returned
, TRUE
);
4783 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4787 if (pDriverInfo
) pDriverInfo
+= needed
;
4788 if (pcReturned
) *pcReturned
+= returned
;
4790 if (pcbNeeded
) *pcbNeeded
+= needed
;
4794 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4795 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
4798 /*****************************************************************************
4799 * EnumPrinterDriversA [WINSPOOL.@]
4801 * see function EnumPrinterDrivers for RETURNS, BUGS
4803 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4804 LPBYTE pDriverInfo
, DWORD cbBuf
,
4805 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4808 UNICODE_STRING pNameW
, pEnvironmentW
;
4809 PWSTR pwstrNameW
, pwstrEnvironmentW
;
4811 pwstrNameW
= asciitounicode(&pNameW
, pName
);
4812 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
4814 if (pEnvironment
&& !strcmp(pEnvironment
, "all"))
4816 DWORD i
, needed
, returned
, bufsize
= cbBuf
;
4818 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4820 needed
= returned
= 0;
4821 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, all_printenv
[i
]->envname
, Level
,
4822 pDriverInfo
, bufsize
, &needed
, &returned
, FALSE
);
4823 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) break;
4827 if (pDriverInfo
) pDriverInfo
+= needed
;
4828 if (pcReturned
) *pcReturned
+= returned
;
4830 if (pcbNeeded
) *pcbNeeded
+= needed
;
4833 else ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
4834 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
4836 RtlFreeUnicodeString(&pNameW
);
4837 RtlFreeUnicodeString(&pEnvironmentW
);
4842 /******************************************************************************
4843 * EnumPortsA (WINSPOOL.@)
4848 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
4849 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4852 LPBYTE bufferW
= NULL
;
4853 LPWSTR nameW
= NULL
;
4855 DWORD numentries
= 0;
4858 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
4859 cbBuf
, pcbNeeded
, pcReturned
);
4861 /* convert servername to unicode */
4863 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
4864 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4865 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
4867 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4868 needed
= cbBuf
* sizeof(WCHAR
);
4869 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
4870 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
4872 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
4873 if (pcbNeeded
) needed
= *pcbNeeded
;
4874 /* HeapReAlloc return NULL, when bufferW was NULL */
4875 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
4876 HeapAlloc(GetProcessHeap(), 0, needed
);
4878 /* Try again with the large Buffer */
4879 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
4881 needed
= pcbNeeded
? *pcbNeeded
: 0;
4882 numentries
= pcReturned
? *pcReturned
: 0;
4885 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4886 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4889 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
4890 DWORD entrysize
= 0;
4893 LPPORT_INFO_2W pi2w
;
4894 LPPORT_INFO_2A pi2a
;
4897 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
4899 /* First pass: calculate the size for all Entries */
4900 pi2w
= (LPPORT_INFO_2W
) bufferW
;
4901 pi2a
= (LPPORT_INFO_2A
) pPorts
;
4903 while (index
< numentries
) {
4905 needed
+= entrysize
; /* PORT_INFO_?A */
4906 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
4908 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
4909 NULL
, 0, NULL
, NULL
);
4911 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
4912 NULL
, 0, NULL
, NULL
);
4913 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
4914 NULL
, 0, NULL
, NULL
);
4916 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4917 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
4918 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
4921 /* check for errors and quit on failure */
4922 if (cbBuf
< needed
) {
4923 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4927 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
4928 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
4929 cbBuf
-= len
; /* free Bytes in the user-Buffer */
4930 pi2w
= (LPPORT_INFO_2W
) bufferW
;
4931 pi2a
= (LPPORT_INFO_2A
) pPorts
;
4933 /* Second Pass: Fill the User Buffer (if we have one) */
4934 while ((index
< numentries
) && pPorts
) {
4936 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
4937 pi2a
->pPortName
= ptr
;
4938 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
4939 ptr
, cbBuf
, NULL
, NULL
);
4943 pi2a
->pMonitorName
= ptr
;
4944 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
4945 ptr
, cbBuf
, NULL
, NULL
);
4949 pi2a
->pDescription
= ptr
;
4950 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
4951 ptr
, cbBuf
, NULL
, NULL
);
4955 pi2a
->fPortType
= pi2w
->fPortType
;
4956 pi2a
->Reserved
= 0; /* documented: "must be zero" */
4959 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4960 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
4961 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
4966 if (pcbNeeded
) *pcbNeeded
= needed
;
4967 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
4969 HeapFree(GetProcessHeap(), 0, nameW
);
4970 HeapFree(GetProcessHeap(), 0, bufferW
);
4972 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4973 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
4979 /******************************************************************************
4980 * EnumPortsW (WINSPOOL.@)
4982 * Enumerate available Ports
4985 * pName [I] Servername or NULL (local Computer)
4986 * Level [I] Structure-Level (1 or 2)
4987 * pPorts [O] PTR to Buffer that receives the Result
4988 * cbBuf [I] Size of Buffer at pPorts
4989 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
4990 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
4994 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
4997 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5000 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5001 cbBuf
, pcbNeeded
, pcReturned
);
5003 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5005 /* Level is not checked in win9x */
5006 if (!Level
|| (Level
> 2)) {
5007 WARN("level (%d) is ignored in win9x\n", Level
);
5008 SetLastError(ERROR_INVALID_LEVEL
);
5011 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5012 SetLastError(RPC_X_NULL_REF_POINTER
);
5016 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5019 /******************************************************************************
5020 * GetDefaultPrinterW (WINSPOOL.@)
5023 * This function must read the value from data 'device' of key
5024 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5026 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5030 WCHAR
*buffer
, *ptr
;
5034 SetLastError(ERROR_INVALID_PARAMETER
);
5038 /* make the buffer big enough for the stuff from the profile/registry,
5039 * the content must fit into the local buffer to compute the correct
5040 * size even if the extern buffer is too small or not given.
5041 * (20 for ,driver,port) */
5043 len
= max(100, (insize
+ 20));
5044 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5046 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5048 SetLastError (ERROR_FILE_NOT_FOUND
);
5052 TRACE("%s\n", debugstr_w(buffer
));
5054 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5056 SetLastError(ERROR_INVALID_NAME
);
5062 *namesize
= strlenW(buffer
) + 1;
5063 if(!name
|| (*namesize
> insize
))
5065 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5069 strcpyW(name
, buffer
);
5072 HeapFree( GetProcessHeap(), 0, buffer
);
5077 /******************************************************************************
5078 * GetDefaultPrinterA (WINSPOOL.@)
5080 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5084 WCHAR
*bufferW
= NULL
;
5088 SetLastError(ERROR_INVALID_PARAMETER
);
5092 if(name
&& *namesize
) {
5094 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5097 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5102 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5106 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5109 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5112 HeapFree( GetProcessHeap(), 0, bufferW
);
5117 /******************************************************************************
5118 * SetDefaultPrinterW (WINSPOOL.204)
5120 * Set the Name of the Default Printer
5123 * pszPrinter [I] Name of the Printer or NULL
5130 * When the Parameter is NULL or points to an Empty String and
5131 * a Default Printer was already present, then this Function changes nothing.
5132 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5133 * the First enumerated local Printer is used.
5136 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5139 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5141 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5145 /******************************************************************************
5146 * SetDefaultPrinterA (WINSPOOL.202)
5148 * See SetDefaultPrinterW.
5151 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5154 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5156 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5161 /******************************************************************************
5162 * SetPrinterDataExA (WINSPOOL.@)
5164 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5165 LPCSTR pValueName
, DWORD Type
,
5166 LPBYTE pData
, DWORD cbData
)
5168 HKEY hkeyPrinter
, hkeySubkey
;
5171 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5172 debugstr_a(pValueName
), Type
, pData
, cbData
);
5174 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5178 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5180 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5181 RegCloseKey(hkeyPrinter
);
5184 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5185 RegCloseKey(hkeySubkey
);
5186 RegCloseKey(hkeyPrinter
);
5190 /******************************************************************************
5191 * SetPrinterDataExW (WINSPOOL.@)
5193 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5194 LPCWSTR pValueName
, DWORD Type
,
5195 LPBYTE pData
, DWORD cbData
)
5197 HKEY hkeyPrinter
, hkeySubkey
;
5200 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5201 debugstr_w(pValueName
), Type
, pData
, cbData
);
5203 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5207 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5209 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5210 RegCloseKey(hkeyPrinter
);
5213 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5214 RegCloseKey(hkeySubkey
);
5215 RegCloseKey(hkeyPrinter
);
5219 /******************************************************************************
5220 * SetPrinterDataA (WINSPOOL.@)
5222 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5223 LPBYTE pData
, DWORD cbData
)
5225 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5229 /******************************************************************************
5230 * SetPrinterDataW (WINSPOOL.@)
5232 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5233 LPBYTE pData
, DWORD cbData
)
5235 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5239 /******************************************************************************
5240 * GetPrinterDataExA (WINSPOOL.@)
5242 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5243 LPCSTR pValueName
, LPDWORD pType
,
5244 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5246 HKEY hkeyPrinter
, hkeySubkey
;
5249 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5250 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5253 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5257 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5259 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5260 RegCloseKey(hkeyPrinter
);
5264 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5265 RegCloseKey(hkeySubkey
);
5266 RegCloseKey(hkeyPrinter
);
5270 /******************************************************************************
5271 * GetPrinterDataExW (WINSPOOL.@)
5273 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5274 LPCWSTR pValueName
, LPDWORD pType
,
5275 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5277 HKEY hkeyPrinter
, hkeySubkey
;
5280 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5281 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5284 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5288 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5290 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5291 RegCloseKey(hkeyPrinter
);
5295 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5296 RegCloseKey(hkeySubkey
);
5297 RegCloseKey(hkeyPrinter
);
5301 /******************************************************************************
5302 * GetPrinterDataA (WINSPOOL.@)
5304 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5305 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5307 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5308 pData
, nSize
, pcbNeeded
);
5311 /******************************************************************************
5312 * GetPrinterDataW (WINSPOOL.@)
5314 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5315 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5317 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5318 pData
, nSize
, pcbNeeded
);
5321 /*******************************************************************************
5322 * EnumPrinterDataExW [WINSPOOL.@]
5324 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5325 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5326 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5328 HKEY hkPrinter
, hkSubKey
;
5329 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5330 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5335 PPRINTER_ENUM_VALUESW ppev
;
5337 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5339 if (pKeyName
== NULL
|| *pKeyName
== 0)
5340 return ERROR_INVALID_PARAMETER
;
5342 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5343 if (ret
!= ERROR_SUCCESS
)
5345 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5350 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5351 if (ret
!= ERROR_SUCCESS
)
5353 r
= RegCloseKey (hkPrinter
);
5354 if (r
!= ERROR_SUCCESS
)
5355 WARN ("RegCloseKey returned %i\n", r
);
5356 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5357 debugstr_w (pKeyName
), ret
);
5361 ret
= RegCloseKey (hkPrinter
);
5362 if (ret
!= ERROR_SUCCESS
)
5364 ERR ("RegCloseKey returned %i\n", ret
);
5365 r
= RegCloseKey (hkSubKey
);
5366 if (r
!= ERROR_SUCCESS
)
5367 WARN ("RegCloseKey returned %i\n", r
);
5371 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5372 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5373 if (ret
!= ERROR_SUCCESS
)
5375 r
= RegCloseKey (hkSubKey
);
5376 if (r
!= ERROR_SUCCESS
)
5377 WARN ("RegCloseKey returned %i\n", r
);
5378 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5382 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5383 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5385 if (cValues
== 0) /* empty key */
5387 r
= RegCloseKey (hkSubKey
);
5388 if (r
!= ERROR_SUCCESS
)
5389 WARN ("RegCloseKey returned %i\n", r
);
5390 *pcbEnumValues
= *pnEnumValues
= 0;
5391 return ERROR_SUCCESS
;
5394 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5396 hHeap
= GetProcessHeap ();
5399 ERR ("GetProcessHeap failed\n");
5400 r
= RegCloseKey (hkSubKey
);
5401 if (r
!= ERROR_SUCCESS
)
5402 WARN ("RegCloseKey returned %i\n", r
);
5403 return ERROR_OUTOFMEMORY
;
5406 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5407 if (lpValueName
== NULL
)
5409 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5410 r
= RegCloseKey (hkSubKey
);
5411 if (r
!= ERROR_SUCCESS
)
5412 WARN ("RegCloseKey returned %i\n", r
);
5413 return ERROR_OUTOFMEMORY
;
5416 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5417 if (lpValue
== NULL
)
5419 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5420 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5421 WARN ("HeapFree failed with code %i\n", GetLastError ());
5422 r
= RegCloseKey (hkSubKey
);
5423 if (r
!= ERROR_SUCCESS
)
5424 WARN ("RegCloseKey returned %i\n", r
);
5425 return ERROR_OUTOFMEMORY
;
5428 TRACE ("pass 1: calculating buffer required for all names and values\n");
5430 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5432 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5434 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5436 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5437 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5438 NULL
, NULL
, lpValue
, &cbValueLen
);
5439 if (ret
!= ERROR_SUCCESS
)
5441 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5442 WARN ("HeapFree failed with code %i\n", GetLastError ());
5443 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5444 WARN ("HeapFree failed with code %i\n", GetLastError ());
5445 r
= RegCloseKey (hkSubKey
);
5446 if (r
!= ERROR_SUCCESS
)
5447 WARN ("RegCloseKey returned %i\n", r
);
5448 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5452 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5453 debugstr_w (lpValueName
), dwIndex
,
5454 cbValueNameLen
+ 1, cbValueLen
);
5456 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5457 cbBufSize
+= cbValueLen
;
5460 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5462 *pcbEnumValues
= cbBufSize
;
5463 *pnEnumValues
= cValues
;
5465 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5467 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5468 WARN ("HeapFree failed with code %i\n", GetLastError ());
5469 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5470 WARN ("HeapFree failed with code %i\n", GetLastError ());
5471 r
= RegCloseKey (hkSubKey
);
5472 if (r
!= ERROR_SUCCESS
)
5473 WARN ("RegCloseKey returned %i\n", r
);
5474 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5475 return ERROR_MORE_DATA
;
5478 TRACE ("pass 2: copying all names and values to buffer\n");
5480 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5481 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5483 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5485 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5486 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5487 NULL
, &dwType
, lpValue
, &cbValueLen
);
5488 if (ret
!= ERROR_SUCCESS
)
5490 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5491 WARN ("HeapFree failed with code %i\n", GetLastError ());
5492 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5493 WARN ("HeapFree failed with code %i\n", GetLastError ());
5494 r
= RegCloseKey (hkSubKey
);
5495 if (r
!= ERROR_SUCCESS
)
5496 WARN ("RegCloseKey returned %i\n", r
);
5497 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5501 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5502 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5503 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5504 pEnumValues
+= cbValueNameLen
;
5506 /* return # of *bytes* (including trailing \0), not # of chars */
5507 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5509 ppev
[dwIndex
].dwType
= dwType
;
5511 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5512 ppev
[dwIndex
].pData
= pEnumValues
;
5513 pEnumValues
+= cbValueLen
;
5515 ppev
[dwIndex
].cbData
= cbValueLen
;
5517 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5518 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5521 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5523 ret
= GetLastError ();
5524 ERR ("HeapFree failed with code %i\n", ret
);
5525 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5526 WARN ("HeapFree failed with code %i\n", GetLastError ());
5527 r
= RegCloseKey (hkSubKey
);
5528 if (r
!= ERROR_SUCCESS
)
5529 WARN ("RegCloseKey returned %i\n", r
);
5533 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5535 ret
= GetLastError ();
5536 ERR ("HeapFree failed with code %i\n", ret
);
5537 r
= RegCloseKey (hkSubKey
);
5538 if (r
!= ERROR_SUCCESS
)
5539 WARN ("RegCloseKey returned %i\n", r
);
5543 ret
= RegCloseKey (hkSubKey
);
5544 if (ret
!= ERROR_SUCCESS
)
5546 ERR ("RegCloseKey returned %i\n", ret
);
5550 return ERROR_SUCCESS
;
5553 /*******************************************************************************
5554 * EnumPrinterDataExA [WINSPOOL.@]
5556 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5557 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5558 * what Windows 2000 SP1 does.
5561 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5562 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5563 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5567 DWORD ret
, dwIndex
, dwBufSize
;
5571 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5573 if (pKeyName
== NULL
|| *pKeyName
== 0)
5574 return ERROR_INVALID_PARAMETER
;
5576 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5579 ret
= GetLastError ();
5580 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5584 hHeap
= GetProcessHeap ();
5587 ERR ("GetProcessHeap failed\n");
5588 return ERROR_OUTOFMEMORY
;
5591 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5592 if (pKeyNameW
== NULL
)
5594 ERR ("Failed to allocate %i bytes from process heap\n",
5595 (LONG
)(len
* sizeof (WCHAR
)));
5596 return ERROR_OUTOFMEMORY
;
5599 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5601 ret
= GetLastError ();
5602 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5603 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5604 WARN ("HeapFree failed with code %i\n", GetLastError ());
5608 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5609 pcbEnumValues
, pnEnumValues
);
5610 if (ret
!= ERROR_SUCCESS
)
5612 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5613 WARN ("HeapFree failed with code %i\n", GetLastError ());
5614 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5618 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5620 ret
= GetLastError ();
5621 ERR ("HeapFree failed with code %i\n", ret
);
5625 if (*pnEnumValues
== 0) /* empty key */
5626 return ERROR_SUCCESS
;
5629 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5631 PPRINTER_ENUM_VALUESW ppev
=
5632 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5634 if (dwBufSize
< ppev
->cbValueName
)
5635 dwBufSize
= ppev
->cbValueName
;
5637 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5638 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5639 dwBufSize
= ppev
->cbData
;
5642 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5644 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5645 if (pBuffer
== NULL
)
5647 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5648 return ERROR_OUTOFMEMORY
;
5651 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5653 PPRINTER_ENUM_VALUESW ppev
=
5654 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5656 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5657 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5661 ret
= GetLastError ();
5662 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5663 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5664 WARN ("HeapFree failed with code %i\n", GetLastError ());
5668 memcpy (ppev
->pValueName
, pBuffer
, len
);
5670 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5672 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5673 ppev
->dwType
!= REG_MULTI_SZ
)
5676 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5677 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5680 ret
= GetLastError ();
5681 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5682 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5683 WARN ("HeapFree failed with code %i\n", GetLastError ());
5687 memcpy (ppev
->pData
, pBuffer
, len
);
5689 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5690 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5693 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5695 ret
= GetLastError ();
5696 ERR ("HeapFree failed with code %i\n", ret
);
5700 return ERROR_SUCCESS
;
5703 /******************************************************************************
5704 * AbortPrinter (WINSPOOL.@)
5706 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5708 FIXME("(%p), stub!\n", hPrinter
);
5712 /******************************************************************************
5713 * AddPortA (WINSPOOL.@)
5718 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5720 LPWSTR nameW
= NULL
;
5721 LPWSTR monitorW
= NULL
;
5725 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
5728 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5729 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5730 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5734 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5735 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5736 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5738 res
= AddPortW(nameW
, hWnd
, monitorW
);
5739 HeapFree(GetProcessHeap(), 0, nameW
);
5740 HeapFree(GetProcessHeap(), 0, monitorW
);
5744 /******************************************************************************
5745 * AddPortW (WINSPOOL.@)
5747 * Add a Port for a specific Monitor
5750 * pName [I] Servername or NULL (local Computer)
5751 * hWnd [I] Handle to parent Window for the Dialog-Box
5752 * pMonitorName [I] Name of the Monitor that manage the Port
5759 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
5761 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
5763 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5765 if (!pMonitorName
) {
5766 SetLastError(RPC_X_NULL_REF_POINTER
);
5770 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
5773 /******************************************************************************
5774 * AddPortExA (WINSPOOL.@)
5779 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
5782 PORT_INFO_2A
* pi2A
;
5783 LPWSTR nameW
= NULL
;
5784 LPWSTR monitorW
= NULL
;
5788 pi2A
= (PORT_INFO_2A
*) pBuffer
;
5790 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
5791 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
5793 if ((level
< 1) || (level
> 2)) {
5794 SetLastError(ERROR_INVALID_LEVEL
);
5799 SetLastError(ERROR_INVALID_PARAMETER
);
5804 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5805 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5806 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5810 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5811 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5812 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5815 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
5817 if (pi2A
->pPortName
) {
5818 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
5819 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5820 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
5824 if (pi2A
->pMonitorName
) {
5825 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
5826 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5827 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
5830 if (pi2A
->pDescription
) {
5831 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
5832 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5833 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
5835 pi2W
.fPortType
= pi2A
->fPortType
;
5836 pi2W
.Reserved
= pi2A
->Reserved
;
5839 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
5841 HeapFree(GetProcessHeap(), 0, nameW
);
5842 HeapFree(GetProcessHeap(), 0, monitorW
);
5843 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
5844 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
5845 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
5850 /******************************************************************************
5851 * AddPortExW (WINSPOOL.@)
5853 * Add a Port for a specific Monitor, without presenting a user interface
5856 * pName [I] Servername or NULL (local Computer)
5857 * level [I] Structure-Level (1 or 2) for pBuffer
5858 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5859 * pMonitorName [I] Name of the Monitor that manage the Port
5866 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
5870 pi2
= (PORT_INFO_2W
*) pBuffer
;
5872 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
5873 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
5874 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
5875 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
5877 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5879 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
5880 SetLastError(ERROR_INVALID_PARAMETER
);
5884 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
5887 /******************************************************************************
5888 * AddPrinterConnectionA (WINSPOOL.@)
5890 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
5892 FIXME("%s\n", debugstr_a(pName
));
5896 /******************************************************************************
5897 * AddPrinterConnectionW (WINSPOOL.@)
5899 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
5901 FIXME("%s\n", debugstr_w(pName
));
5905 /******************************************************************************
5906 * AddPrinterDriverExW (WINSPOOL.@)
5908 * Install a Printer Driver with the Option to upgrade / downgrade the Files
5911 * pName [I] Servername or NULL (local Computer)
5912 * level [I] Level for the supplied DRIVER_INFO_*W struct
5913 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5914 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
5921 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
5923 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
5925 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5927 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
5928 SetLastError(ERROR_INVALID_LEVEL
);
5933 SetLastError(ERROR_INVALID_PARAMETER
);
5937 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
5940 /******************************************************************************
5941 * AddPrinterDriverExA (WINSPOOL.@)
5943 * See AddPrinterDriverExW.
5946 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
5948 DRIVER_INFO_8A
*diA
;
5950 LPWSTR nameW
= NULL
;
5955 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
5957 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
5958 ZeroMemory(&diW
, sizeof(diW
));
5960 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
5961 SetLastError(ERROR_INVALID_LEVEL
);
5966 SetLastError(ERROR_INVALID_PARAMETER
);
5970 /* convert servername to unicode */
5972 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5973 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5974 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5978 diW
.cVersion
= diA
->cVersion
;
5981 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
5982 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5983 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
5986 if (diA
->pEnvironment
) {
5987 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
5988 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5989 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
5992 if (diA
->pDriverPath
) {
5993 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
5994 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5995 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
5998 if (diA
->pDataFile
) {
5999 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6000 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6001 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6004 if (diA
->pConfigFile
) {
6005 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6006 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6007 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6010 if ((Level
> 2) && diA
->pDependentFiles
) {
6011 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6012 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6013 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6014 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6017 if ((Level
> 2) && diA
->pMonitorName
) {
6018 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6019 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6020 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6023 if ((Level
> 3) && diA
->pDefaultDataType
) {
6024 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6025 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6026 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6029 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6030 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6031 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6032 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6033 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6036 if ((Level
> 5) && diA
->pszMfgName
) {
6037 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6038 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6039 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6042 if ((Level
> 5) && diA
->pszOEMUrl
) {
6043 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6044 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6045 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6048 if ((Level
> 5) && diA
->pszHardwareID
) {
6049 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6050 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6051 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6054 if ((Level
> 5) && diA
->pszProvider
) {
6055 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6056 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6057 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6061 FIXME("level %u is incomplete\n", Level
);
6064 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6065 TRACE("got %u with %u\n", res
, GetLastError());
6066 HeapFree(GetProcessHeap(), 0, nameW
);
6067 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6068 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6069 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6070 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6071 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6072 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6073 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6074 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6075 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6076 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6077 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6078 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6079 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6081 TRACE("=> %u with %u\n", res
, GetLastError());
6085 /******************************************************************************
6086 * ConfigurePortA (WINSPOOL.@)
6088 * See ConfigurePortW.
6091 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6093 LPWSTR nameW
= NULL
;
6094 LPWSTR portW
= NULL
;
6098 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6100 /* convert servername to unicode */
6102 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6103 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6104 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6107 /* convert portname to unicode */
6109 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6110 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6111 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6114 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6115 HeapFree(GetProcessHeap(), 0, nameW
);
6116 HeapFree(GetProcessHeap(), 0, portW
);
6120 /******************************************************************************
6121 * ConfigurePortW (WINSPOOL.@)
6123 * Display the Configuration-Dialog for a specific Port
6126 * pName [I] Servername or NULL (local Computer)
6127 * hWnd [I] Handle to parent Window for the Dialog-Box
6128 * pPortName [I] Name of the Port, that should be configured
6135 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6138 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6140 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6143 SetLastError(RPC_X_NULL_REF_POINTER
);
6147 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6150 /******************************************************************************
6151 * ConnectToPrinterDlg (WINSPOOL.@)
6153 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6155 FIXME("%p %x\n", hWnd
, Flags
);
6159 /******************************************************************************
6160 * DeletePrinterConnectionA (WINSPOOL.@)
6162 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6164 FIXME("%s\n", debugstr_a(pName
));
6168 /******************************************************************************
6169 * DeletePrinterConnectionW (WINSPOOL.@)
6171 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6173 FIXME("%s\n", debugstr_w(pName
));
6177 /******************************************************************************
6178 * DeletePrinterDriverExW (WINSPOOL.@)
6180 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6181 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6186 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6187 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6189 if(pName
&& pName
[0])
6191 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6192 SetLastError(ERROR_INVALID_PARAMETER
);
6198 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6199 SetLastError(ERROR_INVALID_PARAMETER
);
6203 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6207 ERR("Can't open drivers key\n");
6211 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6214 RegCloseKey(hkey_drivers
);
6219 /******************************************************************************
6220 * DeletePrinterDriverExA (WINSPOOL.@)
6222 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6223 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6225 UNICODE_STRING NameW
, EnvW
, DriverW
;
6228 asciitounicode(&NameW
, pName
);
6229 asciitounicode(&EnvW
, pEnvironment
);
6230 asciitounicode(&DriverW
, pDriverName
);
6232 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6234 RtlFreeUnicodeString(&DriverW
);
6235 RtlFreeUnicodeString(&EnvW
);
6236 RtlFreeUnicodeString(&NameW
);
6241 /******************************************************************************
6242 * DeletePrinterDataExW (WINSPOOL.@)
6244 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6247 FIXME("%p %s %s\n", hPrinter
,
6248 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6249 return ERROR_INVALID_PARAMETER
;
6252 /******************************************************************************
6253 * DeletePrinterDataExA (WINSPOOL.@)
6255 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6258 FIXME("%p %s %s\n", hPrinter
,
6259 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6260 return ERROR_INVALID_PARAMETER
;
6263 /******************************************************************************
6264 * DeletePrintProcessorA (WINSPOOL.@)
6266 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6268 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6269 debugstr_a(pPrintProcessorName
));
6273 /******************************************************************************
6274 * DeletePrintProcessorW (WINSPOOL.@)
6276 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6278 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6279 debugstr_w(pPrintProcessorName
));
6283 /******************************************************************************
6284 * DeletePrintProvidorA (WINSPOOL.@)
6286 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6288 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6289 debugstr_a(pPrintProviderName
));
6293 /******************************************************************************
6294 * DeletePrintProvidorW (WINSPOOL.@)
6296 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6298 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6299 debugstr_w(pPrintProviderName
));
6303 /******************************************************************************
6304 * EnumFormsA (WINSPOOL.@)
6306 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6307 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6309 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6310 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6314 /******************************************************************************
6315 * EnumFormsW (WINSPOOL.@)
6317 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6318 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6320 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6321 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6325 /*****************************************************************************
6326 * EnumMonitorsA [WINSPOOL.@]
6328 * See EnumMonitorsW.
6331 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6332 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6335 LPBYTE bufferW
= NULL
;
6336 LPWSTR nameW
= NULL
;
6338 DWORD numentries
= 0;
6341 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6342 cbBuf
, pcbNeeded
, pcReturned
);
6344 /* convert servername to unicode */
6346 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6347 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6348 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6350 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6351 needed
= cbBuf
* sizeof(WCHAR
);
6352 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6353 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6355 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6356 if (pcbNeeded
) needed
= *pcbNeeded
;
6357 /* HeapReAlloc return NULL, when bufferW was NULL */
6358 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6359 HeapAlloc(GetProcessHeap(), 0, needed
);
6361 /* Try again with the large Buffer */
6362 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6364 numentries
= pcReturned
? *pcReturned
: 0;
6367 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6368 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6371 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6372 DWORD entrysize
= 0;
6375 LPMONITOR_INFO_2W mi2w
;
6376 LPMONITOR_INFO_2A mi2a
;
6378 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6379 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6381 /* First pass: calculate the size for all Entries */
6382 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6383 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6385 while (index
< numentries
) {
6387 needed
+= entrysize
; /* MONITOR_INFO_?A */
6388 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6390 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6391 NULL
, 0, NULL
, NULL
);
6393 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6394 NULL
, 0, NULL
, NULL
);
6395 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6396 NULL
, 0, NULL
, NULL
);
6398 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6399 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6400 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6403 /* check for errors and quit on failure */
6404 if (cbBuf
< needed
) {
6405 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6409 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6410 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6411 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6412 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6413 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6415 /* Second Pass: Fill the User Buffer (if we have one) */
6416 while ((index
< numentries
) && pMonitors
) {
6418 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6420 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6421 ptr
, cbBuf
, NULL
, NULL
);
6425 mi2a
->pEnvironment
= ptr
;
6426 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6427 ptr
, cbBuf
, NULL
, NULL
);
6431 mi2a
->pDLLName
= ptr
;
6432 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6433 ptr
, cbBuf
, NULL
, NULL
);
6437 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6438 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6439 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6443 if (pcbNeeded
) *pcbNeeded
= needed
;
6444 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6446 HeapFree(GetProcessHeap(), 0, nameW
);
6447 HeapFree(GetProcessHeap(), 0, bufferW
);
6449 TRACE("returning %d with %d (%d byte for %d entries)\n",
6450 (res
), GetLastError(), needed
, numentries
);
6456 /*****************************************************************************
6457 * EnumMonitorsW [WINSPOOL.@]
6459 * Enumerate available Port-Monitors
6462 * pName [I] Servername or NULL (local Computer)
6463 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6464 * pMonitors [O] PTR to Buffer that receives the Result
6465 * cbBuf [I] Size of Buffer at pMonitors
6466 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6467 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6471 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6474 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6475 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6478 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6479 cbBuf
, pcbNeeded
, pcReturned
);
6481 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6483 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6484 SetLastError(RPC_X_NULL_REF_POINTER
);
6488 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6491 /******************************************************************************
6492 * SpoolerInit (WINSPOOL.@)
6494 * Initialize the Spooler
6501 * The function fails on windows, when the spooler service is not running
6504 BOOL WINAPI
SpoolerInit(void)
6507 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6511 /******************************************************************************
6512 * XcvDataW (WINSPOOL.@)
6514 * Execute commands in the Printmonitor DLL
6517 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6518 * pszDataName [i] Name of the command to execute
6519 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6520 * cbInputData [i] Size in Bytes of Buffer at pInputData
6521 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6522 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6523 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6524 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6531 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6532 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6534 * Minimal List of commands, that a Printmonitor DLL should support:
6536 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6537 *| "AddPort" : Add a Port
6538 *| "DeletePort": Delete a Port
6540 * Many Printmonitors support additional commands. Examples for localspl.dll:
6541 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6542 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6545 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6546 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6547 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6549 opened_printer_t
*printer
;
6551 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6552 pInputData
, cbInputData
, pOutputData
,
6553 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6555 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6557 printer
= get_opened_printer(hXcv
);
6558 if (!printer
|| (!printer
->backend_printer
)) {
6559 SetLastError(ERROR_INVALID_HANDLE
);
6563 if (!pcbOutputNeeded
) {
6564 SetLastError(ERROR_INVALID_PARAMETER
);
6568 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6569 SetLastError(RPC_X_NULL_REF_POINTER
);
6573 *pcbOutputNeeded
= 0;
6575 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6576 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6580 /*****************************************************************************
6581 * EnumPrinterDataA [WINSPOOL.@]
6584 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6585 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6586 DWORD cbData
, LPDWORD pcbData
)
6588 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6589 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6590 return ERROR_NO_MORE_ITEMS
;
6593 /*****************************************************************************
6594 * EnumPrinterDataW [WINSPOOL.@]
6597 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6598 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6599 DWORD cbData
, LPDWORD pcbData
)
6601 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6602 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6603 return ERROR_NO_MORE_ITEMS
;
6606 /*****************************************************************************
6607 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6610 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6611 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6612 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6614 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6615 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6616 pcbNeeded
, pcReturned
);
6620 /*****************************************************************************
6621 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6624 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6625 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6626 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6628 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6629 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6630 pcbNeeded
, pcReturned
);
6634 /*****************************************************************************
6635 * EnumPrintProcessorsA [WINSPOOL.@]
6638 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6639 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6641 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
6642 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
6646 /*****************************************************************************
6647 * EnumPrintProcessorsW [WINSPOOL.@]
6650 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6651 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
6653 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6654 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
6655 cbBuf
, pcbNeeded
, pcbReturned
);
6659 /*****************************************************************************
6660 * ExtDeviceMode [WINSPOOL.@]
6663 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6664 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6667 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6668 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6669 debugstr_a(pProfile
), fMode
);
6673 /*****************************************************************************
6674 * FindClosePrinterChangeNotification [WINSPOOL.@]
6677 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6679 FIXME("Stub: %p\n", hChange
);
6683 /*****************************************************************************
6684 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6687 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6688 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6690 FIXME("Stub: %p %x %x %p\n",
6691 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6692 return INVALID_HANDLE_VALUE
;
6695 /*****************************************************************************
6696 * FindNextPrinterChangeNotification [WINSPOOL.@]
6699 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6700 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6702 FIXME("Stub: %p %p %p %p\n",
6703 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
6707 /*****************************************************************************
6708 * FreePrinterNotifyInfo [WINSPOOL.@]
6711 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
6713 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
6717 /*****************************************************************************
6720 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6721 * ansi depending on the unicode parameter.
6723 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
6733 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
6736 memcpy(ptr
, str
, *size
);
6743 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
6746 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
6753 /*****************************************************************************
6756 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
6757 LPDWORD pcbNeeded
, BOOL unicode
)
6759 DWORD size
, left
= cbBuf
;
6760 BOOL space
= (cbBuf
> 0);
6767 ji1
->JobId
= job
->job_id
;
6770 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6771 if(space
&& size
<= left
)
6773 ji1
->pDocument
= (LPWSTR
)ptr
;
6784 /*****************************************************************************
6787 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
6788 LPDWORD pcbNeeded
, BOOL unicode
)
6790 DWORD size
, left
= cbBuf
;
6791 BOOL space
= (cbBuf
> 0);
6798 ji2
->JobId
= job
->job_id
;
6801 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
6802 if(space
&& size
<= left
)
6804 ji2
->pDocument
= (LPWSTR
)ptr
;
6815 /*****************************************************************************
6818 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
6819 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
6822 DWORD needed
= 0, size
;
6826 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
6828 EnterCriticalSection(&printer_handles_cs
);
6829 job
= get_job(hPrinter
, JobId
);
6836 size
= sizeof(JOB_INFO_1W
);
6841 memset(pJob
, 0, size
);
6845 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
6850 size
= sizeof(JOB_INFO_2W
);
6855 memset(pJob
, 0, size
);
6859 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
6864 size
= sizeof(JOB_INFO_3
);
6868 memset(pJob
, 0, size
);
6877 SetLastError(ERROR_INVALID_LEVEL
);
6881 *pcbNeeded
= needed
;
6883 LeaveCriticalSection(&printer_handles_cs
);
6887 /*****************************************************************************
6888 * GetJobA [WINSPOOL.@]
6891 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
6892 DWORD cbBuf
, LPDWORD pcbNeeded
)
6894 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
6897 /*****************************************************************************
6898 * GetJobW [WINSPOOL.@]
6901 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
6902 DWORD cbBuf
, LPDWORD pcbNeeded
)
6904 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
6907 /*****************************************************************************
6910 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
6912 char *unixname
, *queue
, *cmd
;
6913 char fmt
[] = "lpr -P%s %s";
6917 if(!(unixname
= wine_get_unix_file_name(filename
)))
6920 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
6921 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
6922 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
6924 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
6925 sprintf(cmd
, fmt
, queue
, unixname
);
6927 TRACE("printing with: %s\n", cmd
);
6930 HeapFree(GetProcessHeap(), 0, cmd
);
6931 HeapFree(GetProcessHeap(), 0, queue
);
6932 HeapFree(GetProcessHeap(), 0, unixname
);
6936 /*****************************************************************************
6939 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
6941 #ifdef SONAME_LIBCUPS
6944 char *unixname
, *queue
, *unix_doc_title
;
6948 if(!(unixname
= wine_get_unix_file_name(filename
)))
6951 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
6952 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
6953 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
6955 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
6956 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
6957 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
6959 TRACE("printing via cups\n");
6960 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
6961 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
6962 HeapFree(GetProcessHeap(), 0, queue
);
6963 HeapFree(GetProcessHeap(), 0, unixname
);
6969 return schedule_lpr(printer_name
, filename
);
6973 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
6980 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
6984 if(HIWORD(wparam
) == BN_CLICKED
)
6986 if(LOWORD(wparam
) == IDOK
)
6989 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
6992 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
6993 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
6995 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
6997 WCHAR caption
[200], message
[200];
7000 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7001 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7002 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7003 if(mb_ret
== IDCANCEL
)
7005 HeapFree(GetProcessHeap(), 0, filename
);
7009 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7010 if(hf
== INVALID_HANDLE_VALUE
)
7012 WCHAR caption
[200], message
[200];
7014 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7015 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7016 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7017 HeapFree(GetProcessHeap(), 0, filename
);
7021 DeleteFileW(filename
);
7022 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7024 EndDialog(hwnd
, IDOK
);
7027 if(LOWORD(wparam
) == IDCANCEL
)
7029 EndDialog(hwnd
, IDCANCEL
);
7038 /*****************************************************************************
7041 static BOOL
get_filename(LPWSTR
*filename
)
7043 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7044 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7047 /*****************************************************************************
7050 static BOOL
schedule_file(LPCWSTR filename
)
7052 LPWSTR output
= NULL
;
7054 if(get_filename(&output
))
7057 TRACE("copy to %s\n", debugstr_w(output
));
7058 r
= CopyFileW(filename
, output
, FALSE
);
7059 HeapFree(GetProcessHeap(), 0, output
);
7065 /*****************************************************************************
7068 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7071 char *unixname
, *cmdA
;
7073 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7077 if(!(unixname
= wine_get_unix_file_name(filename
)))
7080 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7081 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7082 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7084 TRACE("printing with: %s\n", cmdA
);
7086 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7091 ERR("pipe() failed!\n");
7101 /* reset signals that we previously set to SIG_IGN */
7102 signal(SIGPIPE
, SIG_DFL
);
7103 signal(SIGCHLD
, SIG_DFL
);
7105 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7109 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7110 write(fds
[1], buf
, no_read
);
7115 if(file_fd
!= -1) close(file_fd
);
7116 if(fds
[0] != -1) close(fds
[0]);
7117 if(fds
[1] != -1) close(fds
[1]);
7119 HeapFree(GetProcessHeap(), 0, cmdA
);
7120 HeapFree(GetProcessHeap(), 0, unixname
);
7127 /*****************************************************************************
7130 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7132 int in_fd
, out_fd
, no_read
;
7135 char *unixname
, *outputA
;
7138 if(!(unixname
= wine_get_unix_file_name(filename
)))
7141 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7142 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7143 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7145 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7146 in_fd
= open(unixname
, O_RDONLY
);
7147 if(out_fd
== -1 || in_fd
== -1)
7150 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7151 write(out_fd
, buf
, no_read
);
7155 if(in_fd
!= -1) close(in_fd
);
7156 if(out_fd
!= -1) close(out_fd
);
7157 HeapFree(GetProcessHeap(), 0, outputA
);
7158 HeapFree(GetProcessHeap(), 0, unixname
);
7162 /*****************************************************************************
7163 * ScheduleJob [WINSPOOL.@]
7166 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7168 opened_printer_t
*printer
;
7170 struct list
*cursor
, *cursor2
;
7172 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7173 EnterCriticalSection(&printer_handles_cs
);
7174 printer
= get_opened_printer(hPrinter
);
7178 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7180 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7183 if(job
->job_id
!= dwJobID
) continue;
7185 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7186 if(hf
!= INVALID_HANDLE_VALUE
)
7188 PRINTER_INFO_5W
*pi5
;
7192 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7193 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7195 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7196 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7197 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7198 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7199 debugstr_w(pi5
->pPortName
));
7203 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7204 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7206 DWORD type
, count
= sizeof(output
);
7207 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7210 if(output
[0] == '|')
7212 ret
= schedule_pipe(output
+ 1, job
->filename
);
7216 ret
= schedule_unixfile(output
, job
->filename
);
7218 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7220 ret
= schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7222 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7224 ret
= schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7226 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7228 ret
= schedule_file(job
->filename
);
7232 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7234 HeapFree(GetProcessHeap(), 0, pi5
);
7236 DeleteFileW(job
->filename
);
7238 list_remove(cursor
);
7239 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7240 HeapFree(GetProcessHeap(), 0, job
->filename
);
7241 HeapFree(GetProcessHeap(), 0, job
);
7245 LeaveCriticalSection(&printer_handles_cs
);
7249 /*****************************************************************************
7250 * StartDocDlgA [WINSPOOL.@]
7252 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7254 UNICODE_STRING usBuffer
;
7257 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7260 docW
.cbSize
= sizeof(docW
);
7261 if (doc
->lpszDocName
)
7263 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7264 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7266 if (doc
->lpszOutput
)
7268 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7269 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7271 if (doc
->lpszDatatype
)
7273 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7274 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7276 docW
.fwType
= doc
->fwType
;
7278 retW
= StartDocDlgW(hPrinter
, &docW
);
7282 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7283 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7284 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7285 HeapFree(GetProcessHeap(), 0, retW
);
7288 HeapFree(GetProcessHeap(), 0, datatypeW
);
7289 HeapFree(GetProcessHeap(), 0, outputW
);
7290 HeapFree(GetProcessHeap(), 0, docnameW
);
7295 /*****************************************************************************
7296 * StartDocDlgW [WINSPOOL.@]
7298 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7299 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7300 * port is "FILE:". Also returns the full path if passed a relative path.
7302 * The caller should free the returned string from the process heap.
7304 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7309 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7311 PRINTER_INFO_5W
*pi5
;
7312 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7313 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7315 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7316 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7317 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7319 HeapFree(GetProcessHeap(), 0, pi5
);
7322 HeapFree(GetProcessHeap(), 0, pi5
);
7325 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7329 if (get_filename(&name
))
7331 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7333 HeapFree(GetProcessHeap(), 0, name
);
7336 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7337 GetFullPathNameW(name
, len
, ret
, NULL
);
7338 HeapFree(GetProcessHeap(), 0, name
);
7343 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7346 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7347 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7349 attr
= GetFileAttributesW(ret
);
7350 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7352 HeapFree(GetProcessHeap(), 0, ret
);