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-2010 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
;
101 WCHAR
*document_title
;
109 LPCWSTR versionregpath
;
110 LPCWSTR versionsubdir
;
113 /* ############################### */
115 static opened_printer_t
**printer_handles
;
116 static UINT nb_printer_handles
;
117 static LONG next_job_id
= 1;
119 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
120 WORD fwCapability
, LPSTR lpszOutput
,
122 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
123 LPSTR lpszDevice
, LPSTR lpszPort
,
124 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
127 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
128 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129 'c','o','n','t','r','o','l','\\',
130 'P','r','i','n','t','\\',
131 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
132 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
134 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
135 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
136 'C','o','n','t','r','o','l','\\',
137 'P','r','i','n','t','\\',
138 'P','r','i','n','t','e','r','s',0};
140 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
142 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
143 'M','i','c','r','o','s','o','f','t','\\',
144 'W','i','n','d','o','w','s',' ','N','T','\\',
145 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
146 'W','i','n','d','o','w','s',0};
148 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
149 'M','i','c','r','o','s','o','f','t','\\',
150 'W','i','n','d','o','w','s',' ','N','T','\\',
151 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
152 'D','e','v','i','c','e','s',0};
154 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
155 'M','i','c','r','o','s','o','f','t','\\',
156 'W','i','n','d','o','w','s',' ','N','T','\\',
157 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
158 'P','o','r','t','s',0};
160 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
161 'M','i','c','r','o','s','o','f','t','\\',
162 'W','i','n','d','o','w','s',' ','N','T','\\',
163 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
164 'P','r','i','n','t','e','r','P','o','r','t','s',0};
166 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
167 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
168 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
169 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
170 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
171 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
172 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
173 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
174 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
175 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
176 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
178 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
179 static const WCHAR backslashW
[] = {'\\',0};
180 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
181 'i','o','n',' ','F','i','l','e',0};
182 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
183 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
184 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
185 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
186 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
187 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
188 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
189 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
190 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
191 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
192 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
193 static const WCHAR NameW
[] = {'N','a','m','e',0};
194 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
195 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
196 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
197 static const WCHAR PortW
[] = {'P','o','r','t',0};
198 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
199 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
200 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
201 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
202 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
203 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
204 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
205 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
206 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
207 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
208 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
209 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
210 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
211 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
212 static const WCHAR emptyStringW
[] = {0};
214 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
216 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
217 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
218 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
220 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
221 'D','o','c','u','m','e','n','t',0};
223 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
224 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
225 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
226 0, sizeof(DRIVER_INFO_8W
)};
229 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
230 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
231 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
232 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
233 sizeof(PRINTER_INFO_9W
)};
235 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
236 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
237 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
239 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
241 /******************************************************************
242 * validate the user-supplied printing-environment [internal]
245 * env [I] PTR to Environment-String or NULL
249 * Success: PTR to printenv_t
252 * An empty string is handled the same way as NULL.
253 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
257 static const printenv_t
* validate_envW(LPCWSTR env
)
259 const printenv_t
*result
= NULL
;
262 TRACE("testing %s\n", debugstr_w(env
));
265 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
267 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
269 result
= all_printenv
[i
];
274 if (result
== NULL
) {
275 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
276 SetLastError(ERROR_INVALID_ENVIRONMENT
);
278 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
282 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
284 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
290 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
291 if passed a NULL string. This returns NULLs to the result.
293 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
297 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
298 return usBufferPtr
->Buffer
;
300 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
304 static LPWSTR
strdupW(LPCWSTR p
)
310 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
311 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
316 static LPSTR
strdupWtoA( LPCWSTR str
)
321 if (!str
) return NULL
;
322 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
323 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
324 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
328 /******************************************************************
329 * verify, that the filename is a local file
332 static inline BOOL
is_local_file(LPWSTR name
)
334 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
337 /******************************************************************
338 * Return the number of bytes for an multi_sz string.
339 * The result includes all \0s
340 * (specifically the extra \0, that is needed as multi_sz terminator).
343 static int multi_sz_lenW(const WCHAR
*str
)
345 const WCHAR
*ptr
= str
;
349 ptr
+= lstrlenW(ptr
) + 1;
352 return (ptr
- str
+ 1) * sizeof(WCHAR
);
355 /* ################################ */
357 static int multi_sz_lenA(const char *str
)
359 const char *ptr
= str
;
363 ptr
+= lstrlenA(ptr
) + 1;
366 return ptr
- str
+ 1;
370 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
373 /* If forcing, or no profile string entry for device yet, set the entry
375 * The always change entry if not WINEPS yet is discussable.
378 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
380 !strstr(qbuf
,"WINEPS.DRV")
382 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
385 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
386 WriteProfileStringA("windows","device",buf
);
387 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
388 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
391 HeapFree(GetProcessHeap(),0,buf
);
395 static BOOL
add_printer_driver(const char *name
)
399 static char driver_9x
[] = "wineps16.drv",
400 driver_nt
[] = "wineps.drv",
401 env_9x
[] = "Windows 4.0",
402 env_nt
[] = "Windows NT x86",
403 data_file
[] = "generic.ppd",
404 default_data_type
[] = "RAW";
406 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
408 di3a
.pName
= (char *)name
;
409 di3a
.pEnvironment
= env_nt
;
410 di3a
.pDriverPath
= driver_nt
;
411 di3a
.pDataFile
= data_file
;
412 di3a
.pConfigFile
= driver_nt
;
413 di3a
.pDefaultDataType
= default_data_type
;
415 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
416 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
419 di3a
.pEnvironment
= env_9x
;
420 di3a
.pDriverPath
= driver_9x
;
421 di3a
.pConfigFile
= driver_9x
;
422 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
423 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
428 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
429 debugstr_a(di3a
.pEnvironment
), GetLastError());
433 #ifdef SONAME_LIBCUPS
434 static typeof(cupsFreeDests
) *pcupsFreeDests
;
435 static typeof(cupsGetDests
) *pcupsGetDests
;
436 static typeof(cupsGetPPD
) *pcupsGetPPD
;
437 static typeof(cupsPrintFile
) *pcupsPrintFile
;
438 static void *cupshandle
;
440 static BOOL
CUPS_LoadPrinters(void)
443 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
445 PRINTER_INFO_2A pinfo2a
;
447 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
450 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
452 TRACE("%s\n", loaderror
);
455 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
458 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
459 if (!p##x) return FALSE;
461 DYNCUPS(cupsFreeDests
);
463 DYNCUPS(cupsGetDests
);
464 DYNCUPS(cupsPrintFile
);
467 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
469 ERR("Can't create Printers key\n");
473 nrofdests
= pcupsGetDests(&dests
);
474 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
475 for (i
=0;i
<nrofdests
;i
++) {
476 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
477 port
= HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests
[i
].name
)+1);
478 sprintf(port
,"LPR:%s", dests
[i
].name
);
479 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
480 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
481 sprintf(devline
, "WINEPS.DRV,%s", port
);
482 WriteProfileStringA("devices", dests
[i
].name
, devline
);
483 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
484 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
488 lstrcatA(devline
, ",15,45");
489 WriteProfileStringA("PrinterPorts", dests
[i
].name
, devline
);
490 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
491 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
495 HeapFree(GetProcessHeap(), 0, devline
);
497 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
498 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
499 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
501 TRACE("Printer already exists\n");
502 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
503 RegCloseKey(hkeyPrinter
);
505 static CHAR data_type
[] = "RAW",
506 print_proc
[] = "WinPrint",
507 comment
[] = "WINEPS Printer using CUPS",
508 location
[] = "<physical location of printer>",
509 params
[] = "<parameters?>",
510 share_name
[] = "<share name?>",
511 sep_file
[] = "<sep file?>";
513 add_printer_driver(dests
[i
].name
);
515 memset(&pinfo2a
,0,sizeof(pinfo2a
));
516 pinfo2a
.pPrinterName
= dests
[i
].name
;
517 pinfo2a
.pDatatype
= data_type
;
518 pinfo2a
.pPrintProcessor
= print_proc
;
519 pinfo2a
.pDriverName
= dests
[i
].name
;
520 pinfo2a
.pComment
= comment
;
521 pinfo2a
.pLocation
= location
;
522 pinfo2a
.pPortName
= port
;
523 pinfo2a
.pParameters
= params
;
524 pinfo2a
.pShareName
= share_name
;
525 pinfo2a
.pSepFile
= sep_file
;
527 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
528 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
529 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
532 HeapFree(GetProcessHeap(),0,port
);
535 if (dests
[i
].is_default
) {
536 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
540 if (hadprinter
& !haddefault
)
541 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
542 pcupsFreeDests(nrofdests
, dests
);
543 RegCloseKey(hkeyPrinters
);
549 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
550 PRINTER_INFO_2A pinfo2a
;
551 char *e
,*s
,*name
,*prettyname
,*devname
;
552 BOOL ret
= FALSE
, set_default
= FALSE
;
553 char *port
= NULL
, *devline
,*env_default
;
554 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
556 while (isspace(*pent
)) pent
++;
557 s
= strchr(pent
,':');
559 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
567 TRACE("name=%s entry=%s\n",name
, pent
);
569 if(ispunct(*name
)) { /* a tc entry, not a real printer */
570 TRACE("skipping tc entry\n");
574 if(strstr(pent
,":server")) { /* server only version so skip */
575 TRACE("skipping server entry\n");
579 /* Determine whether this is a postscript printer. */
582 env_default
= getenv("PRINTER");
584 /* Get longest name, usually the one at the right for later display. */
585 while((s
=strchr(prettyname
,'|'))) {
588 while(isspace(*--e
)) *e
= '\0';
589 TRACE("\t%s\n", debugstr_a(prettyname
));
590 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
591 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
594 e
= prettyname
+ strlen(prettyname
);
595 while(isspace(*--e
)) *e
= '\0';
596 TRACE("\t%s\n", debugstr_a(prettyname
));
597 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
599 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
600 * if it is too long, we use it as comment below. */
601 devname
= prettyname
;
602 if (strlen(devname
)>=CCHDEVICENAME
-1)
604 if (strlen(devname
)>=CCHDEVICENAME
-1) {
609 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
610 sprintf(port
,"LPR:%s",name
);
612 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
613 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
614 sprintf(devline
, "WINEPS.DRV,%s", port
);
615 WriteProfileStringA("devices", devname
, devline
);
616 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
617 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
621 lstrcatA(devline
, ",15,45");
622 WriteProfileStringA("PrinterPorts", devname
, devline
);
623 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
624 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
628 HeapFree(GetProcessHeap(),0,devline
);
630 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
632 ERR("Can't create Printers key\n");
636 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
637 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
639 TRACE("Printer already exists\n");
640 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
641 RegCloseKey(hkeyPrinter
);
643 static CHAR data_type
[] = "RAW",
644 print_proc
[] = "WinPrint",
645 comment
[] = "WINEPS Printer using LPR",
646 params
[] = "<parameters?>",
647 share_name
[] = "<share name?>",
648 sep_file
[] = "<sep file?>";
650 add_printer_driver(devname
);
652 memset(&pinfo2a
,0,sizeof(pinfo2a
));
653 pinfo2a
.pPrinterName
= devname
;
654 pinfo2a
.pDatatype
= data_type
;
655 pinfo2a
.pPrintProcessor
= print_proc
;
656 pinfo2a
.pDriverName
= devname
;
657 pinfo2a
.pComment
= comment
;
658 pinfo2a
.pLocation
= prettyname
;
659 pinfo2a
.pPortName
= port
;
660 pinfo2a
.pParameters
= params
;
661 pinfo2a
.pShareName
= share_name
;
662 pinfo2a
.pSepFile
= sep_file
;
664 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
665 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
666 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
669 RegCloseKey(hkeyPrinters
);
671 if (isfirst
|| set_default
)
672 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
675 HeapFree(GetProcessHeap(), 0, port
);
676 HeapFree(GetProcessHeap(), 0, name
);
681 PRINTCAP_LoadPrinters(void) {
682 BOOL hadprinter
= FALSE
;
686 BOOL had_bash
= FALSE
;
688 f
= fopen("/etc/printcap","r");
692 while(fgets(buf
,sizeof(buf
),f
)) {
695 end
=strchr(buf
,'\n');
699 while(isspace(*start
)) start
++;
700 if(*start
== '#' || *start
== '\0')
703 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
704 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
705 HeapFree(GetProcessHeap(),0,pent
);
709 if (end
&& *--end
== '\\') {
716 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
719 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
725 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
726 HeapFree(GetProcessHeap(),0,pent
);
732 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
735 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
736 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
738 return ERROR_FILE_NOT_FOUND
;
741 /******************************************************************
742 * get_servername_from_name (internal)
744 * for an external server, a copy of the serverpart from the full name is returned
747 static LPWSTR
get_servername_from_name(LPCWSTR name
)
751 WCHAR buffer
[MAX_PATH
];
754 if (name
== NULL
) return NULL
;
755 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
757 server
= strdupW(&name
[2]); /* skip over both backslash */
758 if (server
== NULL
) return NULL
;
760 /* strip '\' and the printername */
761 ptr
= strchrW(server
, '\\');
762 if (ptr
) ptr
[0] = '\0';
764 TRACE("found %s\n", debugstr_w(server
));
766 len
= sizeof(buffer
)/sizeof(buffer
[0]);
767 if (GetComputerNameW(buffer
, &len
)) {
768 if (lstrcmpW(buffer
, server
) == 0) {
769 /* The requested Servername is our computername */
770 HeapFree(GetProcessHeap(), 0, server
);
777 /******************************************************************
778 * get_basename_from_name (internal)
780 * skip over the serverpart from the full name
783 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
785 if (name
== NULL
) return NULL
;
786 if ((name
[0] == '\\') && (name
[1] == '\\')) {
787 /* skip over the servername and search for the following '\' */
788 name
= strchrW(&name
[2], '\\');
789 if ((name
) && (name
[1])) {
790 /* found a separator ('\') followed by a name:
791 skip over the separator and return the rest */
796 /* no basename present (we found only a servername) */
803 /******************************************************************
804 * get_opened_printer_entry
805 * Get the first place empty in the opened printer table
808 * - pDefault is ignored
810 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
812 UINT_PTR handle
= nb_printer_handles
, i
;
813 jobqueue_t
*queue
= NULL
;
814 opened_printer_t
*printer
= NULL
;
818 if ((backend
== NULL
) && !load_backend()) return NULL
;
820 servername
= get_servername_from_name(name
);
822 FIXME("server %s not supported\n", debugstr_w(servername
));
823 HeapFree(GetProcessHeap(), 0, servername
);
824 SetLastError(ERROR_INVALID_PRINTER_NAME
);
828 printername
= get_basename_from_name(name
);
829 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
831 /* an empty printername is invalid */
832 if (printername
&& (!printername
[0])) {
833 SetLastError(ERROR_INVALID_PARAMETER
);
837 EnterCriticalSection(&printer_handles_cs
);
839 for (i
= 0; i
< nb_printer_handles
; i
++)
841 if (!printer_handles
[i
])
843 if(handle
== nb_printer_handles
)
848 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
849 queue
= printer_handles
[i
]->queue
;
853 if (handle
>= nb_printer_handles
)
855 opened_printer_t
**new_array
;
857 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
858 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
860 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
861 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
868 printer_handles
= new_array
;
869 nb_printer_handles
+= 16;
872 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
878 /* get a printer handle from the backend */
879 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
884 /* clone the base name. This is NULL for the printserver */
885 printer
->printername
= strdupW(printername
);
887 /* clone the full name */
888 printer
->name
= strdupW(name
);
889 if (name
&& (!printer
->name
)) {
895 printer
->queue
= queue
;
898 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
899 if (!printer
->queue
) {
903 list_init(&printer
->queue
->jobs
);
904 printer
->queue
->ref
= 0;
906 InterlockedIncrement(&printer
->queue
->ref
);
908 printer_handles
[handle
] = printer
;
911 LeaveCriticalSection(&printer_handles_cs
);
912 if (!handle
&& printer
) {
913 /* Something failed: Free all resources */
914 HeapFree(GetProcessHeap(), 0, printer
->printername
);
915 HeapFree(GetProcessHeap(), 0, printer
->name
);
916 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
917 HeapFree(GetProcessHeap(), 0, printer
);
920 return (HANDLE
)handle
;
923 /******************************************************************
925 * Get the pointer to the opened printer referred by the handle
927 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
929 UINT_PTR idx
= (UINT_PTR
)hprn
;
930 opened_printer_t
*ret
= NULL
;
932 EnterCriticalSection(&printer_handles_cs
);
934 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
935 ret
= printer_handles
[idx
- 1];
937 LeaveCriticalSection(&printer_handles_cs
);
941 /******************************************************************
942 * get_opened_printer_name
943 * Get the pointer to the opened printer name referred by the handle
945 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
947 opened_printer_t
*printer
= get_opened_printer(hprn
);
948 if(!printer
) return NULL
;
949 return printer
->name
;
952 /******************************************************************
953 * WINSPOOL_GetOpenedPrinterRegKey
956 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
958 LPCWSTR name
= get_opened_printer_name(hPrinter
);
962 if(!name
) return ERROR_INVALID_HANDLE
;
964 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
968 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
970 ERR("Can't find opened printer %s in registry\n",
972 RegCloseKey(hkeyPrinters
);
973 return ERROR_INVALID_PRINTER_NAME
; /* ? */
975 RegCloseKey(hkeyPrinters
);
976 return ERROR_SUCCESS
;
979 void WINSPOOL_LoadSystemPrinters(void)
981 HKEY hkey
, hkeyPrinters
;
983 DWORD needed
, num
, i
;
984 WCHAR PrinterName
[256];
987 /* This ensures that all printer entries have a valid Name value. If causes
988 problems later if they don't. If one is found to be missed we create one
989 and set it equal to the name of the key */
990 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
991 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
992 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
993 for(i
= 0; i
< num
; i
++) {
994 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
995 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
996 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
997 set_reg_szW(hkey
, NameW
, PrinterName
);
1004 RegCloseKey(hkeyPrinters
);
1007 /* We want to avoid calling AddPrinter on printers as much as
1008 possible, because on cups printers this will (eventually) lead
1009 to a call to cupsGetPPD which takes forever, even with non-cups
1010 printers AddPrinter takes a while. So we'll tag all printers that
1011 were automatically added last time around, if they still exist
1012 we'll leave them be otherwise we'll delete them. */
1013 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1015 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1016 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1017 for(i
= 0; i
< num
; i
++) {
1018 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1019 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1020 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1022 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1030 HeapFree(GetProcessHeap(), 0, pi
);
1034 #ifdef SONAME_LIBCUPS
1035 done
= CUPS_LoadPrinters();
1038 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1039 PRINTCAP_LoadPrinters();
1041 /* Now enumerate the list again and delete any printers that are still tagged */
1042 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1044 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1045 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1046 for(i
= 0; i
< num
; i
++) {
1047 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1048 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1049 BOOL delete_driver
= FALSE
;
1050 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1051 DWORD dw
, type
, size
= sizeof(dw
);
1052 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1053 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1054 DeletePrinter(hprn
);
1055 delete_driver
= TRUE
;
1061 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1066 HeapFree(GetProcessHeap(), 0, pi
);
1073 /******************************************************************
1076 * Get the pointer to the specified job.
1077 * Should hold the printer_handles_cs before calling.
1079 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1081 opened_printer_t
*printer
= get_opened_printer(hprn
);
1084 if(!printer
) return NULL
;
1085 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1087 if(job
->job_id
== JobId
)
1093 /***********************************************************
1096 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1099 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1102 Formname
= (dmA
->dmSize
> off_formname
);
1103 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1104 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1105 dmW
->dmDeviceName
, CCHDEVICENAME
);
1107 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1108 dmA
->dmSize
- CCHDEVICENAME
);
1110 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1111 off_formname
- CCHDEVICENAME
);
1112 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1113 dmW
->dmFormName
, CCHFORMNAME
);
1114 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1115 (off_formname
+ CCHFORMNAME
));
1118 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1119 dmA
->dmDriverExtra
);
1123 /***********************************************************
1125 * Creates an ansi copy of supplied devmode
1127 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1132 if (!dmW
) return NULL
;
1133 size
= dmW
->dmSize
- CCHDEVICENAME
-
1134 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1136 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1137 if (!dmA
) return NULL
;
1139 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1140 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1142 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1143 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1144 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1148 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1149 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1150 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1151 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1153 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1157 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1161 /******************************************************************
1162 * convert_printerinfo_W_to_A [internal]
1165 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1166 DWORD level
, DWORD outlen
, DWORD numentries
)
1172 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1174 len
= pi_sizeof
[level
] * numentries
;
1175 ptr
= (LPSTR
) out
+ len
;
1178 /* copy the numbers of all PRINTER_INFO_* first */
1179 memcpy(out
, pPrintersW
, len
);
1181 while (id
< numentries
) {
1185 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1186 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1188 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1189 if (piW
->pDescription
) {
1190 piA
->pDescription
= ptr
;
1191 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1192 ptr
, outlen
, NULL
, NULL
);
1198 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1199 ptr
, outlen
, NULL
, NULL
);
1203 if (piW
->pComment
) {
1204 piA
->pComment
= ptr
;
1205 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1206 ptr
, outlen
, NULL
, NULL
);
1215 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1216 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1219 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1220 if (piW
->pServerName
) {
1221 piA
->pServerName
= ptr
;
1222 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1223 ptr
, outlen
, NULL
, NULL
);
1227 if (piW
->pPrinterName
) {
1228 piA
->pPrinterName
= ptr
;
1229 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1230 ptr
, outlen
, NULL
, NULL
);
1234 if (piW
->pShareName
) {
1235 piA
->pShareName
= ptr
;
1236 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1237 ptr
, outlen
, NULL
, NULL
);
1241 if (piW
->pPortName
) {
1242 piA
->pPortName
= ptr
;
1243 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1244 ptr
, outlen
, NULL
, NULL
);
1248 if (piW
->pDriverName
) {
1249 piA
->pDriverName
= ptr
;
1250 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1251 ptr
, outlen
, NULL
, NULL
);
1255 if (piW
->pComment
) {
1256 piA
->pComment
= ptr
;
1257 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1258 ptr
, outlen
, NULL
, NULL
);
1262 if (piW
->pLocation
) {
1263 piA
->pLocation
= ptr
;
1264 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1265 ptr
, outlen
, NULL
, NULL
);
1270 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1272 /* align DEVMODEA to a DWORD boundary */
1273 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1277 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1278 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1279 memcpy(ptr
, dmA
, len
);
1280 HeapFree(GetProcessHeap(), 0, dmA
);
1286 if (piW
->pSepFile
) {
1287 piA
->pSepFile
= ptr
;
1288 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1289 ptr
, outlen
, NULL
, NULL
);
1293 if (piW
->pPrintProcessor
) {
1294 piA
->pPrintProcessor
= ptr
;
1295 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1296 ptr
, outlen
, NULL
, NULL
);
1300 if (piW
->pDatatype
) {
1301 piA
->pDatatype
= ptr
;
1302 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1303 ptr
, outlen
, NULL
, NULL
);
1307 if (piW
->pParameters
) {
1308 piA
->pParameters
= ptr
;
1309 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1310 ptr
, outlen
, NULL
, NULL
);
1314 if (piW
->pSecurityDescriptor
) {
1315 piA
->pSecurityDescriptor
= NULL
;
1316 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1323 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1324 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1326 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1328 if (piW
->pPrinterName
) {
1329 piA
->pPrinterName
= ptr
;
1330 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1331 ptr
, outlen
, NULL
, NULL
);
1335 if (piW
->pServerName
) {
1336 piA
->pServerName
= ptr
;
1337 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1338 ptr
, outlen
, NULL
, NULL
);
1347 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1348 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1350 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1352 if (piW
->pPrinterName
) {
1353 piA
->pPrinterName
= ptr
;
1354 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1355 ptr
, outlen
, NULL
, NULL
);
1359 if (piW
->pPortName
) {
1360 piA
->pPortName
= ptr
;
1361 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1362 ptr
, outlen
, NULL
, NULL
);
1369 case 6: /* 6A and 6W are the same structure */
1374 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1375 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1377 TRACE("(%u) #%u\n", level
, id
);
1378 if (piW
->pszObjectGUID
) {
1379 piA
->pszObjectGUID
= ptr
;
1380 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1381 ptr
, outlen
, NULL
, NULL
);
1390 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1391 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1394 TRACE("(%u) #%u\n", level
, id
);
1395 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1397 /* align DEVMODEA to a DWORD boundary */
1398 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1402 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1403 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1404 memcpy(ptr
, dmA
, len
);
1405 HeapFree(GetProcessHeap(), 0, dmA
);
1415 FIXME("for level %u\n", level
);
1417 pPrintersW
+= pi_sizeof
[level
];
1418 out
+= pi_sizeof
[level
];
1423 /******************************************************************
1424 * convert_driverinfo_W_to_A [internal]
1427 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1428 DWORD level
, DWORD outlen
, DWORD numentries
)
1434 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1436 len
= di_sizeof
[level
] * numentries
;
1437 ptr
= (LPSTR
) out
+ len
;
1440 /* copy the numbers of all PRINTER_INFO_* first */
1441 memcpy(out
, pDriversW
, len
);
1443 #define COPY_STRING(fld) \
1446 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1447 ptr += len; outlen -= len;\
1449 #define COPY_MULTIZ_STRING(fld) \
1450 { LPWSTR p = diW->fld; if (p){ \
1453 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1454 ptr += len; outlen -= len; p += len;\
1456 while(len > 1 && outlen > 0); \
1459 while (id
< numentries
)
1465 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1466 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1468 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1475 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1476 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1478 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1481 COPY_STRING(pEnvironment
);
1482 COPY_STRING(pDriverPath
);
1483 COPY_STRING(pDataFile
);
1484 COPY_STRING(pConfigFile
);
1489 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1490 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1492 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1495 COPY_STRING(pEnvironment
);
1496 COPY_STRING(pDriverPath
);
1497 COPY_STRING(pDataFile
);
1498 COPY_STRING(pConfigFile
);
1499 COPY_STRING(pHelpFile
);
1500 COPY_MULTIZ_STRING(pDependentFiles
);
1501 COPY_STRING(pMonitorName
);
1502 COPY_STRING(pDefaultDataType
);
1507 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1508 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1510 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1513 COPY_STRING(pEnvironment
);
1514 COPY_STRING(pDriverPath
);
1515 COPY_STRING(pDataFile
);
1516 COPY_STRING(pConfigFile
);
1517 COPY_STRING(pHelpFile
);
1518 COPY_MULTIZ_STRING(pDependentFiles
);
1519 COPY_STRING(pMonitorName
);
1520 COPY_STRING(pDefaultDataType
);
1521 COPY_MULTIZ_STRING(pszzPreviousNames
);
1526 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1527 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1529 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1532 COPY_STRING(pEnvironment
);
1533 COPY_STRING(pDriverPath
);
1534 COPY_STRING(pDataFile
);
1535 COPY_STRING(pConfigFile
);
1540 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1541 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1543 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1546 COPY_STRING(pEnvironment
);
1547 COPY_STRING(pDriverPath
);
1548 COPY_STRING(pDataFile
);
1549 COPY_STRING(pConfigFile
);
1550 COPY_STRING(pHelpFile
);
1551 COPY_MULTIZ_STRING(pDependentFiles
);
1552 COPY_STRING(pMonitorName
);
1553 COPY_STRING(pDefaultDataType
);
1554 COPY_MULTIZ_STRING(pszzPreviousNames
);
1555 COPY_STRING(pszMfgName
);
1556 COPY_STRING(pszOEMUrl
);
1557 COPY_STRING(pszHardwareID
);
1558 COPY_STRING(pszProvider
);
1563 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1564 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1566 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1569 COPY_STRING(pEnvironment
);
1570 COPY_STRING(pDriverPath
);
1571 COPY_STRING(pDataFile
);
1572 COPY_STRING(pConfigFile
);
1573 COPY_STRING(pHelpFile
);
1574 COPY_MULTIZ_STRING(pDependentFiles
);
1575 COPY_STRING(pMonitorName
);
1576 COPY_STRING(pDefaultDataType
);
1577 COPY_MULTIZ_STRING(pszzPreviousNames
);
1578 COPY_STRING(pszMfgName
);
1579 COPY_STRING(pszOEMUrl
);
1580 COPY_STRING(pszHardwareID
);
1581 COPY_STRING(pszProvider
);
1582 COPY_STRING(pszPrintProcessor
);
1583 COPY_STRING(pszVendorSetup
);
1584 COPY_MULTIZ_STRING(pszzColorProfiles
);
1585 COPY_STRING(pszInfPath
);
1586 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1592 FIXME("for level %u\n", level
);
1595 pDriversW
+= di_sizeof
[level
];
1596 out
+= di_sizeof
[level
];
1601 #undef COPY_MULTIZ_STRING
1605 /***********************************************************
1606 * PRINTER_INFO_2AtoW
1607 * Creates a unicode copy of PRINTER_INFO_2A on heap
1609 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1611 LPPRINTER_INFO_2W piW
;
1612 UNICODE_STRING usBuffer
;
1614 if(!piA
) return NULL
;
1615 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1616 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1618 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1619 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1620 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1621 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1622 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1623 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1624 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1625 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1626 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1627 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1628 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1629 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1633 /***********************************************************
1634 * FREE_PRINTER_INFO_2W
1635 * Free PRINTER_INFO_2W and all strings
1637 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1641 HeapFree(heap
,0,piW
->pServerName
);
1642 HeapFree(heap
,0,piW
->pPrinterName
);
1643 HeapFree(heap
,0,piW
->pShareName
);
1644 HeapFree(heap
,0,piW
->pPortName
);
1645 HeapFree(heap
,0,piW
->pDriverName
);
1646 HeapFree(heap
,0,piW
->pComment
);
1647 HeapFree(heap
,0,piW
->pLocation
);
1648 HeapFree(heap
,0,piW
->pDevMode
);
1649 HeapFree(heap
,0,piW
->pSepFile
);
1650 HeapFree(heap
,0,piW
->pPrintProcessor
);
1651 HeapFree(heap
,0,piW
->pDatatype
);
1652 HeapFree(heap
,0,piW
->pParameters
);
1653 HeapFree(heap
,0,piW
);
1657 /******************************************************************
1658 * DeviceCapabilities [WINSPOOL.@]
1659 * DeviceCapabilitiesA [WINSPOOL.@]
1662 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1663 LPSTR pOutput
, LPDEVMODEA lpdm
)
1667 if (!GDI_CallDeviceCapabilities16
)
1669 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1671 if (!GDI_CallDeviceCapabilities16
) return -1;
1673 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1675 /* If DC_PAPERSIZE map POINT16s to POINTs */
1676 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1677 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1678 POINT
*pt
= (POINT
*)pOutput
;
1680 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1681 for(i
= 0; i
< ret
; i
++, pt
++)
1686 HeapFree( GetProcessHeap(), 0, tmp
);
1692 /*****************************************************************************
1693 * DeviceCapabilitiesW [WINSPOOL.@]
1695 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1698 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1699 WORD fwCapability
, LPWSTR pOutput
,
1700 const DEVMODEW
*pDevMode
)
1702 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1703 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1704 LPSTR pPortA
= strdupWtoA(pPort
);
1707 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1708 fwCapability
== DC_FILEDEPENDENCIES
||
1709 fwCapability
== DC_PAPERNAMES
)) {
1710 /* These need A -> W translation */
1713 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1717 switch(fwCapability
) {
1722 case DC_FILEDEPENDENCIES
:
1726 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1727 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1729 for(i
= 0; i
< ret
; i
++)
1730 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1731 pOutput
+ (i
* size
), size
);
1732 HeapFree(GetProcessHeap(), 0, pOutputA
);
1734 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1735 (LPSTR
)pOutput
, dmA
);
1737 HeapFree(GetProcessHeap(),0,pPortA
);
1738 HeapFree(GetProcessHeap(),0,pDeviceA
);
1739 HeapFree(GetProcessHeap(),0,dmA
);
1743 /******************************************************************
1744 * DocumentPropertiesA [WINSPOOL.@]
1746 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1748 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1749 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1750 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1752 LPSTR lpName
= pDeviceName
;
1753 static CHAR port
[] = "LPT1:";
1756 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1757 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1761 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1763 ERR("no name from hPrinter?\n");
1764 SetLastError(ERROR_INVALID_HANDLE
);
1767 lpName
= strdupWtoA(lpNameW
);
1770 if (!GDI_CallExtDeviceMode16
)
1772 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1774 if (!GDI_CallExtDeviceMode16
) {
1775 ERR("No CallExtDeviceMode16?\n");
1779 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1780 pDevModeInput
, NULL
, fMode
);
1783 HeapFree(GetProcessHeap(),0,lpName
);
1788 /*****************************************************************************
1789 * DocumentPropertiesW (WINSPOOL.@)
1791 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1793 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1795 LPDEVMODEW pDevModeOutput
,
1796 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1799 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1800 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1801 LPDEVMODEA pDevModeOutputA
= NULL
;
1804 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1805 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1807 if(pDevModeOutput
) {
1808 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1809 if(ret
< 0) return ret
;
1810 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1812 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1813 pDevModeInputA
, fMode
);
1814 if(pDevModeOutput
) {
1815 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1816 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1818 if(fMode
== 0 && ret
> 0)
1819 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1820 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1821 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1825 /******************************************************************
1826 * OpenPrinterA [WINSPOOL.@]
1831 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1832 LPPRINTER_DEFAULTSA pDefault
)
1834 UNICODE_STRING lpPrinterNameW
;
1835 UNICODE_STRING usBuffer
;
1836 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1837 PWSTR pwstrPrinterNameW
;
1840 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1843 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1844 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1845 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1846 pDefaultW
= &DefaultW
;
1848 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1850 RtlFreeUnicodeString(&usBuffer
);
1851 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1853 RtlFreeUnicodeString(&lpPrinterNameW
);
1857 /******************************************************************
1858 * OpenPrinterW [WINSPOOL.@]
1860 * Open a Printer / Printserver or a Printer-Object
1863 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1864 * phPrinter [O] The resulting Handle is stored here
1865 * pDefault [I] PTR to Default Printer Settings or NULL
1872 * lpPrinterName is one of:
1873 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1874 *| Printer: "PrinterName"
1875 *| Printer-Object: "PrinterName,Job xxx"
1876 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1877 *| XcvPort: "Servername,XcvPort PortName"
1880 *| Printer-Object not supported
1881 *| pDefaults is ignored
1884 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1887 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1889 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1890 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1894 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1895 SetLastError(ERROR_INVALID_PARAMETER
);
1899 /* Get the unique handle of the printer or Printserver */
1900 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1901 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1902 return (*phPrinter
!= 0);
1905 /******************************************************************
1906 * AddMonitorA [WINSPOOL.@]
1911 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1913 LPWSTR nameW
= NULL
;
1916 LPMONITOR_INFO_2A mi2a
;
1917 MONITOR_INFO_2W mi2w
;
1919 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1920 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1921 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1922 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1923 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1926 SetLastError(ERROR_INVALID_LEVEL
);
1930 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1936 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1937 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1938 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1941 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1943 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1944 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1945 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1947 if (mi2a
->pEnvironment
) {
1948 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1949 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1950 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1952 if (mi2a
->pDLLName
) {
1953 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1954 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1955 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1958 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1960 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1961 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1962 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1964 HeapFree(GetProcessHeap(), 0, nameW
);
1968 /******************************************************************************
1969 * AddMonitorW [WINSPOOL.@]
1971 * Install a Printmonitor
1974 * pName [I] Servername or NULL (local Computer)
1975 * Level [I] Structure-Level (Must be 2)
1976 * pMonitors [I] PTR to MONITOR_INFO_2
1983 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1986 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1988 LPMONITOR_INFO_2W mi2w
;
1990 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1991 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1992 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1993 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1994 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1996 if ((backend
== NULL
) && !load_backend()) return FALSE
;
1999 SetLastError(ERROR_INVALID_LEVEL
);
2003 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2008 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2011 /******************************************************************
2012 * DeletePrinterDriverA [WINSPOOL.@]
2015 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2017 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2020 /******************************************************************
2021 * DeletePrinterDriverW [WINSPOOL.@]
2024 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2026 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2029 /******************************************************************
2030 * DeleteMonitorA [WINSPOOL.@]
2032 * See DeleteMonitorW.
2035 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2037 LPWSTR nameW
= NULL
;
2038 LPWSTR EnvironmentW
= NULL
;
2039 LPWSTR MonitorNameW
= NULL
;
2044 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2045 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2046 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2050 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2051 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2052 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2055 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2056 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2057 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2060 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2062 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2063 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2064 HeapFree(GetProcessHeap(), 0, nameW
);
2068 /******************************************************************
2069 * DeleteMonitorW [WINSPOOL.@]
2071 * Delete a specific Printmonitor from a Printing-Environment
2074 * pName [I] Servername or NULL (local Computer)
2075 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2076 * pMonitorName [I] Name of the Monitor, that should be deleted
2083 * pEnvironment is ignored in Windows for the local Computer.
2086 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2089 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2090 debugstr_w(pMonitorName
));
2092 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2094 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2098 /******************************************************************
2099 * DeletePortA [WINSPOOL.@]
2104 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2106 LPWSTR nameW
= NULL
;
2107 LPWSTR portW
= NULL
;
2111 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2113 /* convert servername to unicode */
2115 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2116 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2117 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2120 /* convert portname to unicode */
2122 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2123 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2124 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2127 res
= DeletePortW(nameW
, hWnd
, portW
);
2128 HeapFree(GetProcessHeap(), 0, nameW
);
2129 HeapFree(GetProcessHeap(), 0, portW
);
2133 /******************************************************************
2134 * DeletePortW [WINSPOOL.@]
2136 * Delete a specific Port
2139 * pName [I] Servername or NULL (local Computer)
2140 * hWnd [I] Handle to parent Window for the Dialog-Box
2141 * pPortName [I] Name of the Port, that should be deleted
2148 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2150 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2152 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2155 SetLastError(RPC_X_NULL_REF_POINTER
);
2159 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2162 /******************************************************************************
2163 * SetPrinterW [WINSPOOL.@]
2165 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2167 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2168 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2172 /******************************************************************************
2173 * WritePrinter [WINSPOOL.@]
2175 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2177 opened_printer_t
*printer
;
2180 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2182 EnterCriticalSection(&printer_handles_cs
);
2183 printer
= get_opened_printer(hPrinter
);
2186 SetLastError(ERROR_INVALID_HANDLE
);
2192 SetLastError(ERROR_SPL_NO_STARTDOC
);
2196 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2198 LeaveCriticalSection(&printer_handles_cs
);
2202 /*****************************************************************************
2203 * AddFormA [WINSPOOL.@]
2205 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2207 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2211 /*****************************************************************************
2212 * AddFormW [WINSPOOL.@]
2214 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2216 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2220 /*****************************************************************************
2221 * AddJobA [WINSPOOL.@]
2223 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2226 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2230 SetLastError(ERROR_INVALID_LEVEL
);
2234 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2237 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2238 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2239 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2240 if(*pcbNeeded
> cbBuf
) {
2241 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2244 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2245 addjobA
->JobId
= addjobW
->JobId
;
2246 addjobA
->Path
= (char *)(addjobA
+ 1);
2247 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2253 /*****************************************************************************
2254 * AddJobW [WINSPOOL.@]
2256 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2258 opened_printer_t
*printer
;
2261 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2262 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2263 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2265 ADDJOB_INFO_1W
*addjob
;
2267 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2269 EnterCriticalSection(&printer_handles_cs
);
2271 printer
= get_opened_printer(hPrinter
);
2274 SetLastError(ERROR_INVALID_HANDLE
);
2279 SetLastError(ERROR_INVALID_LEVEL
);
2283 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2287 job
->job_id
= InterlockedIncrement(&next_job_id
);
2289 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2290 if(path
[len
- 1] != '\\')
2292 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2293 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2295 len
= strlenW(filename
);
2296 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2297 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2298 job
->document_title
= strdupW(default_doc_title
);
2299 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2301 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2302 if(*pcbNeeded
<= cbBuf
) {
2303 addjob
= (ADDJOB_INFO_1W
*)pData
;
2304 addjob
->JobId
= job
->job_id
;
2305 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2306 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2309 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2312 LeaveCriticalSection(&printer_handles_cs
);
2316 /*****************************************************************************
2317 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2319 * Return the PATH for the Print-Processors
2321 * See GetPrintProcessorDirectoryW.
2325 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2326 DWORD level
, LPBYTE Info
,
2327 DWORD cbBuf
, LPDWORD pcbNeeded
)
2329 LPWSTR serverW
= NULL
;
2334 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2335 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2339 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2340 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2341 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2345 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2346 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2347 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2350 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2351 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2353 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2356 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2357 cbBuf
, NULL
, NULL
) > 0;
2360 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2361 HeapFree(GetProcessHeap(), 0, envW
);
2362 HeapFree(GetProcessHeap(), 0, serverW
);
2366 /*****************************************************************************
2367 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2369 * Return the PATH for the Print-Processors
2372 * server [I] Servername (NT only) or NULL (local Computer)
2373 * env [I] Printing-Environment (see below) or NULL (Default)
2374 * level [I] Structure-Level (must be 1)
2375 * Info [O] PTR to Buffer that receives the Result
2376 * cbBuf [I] Size of Buffer at "Info"
2377 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2378 * required for the Buffer at "Info"
2381 * Success: TRUE and in pcbNeeded the Bytes used in Info
2382 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2383 * if cbBuf is too small
2385 * Native Values returned in Info on Success:
2386 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2387 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2388 *| win9x(Windows 4.0): "%winsysdir%"
2390 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2393 * Only NULL or "" is supported for server
2396 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2397 DWORD level
, LPBYTE Info
,
2398 DWORD cbBuf
, LPDWORD pcbNeeded
)
2401 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2402 Info
, cbBuf
, pcbNeeded
);
2404 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2407 /* (Level != 1) is ignored in win9x */
2408 SetLastError(ERROR_INVALID_LEVEL
);
2412 if (pcbNeeded
== NULL
) {
2413 /* (pcbNeeded == NULL) is ignored in win9x */
2414 SetLastError(RPC_X_NULL_REF_POINTER
);
2418 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2421 /*****************************************************************************
2422 * WINSPOOL_OpenDriverReg [internal]
2424 * opens the registry for the printer drivers depending on the given input
2425 * variable pEnvironment
2428 * the opened hkey on success
2431 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2435 const printenv_t
* env
;
2437 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2439 env
= validate_envW(pEnvironment
);
2440 if (!env
) return NULL
;
2442 buffer
= HeapAlloc( GetProcessHeap(), 0,
2443 (strlenW(DriversW
) + strlenW(env
->envname
) +
2444 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2446 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2447 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2448 HeapFree(GetProcessHeap(), 0, buffer
);
2453 /*****************************************************************************
2454 * AddPrinterW [WINSPOOL.@]
2456 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2458 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2462 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2464 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2465 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2466 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2467 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2468 statusW
[] = {'S','t','a','t','u','s',0},
2469 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2471 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2474 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2475 SetLastError(ERROR_INVALID_PARAMETER
);
2479 ERR("Level = %d, unsupported!\n", Level
);
2480 SetLastError(ERROR_INVALID_LEVEL
);
2484 SetLastError(ERROR_INVALID_PARAMETER
);
2487 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2489 ERR("Can't create Printers key\n");
2492 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2493 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2494 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2495 RegCloseKey(hkeyPrinter
);
2496 RegCloseKey(hkeyPrinters
);
2499 RegCloseKey(hkeyPrinter
);
2501 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2503 ERR("Can't create Drivers key\n");
2504 RegCloseKey(hkeyPrinters
);
2507 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2509 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2510 RegCloseKey(hkeyPrinters
);
2511 RegCloseKey(hkeyDrivers
);
2512 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2515 RegCloseKey(hkeyDriver
);
2516 RegCloseKey(hkeyDrivers
);
2518 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2519 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2520 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2521 RegCloseKey(hkeyPrinters
);
2525 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2527 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2528 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2529 RegCloseKey(hkeyPrinters
);
2532 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2533 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2534 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2536 /* See if we can load the driver. We may need the devmode structure anyway
2539 * Note that DocumentPropertiesW will briefly try to open the printer we
2540 * just create to find a DEVMODEA struct (it will use the WINEPS default
2541 * one in case it is not there, so we are ok).
2543 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2546 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2547 size
= sizeof(DEVMODEW
);
2553 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2555 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2557 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2558 HeapFree(GetProcessHeap(),0,dmW
);
2563 /* set devmode to printer name */
2564 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2568 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2569 and we support these drivers. NT writes DEVMODEW so somehow
2570 we'll need to distinguish between these when we support NT
2574 dmA
= DEVMODEdupWtoA(dmW
);
2575 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2576 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2577 HeapFree(GetProcessHeap(), 0, dmA
);
2579 HeapFree(GetProcessHeap(), 0, dmW
);
2581 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2582 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2583 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2584 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2586 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2587 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2588 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2589 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2590 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2591 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2592 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2593 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2594 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2595 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2596 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2597 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2598 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2600 RegCloseKey(hkeyPrinter
);
2601 RegCloseKey(hkeyPrinters
);
2602 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2603 ERR("OpenPrinter failing\n");
2609 /*****************************************************************************
2610 * AddPrinterA [WINSPOOL.@]
2612 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2614 UNICODE_STRING pNameW
;
2616 PRINTER_INFO_2W
*piW
;
2617 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2620 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2622 ERR("Level = %d, unsupported!\n", Level
);
2623 SetLastError(ERROR_INVALID_LEVEL
);
2626 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2627 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2629 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2631 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2632 RtlFreeUnicodeString(&pNameW
);
2637 /*****************************************************************************
2638 * ClosePrinter [WINSPOOL.@]
2640 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2642 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2643 opened_printer_t
*printer
= NULL
;
2646 TRACE("(%p)\n", hPrinter
);
2648 EnterCriticalSection(&printer_handles_cs
);
2650 if ((i
> 0) && (i
<= nb_printer_handles
))
2651 printer
= printer_handles
[i
- 1];
2656 struct list
*cursor
, *cursor2
;
2658 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2660 if (printer
->backend_printer
) {
2661 backend
->fpClosePrinter(printer
->backend_printer
);
2665 EndDocPrinter(hPrinter
);
2667 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2669 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2671 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2672 ScheduleJob(hPrinter
, job
->job_id
);
2674 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2677 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2678 HeapFree(GetProcessHeap(), 0, printer
->name
);
2679 HeapFree(GetProcessHeap(), 0, printer
);
2680 printer_handles
[i
- 1] = NULL
;
2683 LeaveCriticalSection(&printer_handles_cs
);
2687 /*****************************************************************************
2688 * DeleteFormA [WINSPOOL.@]
2690 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2692 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2696 /*****************************************************************************
2697 * DeleteFormW [WINSPOOL.@]
2699 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2701 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2705 /*****************************************************************************
2706 * DeletePrinter [WINSPOOL.@]
2708 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2710 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2711 HKEY hkeyPrinters
, hkey
;
2714 SetLastError(ERROR_INVALID_HANDLE
);
2717 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2718 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2719 RegCloseKey(hkeyPrinters
);
2721 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2722 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2724 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2725 RegDeleteValueW(hkey
, lpNameW
);
2729 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2730 RegDeleteValueW(hkey
, lpNameW
);
2736 /*****************************************************************************
2737 * SetPrinterA [WINSPOOL.@]
2739 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2742 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2746 /*****************************************************************************
2747 * SetJobA [WINSPOOL.@]
2749 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2750 LPBYTE pJob
, DWORD Command
)
2754 UNICODE_STRING usBuffer
;
2756 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2758 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2759 are all ignored by SetJob, so we don't bother copying them */
2767 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2768 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2770 JobW
= (LPBYTE
)info1W
;
2771 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2772 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2773 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2774 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2775 info1W
->Status
= info1A
->Status
;
2776 info1W
->Priority
= info1A
->Priority
;
2777 info1W
->Position
= info1A
->Position
;
2778 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2783 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2784 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2786 JobW
= (LPBYTE
)info2W
;
2787 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2788 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2789 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2790 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2791 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2792 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2793 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2794 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2795 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2796 info2W
->Status
= info2A
->Status
;
2797 info2W
->Priority
= info2A
->Priority
;
2798 info2W
->Position
= info2A
->Position
;
2799 info2W
->StartTime
= info2A
->StartTime
;
2800 info2W
->UntilTime
= info2A
->UntilTime
;
2801 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2805 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2806 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2809 SetLastError(ERROR_INVALID_LEVEL
);
2813 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2819 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2820 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2821 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2822 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2823 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2828 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2829 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2830 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2831 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2832 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2833 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2834 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2835 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2836 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2840 HeapFree(GetProcessHeap(), 0, JobW
);
2845 /*****************************************************************************
2846 * SetJobW [WINSPOOL.@]
2848 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2849 LPBYTE pJob
, DWORD Command
)
2854 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2855 FIXME("Ignoring everything other than document title\n");
2857 EnterCriticalSection(&printer_handles_cs
);
2858 job
= get_job(hPrinter
, JobId
);
2868 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2869 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2870 job
->document_title
= strdupW(info1
->pDocument
);
2875 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2876 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2877 job
->document_title
= strdupW(info2
->pDocument
);
2883 SetLastError(ERROR_INVALID_LEVEL
);
2888 LeaveCriticalSection(&printer_handles_cs
);
2892 /*****************************************************************************
2893 * EndDocPrinter [WINSPOOL.@]
2895 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2897 opened_printer_t
*printer
;
2899 TRACE("(%p)\n", hPrinter
);
2901 EnterCriticalSection(&printer_handles_cs
);
2903 printer
= get_opened_printer(hPrinter
);
2906 SetLastError(ERROR_INVALID_HANDLE
);
2912 SetLastError(ERROR_SPL_NO_STARTDOC
);
2916 CloseHandle(printer
->doc
->hf
);
2917 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2918 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2919 printer
->doc
= NULL
;
2922 LeaveCriticalSection(&printer_handles_cs
);
2926 /*****************************************************************************
2927 * EndPagePrinter [WINSPOOL.@]
2929 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2931 FIXME("(%p): stub\n", hPrinter
);
2935 /*****************************************************************************
2936 * StartDocPrinterA [WINSPOOL.@]
2938 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2940 UNICODE_STRING usBuffer
;
2942 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2945 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2946 or one (DOC_INFO_3) extra DWORDs */
2950 doc2W
.JobId
= doc2
->JobId
;
2953 doc2W
.dwMode
= doc2
->dwMode
;
2956 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2957 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2958 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2962 SetLastError(ERROR_INVALID_LEVEL
);
2966 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2968 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2969 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2970 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
2975 /*****************************************************************************
2976 * StartDocPrinterW [WINSPOOL.@]
2978 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2980 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
2981 opened_printer_t
*printer
;
2982 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2983 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
2984 JOB_INFO_1W job_info
;
2985 DWORD needed
, ret
= 0;
2990 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2991 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
2992 debugstr_w(doc
->pDatatype
));
2994 if(Level
< 1 || Level
> 3)
2996 SetLastError(ERROR_INVALID_LEVEL
);
3000 EnterCriticalSection(&printer_handles_cs
);
3001 printer
= get_opened_printer(hPrinter
);
3004 SetLastError(ERROR_INVALID_HANDLE
);
3010 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3014 /* Even if we're printing to a file we still add a print job, we'll
3015 just ignore the spool file name */
3017 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3019 ERR("AddJob failed gle %u\n", GetLastError());
3023 /* use pOutputFile only, when it is a real filename */
3024 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3025 filename
= doc
->pOutputFile
;
3027 filename
= addjob
->Path
;
3029 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3030 if(hf
== INVALID_HANDLE_VALUE
)
3033 memset(&job_info
, 0, sizeof(job_info
));
3034 job_info
.pDocument
= doc
->pDocName
;
3035 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3037 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3038 printer
->doc
->hf
= hf
;
3039 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3040 job
= get_job(hPrinter
, ret
);
3041 job
->portname
= strdupW(doc
->pOutputFile
);
3044 LeaveCriticalSection(&printer_handles_cs
);
3049 /*****************************************************************************
3050 * StartPagePrinter [WINSPOOL.@]
3052 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3054 FIXME("(%p): stub\n", hPrinter
);
3058 /*****************************************************************************
3059 * GetFormA [WINSPOOL.@]
3061 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3062 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3064 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3065 Level
,pForm
,cbBuf
,pcbNeeded
);
3069 /*****************************************************************************
3070 * GetFormW [WINSPOOL.@]
3072 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3073 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3075 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3076 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3080 /*****************************************************************************
3081 * SetFormA [WINSPOOL.@]
3083 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3086 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3090 /*****************************************************************************
3091 * SetFormW [WINSPOOL.@]
3093 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3096 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3100 /*****************************************************************************
3101 * ReadPrinter [WINSPOOL.@]
3103 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3104 LPDWORD pNoBytesRead
)
3106 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3110 /*****************************************************************************
3111 * ResetPrinterA [WINSPOOL.@]
3113 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3115 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3119 /*****************************************************************************
3120 * ResetPrinterW [WINSPOOL.@]
3122 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3124 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3128 /*****************************************************************************
3129 * WINSPOOL_GetDWORDFromReg
3131 * Return DWORD associated with ValueName from hkey.
3133 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3135 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3138 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3140 if(ret
!= ERROR_SUCCESS
) {
3141 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3144 if(type
!= REG_DWORD
) {
3145 ERR("Got type %d\n", type
);
3152 /*****************************************************************************
3153 * get_filename_from_reg [internal]
3155 * Get ValueName from hkey storing result in out
3156 * when the Value in the registry has only a filename, use driverdir as prefix
3157 * outlen is space left in out
3158 * String is stored either as unicode or ascii
3162 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3163 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3165 WCHAR filename
[MAX_PATH
];
3169 LPWSTR buffer
= filename
;
3173 size
= sizeof(filename
);
3175 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3176 if (ret
== ERROR_MORE_DATA
) {
3177 TRACE("need dynamic buffer: %u\n", size
);
3178 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3180 /* No Memory is bad */
3184 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3187 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3188 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3194 /* do we have a full path ? */
3195 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3196 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3199 /* we must build the full Path */
3201 if ((out
) && (outlen
> dirlen
)) {
3202 lstrcpyW((LPWSTR
)out
, driverdir
);
3210 /* write the filename */
3211 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3212 if ((out
) && (outlen
>= size
)) {
3213 lstrcpyW((LPWSTR
)out
, ptr
);
3220 ptr
+= lstrlenW(ptr
)+1;
3221 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3224 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3226 /* write the multisz-termination */
3227 if (type
== REG_MULTI_SZ
) {
3228 size
= sizeof(WCHAR
);
3231 if (out
&& (outlen
>= size
)) {
3232 memset (out
, 0, size
);
3238 /*****************************************************************************
3239 * WINSPOOL_GetStringFromReg
3241 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3242 * String is stored as unicode.
3244 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3245 DWORD buflen
, DWORD
*needed
)
3247 DWORD sz
= buflen
, type
;
3250 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3251 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3252 WARN("Got ret = %d\n", ret
);
3256 /* add space for terminating '\0' */
3257 sz
+= sizeof(WCHAR
);
3261 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3266 /*****************************************************************************
3267 * WINSPOOL_GetDefaultDevMode
3269 * Get a default DevMode values for wineps.
3273 static void WINSPOOL_GetDefaultDevMode(
3275 DWORD buflen
, DWORD
*needed
)
3278 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3280 /* fill default DEVMODE - should be read from ppd... */
3281 ZeroMemory( &dm
, sizeof(dm
) );
3282 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3283 dm
.dmSpecVersion
= DM_SPECVERSION
;
3284 dm
.dmDriverVersion
= 1;
3285 dm
.dmSize
= sizeof(DEVMODEW
);
3286 dm
.dmDriverExtra
= 0;
3288 DM_ORIENTATION
| DM_PAPERSIZE
|
3289 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3292 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3293 DM_YRESOLUTION
| DM_TTOPTION
;
3295 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3296 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3297 dm
.u1
.s1
.dmPaperLength
= 2970;
3298 dm
.u1
.s1
.dmPaperWidth
= 2100;
3300 dm
.u1
.s1
.dmScale
= 100;
3301 dm
.u1
.s1
.dmCopies
= 1;
3302 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3303 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3306 dm
.dmYResolution
= 300; /* 300dpi */
3307 dm
.dmTTOption
= DMTT_BITMAP
;
3310 /* dm.dmLogPixels */
3311 /* dm.dmBitsPerPel */
3312 /* dm.dmPelsWidth */
3313 /* dm.dmPelsHeight */
3314 /* dm.u2.dmDisplayFlags */
3315 /* dm.dmDisplayFrequency */
3316 /* dm.dmICMMethod */
3317 /* dm.dmICMIntent */
3318 /* dm.dmMediaType */
3319 /* dm.dmDitherType */
3320 /* dm.dmReserved1 */
3321 /* dm.dmReserved2 */
3322 /* dm.dmPanningWidth */
3323 /* dm.dmPanningHeight */
3325 if(buflen
>= sizeof(DEVMODEW
))
3326 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3327 *needed
= sizeof(DEVMODEW
);
3330 /*****************************************************************************
3331 * WINSPOOL_GetDevModeFromReg
3333 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3334 * DevMode is stored either as unicode or ascii.
3336 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3338 DWORD buflen
, DWORD
*needed
)
3340 DWORD sz
= buflen
, type
;
3343 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3344 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3345 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3346 if (sz
< sizeof(DEVMODEA
))
3348 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3351 /* ensures that dmSize is not erratically bogus if registry is invalid */
3352 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3353 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3354 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3355 if (ptr
&& (buflen
>= sz
)) {
3356 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3357 memcpy(ptr
, dmW
, sz
);
3358 HeapFree(GetProcessHeap(),0,dmW
);
3364 /*********************************************************************
3365 * WINSPOOL_GetPrinter_1
3367 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3369 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3370 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3372 DWORD size
, left
= cbBuf
;
3373 BOOL space
= (cbBuf
> 0);
3378 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3379 if(space
&& size
<= left
) {
3380 pi1
->pName
= (LPWSTR
)ptr
;
3388 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3389 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3390 if(space
&& size
<= left
) {
3391 pi1
->pDescription
= (LPWSTR
)ptr
;
3399 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3400 if(space
&& size
<= left
) {
3401 pi1
->pComment
= (LPWSTR
)ptr
;
3409 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3411 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3412 memset(pi1
, 0, sizeof(*pi1
));
3416 /*********************************************************************
3417 * WINSPOOL_GetPrinter_2
3419 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3421 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3422 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3424 DWORD size
, left
= cbBuf
;
3425 BOOL space
= (cbBuf
> 0);
3430 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3431 if(space
&& size
<= left
) {
3432 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3439 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3440 if(space
&& size
<= left
) {
3441 pi2
->pShareName
= (LPWSTR
)ptr
;
3448 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3449 if(space
&& size
<= left
) {
3450 pi2
->pPortName
= (LPWSTR
)ptr
;
3457 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3458 if(space
&& size
<= left
) {
3459 pi2
->pDriverName
= (LPWSTR
)ptr
;
3466 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3467 if(space
&& size
<= left
) {
3468 pi2
->pComment
= (LPWSTR
)ptr
;
3475 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3476 if(space
&& size
<= left
) {
3477 pi2
->pLocation
= (LPWSTR
)ptr
;
3484 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3485 if(space
&& size
<= left
) {
3486 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3495 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3496 if(space
&& size
<= left
) {
3497 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3504 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3505 if(space
&& size
<= left
) {
3506 pi2
->pSepFile
= (LPWSTR
)ptr
;
3513 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3514 if(space
&& size
<= left
) {
3515 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3522 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3523 if(space
&& size
<= left
) {
3524 pi2
->pDatatype
= (LPWSTR
)ptr
;
3531 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3532 if(space
&& size
<= left
) {
3533 pi2
->pParameters
= (LPWSTR
)ptr
;
3541 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3542 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3543 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3544 "Default Priority");
3545 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3546 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3549 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3550 memset(pi2
, 0, sizeof(*pi2
));
3555 /*********************************************************************
3556 * WINSPOOL_GetPrinter_4
3558 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3560 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3561 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3563 DWORD size
, left
= cbBuf
;
3564 BOOL space
= (cbBuf
> 0);
3569 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3570 if(space
&& size
<= left
) {
3571 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3579 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3582 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3583 memset(pi4
, 0, sizeof(*pi4
));
3588 /*********************************************************************
3589 * WINSPOOL_GetPrinter_5
3591 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3593 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3594 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3596 DWORD size
, left
= cbBuf
;
3597 BOOL space
= (cbBuf
> 0);
3602 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3603 if(space
&& size
<= left
) {
3604 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3611 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3612 if(space
&& size
<= left
) {
3613 pi5
->pPortName
= (LPWSTR
)ptr
;
3621 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3622 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3624 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3628 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3629 memset(pi5
, 0, sizeof(*pi5
));
3634 /*********************************************************************
3635 * WINSPOOL_GetPrinter_7
3637 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3639 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3640 DWORD cbBuf
, LPDWORD pcbNeeded
)
3642 DWORD size
, left
= cbBuf
;
3643 BOOL space
= (cbBuf
> 0);
3648 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3651 size
= sizeof(pi7
->pszObjectGUID
);
3653 if (space
&& size
<= left
) {
3654 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3661 /* We do not have a Directory Service */
3662 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3665 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3666 memset(pi7
, 0, sizeof(*pi7
));
3671 /*********************************************************************
3672 * WINSPOOL_GetPrinter_9
3674 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3676 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3677 DWORD cbBuf
, LPDWORD pcbNeeded
)
3680 BOOL space
= (cbBuf
> 0);
3684 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3685 if(space
&& size
<= cbBuf
) {
3686 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3693 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3694 if(space
&& size
<= cbBuf
) {
3695 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3701 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3702 memset(pi9
, 0, sizeof(*pi9
));
3707 /*****************************************************************************
3708 * GetPrinterW [WINSPOOL.@]
3710 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3711 DWORD cbBuf
, LPDWORD pcbNeeded
)
3714 DWORD size
, needed
= 0;
3716 HKEY hkeyPrinter
, hkeyPrinters
;
3719 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3721 if (!(name
= get_opened_printer_name(hPrinter
))) {
3722 SetLastError(ERROR_INVALID_HANDLE
);
3726 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3728 ERR("Can't create Printers key\n");
3731 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3733 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3734 RegCloseKey(hkeyPrinters
);
3735 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3742 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3744 size
= sizeof(PRINTER_INFO_2W
);
3746 ptr
= pPrinter
+ size
;
3748 memset(pPrinter
, 0, size
);
3753 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3760 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3762 size
= sizeof(PRINTER_INFO_4W
);
3764 ptr
= pPrinter
+ size
;
3766 memset(pPrinter
, 0, size
);
3771 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3779 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3781 size
= sizeof(PRINTER_INFO_5W
);
3783 ptr
= pPrinter
+ size
;
3785 memset(pPrinter
, 0, size
);
3791 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3799 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3801 size
= sizeof(PRINTER_INFO_6
);
3802 if (size
<= cbBuf
) {
3803 /* FIXME: We do not update the status yet */
3804 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3816 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3818 size
= sizeof(PRINTER_INFO_7W
);
3819 if (size
<= cbBuf
) {
3820 ptr
= pPrinter
+ size
;
3822 memset(pPrinter
, 0, size
);
3828 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3836 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3838 size
= sizeof(PRINTER_INFO_9W
);
3840 ptr
= pPrinter
+ size
;
3842 memset(pPrinter
, 0, size
);
3848 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3855 FIXME("Unimplemented level %d\n", Level
);
3856 SetLastError(ERROR_INVALID_LEVEL
);
3857 RegCloseKey(hkeyPrinters
);
3858 RegCloseKey(hkeyPrinter
);
3862 RegCloseKey(hkeyPrinter
);
3863 RegCloseKey(hkeyPrinters
);
3865 TRACE("returning %d needed = %d\n", ret
, needed
);
3866 if(pcbNeeded
) *pcbNeeded
= needed
;
3868 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3872 /*****************************************************************************
3873 * GetPrinterA [WINSPOOL.@]
3875 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3876 DWORD cbBuf
, LPDWORD pcbNeeded
)
3882 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
3884 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
3886 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
3887 HeapFree(GetProcessHeap(), 0, buf
);
3892 /*****************************************************************************
3893 * WINSPOOL_EnumPrintersW
3895 * Implementation of EnumPrintersW
3897 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
3898 DWORD dwLevel
, LPBYTE lpbPrinters
,
3899 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3900 LPDWORD lpdwReturned
)
3903 HKEY hkeyPrinters
, hkeyPrinter
;
3904 WCHAR PrinterName
[255];
3905 DWORD needed
= 0, number
= 0;
3906 DWORD used
, i
, left
;
3910 memset(lpbPrinters
, 0, cbBuf
);
3916 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3917 if(dwType
== PRINTER_ENUM_DEFAULT
)
3920 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3921 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3922 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3924 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3930 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3931 FIXME("dwType = %08x\n", dwType
);
3932 SetLastError(ERROR_INVALID_FLAGS
);
3936 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3938 ERR("Can't create Printers key\n");
3942 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3943 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3944 RegCloseKey(hkeyPrinters
);
3945 ERR("Can't query Printers key\n");
3948 TRACE("Found %d printers\n", number
);
3952 used
= number
* sizeof(PRINTER_INFO_1W
);
3955 used
= number
* sizeof(PRINTER_INFO_2W
);
3958 used
= number
* sizeof(PRINTER_INFO_4W
);
3961 used
= number
* sizeof(PRINTER_INFO_5W
);
3965 SetLastError(ERROR_INVALID_LEVEL
);
3966 RegCloseKey(hkeyPrinters
);
3969 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
3971 for(i
= 0; i
< number
; i
++) {
3972 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
3974 ERR("Can't enum key number %d\n", i
);
3975 RegCloseKey(hkeyPrinters
);
3978 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
3979 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
3981 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
3982 RegCloseKey(hkeyPrinters
);
3987 buf
= lpbPrinters
+ used
;
3988 left
= cbBuf
- used
;
3996 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
3999 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4002 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4005 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4008 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4011 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4014 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4017 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4020 ERR("Shouldn't be here!\n");
4021 RegCloseKey(hkeyPrinter
);
4022 RegCloseKey(hkeyPrinters
);
4025 RegCloseKey(hkeyPrinter
);
4027 RegCloseKey(hkeyPrinters
);
4034 memset(lpbPrinters
, 0, cbBuf
);
4035 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4039 *lpdwReturned
= number
;
4040 SetLastError(ERROR_SUCCESS
);
4045 /******************************************************************
4046 * EnumPrintersW [WINSPOOL.@]
4048 * Enumerates the available printers, print servers and print
4049 * providers, depending on the specified flags, name and level.
4053 * If level is set to 1:
4054 * Returns an array of PRINTER_INFO_1 data structures in the
4055 * lpbPrinters buffer.
4057 * If level is set to 2:
4058 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4059 * Returns an array of PRINTER_INFO_2 data structures in the
4060 * lpbPrinters buffer. Note that according to MSDN also an
4061 * OpenPrinter should be performed on every remote printer.
4063 * If level is set to 4 (officially WinNT only):
4064 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4065 * Fast: Only the registry is queried to retrieve printer names,
4066 * no connection to the driver is made.
4067 * Returns an array of PRINTER_INFO_4 data structures in the
4068 * lpbPrinters buffer.
4070 * If level is set to 5 (officially WinNT4/Win9x only):
4071 * Fast: Only the registry is queried to retrieve printer names,
4072 * no connection to the driver is made.
4073 * Returns an array of PRINTER_INFO_5 data structures in the
4074 * lpbPrinters buffer.
4076 * If level set to 3 or 6+:
4077 * returns zero (failure!)
4079 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4083 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4084 * - Only levels 2, 4 and 5 are implemented at the moment.
4085 * - 16-bit printer drivers are not enumerated.
4086 * - Returned amount of bytes used/needed does not match the real Windoze
4087 * implementation (as in this implementation, all strings are part
4088 * of the buffer, whereas Win32 keeps them somewhere else)
4089 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4092 * - In a regular Wine installation, no registry settings for printers
4093 * exist, which makes this function return an empty list.
4095 BOOL WINAPI
EnumPrintersW(
4096 DWORD dwType
, /* [in] Types of print objects to enumerate */
4097 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4098 DWORD dwLevel
, /* [in] type of printer info structure */
4099 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4100 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4101 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4102 LPDWORD lpdwReturned
/* [out] number of entries returned */
4105 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4106 lpdwNeeded
, lpdwReturned
);
4109 /******************************************************************
4110 * EnumPrintersA [WINSPOOL.@]
4115 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4116 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4119 UNICODE_STRING pNameU
;
4123 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4124 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4126 pNameW
= asciitounicode(&pNameU
, pName
);
4128 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4129 MS Office need this */
4130 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4132 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4134 RtlFreeUnicodeString(&pNameU
);
4136 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4138 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4142 /*****************************************************************************
4143 * WINSPOOL_GetDriverInfoFromReg [internal]
4145 * Enters the information from the registry into the DRIVER_INFO struct
4148 * zero if the printer driver does not exist in the registry
4149 * (only if Level > 1) otherwise nonzero
4151 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4154 const printenv_t
* env
,
4156 LPBYTE ptr
, /* DRIVER_INFO */
4157 LPBYTE pDriverStrings
, /* strings buffer */
4158 DWORD cbBuf
, /* size of string buffer */
4159 LPDWORD pcbNeeded
) /* space needed for str. */
4163 WCHAR driverdir
[MAX_PATH
];
4165 LPBYTE strPtr
= pDriverStrings
;
4166 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4168 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4169 debugstr_w(DriverName
), env
,
4170 Level
, di
, pDriverStrings
, cbBuf
);
4172 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4174 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4175 if (*pcbNeeded
<= cbBuf
)
4176 strcpyW((LPWSTR
)strPtr
, DriverName
);
4178 /* pName for level 1 has a different offset! */
4180 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4184 /* .cVersion and .pName for level > 1 */
4186 di
->cVersion
= env
->driverversion
;
4187 di
->pName
= (LPWSTR
) strPtr
;
4188 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4191 /* Reserve Space for the largest subdir and a Backslash*/
4192 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4193 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4194 /* Should never Fail */
4197 lstrcatW(driverdir
, env
->versionsubdir
);
4198 lstrcatW(driverdir
, backslashW
);
4200 /* dirlen must not include the terminating zero */
4201 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4203 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4204 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4205 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4210 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4213 if (*pcbNeeded
<= cbBuf
) {
4214 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4215 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4216 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4219 /* .pDriverPath is the Graphics rendering engine.
4220 The full Path is required to avoid a crash in some apps */
4221 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4223 if (*pcbNeeded
<= cbBuf
)
4224 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4226 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4227 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4230 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4231 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4233 if (*pcbNeeded
<= cbBuf
)
4234 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4236 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4237 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4240 /* .pConfigFile is the Driver user Interface */
4241 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4243 if (*pcbNeeded
<= cbBuf
)
4244 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4246 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4247 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4251 RegCloseKey(hkeyDriver
);
4252 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4257 RegCloseKey(hkeyDriver
);
4258 FIXME("level 5: incomplete\n");
4263 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4265 if (*pcbNeeded
<= cbBuf
)
4266 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4268 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4269 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4272 /* .pDependentFiles */
4273 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4275 if (*pcbNeeded
<= cbBuf
)
4276 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4278 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4279 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4281 else if (GetVersion() & 0x80000000) {
4282 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4283 size
= 2 * sizeof(WCHAR
);
4285 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4287 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4288 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4291 /* .pMonitorName is the optional Language Monitor */
4292 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4294 if (*pcbNeeded
<= cbBuf
)
4295 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4297 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4298 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4301 /* .pDefaultDataType */
4302 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4304 if(*pcbNeeded
<= cbBuf
)
4305 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4307 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4308 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4312 RegCloseKey(hkeyDriver
);
4313 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4317 /* .pszzPreviousNames */
4318 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4320 if(*pcbNeeded
<= cbBuf
)
4321 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4323 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4324 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4328 RegCloseKey(hkeyDriver
);
4329 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4333 /* support is missing, but not important enough for a FIXME */
4334 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4337 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4339 if(*pcbNeeded
<= cbBuf
)
4340 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4342 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4343 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4347 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4349 if(*pcbNeeded
<= cbBuf
)
4350 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4352 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4353 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4356 /* .pszHardwareID */
4357 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4359 if(*pcbNeeded
<= cbBuf
)
4360 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4362 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4363 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4367 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4369 if(*pcbNeeded
<= cbBuf
)
4370 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4372 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4373 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4377 RegCloseKey(hkeyDriver
);
4381 /* support is missing, but not important enough for a FIXME */
4382 TRACE("level 8: incomplete\n");
4384 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4385 RegCloseKey(hkeyDriver
);
4389 /*****************************************************************************
4390 * GetPrinterDriverW [WINSPOOL.@]
4392 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4393 DWORD Level
, LPBYTE pDriverInfo
,
4394 DWORD cbBuf
, LPDWORD pcbNeeded
)
4397 WCHAR DriverName
[100];
4398 DWORD ret
, type
, size
, needed
= 0;
4400 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4401 const printenv_t
* env
;
4403 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4404 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4407 ZeroMemory(pDriverInfo
, cbBuf
);
4409 if (!(name
= get_opened_printer_name(hPrinter
))) {
4410 SetLastError(ERROR_INVALID_HANDLE
);
4414 if (Level
< 1 || Level
== 7 || Level
> 8) {
4415 SetLastError(ERROR_INVALID_LEVEL
);
4419 env
= validate_envW(pEnvironment
);
4420 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4422 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4424 ERR("Can't create Printers key\n");
4427 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4429 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4430 RegCloseKey(hkeyPrinters
);
4431 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4434 size
= sizeof(DriverName
);
4436 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4437 (LPBYTE
)DriverName
, &size
);
4438 RegCloseKey(hkeyPrinter
);
4439 RegCloseKey(hkeyPrinters
);
4440 if(ret
!= ERROR_SUCCESS
) {
4441 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4445 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4447 ERR("Can't create Drivers key\n");
4451 size
= di_sizeof
[Level
];
4452 if ((size
<= cbBuf
) && pDriverInfo
)
4453 ptr
= pDriverInfo
+ size
;
4455 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4456 env
, Level
, pDriverInfo
, ptr
,
4457 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4459 RegCloseKey(hkeyDrivers
);
4463 RegCloseKey(hkeyDrivers
);
4465 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4466 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4467 if(cbBuf
>= size
+ needed
) return TRUE
;
4468 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4472 /*****************************************************************************
4473 * GetPrinterDriverA [WINSPOOL.@]
4475 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4476 DWORD Level
, LPBYTE pDriverInfo
,
4477 DWORD cbBuf
, LPDWORD pcbNeeded
)
4480 UNICODE_STRING pEnvW
;
4486 ZeroMemory(pDriverInfo
, cbBuf
);
4487 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4490 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4491 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4494 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4496 HeapFree(GetProcessHeap(), 0, buf
);
4498 RtlFreeUnicodeString(&pEnvW
);
4502 /*****************************************************************************
4503 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4505 * Return the PATH for the Printer-Drivers (UNICODE)
4508 * pName [I] Servername (NT only) or NULL (local Computer)
4509 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4510 * Level [I] Structure-Level (must be 1)
4511 * pDriverDirectory [O] PTR to Buffer that receives the Result
4512 * cbBuf [I] Size of Buffer at pDriverDirectory
4513 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4514 * required for pDriverDirectory
4517 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4518 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4519 * if cbBuf is too small
4521 * Native Values returned in pDriverDirectory on Success:
4522 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4523 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4524 *| win9x(Windows 4.0): "%winsysdir%"
4526 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4529 *- Only NULL or "" is supported for pName
4532 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4533 DWORD Level
, LPBYTE pDriverDirectory
,
4534 DWORD cbBuf
, LPDWORD pcbNeeded
)
4536 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4537 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4539 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4542 /* (Level != 1) is ignored in win9x */
4543 SetLastError(ERROR_INVALID_LEVEL
);
4546 if (pcbNeeded
== NULL
) {
4547 /* (pcbNeeded == NULL) is ignored in win9x */
4548 SetLastError(RPC_X_NULL_REF_POINTER
);
4552 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4553 pDriverDirectory
, cbBuf
, pcbNeeded
);
4558 /*****************************************************************************
4559 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4561 * Return the PATH for the Printer-Drivers (ANSI)
4563 * See GetPrinterDriverDirectoryW.
4566 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4569 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4570 DWORD Level
, LPBYTE pDriverDirectory
,
4571 DWORD cbBuf
, LPDWORD pcbNeeded
)
4573 UNICODE_STRING nameW
, environmentW
;
4576 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4577 WCHAR
*driverDirectoryW
= NULL
;
4579 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4580 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4582 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4584 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4585 else nameW
.Buffer
= NULL
;
4586 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4587 else environmentW
.Buffer
= NULL
;
4589 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4590 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4593 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4594 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4596 *pcbNeeded
= needed
;
4597 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4599 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4601 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4603 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4604 RtlFreeUnicodeString(&environmentW
);
4605 RtlFreeUnicodeString(&nameW
);
4610 /*****************************************************************************
4611 * AddPrinterDriverA [WINSPOOL.@]
4613 * See AddPrinterDriverW.
4616 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4618 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4619 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4622 /******************************************************************************
4623 * AddPrinterDriverW (WINSPOOL.@)
4625 * Install a Printer Driver
4628 * pName [I] Servername or NULL (local Computer)
4629 * level [I] Level for the supplied DRIVER_INFO_*W struct
4630 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4637 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4639 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4640 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4643 /*****************************************************************************
4644 * AddPrintProcessorA [WINSPOOL.@]
4646 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4647 LPSTR pPrintProcessorName
)
4649 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4650 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4654 /*****************************************************************************
4655 * AddPrintProcessorW [WINSPOOL.@]
4657 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4658 LPWSTR pPrintProcessorName
)
4660 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4661 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4665 /*****************************************************************************
4666 * AddPrintProvidorA [WINSPOOL.@]
4668 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4670 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4674 /*****************************************************************************
4675 * AddPrintProvidorW [WINSPOOL.@]
4677 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4679 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4683 /*****************************************************************************
4684 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4686 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4687 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4689 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4690 pDevModeOutput
, pDevModeInput
);
4694 /*****************************************************************************
4695 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4697 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4698 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4700 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4701 pDevModeOutput
, pDevModeInput
);
4705 /*****************************************************************************
4706 * PrinterProperties [WINSPOOL.@]
4708 * Displays a dialog to set the properties of the printer.
4711 * nonzero on success or zero on failure
4714 * implemented as stub only
4716 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4717 HANDLE hPrinter
/* [in] handle to printer object */
4719 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4720 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4724 /*****************************************************************************
4725 * EnumJobsA [WINSPOOL.@]
4728 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4729 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4732 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4733 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4735 if(pcbNeeded
) *pcbNeeded
= 0;
4736 if(pcReturned
) *pcReturned
= 0;
4741 /*****************************************************************************
4742 * EnumJobsW [WINSPOOL.@]
4745 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4746 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4749 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4750 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4752 if(pcbNeeded
) *pcbNeeded
= 0;
4753 if(pcReturned
) *pcReturned
= 0;
4757 /*****************************************************************************
4758 * WINSPOOL_EnumPrinterDrivers [internal]
4760 * Delivers information about all printer drivers installed on the
4761 * localhost or a given server
4764 * nonzero on success or zero on failure. If the buffer for the returned
4765 * information is too small the function will return an error
4768 * - only implemented for localhost, foreign hosts will return an error
4770 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4771 DWORD Level
, LPBYTE pDriverInfo
,
4773 DWORD cbBuf
, LPDWORD pcbNeeded
,
4774 LPDWORD pcFound
, DWORD data_offset
)
4778 const printenv_t
* env
;
4780 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4781 debugstr_w(pName
), debugstr_w(pEnvironment
),
4782 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4784 env
= validate_envW(pEnvironment
);
4785 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4789 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4791 ERR("Can't open Drivers key\n");
4795 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4796 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4797 RegCloseKey(hkeyDrivers
);
4798 ERR("Can't query Drivers key\n");
4801 TRACE("Found %d Drivers\n", *pcFound
);
4803 /* get size of single struct
4804 * unicode and ascii structure have the same size
4806 size
= di_sizeof
[Level
];
4808 if (data_offset
== 0)
4809 data_offset
= size
* (*pcFound
);
4810 *pcbNeeded
= data_offset
;
4812 for( i
= 0; i
< *pcFound
; i
++) {
4813 WCHAR DriverNameW
[255];
4814 PBYTE table_ptr
= NULL
;
4815 PBYTE data_ptr
= NULL
;
4818 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4820 ERR("Can't enum key number %d\n", i
);
4821 RegCloseKey(hkeyDrivers
);
4825 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4826 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4827 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4828 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4830 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4831 env
, Level
, table_ptr
, data_ptr
,
4832 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4834 RegCloseKey(hkeyDrivers
);
4838 *pcbNeeded
+= needed
;
4841 RegCloseKey(hkeyDrivers
);
4843 if(cbBuf
< *pcbNeeded
){
4844 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4851 /*****************************************************************************
4852 * EnumPrinterDriversW [WINSPOOL.@]
4854 * see function EnumPrinterDrivers for RETURNS, BUGS
4856 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4857 LPBYTE pDriverInfo
, DWORD cbBuf
,
4858 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4860 static const WCHAR allW
[] = {'a','l','l',0};
4864 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
4866 SetLastError(RPC_X_NULL_REF_POINTER
);
4870 /* check for local drivers */
4871 if((pName
) && (pName
[0])) {
4872 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4873 SetLastError(ERROR_ACCESS_DENIED
);
4877 /* check input parameter */
4878 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4879 SetLastError(ERROR_INVALID_LEVEL
);
4883 if(pDriverInfo
&& cbBuf
> 0)
4884 memset( pDriverInfo
, 0, cbBuf
);
4886 /* Exception: pull all printers */
4887 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4889 DWORD i
, needed
, bufsize
= cbBuf
;
4890 DWORD total_needed
= 0;
4891 DWORD total_found
= 0;
4894 /* Precompute the overall total; we need this to know
4895 where pointers end and data begins (i.e. data_offset) */
4896 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4899 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4900 NULL
, 0, 0, &needed
, &found
, 0);
4901 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4902 total_needed
+= needed
;
4903 total_found
+= found
;
4906 data_offset
= di_sizeof
[Level
] * total_found
;
4911 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4914 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4915 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
4916 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4918 *pcReturned
+= found
;
4919 *pcbNeeded
= needed
;
4920 data_offset
= needed
;
4921 total_found
+= found
;
4926 /* Normal behavior */
4927 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4928 0, cbBuf
, pcbNeeded
, &found
, 0);
4930 *pcReturned
= found
;
4935 /*****************************************************************************
4936 * EnumPrinterDriversA [WINSPOOL.@]
4938 * see function EnumPrinterDrivers for RETURNS, BUGS
4940 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4941 LPBYTE pDriverInfo
, DWORD cbBuf
,
4942 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4945 UNICODE_STRING pNameW
, pEnvironmentW
;
4946 PWSTR pwstrNameW
, pwstrEnvironmentW
;
4950 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4952 pwstrNameW
= asciitounicode(&pNameW
, pName
);
4953 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
4955 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
4956 buf
, cbBuf
, pcbNeeded
, pcReturned
);
4958 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
4960 HeapFree(GetProcessHeap(), 0, buf
);
4962 RtlFreeUnicodeString(&pNameW
);
4963 RtlFreeUnicodeString(&pEnvironmentW
);
4968 /******************************************************************************
4969 * EnumPortsA (WINSPOOL.@)
4974 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
4975 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4978 LPBYTE bufferW
= NULL
;
4979 LPWSTR nameW
= NULL
;
4981 DWORD numentries
= 0;
4984 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
4985 cbBuf
, pcbNeeded
, pcReturned
);
4987 /* convert servername to unicode */
4989 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
4990 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4991 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
4993 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4994 needed
= cbBuf
* sizeof(WCHAR
);
4995 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
4996 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
4998 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
4999 if (pcbNeeded
) needed
= *pcbNeeded
;
5000 /* HeapReAlloc return NULL, when bufferW was NULL */
5001 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5002 HeapAlloc(GetProcessHeap(), 0, needed
);
5004 /* Try again with the large Buffer */
5005 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5007 needed
= pcbNeeded
? *pcbNeeded
: 0;
5008 numentries
= pcReturned
? *pcReturned
: 0;
5011 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5012 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5015 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5016 DWORD entrysize
= 0;
5019 LPPORT_INFO_2W pi2w
;
5020 LPPORT_INFO_2A pi2a
;
5023 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5025 /* First pass: calculate the size for all Entries */
5026 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5027 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5029 while (index
< numentries
) {
5031 needed
+= entrysize
; /* PORT_INFO_?A */
5032 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5034 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5035 NULL
, 0, NULL
, NULL
);
5037 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5038 NULL
, 0, NULL
, NULL
);
5039 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5040 NULL
, 0, NULL
, NULL
);
5042 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5043 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5044 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5047 /* check for errors and quit on failure */
5048 if (cbBuf
< needed
) {
5049 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5053 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5054 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5055 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5056 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5057 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5059 /* Second Pass: Fill the User Buffer (if we have one) */
5060 while ((index
< numentries
) && pPorts
) {
5062 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5063 pi2a
->pPortName
= ptr
;
5064 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5065 ptr
, cbBuf
, NULL
, NULL
);
5069 pi2a
->pMonitorName
= ptr
;
5070 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5071 ptr
, cbBuf
, NULL
, NULL
);
5075 pi2a
->pDescription
= ptr
;
5076 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5077 ptr
, cbBuf
, NULL
, NULL
);
5081 pi2a
->fPortType
= pi2w
->fPortType
;
5082 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5085 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5086 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5087 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5092 if (pcbNeeded
) *pcbNeeded
= needed
;
5093 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5095 HeapFree(GetProcessHeap(), 0, nameW
);
5096 HeapFree(GetProcessHeap(), 0, bufferW
);
5098 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5099 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5105 /******************************************************************************
5106 * EnumPortsW (WINSPOOL.@)
5108 * Enumerate available Ports
5111 * pName [I] Servername or NULL (local Computer)
5112 * Level [I] Structure-Level (1 or 2)
5113 * pPorts [O] PTR to Buffer that receives the Result
5114 * cbBuf [I] Size of Buffer at pPorts
5115 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5116 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5120 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5123 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5126 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5127 cbBuf
, pcbNeeded
, pcReturned
);
5129 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5131 /* Level is not checked in win9x */
5132 if (!Level
|| (Level
> 2)) {
5133 WARN("level (%d) is ignored in win9x\n", Level
);
5134 SetLastError(ERROR_INVALID_LEVEL
);
5137 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5138 SetLastError(RPC_X_NULL_REF_POINTER
);
5142 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5145 /******************************************************************************
5146 * GetDefaultPrinterW (WINSPOOL.@)
5149 * This function must read the value from data 'device' of key
5150 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5152 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5156 WCHAR
*buffer
, *ptr
;
5160 SetLastError(ERROR_INVALID_PARAMETER
);
5164 /* make the buffer big enough for the stuff from the profile/registry,
5165 * the content must fit into the local buffer to compute the correct
5166 * size even if the extern buffer is too small or not given.
5167 * (20 for ,driver,port) */
5169 len
= max(100, (insize
+ 20));
5170 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5172 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5174 SetLastError (ERROR_FILE_NOT_FOUND
);
5178 TRACE("%s\n", debugstr_w(buffer
));
5180 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5182 SetLastError(ERROR_INVALID_NAME
);
5188 *namesize
= strlenW(buffer
) + 1;
5189 if(!name
|| (*namesize
> insize
))
5191 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5195 strcpyW(name
, buffer
);
5198 HeapFree( GetProcessHeap(), 0, buffer
);
5203 /******************************************************************************
5204 * GetDefaultPrinterA (WINSPOOL.@)
5206 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5210 WCHAR
*bufferW
= NULL
;
5214 SetLastError(ERROR_INVALID_PARAMETER
);
5218 if(name
&& *namesize
) {
5220 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5223 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5228 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5232 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5235 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5238 HeapFree( GetProcessHeap(), 0, bufferW
);
5243 /******************************************************************************
5244 * SetDefaultPrinterW (WINSPOOL.204)
5246 * Set the Name of the Default Printer
5249 * pszPrinter [I] Name of the Printer or NULL
5256 * When the Parameter is NULL or points to an Empty String and
5257 * a Default Printer was already present, then this Function changes nothing.
5258 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5259 * the First enumerated local Printer is used.
5262 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5265 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5267 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5271 /******************************************************************************
5272 * SetDefaultPrinterA (WINSPOOL.202)
5274 * See SetDefaultPrinterW.
5277 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5280 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5282 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5287 /******************************************************************************
5288 * SetPrinterDataExA (WINSPOOL.@)
5290 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5291 LPCSTR pValueName
, DWORD Type
,
5292 LPBYTE pData
, DWORD cbData
)
5294 HKEY hkeyPrinter
, hkeySubkey
;
5297 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5298 debugstr_a(pValueName
), Type
, pData
, cbData
);
5300 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5304 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5306 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5307 RegCloseKey(hkeyPrinter
);
5310 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5311 RegCloseKey(hkeySubkey
);
5312 RegCloseKey(hkeyPrinter
);
5316 /******************************************************************************
5317 * SetPrinterDataExW (WINSPOOL.@)
5319 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5320 LPCWSTR pValueName
, DWORD Type
,
5321 LPBYTE pData
, DWORD cbData
)
5323 HKEY hkeyPrinter
, hkeySubkey
;
5326 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5327 debugstr_w(pValueName
), Type
, pData
, cbData
);
5329 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5333 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5335 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5336 RegCloseKey(hkeyPrinter
);
5339 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5340 RegCloseKey(hkeySubkey
);
5341 RegCloseKey(hkeyPrinter
);
5345 /******************************************************************************
5346 * SetPrinterDataA (WINSPOOL.@)
5348 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5349 LPBYTE pData
, DWORD cbData
)
5351 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5355 /******************************************************************************
5356 * SetPrinterDataW (WINSPOOL.@)
5358 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5359 LPBYTE pData
, DWORD cbData
)
5361 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5365 /******************************************************************************
5366 * GetPrinterDataExA (WINSPOOL.@)
5368 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5369 LPCSTR pValueName
, LPDWORD pType
,
5370 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5372 opened_printer_t
*printer
;
5373 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5376 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5377 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5379 printer
= get_opened_printer(hPrinter
);
5380 if(!printer
) return ERROR_INVALID_HANDLE
;
5382 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5383 if (ret
) return ret
;
5385 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5387 if (printer
->name
) {
5389 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5391 RegCloseKey(hkeyPrinters
);
5394 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5395 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5396 RegCloseKey(hkeyPrinter
);
5397 RegCloseKey(hkeyPrinters
);
5402 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5403 0, pType
, pData
, pcbNeeded
);
5405 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5407 RegCloseKey(hkeySubkey
);
5408 RegCloseKey(hkeyPrinter
);
5409 RegCloseKey(hkeyPrinters
);
5411 TRACE("--> %d\n", ret
);
5415 /******************************************************************************
5416 * GetPrinterDataExW (WINSPOOL.@)
5418 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5419 LPCWSTR pValueName
, LPDWORD pType
,
5420 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5422 opened_printer_t
*printer
;
5423 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5426 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5427 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5429 printer
= get_opened_printer(hPrinter
);
5430 if(!printer
) return ERROR_INVALID_HANDLE
;
5432 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5433 if (ret
) return ret
;
5435 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5437 if (printer
->name
) {
5439 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5441 RegCloseKey(hkeyPrinters
);
5444 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5445 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5446 RegCloseKey(hkeyPrinter
);
5447 RegCloseKey(hkeyPrinters
);
5452 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5453 0, pType
, pData
, pcbNeeded
);
5455 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5457 RegCloseKey(hkeySubkey
);
5458 RegCloseKey(hkeyPrinter
);
5459 RegCloseKey(hkeyPrinters
);
5461 TRACE("--> %d\n", ret
);
5465 /******************************************************************************
5466 * GetPrinterDataA (WINSPOOL.@)
5468 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5469 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5471 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5472 pData
, nSize
, pcbNeeded
);
5475 /******************************************************************************
5476 * GetPrinterDataW (WINSPOOL.@)
5478 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5479 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5481 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5482 pData
, nSize
, pcbNeeded
);
5485 /*******************************************************************************
5486 * EnumPrinterDataExW [WINSPOOL.@]
5488 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5489 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5490 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5492 HKEY hkPrinter
, hkSubKey
;
5493 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5494 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5499 PPRINTER_ENUM_VALUESW ppev
;
5501 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5503 if (pKeyName
== NULL
|| *pKeyName
== 0)
5504 return ERROR_INVALID_PARAMETER
;
5506 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5507 if (ret
!= ERROR_SUCCESS
)
5509 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5514 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5515 if (ret
!= ERROR_SUCCESS
)
5517 r
= RegCloseKey (hkPrinter
);
5518 if (r
!= ERROR_SUCCESS
)
5519 WARN ("RegCloseKey returned %i\n", r
);
5520 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5521 debugstr_w (pKeyName
), ret
);
5525 ret
= RegCloseKey (hkPrinter
);
5526 if (ret
!= ERROR_SUCCESS
)
5528 ERR ("RegCloseKey returned %i\n", ret
);
5529 r
= RegCloseKey (hkSubKey
);
5530 if (r
!= ERROR_SUCCESS
)
5531 WARN ("RegCloseKey returned %i\n", r
);
5535 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5536 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5537 if (ret
!= ERROR_SUCCESS
)
5539 r
= RegCloseKey (hkSubKey
);
5540 if (r
!= ERROR_SUCCESS
)
5541 WARN ("RegCloseKey returned %i\n", r
);
5542 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5546 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5547 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5549 if (cValues
== 0) /* empty key */
5551 r
= RegCloseKey (hkSubKey
);
5552 if (r
!= ERROR_SUCCESS
)
5553 WARN ("RegCloseKey returned %i\n", r
);
5554 *pcbEnumValues
= *pnEnumValues
= 0;
5555 return ERROR_SUCCESS
;
5558 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5560 hHeap
= GetProcessHeap ();
5563 ERR ("GetProcessHeap failed\n");
5564 r
= RegCloseKey (hkSubKey
);
5565 if (r
!= ERROR_SUCCESS
)
5566 WARN ("RegCloseKey returned %i\n", r
);
5567 return ERROR_OUTOFMEMORY
;
5570 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5571 if (lpValueName
== NULL
)
5573 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5574 r
= RegCloseKey (hkSubKey
);
5575 if (r
!= ERROR_SUCCESS
)
5576 WARN ("RegCloseKey returned %i\n", r
);
5577 return ERROR_OUTOFMEMORY
;
5580 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5581 if (lpValue
== NULL
)
5583 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5584 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5585 WARN ("HeapFree failed with code %i\n", GetLastError ());
5586 r
= RegCloseKey (hkSubKey
);
5587 if (r
!= ERROR_SUCCESS
)
5588 WARN ("RegCloseKey returned %i\n", r
);
5589 return ERROR_OUTOFMEMORY
;
5592 TRACE ("pass 1: calculating buffer required for all names and values\n");
5594 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5596 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5598 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5600 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5601 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5602 NULL
, NULL
, lpValue
, &cbValueLen
);
5603 if (ret
!= ERROR_SUCCESS
)
5605 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5606 WARN ("HeapFree failed with code %i\n", GetLastError ());
5607 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5608 WARN ("HeapFree failed with code %i\n", GetLastError ());
5609 r
= RegCloseKey (hkSubKey
);
5610 if (r
!= ERROR_SUCCESS
)
5611 WARN ("RegCloseKey returned %i\n", r
);
5612 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5616 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5617 debugstr_w (lpValueName
), dwIndex
,
5618 cbValueNameLen
+ 1, cbValueLen
);
5620 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5621 cbBufSize
+= cbValueLen
;
5624 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5626 *pcbEnumValues
= cbBufSize
;
5627 *pnEnumValues
= cValues
;
5629 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5631 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5632 WARN ("HeapFree failed with code %i\n", GetLastError ());
5633 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5634 WARN ("HeapFree failed with code %i\n", GetLastError ());
5635 r
= RegCloseKey (hkSubKey
);
5636 if (r
!= ERROR_SUCCESS
)
5637 WARN ("RegCloseKey returned %i\n", r
);
5638 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5639 return ERROR_MORE_DATA
;
5642 TRACE ("pass 2: copying all names and values to buffer\n");
5644 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5645 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5647 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5649 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5650 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5651 NULL
, &dwType
, lpValue
, &cbValueLen
);
5652 if (ret
!= ERROR_SUCCESS
)
5654 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5655 WARN ("HeapFree failed with code %i\n", GetLastError ());
5656 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5657 WARN ("HeapFree failed with code %i\n", GetLastError ());
5658 r
= RegCloseKey (hkSubKey
);
5659 if (r
!= ERROR_SUCCESS
)
5660 WARN ("RegCloseKey returned %i\n", r
);
5661 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5665 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5666 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5667 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5668 pEnumValues
+= cbValueNameLen
;
5670 /* return # of *bytes* (including trailing \0), not # of chars */
5671 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5673 ppev
[dwIndex
].dwType
= dwType
;
5675 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5676 ppev
[dwIndex
].pData
= pEnumValues
;
5677 pEnumValues
+= cbValueLen
;
5679 ppev
[dwIndex
].cbData
= cbValueLen
;
5681 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5682 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5685 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5687 ret
= GetLastError ();
5688 ERR ("HeapFree failed with code %i\n", ret
);
5689 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5690 WARN ("HeapFree failed with code %i\n", GetLastError ());
5691 r
= RegCloseKey (hkSubKey
);
5692 if (r
!= ERROR_SUCCESS
)
5693 WARN ("RegCloseKey returned %i\n", r
);
5697 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5699 ret
= GetLastError ();
5700 ERR ("HeapFree failed with code %i\n", ret
);
5701 r
= RegCloseKey (hkSubKey
);
5702 if (r
!= ERROR_SUCCESS
)
5703 WARN ("RegCloseKey returned %i\n", r
);
5707 ret
= RegCloseKey (hkSubKey
);
5708 if (ret
!= ERROR_SUCCESS
)
5710 ERR ("RegCloseKey returned %i\n", ret
);
5714 return ERROR_SUCCESS
;
5717 /*******************************************************************************
5718 * EnumPrinterDataExA [WINSPOOL.@]
5720 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5721 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5722 * what Windows 2000 SP1 does.
5725 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5726 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5727 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5731 DWORD ret
, dwIndex
, dwBufSize
;
5735 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5737 if (pKeyName
== NULL
|| *pKeyName
== 0)
5738 return ERROR_INVALID_PARAMETER
;
5740 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5743 ret
= GetLastError ();
5744 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5748 hHeap
= GetProcessHeap ();
5751 ERR ("GetProcessHeap failed\n");
5752 return ERROR_OUTOFMEMORY
;
5755 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5756 if (pKeyNameW
== NULL
)
5758 ERR ("Failed to allocate %i bytes from process heap\n",
5759 (LONG
)(len
* sizeof (WCHAR
)));
5760 return ERROR_OUTOFMEMORY
;
5763 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5765 ret
= GetLastError ();
5766 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5767 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5768 WARN ("HeapFree failed with code %i\n", GetLastError ());
5772 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5773 pcbEnumValues
, pnEnumValues
);
5774 if (ret
!= ERROR_SUCCESS
)
5776 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5777 WARN ("HeapFree failed with code %i\n", GetLastError ());
5778 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5782 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5784 ret
= GetLastError ();
5785 ERR ("HeapFree failed with code %i\n", ret
);
5789 if (*pnEnumValues
== 0) /* empty key */
5790 return ERROR_SUCCESS
;
5793 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5795 PPRINTER_ENUM_VALUESW ppev
=
5796 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5798 if (dwBufSize
< ppev
->cbValueName
)
5799 dwBufSize
= ppev
->cbValueName
;
5801 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5802 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5803 dwBufSize
= ppev
->cbData
;
5806 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5808 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5809 if (pBuffer
== NULL
)
5811 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5812 return ERROR_OUTOFMEMORY
;
5815 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5817 PPRINTER_ENUM_VALUESW ppev
=
5818 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5820 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5821 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5825 ret
= GetLastError ();
5826 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5827 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5828 WARN ("HeapFree failed with code %i\n", GetLastError ());
5832 memcpy (ppev
->pValueName
, pBuffer
, len
);
5834 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5836 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5837 ppev
->dwType
!= REG_MULTI_SZ
)
5840 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5841 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5844 ret
= GetLastError ();
5845 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5846 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5847 WARN ("HeapFree failed with code %i\n", GetLastError ());
5851 memcpy (ppev
->pData
, pBuffer
, len
);
5853 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5854 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5857 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5859 ret
= GetLastError ();
5860 ERR ("HeapFree failed with code %i\n", ret
);
5864 return ERROR_SUCCESS
;
5867 /******************************************************************************
5868 * AbortPrinter (WINSPOOL.@)
5870 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5872 FIXME("(%p), stub!\n", hPrinter
);
5876 /******************************************************************************
5877 * AddPortA (WINSPOOL.@)
5882 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5884 LPWSTR nameW
= NULL
;
5885 LPWSTR monitorW
= NULL
;
5889 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
5892 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5893 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5894 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5898 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5899 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5900 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5902 res
= AddPortW(nameW
, hWnd
, monitorW
);
5903 HeapFree(GetProcessHeap(), 0, nameW
);
5904 HeapFree(GetProcessHeap(), 0, monitorW
);
5908 /******************************************************************************
5909 * AddPortW (WINSPOOL.@)
5911 * Add a Port for a specific Monitor
5914 * pName [I] Servername or NULL (local Computer)
5915 * hWnd [I] Handle to parent Window for the Dialog-Box
5916 * pMonitorName [I] Name of the Monitor that manage the Port
5923 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
5925 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
5927 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5929 if (!pMonitorName
) {
5930 SetLastError(RPC_X_NULL_REF_POINTER
);
5934 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
5937 /******************************************************************************
5938 * AddPortExA (WINSPOOL.@)
5943 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
5946 PORT_INFO_2A
* pi2A
;
5947 LPWSTR nameW
= NULL
;
5948 LPWSTR monitorW
= NULL
;
5952 pi2A
= (PORT_INFO_2A
*) pBuffer
;
5954 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
5955 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
5957 if ((level
< 1) || (level
> 2)) {
5958 SetLastError(ERROR_INVALID_LEVEL
);
5963 SetLastError(ERROR_INVALID_PARAMETER
);
5968 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5969 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5970 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5974 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5975 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5976 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5979 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
5981 if (pi2A
->pPortName
) {
5982 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
5983 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5984 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
5988 if (pi2A
->pMonitorName
) {
5989 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
5990 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5991 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
5994 if (pi2A
->pDescription
) {
5995 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
5996 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5997 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
5999 pi2W
.fPortType
= pi2A
->fPortType
;
6000 pi2W
.Reserved
= pi2A
->Reserved
;
6003 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6005 HeapFree(GetProcessHeap(), 0, nameW
);
6006 HeapFree(GetProcessHeap(), 0, monitorW
);
6007 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6008 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6009 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6014 /******************************************************************************
6015 * AddPortExW (WINSPOOL.@)
6017 * Add a Port for a specific Monitor, without presenting a user interface
6020 * pName [I] Servername or NULL (local Computer)
6021 * level [I] Structure-Level (1 or 2) for pBuffer
6022 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6023 * pMonitorName [I] Name of the Monitor that manage the Port
6030 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6034 pi2
= (PORT_INFO_2W
*) pBuffer
;
6036 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6037 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6038 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6039 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6041 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6043 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6044 SetLastError(ERROR_INVALID_PARAMETER
);
6048 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6051 /******************************************************************************
6052 * AddPrinterConnectionA (WINSPOOL.@)
6054 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6056 FIXME("%s\n", debugstr_a(pName
));
6060 /******************************************************************************
6061 * AddPrinterConnectionW (WINSPOOL.@)
6063 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6065 FIXME("%s\n", debugstr_w(pName
));
6069 /******************************************************************************
6070 * AddPrinterDriverExW (WINSPOOL.@)
6072 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6075 * pName [I] Servername or NULL (local Computer)
6076 * level [I] Level for the supplied DRIVER_INFO_*W struct
6077 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6078 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6085 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6087 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6089 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6091 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6092 SetLastError(ERROR_INVALID_LEVEL
);
6097 SetLastError(ERROR_INVALID_PARAMETER
);
6101 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6104 /******************************************************************************
6105 * AddPrinterDriverExA (WINSPOOL.@)
6107 * See AddPrinterDriverExW.
6110 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6112 DRIVER_INFO_8A
*diA
;
6114 LPWSTR nameW
= NULL
;
6119 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6121 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6122 ZeroMemory(&diW
, sizeof(diW
));
6124 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6125 SetLastError(ERROR_INVALID_LEVEL
);
6130 SetLastError(ERROR_INVALID_PARAMETER
);
6134 /* convert servername to unicode */
6136 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6137 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6138 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6142 diW
.cVersion
= diA
->cVersion
;
6145 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6146 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6147 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6150 if (diA
->pEnvironment
) {
6151 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6152 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6153 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6156 if (diA
->pDriverPath
) {
6157 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6158 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6159 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6162 if (diA
->pDataFile
) {
6163 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6164 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6165 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6168 if (diA
->pConfigFile
) {
6169 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6170 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6171 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6174 if ((Level
> 2) && diA
->pDependentFiles
) {
6175 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6176 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6177 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6178 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6181 if ((Level
> 2) && diA
->pMonitorName
) {
6182 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6183 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6184 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6187 if ((Level
> 3) && diA
->pDefaultDataType
) {
6188 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6189 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6190 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6193 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6194 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6195 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6196 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6197 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6200 if ((Level
> 5) && diA
->pszMfgName
) {
6201 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6202 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6203 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6206 if ((Level
> 5) && diA
->pszOEMUrl
) {
6207 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6208 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6209 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6212 if ((Level
> 5) && diA
->pszHardwareID
) {
6213 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6214 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6215 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6218 if ((Level
> 5) && diA
->pszProvider
) {
6219 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6220 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6221 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6225 FIXME("level %u is incomplete\n", Level
);
6228 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6229 TRACE("got %u with %u\n", res
, GetLastError());
6230 HeapFree(GetProcessHeap(), 0, nameW
);
6231 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6232 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6233 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6234 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6235 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6236 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6237 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6238 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6239 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6240 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6241 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6242 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6243 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6245 TRACE("=> %u with %u\n", res
, GetLastError());
6249 /******************************************************************************
6250 * ConfigurePortA (WINSPOOL.@)
6252 * See ConfigurePortW.
6255 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6257 LPWSTR nameW
= NULL
;
6258 LPWSTR portW
= NULL
;
6262 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6264 /* convert servername to unicode */
6266 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6267 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6268 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6271 /* convert portname to unicode */
6273 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6274 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6275 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6278 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6279 HeapFree(GetProcessHeap(), 0, nameW
);
6280 HeapFree(GetProcessHeap(), 0, portW
);
6284 /******************************************************************************
6285 * ConfigurePortW (WINSPOOL.@)
6287 * Display the Configuration-Dialog for a specific Port
6290 * pName [I] Servername or NULL (local Computer)
6291 * hWnd [I] Handle to parent Window for the Dialog-Box
6292 * pPortName [I] Name of the Port, that should be configured
6299 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6302 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6304 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6307 SetLastError(RPC_X_NULL_REF_POINTER
);
6311 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6314 /******************************************************************************
6315 * ConnectToPrinterDlg (WINSPOOL.@)
6317 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6319 FIXME("%p %x\n", hWnd
, Flags
);
6323 /******************************************************************************
6324 * DeletePrinterConnectionA (WINSPOOL.@)
6326 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6328 FIXME("%s\n", debugstr_a(pName
));
6332 /******************************************************************************
6333 * DeletePrinterConnectionW (WINSPOOL.@)
6335 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6337 FIXME("%s\n", debugstr_w(pName
));
6341 /******************************************************************************
6342 * DeletePrinterDriverExW (WINSPOOL.@)
6344 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6345 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6350 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6351 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6353 if(pName
&& pName
[0])
6355 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6356 SetLastError(ERROR_INVALID_PARAMETER
);
6362 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6363 SetLastError(ERROR_INVALID_PARAMETER
);
6367 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6371 ERR("Can't open drivers key\n");
6375 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6378 RegCloseKey(hkey_drivers
);
6383 /******************************************************************************
6384 * DeletePrinterDriverExA (WINSPOOL.@)
6386 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6387 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6389 UNICODE_STRING NameW
, EnvW
, DriverW
;
6392 asciitounicode(&NameW
, pName
);
6393 asciitounicode(&EnvW
, pEnvironment
);
6394 asciitounicode(&DriverW
, pDriverName
);
6396 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6398 RtlFreeUnicodeString(&DriverW
);
6399 RtlFreeUnicodeString(&EnvW
);
6400 RtlFreeUnicodeString(&NameW
);
6405 /******************************************************************************
6406 * DeletePrinterDataExW (WINSPOOL.@)
6408 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6411 FIXME("%p %s %s\n", hPrinter
,
6412 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6413 return ERROR_INVALID_PARAMETER
;
6416 /******************************************************************************
6417 * DeletePrinterDataExA (WINSPOOL.@)
6419 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6422 FIXME("%p %s %s\n", hPrinter
,
6423 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6424 return ERROR_INVALID_PARAMETER
;
6427 /******************************************************************************
6428 * DeletePrintProcessorA (WINSPOOL.@)
6430 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6432 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6433 debugstr_a(pPrintProcessorName
));
6437 /******************************************************************************
6438 * DeletePrintProcessorW (WINSPOOL.@)
6440 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6442 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6443 debugstr_w(pPrintProcessorName
));
6447 /******************************************************************************
6448 * DeletePrintProvidorA (WINSPOOL.@)
6450 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6452 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6453 debugstr_a(pPrintProviderName
));
6457 /******************************************************************************
6458 * DeletePrintProvidorW (WINSPOOL.@)
6460 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6462 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6463 debugstr_w(pPrintProviderName
));
6467 /******************************************************************************
6468 * EnumFormsA (WINSPOOL.@)
6470 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6471 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6473 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6474 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6478 /******************************************************************************
6479 * EnumFormsW (WINSPOOL.@)
6481 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6482 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6484 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6485 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6489 /*****************************************************************************
6490 * EnumMonitorsA [WINSPOOL.@]
6492 * See EnumMonitorsW.
6495 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6496 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6499 LPBYTE bufferW
= NULL
;
6500 LPWSTR nameW
= NULL
;
6502 DWORD numentries
= 0;
6505 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6506 cbBuf
, pcbNeeded
, pcReturned
);
6508 /* convert servername to unicode */
6510 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6511 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6512 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6514 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6515 needed
= cbBuf
* sizeof(WCHAR
);
6516 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6517 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6519 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6520 if (pcbNeeded
) needed
= *pcbNeeded
;
6521 /* HeapReAlloc return NULL, when bufferW was NULL */
6522 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6523 HeapAlloc(GetProcessHeap(), 0, needed
);
6525 /* Try again with the large Buffer */
6526 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6528 numentries
= pcReturned
? *pcReturned
: 0;
6531 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6532 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6535 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6536 DWORD entrysize
= 0;
6539 LPMONITOR_INFO_2W mi2w
;
6540 LPMONITOR_INFO_2A mi2a
;
6542 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6543 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6545 /* First pass: calculate the size for all Entries */
6546 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6547 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6549 while (index
< numentries
) {
6551 needed
+= entrysize
; /* MONITOR_INFO_?A */
6552 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6554 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6555 NULL
, 0, NULL
, NULL
);
6557 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6558 NULL
, 0, NULL
, NULL
);
6559 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6560 NULL
, 0, NULL
, NULL
);
6562 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6563 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6564 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6567 /* check for errors and quit on failure */
6568 if (cbBuf
< needed
) {
6569 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6573 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6574 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6575 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6576 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6577 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6579 /* Second Pass: Fill the User Buffer (if we have one) */
6580 while ((index
< numentries
) && pMonitors
) {
6582 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6584 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6585 ptr
, cbBuf
, NULL
, NULL
);
6589 mi2a
->pEnvironment
= ptr
;
6590 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6591 ptr
, cbBuf
, NULL
, NULL
);
6595 mi2a
->pDLLName
= ptr
;
6596 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6597 ptr
, cbBuf
, NULL
, NULL
);
6601 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6602 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6603 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6607 if (pcbNeeded
) *pcbNeeded
= needed
;
6608 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6610 HeapFree(GetProcessHeap(), 0, nameW
);
6611 HeapFree(GetProcessHeap(), 0, bufferW
);
6613 TRACE("returning %d with %d (%d byte for %d entries)\n",
6614 (res
), GetLastError(), needed
, numentries
);
6620 /*****************************************************************************
6621 * EnumMonitorsW [WINSPOOL.@]
6623 * Enumerate available Port-Monitors
6626 * pName [I] Servername or NULL (local Computer)
6627 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6628 * pMonitors [O] PTR to Buffer that receives the Result
6629 * cbBuf [I] Size of Buffer at pMonitors
6630 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6631 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6635 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6638 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6639 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6642 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6643 cbBuf
, pcbNeeded
, pcReturned
);
6645 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6647 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6648 SetLastError(RPC_X_NULL_REF_POINTER
);
6652 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6655 /******************************************************************************
6656 * SpoolerInit (WINSPOOL.@)
6658 * Initialize the Spooler
6665 * The function fails on windows, when the spooler service is not running
6668 BOOL WINAPI
SpoolerInit(void)
6671 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6675 /******************************************************************************
6676 * XcvDataW (WINSPOOL.@)
6678 * Execute commands in the Printmonitor DLL
6681 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6682 * pszDataName [i] Name of the command to execute
6683 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6684 * cbInputData [i] Size in Bytes of Buffer at pInputData
6685 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6686 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6687 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6688 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6695 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6696 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6698 * Minimal List of commands, that a Printmonitor DLL should support:
6700 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6701 *| "AddPort" : Add a Port
6702 *| "DeletePort": Delete a Port
6704 * Many Printmonitors support additional commands. Examples for localspl.dll:
6705 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6706 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6709 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6710 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6711 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6713 opened_printer_t
*printer
;
6715 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6716 pInputData
, cbInputData
, pOutputData
,
6717 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6719 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6721 printer
= get_opened_printer(hXcv
);
6722 if (!printer
|| (!printer
->backend_printer
)) {
6723 SetLastError(ERROR_INVALID_HANDLE
);
6727 if (!pcbOutputNeeded
) {
6728 SetLastError(ERROR_INVALID_PARAMETER
);
6732 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6733 SetLastError(RPC_X_NULL_REF_POINTER
);
6737 *pcbOutputNeeded
= 0;
6739 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6740 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6744 /*****************************************************************************
6745 * EnumPrinterDataA [WINSPOOL.@]
6748 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6749 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6750 DWORD cbData
, LPDWORD pcbData
)
6752 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6753 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6754 return ERROR_NO_MORE_ITEMS
;
6757 /*****************************************************************************
6758 * EnumPrinterDataW [WINSPOOL.@]
6761 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6762 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6763 DWORD cbData
, LPDWORD pcbData
)
6765 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6766 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6767 return ERROR_NO_MORE_ITEMS
;
6770 /*****************************************************************************
6771 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6774 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6775 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6776 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6778 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6779 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6780 pcbNeeded
, pcReturned
);
6784 /*****************************************************************************
6785 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6788 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6789 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6790 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6792 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6793 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6794 pcbNeeded
, pcReturned
);
6798 /*****************************************************************************
6799 * EnumPrintProcessorsA [WINSPOOL.@]
6801 * See EnumPrintProcessorsW.
6804 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6805 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6808 LPBYTE bufferW
= NULL
;
6809 LPWSTR nameW
= NULL
;
6812 DWORD numentries
= 0;
6815 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6816 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6818 /* convert names to unicode */
6820 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6821 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6822 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6825 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
6826 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6827 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
6830 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6831 needed
= cbBuf
* sizeof(WCHAR
);
6832 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6833 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6835 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6836 if (pcbNeeded
) needed
= *pcbNeeded
;
6837 /* HeapReAlloc return NULL, when bufferW was NULL */
6838 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6839 HeapAlloc(GetProcessHeap(), 0, needed
);
6841 /* Try again with the large Buffer */
6842 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6844 numentries
= pcReturned
? *pcReturned
: 0;
6848 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6851 PPRINTPROCESSOR_INFO_1W ppiw
;
6852 PPRINTPROCESSOR_INFO_1A ppia
;
6854 /* First pass: calculate the size for all Entries */
6855 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
6856 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
6858 while (index
< numentries
) {
6860 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
6861 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
6863 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
6864 NULL
, 0, NULL
, NULL
);
6866 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
6867 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
6870 /* check for errors and quit on failure */
6871 if (cbBuf
< needed
) {
6872 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6877 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
6878 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
6879 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6880 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
6881 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
6883 /* Second Pass: Fill the User Buffer (if we have one) */
6884 while ((index
< numentries
) && pPPInfo
) {
6886 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
6888 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
6889 ptr
, cbBuf
, NULL
, NULL
);
6893 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
6894 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
6899 if (pcbNeeded
) *pcbNeeded
= needed
;
6900 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6902 HeapFree(GetProcessHeap(), 0, nameW
);
6903 HeapFree(GetProcessHeap(), 0, envW
);
6904 HeapFree(GetProcessHeap(), 0, bufferW
);
6906 TRACE("returning %d with %d (%d byte for %d entries)\n",
6907 (res
), GetLastError(), needed
, numentries
);
6912 /*****************************************************************************
6913 * EnumPrintProcessorsW [WINSPOOL.@]
6915 * Enumerate available Print Processors
6918 * pName [I] Servername or NULL (local Computer)
6919 * pEnvironment [I] Printing-Environment or NULL (Default)
6920 * Level [I] Structure-Level (Only 1 is allowed)
6921 * pPPInfo [O] PTR to Buffer that receives the Result
6922 * cbBuf [I] Size of Buffer at pPPInfo
6923 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6924 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6928 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6931 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6932 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6935 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6936 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6938 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6940 if (!pcbNeeded
|| !pcReturned
) {
6941 SetLastError(RPC_X_NULL_REF_POINTER
);
6945 if (!pPPInfo
&& (cbBuf
> 0)) {
6946 SetLastError(ERROR_INVALID_USER_BUFFER
);
6950 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
6951 cbBuf
, pcbNeeded
, pcReturned
);
6954 /*****************************************************************************
6955 * ExtDeviceMode [WINSPOOL.@]
6958 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6959 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6962 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6963 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6964 debugstr_a(pProfile
), fMode
);
6968 /*****************************************************************************
6969 * FindClosePrinterChangeNotification [WINSPOOL.@]
6972 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6974 FIXME("Stub: %p\n", hChange
);
6978 /*****************************************************************************
6979 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6982 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6983 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6985 FIXME("Stub: %p %x %x %p\n",
6986 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6987 return INVALID_HANDLE_VALUE
;
6990 /*****************************************************************************
6991 * FindNextPrinterChangeNotification [WINSPOOL.@]
6994 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6995 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6997 FIXME("Stub: %p %p %p %p\n",
6998 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7002 /*****************************************************************************
7003 * FreePrinterNotifyInfo [WINSPOOL.@]
7006 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7008 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7012 /*****************************************************************************
7015 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7016 * ansi depending on the unicode parameter.
7018 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7028 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7031 memcpy(ptr
, str
, *size
);
7038 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7041 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7048 /*****************************************************************************
7051 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7052 LPDWORD pcbNeeded
, BOOL unicode
)
7054 DWORD size
, left
= cbBuf
;
7055 BOOL space
= (cbBuf
> 0);
7062 ji1
->JobId
= job
->job_id
;
7065 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7066 if(space
&& size
<= left
)
7068 ji1
->pDocument
= (LPWSTR
)ptr
;
7079 /*****************************************************************************
7082 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7083 LPDWORD pcbNeeded
, BOOL unicode
)
7085 DWORD size
, left
= cbBuf
;
7086 BOOL space
= (cbBuf
> 0);
7093 ji2
->JobId
= job
->job_id
;
7096 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7097 if(space
&& size
<= left
)
7099 ji2
->pDocument
= (LPWSTR
)ptr
;
7110 /*****************************************************************************
7113 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7114 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7117 DWORD needed
= 0, size
;
7121 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7123 EnterCriticalSection(&printer_handles_cs
);
7124 job
= get_job(hPrinter
, JobId
);
7131 size
= sizeof(JOB_INFO_1W
);
7136 memset(pJob
, 0, size
);
7140 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7145 size
= sizeof(JOB_INFO_2W
);
7150 memset(pJob
, 0, size
);
7154 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7159 size
= sizeof(JOB_INFO_3
);
7163 memset(pJob
, 0, size
);
7172 SetLastError(ERROR_INVALID_LEVEL
);
7176 *pcbNeeded
= needed
;
7178 LeaveCriticalSection(&printer_handles_cs
);
7182 /*****************************************************************************
7183 * GetJobA [WINSPOOL.@]
7186 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7187 DWORD cbBuf
, LPDWORD pcbNeeded
)
7189 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7192 /*****************************************************************************
7193 * GetJobW [WINSPOOL.@]
7196 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7197 DWORD cbBuf
, LPDWORD pcbNeeded
)
7199 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7202 /*****************************************************************************
7205 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7207 char *unixname
, *queue
, *cmd
;
7208 char fmt
[] = "lpr -P'%s' '%s'";
7212 if(!(unixname
= wine_get_unix_file_name(filename
)))
7215 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7216 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7217 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7219 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7220 sprintf(cmd
, fmt
, queue
, unixname
);
7222 TRACE("printing with: %s\n", cmd
);
7225 HeapFree(GetProcessHeap(), 0, cmd
);
7226 HeapFree(GetProcessHeap(), 0, queue
);
7227 HeapFree(GetProcessHeap(), 0, unixname
);
7231 /*****************************************************************************
7234 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7236 #ifdef SONAME_LIBCUPS
7239 char *unixname
, *queue
, *unix_doc_title
;
7243 if(!(unixname
= wine_get_unix_file_name(filename
)))
7246 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7247 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7248 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7250 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7251 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7252 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7254 TRACE("printing via cups\n");
7255 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7256 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7257 HeapFree(GetProcessHeap(), 0, queue
);
7258 HeapFree(GetProcessHeap(), 0, unixname
);
7264 return schedule_lpr(printer_name
, filename
);
7268 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7275 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7279 if(HIWORD(wparam
) == BN_CLICKED
)
7281 if(LOWORD(wparam
) == IDOK
)
7284 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7287 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7288 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7290 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7292 WCHAR caption
[200], message
[200];
7295 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7296 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7297 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7298 if(mb_ret
== IDCANCEL
)
7300 HeapFree(GetProcessHeap(), 0, filename
);
7304 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7305 if(hf
== INVALID_HANDLE_VALUE
)
7307 WCHAR caption
[200], message
[200];
7309 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7310 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7311 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7312 HeapFree(GetProcessHeap(), 0, filename
);
7316 DeleteFileW(filename
);
7317 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7319 EndDialog(hwnd
, IDOK
);
7322 if(LOWORD(wparam
) == IDCANCEL
)
7324 EndDialog(hwnd
, IDCANCEL
);
7333 /*****************************************************************************
7336 static BOOL
get_filename(LPWSTR
*filename
)
7338 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7339 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7342 /*****************************************************************************
7345 static BOOL
schedule_file(LPCWSTR filename
)
7347 LPWSTR output
= NULL
;
7349 if(get_filename(&output
))
7352 TRACE("copy to %s\n", debugstr_w(output
));
7353 r
= CopyFileW(filename
, output
, FALSE
);
7354 HeapFree(GetProcessHeap(), 0, output
);
7360 /*****************************************************************************
7363 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7366 char *unixname
, *cmdA
;
7368 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7372 if(!(unixname
= wine_get_unix_file_name(filename
)))
7375 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7376 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7377 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7379 TRACE("printing with: %s\n", cmdA
);
7381 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7386 ERR("pipe() failed!\n");
7396 /* reset signals that we previously set to SIG_IGN */
7397 signal(SIGPIPE
, SIG_DFL
);
7398 signal(SIGCHLD
, SIG_DFL
);
7400 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7404 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7405 write(fds
[1], buf
, no_read
);
7410 if(file_fd
!= -1) close(file_fd
);
7411 if(fds
[0] != -1) close(fds
[0]);
7412 if(fds
[1] != -1) close(fds
[1]);
7414 HeapFree(GetProcessHeap(), 0, cmdA
);
7415 HeapFree(GetProcessHeap(), 0, unixname
);
7422 /*****************************************************************************
7425 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7427 int in_fd
, out_fd
, no_read
;
7430 char *unixname
, *outputA
;
7433 if(!(unixname
= wine_get_unix_file_name(filename
)))
7436 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7437 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7438 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7440 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7441 in_fd
= open(unixname
, O_RDONLY
);
7442 if(out_fd
== -1 || in_fd
== -1)
7445 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7446 write(out_fd
, buf
, no_read
);
7450 if(in_fd
!= -1) close(in_fd
);
7451 if(out_fd
!= -1) close(out_fd
);
7452 HeapFree(GetProcessHeap(), 0, outputA
);
7453 HeapFree(GetProcessHeap(), 0, unixname
);
7457 /*****************************************************************************
7458 * ScheduleJob [WINSPOOL.@]
7461 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7463 opened_printer_t
*printer
;
7465 struct list
*cursor
, *cursor2
;
7467 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7468 EnterCriticalSection(&printer_handles_cs
);
7469 printer
= get_opened_printer(hPrinter
);
7473 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7475 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7478 if(job
->job_id
!= dwJobID
) continue;
7480 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7481 if(hf
!= INVALID_HANDLE_VALUE
)
7483 PRINTER_INFO_5W
*pi5
= NULL
;
7484 LPWSTR portname
= job
->portname
;
7488 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7489 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7493 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7494 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7495 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7496 portname
= pi5
->pPortName
;
7498 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7499 debugstr_w(portname
));
7503 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7504 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7506 DWORD type
, count
= sizeof(output
);
7507 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7510 if(output
[0] == '|')
7512 ret
= schedule_pipe(output
+ 1, job
->filename
);
7516 ret
= schedule_unixfile(output
, job
->filename
);
7518 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7520 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7522 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7524 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7526 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7528 ret
= schedule_file(job
->filename
);
7532 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7534 HeapFree(GetProcessHeap(), 0, pi5
);
7536 DeleteFileW(job
->filename
);
7538 list_remove(cursor
);
7539 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7540 HeapFree(GetProcessHeap(), 0, job
->portname
);
7541 HeapFree(GetProcessHeap(), 0, job
->filename
);
7542 HeapFree(GetProcessHeap(), 0, job
);
7546 LeaveCriticalSection(&printer_handles_cs
);
7550 /*****************************************************************************
7551 * StartDocDlgA [WINSPOOL.@]
7553 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7555 UNICODE_STRING usBuffer
;
7558 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7561 docW
.cbSize
= sizeof(docW
);
7562 if (doc
->lpszDocName
)
7564 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7565 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7567 if (doc
->lpszOutput
)
7569 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7570 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7572 if (doc
->lpszDatatype
)
7574 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7575 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7577 docW
.fwType
= doc
->fwType
;
7579 retW
= StartDocDlgW(hPrinter
, &docW
);
7583 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7584 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7585 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7586 HeapFree(GetProcessHeap(), 0, retW
);
7589 HeapFree(GetProcessHeap(), 0, datatypeW
);
7590 HeapFree(GetProcessHeap(), 0, outputW
);
7591 HeapFree(GetProcessHeap(), 0, docnameW
);
7596 /*****************************************************************************
7597 * StartDocDlgW [WINSPOOL.@]
7599 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7600 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7601 * port is "FILE:". Also returns the full path if passed a relative path.
7603 * The caller should free the returned string from the process heap.
7605 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7610 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7612 PRINTER_INFO_5W
*pi5
;
7613 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7614 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7616 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7617 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7618 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7620 HeapFree(GetProcessHeap(), 0, pi5
);
7623 HeapFree(GetProcessHeap(), 0, pi5
);
7626 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7630 if (get_filename(&name
))
7632 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7634 HeapFree(GetProcessHeap(), 0, name
);
7637 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7638 GetFullPathNameW(name
, len
, ret
, NULL
);
7639 HeapFree(GetProcessHeap(), 0, name
);
7644 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7647 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7648 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7650 attr
= GetFileAttributesW(ret
);
7651 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7653 HeapFree(GetProcessHeap(), 0, ret
);