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
;
110 LPCWSTR versionregpath
;
111 LPCWSTR versionsubdir
;
114 /* ############################### */
116 static opened_printer_t
**printer_handles
;
117 static UINT nb_printer_handles
;
118 static LONG next_job_id
= 1;
120 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
121 WORD fwCapability
, LPSTR lpszOutput
,
123 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
124 LPSTR lpszDevice
, LPSTR lpszPort
,
125 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
128 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
129 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
130 'c','o','n','t','r','o','l','\\',
131 'P','r','i','n','t','\\',
132 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
133 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
135 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'C','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'P','r','i','n','t','e','r','s',0};
141 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
143 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'W','i','n','d','o','w','s',0};
149 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
150 'M','i','c','r','o','s','o','f','t','\\',
151 'W','i','n','d','o','w','s',' ','N','T','\\',
152 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
153 'D','e','v','i','c','e','s',0};
155 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
156 'M','i','c','r','o','s','o','f','t','\\',
157 'W','i','n','d','o','w','s',' ','N','T','\\',
158 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
159 'P','o','r','t','s',0};
161 static const WCHAR WinNT_CV_PrinterPortsW
[] = { 'S','o','f','t','w','a','r','e','\\',
162 'M','i','c','r','o','s','o','f','t','\\',
163 'W','i','n','d','o','w','s',' ','N','T','\\',
164 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
165 'P','r','i','n','t','e','r','P','o','r','t','s',0};
167 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
168 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
169 static const WCHAR envname_x64W
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
170 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
171 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
172 static const WCHAR subdir_x64W
[] = {'x','6','4',0};
173 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
174 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
175 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
176 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
177 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
179 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
180 static const WCHAR backslashW
[] = {'\\',0};
181 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
182 'i','o','n',' ','F','i','l','e',0};
183 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
184 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
185 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
186 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
187 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
188 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
189 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
190 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
191 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
192 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
193 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
194 static const WCHAR NameW
[] = {'N','a','m','e',0};
195 static const WCHAR ObjectGUIDW
[] = {'O','b','j','e','c','t','G','U','I','D',0};
196 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
197 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
198 static const WCHAR PortW
[] = {'P','o','r','t',0};
199 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
200 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
201 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
202 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
203 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
204 static const WCHAR PrinterPortsW
[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
205 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
206 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
207 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
208 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
209 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
210 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
211 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
212 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
213 static const WCHAR emptyStringW
[] = {0};
215 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
217 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
218 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
219 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
221 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
222 'D','o','c','u','m','e','n','t',0};
224 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
225 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
226 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
227 0, sizeof(DRIVER_INFO_8W
)};
230 static const DWORD pi_sizeof
[] = {0, sizeof(PRINTER_INFO_1W
), sizeof(PRINTER_INFO_2W
),
231 sizeof(PRINTER_INFO_3
), sizeof(PRINTER_INFO_4W
),
232 sizeof(PRINTER_INFO_5W
), sizeof(PRINTER_INFO_6
),
233 sizeof(PRINTER_INFO_7W
), sizeof(PRINTER_INFO_8W
),
234 sizeof(PRINTER_INFO_9W
)};
236 static const printenv_t env_x64
= {envname_x64W
, subdir_x64W
, 3, Version3_RegPathW
, Version3_SubdirW
};
237 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
, 3, Version3_RegPathW
, Version3_SubdirW
};
238 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
, 0, Version0_RegPathW
, Version0_SubdirW
};
240 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
242 /******************************************************************
243 * validate the user-supplied printing-environment [internal]
246 * env [I] PTR to Environment-String or NULL
250 * Success: PTR to printenv_t
253 * An empty string is handled the same way as NULL.
254 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
258 static const printenv_t
* validate_envW(LPCWSTR env
)
260 const printenv_t
*result
= NULL
;
263 TRACE("testing %s\n", debugstr_w(env
));
266 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
268 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
270 result
= all_printenv
[i
];
275 if (result
== NULL
) {
276 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
277 SetLastError(ERROR_INVALID_ENVIRONMENT
);
279 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
283 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
285 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
291 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
292 if passed a NULL string. This returns NULLs to the result.
294 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
298 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
299 return usBufferPtr
->Buffer
;
301 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
305 static LPWSTR
strdupW(LPCWSTR p
)
311 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
312 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
317 static LPSTR
strdupWtoA( LPCWSTR str
)
322 if (!str
) return NULL
;
323 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
324 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
325 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
329 /******************************************************************
330 * verify, that the filename is a local file
333 static inline BOOL
is_local_file(LPWSTR name
)
335 return (name
[0] && (name
[1] == ':') && (name
[2] == '\\'));
338 /******************************************************************
339 * Return the number of bytes for an multi_sz string.
340 * The result includes all \0s
341 * (specifically the extra \0, that is needed as multi_sz terminator).
344 static int multi_sz_lenW(const WCHAR
*str
)
346 const WCHAR
*ptr
= str
;
350 ptr
+= lstrlenW(ptr
) + 1;
353 return (ptr
- str
+ 1) * sizeof(WCHAR
);
356 /* ################################ */
358 static int multi_sz_lenA(const char *str
)
360 const char *ptr
= str
;
364 ptr
+= lstrlenA(ptr
) + 1;
367 return ptr
- str
+ 1;
371 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
374 /* If forcing, or no profile string entry for device yet, set the entry
376 * The always change entry if not WINEPS yet is discussable.
379 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
381 !strstr(qbuf
,"WINEPS.DRV")
383 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
386 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
387 WriteProfileStringA("windows","device",buf
);
388 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
389 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
392 HeapFree(GetProcessHeap(),0,buf
);
396 static BOOL
add_printer_driver(const char *name
)
400 static char driver_9x
[] = "wineps16.drv",
401 driver_nt
[] = "wineps.drv",
402 env_9x
[] = "Windows 4.0",
403 env_nt
[] = "Windows NT x86",
404 data_file
[] = "generic.ppd",
405 default_data_type
[] = "RAW";
407 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
409 di3a
.pName
= (char *)name
;
410 di3a
.pEnvironment
= env_nt
;
411 di3a
.pDriverPath
= driver_nt
;
412 di3a
.pDataFile
= data_file
;
413 di3a
.pConfigFile
= driver_nt
;
414 di3a
.pDefaultDataType
= default_data_type
;
416 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
417 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
420 di3a
.pEnvironment
= env_9x
;
421 di3a
.pDriverPath
= driver_9x
;
422 di3a
.pConfigFile
= driver_9x
;
423 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
) ||
424 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
))
429 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a
.pDriverPath
),
430 debugstr_a(di3a
.pEnvironment
), GetLastError());
434 #ifdef SONAME_LIBCUPS
435 static typeof(cupsFreeDests
) *pcupsFreeDests
;
436 static typeof(cupsGetDests
) *pcupsGetDests
;
437 static typeof(cupsGetPPD
) *pcupsGetPPD
;
438 static typeof(cupsPrintFile
) *pcupsPrintFile
;
439 static void *cupshandle
;
441 static BOOL
CUPS_LoadPrinters(void)
444 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
446 PRINTER_INFO_2A pinfo2a
;
448 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
451 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
453 TRACE("%s\n", loaderror
);
456 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
459 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
460 if (!p##x) return FALSE;
462 DYNCUPS(cupsFreeDests
);
464 DYNCUPS(cupsGetDests
);
465 DYNCUPS(cupsPrintFile
);
468 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
470 ERR("Can't create Printers key\n");
474 nrofdests
= pcupsGetDests(&dests
);
475 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
476 for (i
=0;i
<nrofdests
;i
++) {
477 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
478 port
= HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests
[i
].name
)+1);
479 sprintf(port
,"LPR:%s", dests
[i
].name
);
480 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
481 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
482 sprintf(devline
, "WINEPS.DRV,%s", port
);
483 WriteProfileStringA("devices", dests
[i
].name
, devline
);
484 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
485 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
489 lstrcatA(devline
, ",15,45");
490 WriteProfileStringA("PrinterPorts", dests
[i
].name
, devline
);
491 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
492 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
496 HeapFree(GetProcessHeap(), 0, devline
);
498 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
499 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
500 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
502 TRACE("Printer already exists\n");
503 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
504 RegCloseKey(hkeyPrinter
);
506 static CHAR data_type
[] = "RAW",
507 print_proc
[] = "WinPrint",
508 comment
[] = "WINEPS Printer using CUPS",
509 location
[] = "<physical location of printer>",
510 params
[] = "<parameters?>",
511 share_name
[] = "<share name?>",
512 sep_file
[] = "<sep file?>";
514 add_printer_driver(dests
[i
].name
);
516 memset(&pinfo2a
,0,sizeof(pinfo2a
));
517 pinfo2a
.pPrinterName
= dests
[i
].name
;
518 pinfo2a
.pDatatype
= data_type
;
519 pinfo2a
.pPrintProcessor
= print_proc
;
520 pinfo2a
.pDriverName
= dests
[i
].name
;
521 pinfo2a
.pComment
= comment
;
522 pinfo2a
.pLocation
= location
;
523 pinfo2a
.pPortName
= port
;
524 pinfo2a
.pParameters
= params
;
525 pinfo2a
.pShareName
= share_name
;
526 pinfo2a
.pSepFile
= sep_file
;
528 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
529 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
530 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
533 HeapFree(GetProcessHeap(),0,port
);
536 if (dests
[i
].is_default
) {
537 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
541 if (hadprinter
& !haddefault
)
542 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
543 pcupsFreeDests(nrofdests
, dests
);
544 RegCloseKey(hkeyPrinters
);
550 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
551 PRINTER_INFO_2A pinfo2a
;
552 char *e
,*s
,*name
,*prettyname
,*devname
;
553 BOOL ret
= FALSE
, set_default
= FALSE
;
554 char *port
= NULL
, *devline
,*env_default
;
555 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
557 while (isspace(*pent
)) pent
++;
558 s
= strchr(pent
,':');
560 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
568 TRACE("name=%s entry=%s\n",name
, pent
);
570 if(ispunct(*name
)) { /* a tc entry, not a real printer */
571 TRACE("skipping tc entry\n");
575 if(strstr(pent
,":server")) { /* server only version so skip */
576 TRACE("skipping server entry\n");
580 /* Determine whether this is a postscript printer. */
583 env_default
= getenv("PRINTER");
585 /* Get longest name, usually the one at the right for later display. */
586 while((s
=strchr(prettyname
,'|'))) {
589 while(isspace(*--e
)) *e
= '\0';
590 TRACE("\t%s\n", debugstr_a(prettyname
));
591 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
592 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
595 e
= prettyname
+ strlen(prettyname
);
596 while(isspace(*--e
)) *e
= '\0';
597 TRACE("\t%s\n", debugstr_a(prettyname
));
598 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
600 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
601 * if it is too long, we use it as comment below. */
602 devname
= prettyname
;
603 if (strlen(devname
)>=CCHDEVICENAME
-1)
605 if (strlen(devname
)>=CCHDEVICENAME
-1) {
610 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
611 sprintf(port
,"LPR:%s",name
);
613 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
614 devline
= HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port
));
615 sprintf(devline
, "WINEPS.DRV,%s", port
);
616 WriteProfileStringA("devices", devname
, devline
);
617 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
618 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
622 lstrcatA(devline
, ",15,45");
623 WriteProfileStringA("PrinterPorts", devname
, devline
);
624 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
625 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
629 HeapFree(GetProcessHeap(),0,devline
);
631 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
633 ERR("Can't create Printers key\n");
637 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
638 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
640 TRACE("Printer already exists\n");
641 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
642 RegCloseKey(hkeyPrinter
);
644 static CHAR data_type
[] = "RAW",
645 print_proc
[] = "WinPrint",
646 comment
[] = "WINEPS Printer using LPR",
647 params
[] = "<parameters?>",
648 share_name
[] = "<share name?>",
649 sep_file
[] = "<sep file?>";
651 add_printer_driver(devname
);
653 memset(&pinfo2a
,0,sizeof(pinfo2a
));
654 pinfo2a
.pPrinterName
= devname
;
655 pinfo2a
.pDatatype
= data_type
;
656 pinfo2a
.pPrintProcessor
= print_proc
;
657 pinfo2a
.pDriverName
= devname
;
658 pinfo2a
.pComment
= comment
;
659 pinfo2a
.pLocation
= prettyname
;
660 pinfo2a
.pPortName
= port
;
661 pinfo2a
.pParameters
= params
;
662 pinfo2a
.pShareName
= share_name
;
663 pinfo2a
.pSepFile
= sep_file
;
665 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
666 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
667 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
670 RegCloseKey(hkeyPrinters
);
672 if (isfirst
|| set_default
)
673 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
676 HeapFree(GetProcessHeap(), 0, port
);
677 HeapFree(GetProcessHeap(), 0, name
);
682 PRINTCAP_LoadPrinters(void) {
683 BOOL hadprinter
= FALSE
;
687 BOOL had_bash
= FALSE
;
689 f
= fopen("/etc/printcap","r");
693 while(fgets(buf
,sizeof(buf
),f
)) {
696 end
=strchr(buf
,'\n');
700 while(isspace(*start
)) start
++;
701 if(*start
== '#' || *start
== '\0')
704 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
705 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
706 HeapFree(GetProcessHeap(),0,pent
);
710 if (end
&& *--end
== '\\') {
717 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
720 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
726 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
727 HeapFree(GetProcessHeap(),0,pent
);
733 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
736 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
737 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
739 return ERROR_FILE_NOT_FOUND
;
742 /******************************************************************
743 * get_servername_from_name (internal)
745 * for an external server, a copy of the serverpart from the full name is returned
748 static LPWSTR
get_servername_from_name(LPCWSTR name
)
752 WCHAR buffer
[MAX_PATH
];
755 if (name
== NULL
) return NULL
;
756 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
758 server
= strdupW(&name
[2]); /* skip over both backslash */
759 if (server
== NULL
) return NULL
;
761 /* strip '\' and the printername */
762 ptr
= strchrW(server
, '\\');
763 if (ptr
) ptr
[0] = '\0';
765 TRACE("found %s\n", debugstr_w(server
));
767 len
= sizeof(buffer
)/sizeof(buffer
[0]);
768 if (GetComputerNameW(buffer
, &len
)) {
769 if (lstrcmpW(buffer
, server
) == 0) {
770 /* The requested Servername is our computername */
771 HeapFree(GetProcessHeap(), 0, server
);
778 /******************************************************************
779 * get_basename_from_name (internal)
781 * skip over the serverpart from the full name
784 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
786 if (name
== NULL
) return NULL
;
787 if ((name
[0] == '\\') && (name
[1] == '\\')) {
788 /* skip over the servername and search for the following '\' */
789 name
= strchrW(&name
[2], '\\');
790 if ((name
) && (name
[1])) {
791 /* found a separator ('\') followed by a name:
792 skip over the separator and return the rest */
797 /* no basename present (we found only a servername) */
804 /******************************************************************
805 * get_opened_printer_entry
806 * Get the first place empty in the opened printer table
809 * - pDefault is ignored
811 static HANDLE
get_opened_printer_entry(LPWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
813 UINT_PTR handle
= nb_printer_handles
, i
;
814 jobqueue_t
*queue
= NULL
;
815 opened_printer_t
*printer
= NULL
;
819 if ((backend
== NULL
) && !load_backend()) return NULL
;
821 servername
= get_servername_from_name(name
);
823 FIXME("server %s not supported\n", debugstr_w(servername
));
824 HeapFree(GetProcessHeap(), 0, servername
);
825 SetLastError(ERROR_INVALID_PRINTER_NAME
);
829 printername
= get_basename_from_name(name
);
830 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
832 /* an empty printername is invalid */
833 if (printername
&& (!printername
[0])) {
834 SetLastError(ERROR_INVALID_PARAMETER
);
838 EnterCriticalSection(&printer_handles_cs
);
840 for (i
= 0; i
< nb_printer_handles
; i
++)
842 if (!printer_handles
[i
])
844 if(handle
== nb_printer_handles
)
849 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
850 queue
= printer_handles
[i
]->queue
;
854 if (handle
>= nb_printer_handles
)
856 opened_printer_t
**new_array
;
858 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
859 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
861 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
862 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
869 printer_handles
= new_array
;
870 nb_printer_handles
+= 16;
873 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
879 /* get a printer handle from the backend */
880 if (! backend
->fpOpenPrinter(name
, &printer
->backend_printer
, pDefault
)) {
885 /* clone the base name. This is NULL for the printserver */
886 printer
->printername
= strdupW(printername
);
888 /* clone the full name */
889 printer
->name
= strdupW(name
);
890 if (name
&& (!printer
->name
)) {
896 printer
->queue
= queue
;
899 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
900 if (!printer
->queue
) {
904 list_init(&printer
->queue
->jobs
);
905 printer
->queue
->ref
= 0;
907 InterlockedIncrement(&printer
->queue
->ref
);
909 printer_handles
[handle
] = printer
;
912 LeaveCriticalSection(&printer_handles_cs
);
913 if (!handle
&& printer
) {
914 /* Something failed: Free all resources */
915 HeapFree(GetProcessHeap(), 0, printer
->printername
);
916 HeapFree(GetProcessHeap(), 0, printer
->name
);
917 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
918 HeapFree(GetProcessHeap(), 0, printer
);
921 return (HANDLE
)handle
;
924 /******************************************************************
926 * Get the pointer to the opened printer referred by the handle
928 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
930 UINT_PTR idx
= (UINT_PTR
)hprn
;
931 opened_printer_t
*ret
= NULL
;
933 EnterCriticalSection(&printer_handles_cs
);
935 if ((idx
> 0) && (idx
<= nb_printer_handles
)) {
936 ret
= printer_handles
[idx
- 1];
938 LeaveCriticalSection(&printer_handles_cs
);
942 /******************************************************************
943 * get_opened_printer_name
944 * Get the pointer to the opened printer name referred by the handle
946 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
948 opened_printer_t
*printer
= get_opened_printer(hprn
);
949 if(!printer
) return NULL
;
950 return printer
->name
;
953 /******************************************************************
954 * WINSPOOL_GetOpenedPrinterRegKey
957 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
959 LPCWSTR name
= get_opened_printer_name(hPrinter
);
963 if(!name
) return ERROR_INVALID_HANDLE
;
965 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
969 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
971 ERR("Can't find opened printer %s in registry\n",
973 RegCloseKey(hkeyPrinters
);
974 return ERROR_INVALID_PRINTER_NAME
; /* ? */
976 RegCloseKey(hkeyPrinters
);
977 return ERROR_SUCCESS
;
980 void WINSPOOL_LoadSystemPrinters(void)
982 HKEY hkey
, hkeyPrinters
;
984 DWORD needed
, num
, i
;
985 WCHAR PrinterName
[256];
988 /* This ensures that all printer entries have a valid Name value. If causes
989 problems later if they don't. If one is found to be missed we create one
990 and set it equal to the name of the key */
991 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
992 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
993 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
994 for(i
= 0; i
< num
; i
++) {
995 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) == ERROR_SUCCESS
) {
996 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
997 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
998 set_reg_szW(hkey
, NameW
, PrinterName
);
1005 RegCloseKey(hkeyPrinters
);
1008 /* We want to avoid calling AddPrinter on printers as much as
1009 possible, because on cups printers this will (eventually) lead
1010 to a call to cupsGetPPD which takes forever, even with non-cups
1011 printers AddPrinter takes a while. So we'll tag all printers that
1012 were automatically added last time around, if they still exist
1013 we'll leave them be otherwise we'll delete them. */
1014 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1016 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1017 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1018 for(i
= 0; i
< num
; i
++) {
1019 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1020 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1021 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1023 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1031 HeapFree(GetProcessHeap(), 0, pi
);
1035 #ifdef SONAME_LIBCUPS
1036 done
= CUPS_LoadPrinters();
1039 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1040 PRINTCAP_LoadPrinters();
1042 /* Now enumerate the list again and delete any printers that are still tagged */
1043 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1045 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1046 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1047 for(i
= 0; i
< num
; i
++) {
1048 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1049 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1050 BOOL delete_driver
= FALSE
;
1051 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1052 DWORD dw
, type
, size
= sizeof(dw
);
1053 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1054 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1055 DeletePrinter(hprn
);
1056 delete_driver
= TRUE
;
1062 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1067 HeapFree(GetProcessHeap(), 0, pi
);
1074 /******************************************************************
1077 * Get the pointer to the specified job.
1078 * Should hold the printer_handles_cs before calling.
1080 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1082 opened_printer_t
*printer
= get_opened_printer(hprn
);
1085 if(!printer
) return NULL
;
1086 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1088 if(job
->job_id
== JobId
)
1094 /***********************************************************
1097 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1100 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1103 Formname
= (dmA
->dmSize
> off_formname
);
1104 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1105 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1106 dmW
->dmDeviceName
, CCHDEVICENAME
);
1108 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1109 dmA
->dmSize
- CCHDEVICENAME
);
1111 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1112 off_formname
- CCHDEVICENAME
);
1113 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1114 dmW
->dmFormName
, CCHFORMNAME
);
1115 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1116 (off_formname
+ CCHFORMNAME
));
1119 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1120 dmA
->dmDriverExtra
);
1124 /***********************************************************
1126 * Creates an ansi copy of supplied devmode
1128 static LPDEVMODEA
DEVMODEdupWtoA(const DEVMODEW
*dmW
)
1133 if (!dmW
) return NULL
;
1134 size
= dmW
->dmSize
- CCHDEVICENAME
-
1135 ((dmW
->dmSize
> FIELD_OFFSET(DEVMODEW
, dmFormName
)) ? CCHFORMNAME
: 0);
1137 dmA
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1138 if (!dmA
) return NULL
;
1140 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1141 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1143 if (FIELD_OFFSET(DEVMODEW
, dmFormName
) >= dmW
->dmSize
) {
1144 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1145 dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1149 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1150 FIELD_OFFSET(DEVMODEW
, dmFormName
) - FIELD_OFFSET(DEVMODEW
, dmSpecVersion
));
1151 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1152 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1154 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmLogPixels
));
1158 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
, dmW
->dmDriverExtra
);
1162 /******************************************************************
1163 * convert_printerinfo_W_to_A [internal]
1166 static void convert_printerinfo_W_to_A(LPBYTE out
, LPBYTE pPrintersW
,
1167 DWORD level
, DWORD outlen
, DWORD numentries
)
1173 TRACE("(%p, %p, %d, %u, %u)\n", out
, pPrintersW
, level
, outlen
, numentries
);
1175 len
= pi_sizeof
[level
] * numentries
;
1176 ptr
= (LPSTR
) out
+ len
;
1179 /* copy the numbers of all PRINTER_INFO_* first */
1180 memcpy(out
, pPrintersW
, len
);
1182 while (id
< numentries
) {
1186 PRINTER_INFO_1W
* piW
= (PRINTER_INFO_1W
*) pPrintersW
;
1187 PRINTER_INFO_1A
* piA
= (PRINTER_INFO_1A
*) out
;
1189 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pName
));
1190 if (piW
->pDescription
) {
1191 piA
->pDescription
= ptr
;
1192 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDescription
, -1,
1193 ptr
, outlen
, NULL
, NULL
);
1199 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pName
, -1,
1200 ptr
, outlen
, NULL
, NULL
);
1204 if (piW
->pComment
) {
1205 piA
->pComment
= ptr
;
1206 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1207 ptr
, outlen
, NULL
, NULL
);
1216 PRINTER_INFO_2W
* piW
= (PRINTER_INFO_2W
*) pPrintersW
;
1217 PRINTER_INFO_2A
* piA
= (PRINTER_INFO_2A
*) out
;
1220 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1221 if (piW
->pServerName
) {
1222 piA
->pServerName
= ptr
;
1223 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1224 ptr
, outlen
, NULL
, NULL
);
1228 if (piW
->pPrinterName
) {
1229 piA
->pPrinterName
= ptr
;
1230 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1231 ptr
, outlen
, NULL
, NULL
);
1235 if (piW
->pShareName
) {
1236 piA
->pShareName
= ptr
;
1237 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pShareName
, -1,
1238 ptr
, outlen
, NULL
, NULL
);
1242 if (piW
->pPortName
) {
1243 piA
->pPortName
= ptr
;
1244 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1245 ptr
, outlen
, NULL
, NULL
);
1249 if (piW
->pDriverName
) {
1250 piA
->pDriverName
= ptr
;
1251 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDriverName
, -1,
1252 ptr
, outlen
, NULL
, NULL
);
1256 if (piW
->pComment
) {
1257 piA
->pComment
= ptr
;
1258 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pComment
, -1,
1259 ptr
, outlen
, NULL
, NULL
);
1263 if (piW
->pLocation
) {
1264 piA
->pLocation
= ptr
;
1265 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pLocation
, -1,
1266 ptr
, outlen
, NULL
, NULL
);
1271 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1273 /* align DEVMODEA to a DWORD boundary */
1274 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1278 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1279 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1280 memcpy(ptr
, dmA
, len
);
1281 HeapFree(GetProcessHeap(), 0, dmA
);
1287 if (piW
->pSepFile
) {
1288 piA
->pSepFile
= ptr
;
1289 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pSepFile
, -1,
1290 ptr
, outlen
, NULL
, NULL
);
1294 if (piW
->pPrintProcessor
) {
1295 piA
->pPrintProcessor
= ptr
;
1296 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrintProcessor
, -1,
1297 ptr
, outlen
, NULL
, NULL
);
1301 if (piW
->pDatatype
) {
1302 piA
->pDatatype
= ptr
;
1303 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pDatatype
, -1,
1304 ptr
, outlen
, NULL
, NULL
);
1308 if (piW
->pParameters
) {
1309 piA
->pParameters
= ptr
;
1310 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pParameters
, -1,
1311 ptr
, outlen
, NULL
, NULL
);
1315 if (piW
->pSecurityDescriptor
) {
1316 piA
->pSecurityDescriptor
= NULL
;
1317 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW
->pPrinterName
));
1324 PRINTER_INFO_4W
* piW
= (PRINTER_INFO_4W
*) pPrintersW
;
1325 PRINTER_INFO_4A
* piA
= (PRINTER_INFO_4A
*) out
;
1327 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1329 if (piW
->pPrinterName
) {
1330 piA
->pPrinterName
= ptr
;
1331 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1332 ptr
, outlen
, NULL
, NULL
);
1336 if (piW
->pServerName
) {
1337 piA
->pServerName
= ptr
;
1338 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pServerName
, -1,
1339 ptr
, outlen
, NULL
, NULL
);
1348 PRINTER_INFO_5W
* piW
= (PRINTER_INFO_5W
*) pPrintersW
;
1349 PRINTER_INFO_5A
* piA
= (PRINTER_INFO_5A
*) out
;
1351 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(piW
->pPrinterName
));
1353 if (piW
->pPrinterName
) {
1354 piA
->pPrinterName
= ptr
;
1355 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPrinterName
, -1,
1356 ptr
, outlen
, NULL
, NULL
);
1360 if (piW
->pPortName
) {
1361 piA
->pPortName
= ptr
;
1362 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pPortName
, -1,
1363 ptr
, outlen
, NULL
, NULL
);
1370 case 6: /* 6A and 6W are the same structure */
1375 PRINTER_INFO_7W
* piW
= (PRINTER_INFO_7W
*) pPrintersW
;
1376 PRINTER_INFO_7A
* piA
= (PRINTER_INFO_7A
*) out
;
1378 TRACE("(%u) #%u\n", level
, id
);
1379 if (piW
->pszObjectGUID
) {
1380 piA
->pszObjectGUID
= ptr
;
1381 len
= WideCharToMultiByte(CP_ACP
, 0, piW
->pszObjectGUID
, -1,
1382 ptr
, outlen
, NULL
, NULL
);
1391 PRINTER_INFO_9W
* piW
= (PRINTER_INFO_9W
*) pPrintersW
;
1392 PRINTER_INFO_9A
* piA
= (PRINTER_INFO_9A
*) out
;
1395 TRACE("(%u) #%u\n", level
, id
);
1396 dmA
= DEVMODEdupWtoA(piW
->pDevMode
);
1398 /* align DEVMODEA to a DWORD boundary */
1399 len
= (4 - ( (DWORD_PTR
) ptr
& 3)) & 3;
1403 piA
->pDevMode
= (LPDEVMODEA
) ptr
;
1404 len
= dmA
->dmSize
+ dmA
->dmDriverExtra
;
1405 memcpy(ptr
, dmA
, len
);
1406 HeapFree(GetProcessHeap(), 0, dmA
);
1416 FIXME("for level %u\n", level
);
1418 pPrintersW
+= pi_sizeof
[level
];
1419 out
+= pi_sizeof
[level
];
1424 /******************************************************************
1425 * convert_driverinfo_W_to_A [internal]
1428 static void convert_driverinfo_W_to_A(LPBYTE out
, LPBYTE pDriversW
,
1429 DWORD level
, DWORD outlen
, DWORD numentries
)
1435 TRACE("(%p, %p, %d, %u, %u)\n", out
, pDriversW
, level
, outlen
, numentries
);
1437 len
= di_sizeof
[level
] * numentries
;
1438 ptr
= (LPSTR
) out
+ len
;
1441 /* copy the numbers of all PRINTER_INFO_* first */
1442 memcpy(out
, pDriversW
, len
);
1444 #define COPY_STRING(fld) \
1447 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1448 ptr += len; outlen -= len;\
1450 #define COPY_MULTIZ_STRING(fld) \
1451 { LPWSTR p = diW->fld; if (p){ \
1454 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1455 ptr += len; outlen -= len; p += len;\
1457 while(len > 1 && outlen > 0); \
1460 while (id
< numentries
)
1466 DRIVER_INFO_1W
* diW
= (DRIVER_INFO_1W
*) pDriversW
;
1467 DRIVER_INFO_1A
* diA
= (DRIVER_INFO_1A
*) out
;
1469 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1476 DRIVER_INFO_2W
* diW
= (DRIVER_INFO_2W
*) pDriversW
;
1477 DRIVER_INFO_2A
* diA
= (DRIVER_INFO_2A
*) out
;
1479 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1482 COPY_STRING(pEnvironment
);
1483 COPY_STRING(pDriverPath
);
1484 COPY_STRING(pDataFile
);
1485 COPY_STRING(pConfigFile
);
1490 DRIVER_INFO_3W
* diW
= (DRIVER_INFO_3W
*) pDriversW
;
1491 DRIVER_INFO_3A
* diA
= (DRIVER_INFO_3A
*) out
;
1493 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1496 COPY_STRING(pEnvironment
);
1497 COPY_STRING(pDriverPath
);
1498 COPY_STRING(pDataFile
);
1499 COPY_STRING(pConfigFile
);
1500 COPY_STRING(pHelpFile
);
1501 COPY_MULTIZ_STRING(pDependentFiles
);
1502 COPY_STRING(pMonitorName
);
1503 COPY_STRING(pDefaultDataType
);
1508 DRIVER_INFO_4W
* diW
= (DRIVER_INFO_4W
*) pDriversW
;
1509 DRIVER_INFO_4A
* diA
= (DRIVER_INFO_4A
*) out
;
1511 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1514 COPY_STRING(pEnvironment
);
1515 COPY_STRING(pDriverPath
);
1516 COPY_STRING(pDataFile
);
1517 COPY_STRING(pConfigFile
);
1518 COPY_STRING(pHelpFile
);
1519 COPY_MULTIZ_STRING(pDependentFiles
);
1520 COPY_STRING(pMonitorName
);
1521 COPY_STRING(pDefaultDataType
);
1522 COPY_MULTIZ_STRING(pszzPreviousNames
);
1527 DRIVER_INFO_5W
* diW
= (DRIVER_INFO_5W
*) pDriversW
;
1528 DRIVER_INFO_5A
* diA
= (DRIVER_INFO_5A
*) out
;
1530 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1533 COPY_STRING(pEnvironment
);
1534 COPY_STRING(pDriverPath
);
1535 COPY_STRING(pDataFile
);
1536 COPY_STRING(pConfigFile
);
1541 DRIVER_INFO_6W
* diW
= (DRIVER_INFO_6W
*) pDriversW
;
1542 DRIVER_INFO_6A
* diA
= (DRIVER_INFO_6A
*) out
;
1544 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1547 COPY_STRING(pEnvironment
);
1548 COPY_STRING(pDriverPath
);
1549 COPY_STRING(pDataFile
);
1550 COPY_STRING(pConfigFile
);
1551 COPY_STRING(pHelpFile
);
1552 COPY_MULTIZ_STRING(pDependentFiles
);
1553 COPY_STRING(pMonitorName
);
1554 COPY_STRING(pDefaultDataType
);
1555 COPY_MULTIZ_STRING(pszzPreviousNames
);
1556 COPY_STRING(pszMfgName
);
1557 COPY_STRING(pszOEMUrl
);
1558 COPY_STRING(pszHardwareID
);
1559 COPY_STRING(pszProvider
);
1564 DRIVER_INFO_8W
* diW
= (DRIVER_INFO_8W
*) pDriversW
;
1565 DRIVER_INFO_8A
* diA
= (DRIVER_INFO_8A
*) out
;
1567 TRACE("(%u) #%u: %s\n", level
, id
, debugstr_w(diW
->pName
));
1570 COPY_STRING(pEnvironment
);
1571 COPY_STRING(pDriverPath
);
1572 COPY_STRING(pDataFile
);
1573 COPY_STRING(pConfigFile
);
1574 COPY_STRING(pHelpFile
);
1575 COPY_MULTIZ_STRING(pDependentFiles
);
1576 COPY_STRING(pMonitorName
);
1577 COPY_STRING(pDefaultDataType
);
1578 COPY_MULTIZ_STRING(pszzPreviousNames
);
1579 COPY_STRING(pszMfgName
);
1580 COPY_STRING(pszOEMUrl
);
1581 COPY_STRING(pszHardwareID
);
1582 COPY_STRING(pszProvider
);
1583 COPY_STRING(pszPrintProcessor
);
1584 COPY_STRING(pszVendorSetup
);
1585 COPY_MULTIZ_STRING(pszzColorProfiles
);
1586 COPY_STRING(pszInfPath
);
1587 COPY_MULTIZ_STRING(pszzCoreDriverDependencies
);
1593 FIXME("for level %u\n", level
);
1596 pDriversW
+= di_sizeof
[level
];
1597 out
+= di_sizeof
[level
];
1602 #undef COPY_MULTIZ_STRING
1606 /***********************************************************
1607 * PRINTER_INFO_2AtoW
1608 * Creates a unicode copy of PRINTER_INFO_2A on heap
1610 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1612 LPPRINTER_INFO_2W piW
;
1613 UNICODE_STRING usBuffer
;
1615 if(!piA
) return NULL
;
1616 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1617 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1619 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1620 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1621 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1622 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1623 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1624 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1625 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1626 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1627 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1628 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1629 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1630 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1634 /***********************************************************
1635 * FREE_PRINTER_INFO_2W
1636 * Free PRINTER_INFO_2W and all strings
1638 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1642 HeapFree(heap
,0,piW
->pServerName
);
1643 HeapFree(heap
,0,piW
->pPrinterName
);
1644 HeapFree(heap
,0,piW
->pShareName
);
1645 HeapFree(heap
,0,piW
->pPortName
);
1646 HeapFree(heap
,0,piW
->pDriverName
);
1647 HeapFree(heap
,0,piW
->pComment
);
1648 HeapFree(heap
,0,piW
->pLocation
);
1649 HeapFree(heap
,0,piW
->pDevMode
);
1650 HeapFree(heap
,0,piW
->pSepFile
);
1651 HeapFree(heap
,0,piW
->pPrintProcessor
);
1652 HeapFree(heap
,0,piW
->pDatatype
);
1653 HeapFree(heap
,0,piW
->pParameters
);
1654 HeapFree(heap
,0,piW
);
1658 /******************************************************************
1659 * DeviceCapabilities [WINSPOOL.@]
1660 * DeviceCapabilitiesA [WINSPOOL.@]
1663 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1664 LPSTR pOutput
, LPDEVMODEA lpdm
)
1668 if (!GDI_CallDeviceCapabilities16
)
1670 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1672 if (!GDI_CallDeviceCapabilities16
) return -1;
1674 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1676 /* If DC_PAPERSIZE map POINT16s to POINTs */
1677 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1678 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1679 POINT
*pt
= (POINT
*)pOutput
;
1681 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1682 for(i
= 0; i
< ret
; i
++, pt
++)
1687 HeapFree( GetProcessHeap(), 0, tmp
);
1693 /*****************************************************************************
1694 * DeviceCapabilitiesW [WINSPOOL.@]
1696 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1699 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1700 WORD fwCapability
, LPWSTR pOutput
,
1701 const DEVMODEW
*pDevMode
)
1703 LPDEVMODEA dmA
= DEVMODEdupWtoA(pDevMode
);
1704 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1705 LPSTR pPortA
= strdupWtoA(pPort
);
1708 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1709 fwCapability
== DC_FILEDEPENDENCIES
||
1710 fwCapability
== DC_PAPERNAMES
)) {
1711 /* These need A -> W translation */
1714 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1718 switch(fwCapability
) {
1723 case DC_FILEDEPENDENCIES
:
1727 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1728 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1730 for(i
= 0; i
< ret
; i
++)
1731 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1732 pOutput
+ (i
* size
), size
);
1733 HeapFree(GetProcessHeap(), 0, pOutputA
);
1735 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1736 (LPSTR
)pOutput
, dmA
);
1738 HeapFree(GetProcessHeap(),0,pPortA
);
1739 HeapFree(GetProcessHeap(),0,pDeviceA
);
1740 HeapFree(GetProcessHeap(),0,dmA
);
1744 /******************************************************************
1745 * DocumentPropertiesA [WINSPOOL.@]
1747 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1749 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1750 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1751 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1753 LPSTR lpName
= pDeviceName
;
1754 static CHAR port
[] = "LPT1:";
1757 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1758 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1762 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1764 ERR("no name from hPrinter?\n");
1765 SetLastError(ERROR_INVALID_HANDLE
);
1768 lpName
= strdupWtoA(lpNameW
);
1771 if (!GDI_CallExtDeviceMode16
)
1773 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1775 if (!GDI_CallExtDeviceMode16
) {
1776 ERR("No CallExtDeviceMode16?\n");
1780 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1781 pDevModeInput
, NULL
, fMode
);
1784 HeapFree(GetProcessHeap(),0,lpName
);
1789 /*****************************************************************************
1790 * DocumentPropertiesW (WINSPOOL.@)
1792 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1794 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1796 LPDEVMODEW pDevModeOutput
,
1797 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1800 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1801 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(pDevModeInput
);
1802 LPDEVMODEA pDevModeOutputA
= NULL
;
1805 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1806 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1808 if(pDevModeOutput
) {
1809 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1810 if(ret
< 0) return ret
;
1811 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1813 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1814 pDevModeInputA
, fMode
);
1815 if(pDevModeOutput
) {
1816 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
1817 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
1819 if(fMode
== 0 && ret
> 0)
1820 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
1821 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
1822 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
1826 /******************************************************************
1827 * OpenPrinterA [WINSPOOL.@]
1832 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
1833 LPPRINTER_DEFAULTSA pDefault
)
1835 UNICODE_STRING lpPrinterNameW
;
1836 UNICODE_STRING usBuffer
;
1837 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
1838 PWSTR pwstrPrinterNameW
;
1841 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
1844 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
1845 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
1846 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
1847 pDefaultW
= &DefaultW
;
1849 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
1851 RtlFreeUnicodeString(&usBuffer
);
1852 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
1854 RtlFreeUnicodeString(&lpPrinterNameW
);
1858 /******************************************************************
1859 * OpenPrinterW [WINSPOOL.@]
1861 * Open a Printer / Printserver or a Printer-Object
1864 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1865 * phPrinter [O] The resulting Handle is stored here
1866 * pDefault [I] PTR to Default Printer Settings or NULL
1873 * lpPrinterName is one of:
1874 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1875 *| Printer: "PrinterName"
1876 *| Printer-Object: "PrinterName,Job xxx"
1877 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1878 *| XcvPort: "Servername,XcvPort PortName"
1881 *| Printer-Object not supported
1882 *| pDefaults is ignored
1885 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
1888 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
1890 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1891 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
1895 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1896 SetLastError(ERROR_INVALID_PARAMETER
);
1900 /* Get the unique handle of the printer or Printserver */
1901 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
1902 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
1903 return (*phPrinter
!= 0);
1906 /******************************************************************
1907 * AddMonitorA [WINSPOOL.@]
1912 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1914 LPWSTR nameW
= NULL
;
1917 LPMONITOR_INFO_2A mi2a
;
1918 MONITOR_INFO_2W mi2w
;
1920 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
1921 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
1922 debugstr_a(mi2a
? mi2a
->pName
: NULL
),
1923 debugstr_a(mi2a
? mi2a
->pEnvironment
: NULL
),
1924 debugstr_a(mi2a
? mi2a
->pDLLName
: NULL
));
1927 SetLastError(ERROR_INVALID_LEVEL
);
1931 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1937 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
1938 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1939 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
1942 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
1944 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
1945 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1946 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
1948 if (mi2a
->pEnvironment
) {
1949 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
1950 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1951 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
1953 if (mi2a
->pDLLName
) {
1954 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
1955 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1956 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
1959 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
1961 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
1962 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
1963 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
1965 HeapFree(GetProcessHeap(), 0, nameW
);
1969 /******************************************************************************
1970 * AddMonitorW [WINSPOOL.@]
1972 * Install a Printmonitor
1975 * pName [I] Servername or NULL (local Computer)
1976 * Level [I] Structure-Level (Must be 2)
1977 * pMonitors [I] PTR to MONITOR_INFO_2
1984 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1987 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1989 LPMONITOR_INFO_2W mi2w
;
1991 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1992 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1993 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1994 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1995 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1997 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2000 SetLastError(ERROR_INVALID_LEVEL
);
2004 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2009 return backend
->fpAddMonitor(pName
, Level
, pMonitors
);
2012 /******************************************************************
2013 * DeletePrinterDriverA [WINSPOOL.@]
2016 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2018 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2021 /******************************************************************
2022 * DeletePrinterDriverW [WINSPOOL.@]
2025 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2027 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2030 /******************************************************************
2031 * DeleteMonitorA [WINSPOOL.@]
2033 * See DeleteMonitorW.
2036 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2038 LPWSTR nameW
= NULL
;
2039 LPWSTR EnvironmentW
= NULL
;
2040 LPWSTR MonitorNameW
= NULL
;
2045 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2046 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2047 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2051 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2052 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2053 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2056 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2057 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2058 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2061 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2063 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2064 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2065 HeapFree(GetProcessHeap(), 0, nameW
);
2069 /******************************************************************
2070 * DeleteMonitorW [WINSPOOL.@]
2072 * Delete a specific Printmonitor from a Printing-Environment
2075 * pName [I] Servername or NULL (local Computer)
2076 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2077 * pMonitorName [I] Name of the Monitor, that should be deleted
2084 * pEnvironment is ignored in Windows for the local Computer.
2087 BOOL WINAPI
DeleteMonitorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2090 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2091 debugstr_w(pMonitorName
));
2093 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2095 return backend
->fpDeleteMonitor(pName
, pEnvironment
, pMonitorName
);
2099 /******************************************************************
2100 * DeletePortA [WINSPOOL.@]
2105 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2107 LPWSTR nameW
= NULL
;
2108 LPWSTR portW
= NULL
;
2112 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2114 /* convert servername to unicode */
2116 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2117 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2118 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2121 /* convert portname to unicode */
2123 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2124 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2125 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2128 res
= DeletePortW(nameW
, hWnd
, portW
);
2129 HeapFree(GetProcessHeap(), 0, nameW
);
2130 HeapFree(GetProcessHeap(), 0, portW
);
2134 /******************************************************************
2135 * DeletePortW [WINSPOOL.@]
2137 * Delete a specific Port
2140 * pName [I] Servername or NULL (local Computer)
2141 * hWnd [I] Handle to parent Window for the Dialog-Box
2142 * pPortName [I] Name of the Port, that should be deleted
2149 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2151 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2153 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2156 SetLastError(RPC_X_NULL_REF_POINTER
);
2160 return backend
->fpDeletePort(pName
, hWnd
, pPortName
);
2163 /******************************************************************************
2164 * SetPrinterW [WINSPOOL.@]
2166 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2168 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2169 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2173 /******************************************************************************
2174 * WritePrinter [WINSPOOL.@]
2176 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2178 opened_printer_t
*printer
;
2181 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2183 EnterCriticalSection(&printer_handles_cs
);
2184 printer
= get_opened_printer(hPrinter
);
2187 SetLastError(ERROR_INVALID_HANDLE
);
2193 SetLastError(ERROR_SPL_NO_STARTDOC
);
2197 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2199 LeaveCriticalSection(&printer_handles_cs
);
2203 /*****************************************************************************
2204 * AddFormA [WINSPOOL.@]
2206 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2208 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2212 /*****************************************************************************
2213 * AddFormW [WINSPOOL.@]
2215 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2217 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2221 /*****************************************************************************
2222 * AddJobA [WINSPOOL.@]
2224 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2227 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2231 SetLastError(ERROR_INVALID_LEVEL
);
2235 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2238 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2239 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2240 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2241 if(*pcbNeeded
> cbBuf
) {
2242 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2245 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2246 addjobA
->JobId
= addjobW
->JobId
;
2247 addjobA
->Path
= (char *)(addjobA
+ 1);
2248 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2254 /*****************************************************************************
2255 * AddJobW [WINSPOOL.@]
2257 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2259 opened_printer_t
*printer
;
2262 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2263 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2264 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2266 ADDJOB_INFO_1W
*addjob
;
2268 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2270 EnterCriticalSection(&printer_handles_cs
);
2272 printer
= get_opened_printer(hPrinter
);
2275 SetLastError(ERROR_INVALID_HANDLE
);
2280 SetLastError(ERROR_INVALID_LEVEL
);
2284 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2288 job
->job_id
= InterlockedIncrement(&next_job_id
);
2290 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2291 if(path
[len
- 1] != '\\')
2293 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2294 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2296 len
= strlenW(filename
);
2297 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2298 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2299 job
->document_title
= strdupW(default_doc_title
);
2300 job
->printer_name
= strdupW(printer
->name
);
2301 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2303 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2304 if(*pcbNeeded
<= cbBuf
) {
2305 addjob
= (ADDJOB_INFO_1W
*)pData
;
2306 addjob
->JobId
= job
->job_id
;
2307 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2308 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2311 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2314 LeaveCriticalSection(&printer_handles_cs
);
2318 /*****************************************************************************
2319 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2321 * Return the PATH for the Print-Processors
2323 * See GetPrintProcessorDirectoryW.
2327 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2328 DWORD level
, LPBYTE Info
,
2329 DWORD cbBuf
, LPDWORD pcbNeeded
)
2331 LPWSTR serverW
= NULL
;
2336 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2337 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2341 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2342 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2343 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2347 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2348 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2349 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2352 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2353 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2355 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2358 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2359 cbBuf
, NULL
, NULL
) > 0;
2362 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2363 HeapFree(GetProcessHeap(), 0, envW
);
2364 HeapFree(GetProcessHeap(), 0, serverW
);
2368 /*****************************************************************************
2369 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2371 * Return the PATH for the Print-Processors
2374 * server [I] Servername (NT only) or NULL (local Computer)
2375 * env [I] Printing-Environment (see below) or NULL (Default)
2376 * level [I] Structure-Level (must be 1)
2377 * Info [O] PTR to Buffer that receives the Result
2378 * cbBuf [I] Size of Buffer at "Info"
2379 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2380 * required for the Buffer at "Info"
2383 * Success: TRUE and in pcbNeeded the Bytes used in Info
2384 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2385 * if cbBuf is too small
2387 * Native Values returned in Info on Success:
2388 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2389 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2390 *| win9x(Windows 4.0): "%winsysdir%"
2392 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2395 * Only NULL or "" is supported for server
2398 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2399 DWORD level
, LPBYTE Info
,
2400 DWORD cbBuf
, LPDWORD pcbNeeded
)
2403 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
), debugstr_w(env
), level
,
2404 Info
, cbBuf
, pcbNeeded
);
2406 if ((backend
== NULL
) && !load_backend()) return FALSE
;
2409 /* (Level != 1) is ignored in win9x */
2410 SetLastError(ERROR_INVALID_LEVEL
);
2414 if (pcbNeeded
== NULL
) {
2415 /* (pcbNeeded == NULL) is ignored in win9x */
2416 SetLastError(RPC_X_NULL_REF_POINTER
);
2420 return backend
->fpGetPrintProcessorDirectory(server
, env
, level
, Info
, cbBuf
, pcbNeeded
);
2423 /*****************************************************************************
2424 * WINSPOOL_OpenDriverReg [internal]
2426 * opens the registry for the printer drivers depending on the given input
2427 * variable pEnvironment
2430 * the opened hkey on success
2433 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
)
2437 const printenv_t
* env
;
2439 TRACE("(%s)\n", debugstr_w(pEnvironment
));
2441 env
= validate_envW(pEnvironment
);
2442 if (!env
) return NULL
;
2444 buffer
= HeapAlloc( GetProcessHeap(), 0,
2445 (strlenW(DriversW
) + strlenW(env
->envname
) +
2446 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2448 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2449 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2450 HeapFree(GetProcessHeap(), 0, buffer
);
2455 /*****************************************************************************
2456 * AddPrinterW [WINSPOOL.@]
2458 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2460 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2464 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2466 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2467 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2468 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2469 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2470 statusW
[] = {'S','t','a','t','u','s',0},
2471 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2473 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2476 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2477 SetLastError(ERROR_INVALID_PARAMETER
);
2481 ERR("Level = %d, unsupported!\n", Level
);
2482 SetLastError(ERROR_INVALID_LEVEL
);
2486 SetLastError(ERROR_INVALID_PARAMETER
);
2489 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2491 ERR("Can't create Printers key\n");
2494 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2495 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2496 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2497 RegCloseKey(hkeyPrinter
);
2498 RegCloseKey(hkeyPrinters
);
2501 RegCloseKey(hkeyPrinter
);
2503 hkeyDrivers
= WINSPOOL_OpenDriverReg(NULL
);
2505 ERR("Can't create Drivers key\n");
2506 RegCloseKey(hkeyPrinters
);
2509 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2511 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2512 RegCloseKey(hkeyPrinters
);
2513 RegCloseKey(hkeyDrivers
);
2514 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2517 RegCloseKey(hkeyDriver
);
2518 RegCloseKey(hkeyDrivers
);
2520 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2521 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2522 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2523 RegCloseKey(hkeyPrinters
);
2527 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2529 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2530 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2531 RegCloseKey(hkeyPrinters
);
2534 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2535 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2536 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2538 /* See if we can load the driver. We may need the devmode structure anyway
2541 * Note that DocumentPropertiesW will briefly try to open the printer we
2542 * just create to find a DEVMODEA struct (it will use the WINEPS default
2543 * one in case it is not there, so we are ok).
2545 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2548 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2549 size
= sizeof(DEVMODEW
);
2555 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2557 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2559 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2560 HeapFree(GetProcessHeap(),0,dmW
);
2565 /* set devmode to printer name */
2566 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2570 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2571 and we support these drivers. NT writes DEVMODEW so somehow
2572 we'll need to distinguish between these when we support NT
2576 dmA
= DEVMODEdupWtoA(dmW
);
2577 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2578 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2579 HeapFree(GetProcessHeap(), 0, dmA
);
2581 HeapFree(GetProcessHeap(), 0, dmW
);
2583 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2584 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2585 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2586 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2588 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2589 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2590 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2591 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2592 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2593 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2594 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2595 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2596 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2597 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2598 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2599 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2600 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2602 RegCloseKey(hkeyPrinter
);
2603 RegCloseKey(hkeyPrinters
);
2604 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2605 ERR("OpenPrinter failing\n");
2611 /*****************************************************************************
2612 * AddPrinterA [WINSPOOL.@]
2614 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2616 UNICODE_STRING pNameW
;
2618 PRINTER_INFO_2W
*piW
;
2619 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2622 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2624 ERR("Level = %d, unsupported!\n", Level
);
2625 SetLastError(ERROR_INVALID_LEVEL
);
2628 pwstrNameW
= asciitounicode(&pNameW
,pName
);
2629 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
2631 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
2633 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
2634 RtlFreeUnicodeString(&pNameW
);
2639 /*****************************************************************************
2640 * ClosePrinter [WINSPOOL.@]
2642 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
2644 UINT_PTR i
= (UINT_PTR
)hPrinter
;
2645 opened_printer_t
*printer
= NULL
;
2648 TRACE("(%p)\n", hPrinter
);
2650 EnterCriticalSection(&printer_handles_cs
);
2652 if ((i
> 0) && (i
<= nb_printer_handles
))
2653 printer
= printer_handles
[i
- 1];
2658 struct list
*cursor
, *cursor2
;
2660 TRACE("closing %s (doc: %p)\n", debugstr_w(printer
->name
), printer
->doc
);
2662 if (printer
->backend_printer
) {
2663 backend
->fpClosePrinter(printer
->backend_printer
);
2667 EndDocPrinter(hPrinter
);
2669 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
2671 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
2673 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
2674 ScheduleJob(hPrinter
, job
->job_id
);
2676 HeapFree(GetProcessHeap(), 0, printer
->queue
);
2679 HeapFree(GetProcessHeap(), 0, printer
->printername
);
2680 HeapFree(GetProcessHeap(), 0, printer
->name
);
2681 HeapFree(GetProcessHeap(), 0, printer
);
2682 printer_handles
[i
- 1] = NULL
;
2685 LeaveCriticalSection(&printer_handles_cs
);
2689 /*****************************************************************************
2690 * DeleteFormA [WINSPOOL.@]
2692 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
2694 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
2698 /*****************************************************************************
2699 * DeleteFormW [WINSPOOL.@]
2701 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
2703 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
2707 /*****************************************************************************
2708 * DeletePrinter [WINSPOOL.@]
2710 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
2712 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
2713 HKEY hkeyPrinters
, hkey
;
2716 SetLastError(ERROR_INVALID_HANDLE
);
2719 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
2720 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
2721 RegCloseKey(hkeyPrinters
);
2723 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
2724 WriteProfileStringW(PrinterPortsW
, lpNameW
, NULL
);
2726 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
2727 RegDeleteValueW(hkey
, lpNameW
);
2731 if(RegCreateKeyW(HKEY_CURRENT_USER
, WinNT_CV_PrinterPortsW
, &hkey
) == ERROR_SUCCESS
) {
2732 RegDeleteValueW(hkey
, lpNameW
);
2738 /*****************************************************************************
2739 * SetPrinterA [WINSPOOL.@]
2741 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
2744 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
2748 /*****************************************************************************
2749 * SetJobA [WINSPOOL.@]
2751 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2752 LPBYTE pJob
, DWORD Command
)
2756 UNICODE_STRING usBuffer
;
2758 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
2760 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2761 are all ignored by SetJob, so we don't bother copying them */
2769 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
2770 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
2772 JobW
= (LPBYTE
)info1W
;
2773 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
2774 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
2775 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
2776 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
2777 info1W
->Status
= info1A
->Status
;
2778 info1W
->Priority
= info1A
->Priority
;
2779 info1W
->Position
= info1A
->Position
;
2780 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
2785 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
2786 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
2788 JobW
= (LPBYTE
)info2W
;
2789 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
2790 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
2791 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
2792 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
2793 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
2794 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
2795 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
2796 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
2797 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
2798 info2W
->Status
= info2A
->Status
;
2799 info2W
->Priority
= info2A
->Priority
;
2800 info2W
->Position
= info2A
->Position
;
2801 info2W
->StartTime
= info2A
->StartTime
;
2802 info2W
->UntilTime
= info2A
->UntilTime
;
2803 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
2807 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
2808 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
2811 SetLastError(ERROR_INVALID_LEVEL
);
2815 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
2821 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
2822 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
2823 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
2824 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
2825 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
2830 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
2831 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
2832 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
2833 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
2834 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
2835 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
2836 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
2837 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
2838 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
2842 HeapFree(GetProcessHeap(), 0, JobW
);
2847 /*****************************************************************************
2848 * SetJobW [WINSPOOL.@]
2850 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
2851 LPBYTE pJob
, DWORD Command
)
2856 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
2857 FIXME("Ignoring everything other than document title\n");
2859 EnterCriticalSection(&printer_handles_cs
);
2860 job
= get_job(hPrinter
, JobId
);
2870 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
2871 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2872 job
->document_title
= strdupW(info1
->pDocument
);
2877 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
2878 HeapFree(GetProcessHeap(), 0, job
->document_title
);
2879 job
->document_title
= strdupW(info2
->pDocument
);
2885 SetLastError(ERROR_INVALID_LEVEL
);
2890 LeaveCriticalSection(&printer_handles_cs
);
2894 /*****************************************************************************
2895 * EndDocPrinter [WINSPOOL.@]
2897 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
2899 opened_printer_t
*printer
;
2901 TRACE("(%p)\n", hPrinter
);
2903 EnterCriticalSection(&printer_handles_cs
);
2905 printer
= get_opened_printer(hPrinter
);
2908 SetLastError(ERROR_INVALID_HANDLE
);
2914 SetLastError(ERROR_SPL_NO_STARTDOC
);
2918 CloseHandle(printer
->doc
->hf
);
2919 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
2920 HeapFree(GetProcessHeap(), 0, printer
->doc
);
2921 printer
->doc
= NULL
;
2924 LeaveCriticalSection(&printer_handles_cs
);
2928 /*****************************************************************************
2929 * EndPagePrinter [WINSPOOL.@]
2931 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
2933 FIXME("(%p): stub\n", hPrinter
);
2937 /*****************************************************************************
2938 * StartDocPrinterA [WINSPOOL.@]
2940 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2942 UNICODE_STRING usBuffer
;
2944 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
2947 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2948 or one (DOC_INFO_3) extra DWORDs */
2952 doc2W
.JobId
= doc2
->JobId
;
2955 doc2W
.dwMode
= doc2
->dwMode
;
2958 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
2959 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
2960 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
2964 SetLastError(ERROR_INVALID_LEVEL
);
2968 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
2970 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
2971 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
2972 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
2977 /*****************************************************************************
2978 * StartDocPrinterW [WINSPOOL.@]
2980 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
2982 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
2983 opened_printer_t
*printer
;
2984 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2985 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
2986 JOB_INFO_1W job_info
;
2987 DWORD needed
, ret
= 0;
2992 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2993 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
2994 debugstr_w(doc
->pDatatype
));
2996 if(Level
< 1 || Level
> 3)
2998 SetLastError(ERROR_INVALID_LEVEL
);
3002 EnterCriticalSection(&printer_handles_cs
);
3003 printer
= get_opened_printer(hPrinter
);
3006 SetLastError(ERROR_INVALID_HANDLE
);
3012 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3016 /* Even if we're printing to a file we still add a print job, we'll
3017 just ignore the spool file name */
3019 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3021 ERR("AddJob failed gle %u\n", GetLastError());
3025 /* use pOutputFile only, when it is a real filename */
3026 if ((doc
->pOutputFile
) && is_local_file(doc
->pOutputFile
))
3027 filename
= doc
->pOutputFile
;
3029 filename
= addjob
->Path
;
3031 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3032 if(hf
== INVALID_HANDLE_VALUE
)
3035 memset(&job_info
, 0, sizeof(job_info
));
3036 job_info
.pDocument
= doc
->pDocName
;
3037 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3039 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3040 printer
->doc
->hf
= hf
;
3041 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3042 job
= get_job(hPrinter
, ret
);
3043 job
->portname
= strdupW(doc
->pOutputFile
);
3046 LeaveCriticalSection(&printer_handles_cs
);
3051 /*****************************************************************************
3052 * StartPagePrinter [WINSPOOL.@]
3054 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3056 FIXME("(%p): stub\n", hPrinter
);
3060 /*****************************************************************************
3061 * GetFormA [WINSPOOL.@]
3063 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3064 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3066 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3067 Level
,pForm
,cbBuf
,pcbNeeded
);
3071 /*****************************************************************************
3072 * GetFormW [WINSPOOL.@]
3074 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3075 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3077 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3078 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3082 /*****************************************************************************
3083 * SetFormA [WINSPOOL.@]
3085 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3088 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3092 /*****************************************************************************
3093 * SetFormW [WINSPOOL.@]
3095 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3098 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3102 /*****************************************************************************
3103 * ReadPrinter [WINSPOOL.@]
3105 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3106 LPDWORD pNoBytesRead
)
3108 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3112 /*****************************************************************************
3113 * ResetPrinterA [WINSPOOL.@]
3115 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3117 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3121 /*****************************************************************************
3122 * ResetPrinterW [WINSPOOL.@]
3124 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3126 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3130 /*****************************************************************************
3131 * WINSPOOL_GetDWORDFromReg
3133 * Return DWORD associated with ValueName from hkey.
3135 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3137 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3140 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3142 if(ret
!= ERROR_SUCCESS
) {
3143 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3146 if(type
!= REG_DWORD
) {
3147 ERR("Got type %d\n", type
);
3154 /*****************************************************************************
3155 * get_filename_from_reg [internal]
3157 * Get ValueName from hkey storing result in out
3158 * when the Value in the registry has only a filename, use driverdir as prefix
3159 * outlen is space left in out
3160 * String is stored either as unicode or ascii
3164 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3165 LPBYTE out
, DWORD outlen
, LPDWORD needed
)
3167 WCHAR filename
[MAX_PATH
];
3171 LPWSTR buffer
= filename
;
3175 size
= sizeof(filename
);
3177 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3178 if (ret
== ERROR_MORE_DATA
) {
3179 TRACE("need dynamic buffer: %u\n", size
);
3180 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3182 /* No Memory is bad */
3186 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3189 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3190 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3196 /* do we have a full path ? */
3197 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3198 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3201 /* we must build the full Path */
3203 if ((out
) && (outlen
> dirlen
)) {
3204 lstrcpyW((LPWSTR
)out
, driverdir
);
3212 /* write the filename */
3213 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3214 if ((out
) && (outlen
>= size
)) {
3215 lstrcpyW((LPWSTR
)out
, ptr
);
3222 ptr
+= lstrlenW(ptr
)+1;
3223 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3226 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3228 /* write the multisz-termination */
3229 if (type
== REG_MULTI_SZ
) {
3230 size
= sizeof(WCHAR
);
3233 if (out
&& (outlen
>= size
)) {
3234 memset (out
, 0, size
);
3240 /*****************************************************************************
3241 * WINSPOOL_GetStringFromReg
3243 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3244 * String is stored as unicode.
3246 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3247 DWORD buflen
, DWORD
*needed
)
3249 DWORD sz
= buflen
, type
;
3252 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3253 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3254 WARN("Got ret = %d\n", ret
);
3258 /* add space for terminating '\0' */
3259 sz
+= sizeof(WCHAR
);
3263 TRACE("%s: %s\n", debugstr_w(ValueName
), debugstr_w((LPCWSTR
)ptr
));
3268 /*****************************************************************************
3269 * WINSPOOL_GetDefaultDevMode
3271 * Get a default DevMode values for wineps.
3275 static void WINSPOOL_GetDefaultDevMode(
3277 DWORD buflen
, DWORD
*needed
)
3280 static const WCHAR szWwps
[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3282 /* fill default DEVMODE - should be read from ppd... */
3283 ZeroMemory( &dm
, sizeof(dm
) );
3284 memcpy(dm
.dmDeviceName
,szWwps
,sizeof szWwps
);
3285 dm
.dmSpecVersion
= DM_SPECVERSION
;
3286 dm
.dmDriverVersion
= 1;
3287 dm
.dmSize
= sizeof(DEVMODEW
);
3288 dm
.dmDriverExtra
= 0;
3290 DM_ORIENTATION
| DM_PAPERSIZE
|
3291 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3294 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3295 DM_YRESOLUTION
| DM_TTOPTION
;
3297 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3298 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3299 dm
.u1
.s1
.dmPaperLength
= 2970;
3300 dm
.u1
.s1
.dmPaperWidth
= 2100;
3302 dm
.u1
.s1
.dmScale
= 100;
3303 dm
.u1
.s1
.dmCopies
= 1;
3304 dm
.u1
.s1
.dmDefaultSource
= DMBIN_AUTO
;
3305 dm
.u1
.s1
.dmPrintQuality
= DMRES_MEDIUM
;
3308 dm
.dmYResolution
= 300; /* 300dpi */
3309 dm
.dmTTOption
= DMTT_BITMAP
;
3312 /* dm.dmLogPixels */
3313 /* dm.dmBitsPerPel */
3314 /* dm.dmPelsWidth */
3315 /* dm.dmPelsHeight */
3316 /* dm.u2.dmDisplayFlags */
3317 /* dm.dmDisplayFrequency */
3318 /* dm.dmICMMethod */
3319 /* dm.dmICMIntent */
3320 /* dm.dmMediaType */
3321 /* dm.dmDitherType */
3322 /* dm.dmReserved1 */
3323 /* dm.dmReserved2 */
3324 /* dm.dmPanningWidth */
3325 /* dm.dmPanningHeight */
3327 if(buflen
>= sizeof(DEVMODEW
))
3328 memcpy(ptr
, &dm
, sizeof(DEVMODEW
));
3329 *needed
= sizeof(DEVMODEW
);
3332 /*****************************************************************************
3333 * WINSPOOL_GetDevModeFromReg
3335 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3336 * DevMode is stored either as unicode or ascii.
3338 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3340 DWORD buflen
, DWORD
*needed
)
3342 DWORD sz
= buflen
, type
;
3345 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3346 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3347 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3348 if (sz
< sizeof(DEVMODEA
))
3350 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3353 /* ensures that dmSize is not erratically bogus if registry is invalid */
3354 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3355 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3356 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3357 if (ptr
&& (buflen
>= sz
)) {
3358 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3359 memcpy(ptr
, dmW
, sz
);
3360 HeapFree(GetProcessHeap(),0,dmW
);
3366 /*********************************************************************
3367 * WINSPOOL_GetPrinter_1
3369 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3371 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3372 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3374 DWORD size
, left
= cbBuf
;
3375 BOOL space
= (cbBuf
> 0);
3380 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3381 if(space
&& size
<= left
) {
3382 pi1
->pName
= (LPWSTR
)ptr
;
3390 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3391 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3392 if(space
&& size
<= left
) {
3393 pi1
->pDescription
= (LPWSTR
)ptr
;
3401 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3402 if(space
&& size
<= left
) {
3403 pi1
->pComment
= (LPWSTR
)ptr
;
3411 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3413 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3414 memset(pi1
, 0, sizeof(*pi1
));
3418 /*********************************************************************
3419 * WINSPOOL_GetPrinter_2
3421 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3423 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3424 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3426 DWORD size
, left
= cbBuf
;
3427 BOOL space
= (cbBuf
> 0);
3432 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3433 if(space
&& size
<= left
) {
3434 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3441 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
)) {
3442 if(space
&& size
<= left
) {
3443 pi2
->pShareName
= (LPWSTR
)ptr
;
3450 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3451 if(space
&& size
<= left
) {
3452 pi2
->pPortName
= (LPWSTR
)ptr
;
3459 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
, &size
)) {
3460 if(space
&& size
<= left
) {
3461 pi2
->pDriverName
= (LPWSTR
)ptr
;
3468 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
)) {
3469 if(space
&& size
<= left
) {
3470 pi2
->pComment
= (LPWSTR
)ptr
;
3477 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
)) {
3478 if(space
&& size
<= left
) {
3479 pi2
->pLocation
= (LPWSTR
)ptr
;
3486 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
, &size
)) {
3487 if(space
&& size
<= left
) {
3488 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3497 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
);
3498 if(space
&& size
<= left
) {
3499 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3506 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
, &size
)) {
3507 if(space
&& size
<= left
) {
3508 pi2
->pSepFile
= (LPWSTR
)ptr
;
3515 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
, &size
)) {
3516 if(space
&& size
<= left
) {
3517 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3524 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
, &size
)) {
3525 if(space
&& size
<= left
) {
3526 pi2
->pDatatype
= (LPWSTR
)ptr
;
3533 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
, &size
)) {
3534 if(space
&& size
<= left
) {
3535 pi2
->pParameters
= (LPWSTR
)ptr
;
3543 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3544 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3545 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3546 "Default Priority");
3547 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3548 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3551 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3552 memset(pi2
, 0, sizeof(*pi2
));
3557 /*********************************************************************
3558 * WINSPOOL_GetPrinter_4
3560 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3562 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3563 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3565 DWORD size
, left
= cbBuf
;
3566 BOOL space
= (cbBuf
> 0);
3571 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3572 if(space
&& size
<= left
) {
3573 pi4
->pPrinterName
= (LPWSTR
)ptr
;
3581 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3584 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
3585 memset(pi4
, 0, sizeof(*pi4
));
3590 /*********************************************************************
3591 * WINSPOOL_GetPrinter_5
3593 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3595 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
3596 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3598 DWORD size
, left
= cbBuf
;
3599 BOOL space
= (cbBuf
> 0);
3604 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
)) {
3605 if(space
&& size
<= left
) {
3606 pi5
->pPrinterName
= (LPWSTR
)ptr
;
3613 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
)) {
3614 if(space
&& size
<= left
) {
3615 pi5
->pPortName
= (LPWSTR
)ptr
;
3623 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3624 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3626 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3630 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
3631 memset(pi5
, 0, sizeof(*pi5
));
3636 /*********************************************************************
3637 * WINSPOOL_GetPrinter_7
3639 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3641 static BOOL
WINSPOOL_GetPrinter_7(HKEY hkeyPrinter
, PRINTER_INFO_7W
*pi7
, LPBYTE buf
,
3642 DWORD cbBuf
, LPDWORD pcbNeeded
)
3644 DWORD size
, left
= cbBuf
;
3645 BOOL space
= (cbBuf
> 0);
3650 if (! WINSPOOL_GetStringFromReg(hkeyPrinter
, ObjectGUIDW
, ptr
, left
, &size
))
3653 size
= sizeof(pi7
->pszObjectGUID
);
3655 if (space
&& size
<= left
) {
3656 pi7
->pszObjectGUID
= (LPWSTR
)ptr
;
3663 /* We do not have a Directory Service */
3664 pi7
->dwAction
= DSPRINT_UNPUBLISH
;
3667 if (!space
&& pi7
) /* zero out pi7 if we can't completely fill buf */
3668 memset(pi7
, 0, sizeof(*pi7
));
3673 /*********************************************************************
3674 * WINSPOOL_GetPrinter_9
3676 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3678 static BOOL
WINSPOOL_GetPrinter_9(HKEY hkeyPrinter
, PRINTER_INFO_9W
*pi9
, LPBYTE buf
,
3679 DWORD cbBuf
, LPDWORD pcbNeeded
)
3682 BOOL space
= (cbBuf
> 0);
3686 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, buf
, cbBuf
, &size
)) {
3687 if(space
&& size
<= cbBuf
) {
3688 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3695 WINSPOOL_GetDefaultDevMode(buf
, cbBuf
, &size
);
3696 if(space
&& size
<= cbBuf
) {
3697 pi9
->pDevMode
= (LPDEVMODEW
)buf
;
3703 if(!space
&& pi9
) /* zero out pi9 if we can't completely fill buf */
3704 memset(pi9
, 0, sizeof(*pi9
));
3709 /*****************************************************************************
3710 * GetPrinterW [WINSPOOL.@]
3712 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3713 DWORD cbBuf
, LPDWORD pcbNeeded
)
3716 DWORD size
, needed
= 0;
3718 HKEY hkeyPrinter
, hkeyPrinters
;
3721 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
3723 if (!(name
= get_opened_printer_name(hPrinter
))) {
3724 SetLastError(ERROR_INVALID_HANDLE
);
3728 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3730 ERR("Can't create Printers key\n");
3733 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
3735 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
3736 RegCloseKey(hkeyPrinters
);
3737 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
3744 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
3746 size
= sizeof(PRINTER_INFO_2W
);
3748 ptr
= pPrinter
+ size
;
3750 memset(pPrinter
, 0, size
);
3755 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
);
3762 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
3764 size
= sizeof(PRINTER_INFO_4W
);
3766 ptr
= pPrinter
+ size
;
3768 memset(pPrinter
, 0, size
);
3773 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
);
3781 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
3783 size
= sizeof(PRINTER_INFO_5W
);
3785 ptr
= pPrinter
+ size
;
3787 memset(pPrinter
, 0, size
);
3793 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
);
3801 PRINTER_INFO_6
*pi6
= (PRINTER_INFO_6
*) pPrinter
;
3803 size
= sizeof(PRINTER_INFO_6
);
3804 if (size
<= cbBuf
) {
3805 /* FIXME: We do not update the status yet */
3806 pi6
->dwStatus
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Status");
3818 PRINTER_INFO_7W
*pi7
= (PRINTER_INFO_7W
*) pPrinter
;
3820 size
= sizeof(PRINTER_INFO_7W
);
3821 if (size
<= cbBuf
) {
3822 ptr
= pPrinter
+ size
;
3824 memset(pPrinter
, 0, size
);
3830 ret
= WINSPOOL_GetPrinter_7(hkeyPrinter
, pi7
, ptr
, cbBuf
, &needed
);
3838 PRINTER_INFO_9W
*pi9
= (PRINTER_INFO_9W
*)pPrinter
;
3840 size
= sizeof(PRINTER_INFO_9W
);
3842 ptr
= pPrinter
+ size
;
3844 memset(pPrinter
, 0, size
);
3850 ret
= WINSPOOL_GetPrinter_9(hkeyPrinter
, pi9
, ptr
, cbBuf
, &needed
);
3857 FIXME("Unimplemented level %d\n", Level
);
3858 SetLastError(ERROR_INVALID_LEVEL
);
3859 RegCloseKey(hkeyPrinters
);
3860 RegCloseKey(hkeyPrinter
);
3864 RegCloseKey(hkeyPrinter
);
3865 RegCloseKey(hkeyPrinters
);
3867 TRACE("returning %d needed = %d\n", ret
, needed
);
3868 if(pcbNeeded
) *pcbNeeded
= needed
;
3870 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
3874 /*****************************************************************************
3875 * GetPrinterA [WINSPOOL.@]
3877 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3878 DWORD cbBuf
, LPDWORD pcbNeeded
)
3884 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
3886 ret
= GetPrinterW(hPrinter
, Level
, buf
, cbBuf
, pcbNeeded
);
3888 convert_printerinfo_W_to_A(pPrinter
, buf
, Level
, cbBuf
, 1);
3889 HeapFree(GetProcessHeap(), 0, buf
);
3894 /*****************************************************************************
3895 * WINSPOOL_EnumPrintersW
3897 * Implementation of EnumPrintersW
3899 static BOOL
WINSPOOL_EnumPrintersW(DWORD dwType
, LPWSTR lpszName
,
3900 DWORD dwLevel
, LPBYTE lpbPrinters
,
3901 DWORD cbBuf
, LPDWORD lpdwNeeded
,
3902 LPDWORD lpdwReturned
)
3905 HKEY hkeyPrinters
, hkeyPrinter
;
3906 WCHAR PrinterName
[255];
3907 DWORD needed
= 0, number
= 0;
3908 DWORD used
, i
, left
;
3912 memset(lpbPrinters
, 0, cbBuf
);
3918 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3919 if(dwType
== PRINTER_ENUM_DEFAULT
)
3922 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
3923 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3924 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
3926 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3932 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
3933 FIXME("dwType = %08x\n", dwType
);
3934 SetLastError(ERROR_INVALID_FLAGS
);
3938 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
3940 ERR("Can't create Printers key\n");
3944 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
3945 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
3946 RegCloseKey(hkeyPrinters
);
3947 ERR("Can't query Printers key\n");
3950 TRACE("Found %d printers\n", number
);
3954 used
= number
* sizeof(PRINTER_INFO_1W
);
3957 used
= number
* sizeof(PRINTER_INFO_2W
);
3960 used
= number
* sizeof(PRINTER_INFO_4W
);
3963 used
= number
* sizeof(PRINTER_INFO_5W
);
3967 SetLastError(ERROR_INVALID_LEVEL
);
3968 RegCloseKey(hkeyPrinters
);
3971 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
3973 for(i
= 0; i
< number
; i
++) {
3974 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)/sizeof(PrinterName
[0])) !=
3976 ERR("Can't enum key number %d\n", i
);
3977 RegCloseKey(hkeyPrinters
);
3980 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
3981 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
3983 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
3984 RegCloseKey(hkeyPrinters
);
3989 buf
= lpbPrinters
+ used
;
3990 left
= cbBuf
- used
;
3998 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4001 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4004 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4007 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4010 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4013 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4016 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4019 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4022 ERR("Shouldn't be here!\n");
4023 RegCloseKey(hkeyPrinter
);
4024 RegCloseKey(hkeyPrinters
);
4027 RegCloseKey(hkeyPrinter
);
4029 RegCloseKey(hkeyPrinters
);
4036 memset(lpbPrinters
, 0, cbBuf
);
4037 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4041 *lpdwReturned
= number
;
4042 SetLastError(ERROR_SUCCESS
);
4047 /******************************************************************
4048 * EnumPrintersW [WINSPOOL.@]
4050 * Enumerates the available printers, print servers and print
4051 * providers, depending on the specified flags, name and level.
4055 * If level is set to 1:
4056 * Returns an array of PRINTER_INFO_1 data structures in the
4057 * lpbPrinters buffer.
4059 * If level is set to 2:
4060 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4061 * Returns an array of PRINTER_INFO_2 data structures in the
4062 * lpbPrinters buffer. Note that according to MSDN also an
4063 * OpenPrinter should be performed on every remote printer.
4065 * If level is set to 4 (officially WinNT only):
4066 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4067 * Fast: Only the registry is queried to retrieve printer names,
4068 * no connection to the driver is made.
4069 * Returns an array of PRINTER_INFO_4 data structures in the
4070 * lpbPrinters buffer.
4072 * If level is set to 5 (officially WinNT4/Win9x only):
4073 * Fast: Only the registry is queried to retrieve printer names,
4074 * no connection to the driver is made.
4075 * Returns an array of PRINTER_INFO_5 data structures in the
4076 * lpbPrinters buffer.
4078 * If level set to 3 or 6+:
4079 * returns zero (failure!)
4081 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4085 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4086 * - Only levels 2, 4 and 5 are implemented at the moment.
4087 * - 16-bit printer drivers are not enumerated.
4088 * - Returned amount of bytes used/needed does not match the real Windoze
4089 * implementation (as in this implementation, all strings are part
4090 * of the buffer, whereas Win32 keeps them somewhere else)
4091 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4094 * - In a regular Wine installation, no registry settings for printers
4095 * exist, which makes this function return an empty list.
4097 BOOL WINAPI
EnumPrintersW(
4098 DWORD dwType
, /* [in] Types of print objects to enumerate */
4099 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4100 DWORD dwLevel
, /* [in] type of printer info structure */
4101 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4102 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4103 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4104 LPDWORD lpdwReturned
/* [out] number of entries returned */
4107 return WINSPOOL_EnumPrintersW(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4108 lpdwNeeded
, lpdwReturned
);
4111 /******************************************************************
4112 * EnumPrintersA [WINSPOOL.@]
4117 BOOL WINAPI
EnumPrintersA(DWORD flags
, LPSTR pName
, DWORD level
, LPBYTE pPrinters
,
4118 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4121 UNICODE_STRING pNameU
;
4125 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags
, debugstr_a(pName
), level
,
4126 pPrinters
, cbBuf
, pcbNeeded
, pcReturned
);
4128 pNameW
= asciitounicode(&pNameU
, pName
);
4130 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4131 MS Office need this */
4132 pPrintersW
= (pPrinters
&& cbBuf
) ? HeapAlloc(GetProcessHeap(), 0, cbBuf
) : NULL
;
4134 ret
= EnumPrintersW(flags
, pNameW
, level
, pPrintersW
, cbBuf
, pcbNeeded
, pcReturned
);
4136 RtlFreeUnicodeString(&pNameU
);
4138 convert_printerinfo_W_to_A(pPrinters
, pPrintersW
, level
, *pcbNeeded
, *pcReturned
);
4140 HeapFree(GetProcessHeap(), 0, pPrintersW
);
4144 /*****************************************************************************
4145 * WINSPOOL_GetDriverInfoFromReg [internal]
4147 * Enters the information from the registry into the DRIVER_INFO struct
4150 * zero if the printer driver does not exist in the registry
4151 * (only if Level > 1) otherwise nonzero
4153 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4156 const printenv_t
* env
,
4158 LPBYTE ptr
, /* DRIVER_INFO */
4159 LPBYTE pDriverStrings
, /* strings buffer */
4160 DWORD cbBuf
, /* size of string buffer */
4161 LPDWORD pcbNeeded
) /* space needed for str. */
4165 WCHAR driverdir
[MAX_PATH
];
4167 LPBYTE strPtr
= pDriverStrings
;
4168 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4170 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers
,
4171 debugstr_w(DriverName
), env
,
4172 Level
, di
, pDriverStrings
, cbBuf
);
4174 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4176 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4177 if (*pcbNeeded
<= cbBuf
)
4178 strcpyW((LPWSTR
)strPtr
, DriverName
);
4180 /* pName for level 1 has a different offset! */
4182 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4186 /* .cVersion and .pName for level > 1 */
4188 di
->cVersion
= env
->driverversion
;
4189 di
->pName
= (LPWSTR
) strPtr
;
4190 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4193 /* Reserve Space for the largest subdir and a Backslash*/
4194 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4195 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4196 /* Should never Fail */
4199 lstrcatW(driverdir
, env
->versionsubdir
);
4200 lstrcatW(driverdir
, backslashW
);
4202 /* dirlen must not include the terminating zero */
4203 dirlen
= lstrlenW(driverdir
) * sizeof(WCHAR
);
4205 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4206 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4207 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4212 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4215 if (*pcbNeeded
<= cbBuf
) {
4216 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4217 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4218 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4221 /* .pDriverPath is the Graphics rendering engine.
4222 The full Path is required to avoid a crash in some apps */
4223 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
)) {
4225 if (*pcbNeeded
<= cbBuf
)
4226 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
);
4228 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4229 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4232 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4233 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
)) {
4235 if (*pcbNeeded
<= cbBuf
)
4236 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
);
4238 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4239 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4242 /* .pConfigFile is the Driver user Interface */
4243 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
)) {
4245 if (*pcbNeeded
<= cbBuf
)
4246 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
);
4248 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4249 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4253 RegCloseKey(hkeyDriver
);
4254 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4259 RegCloseKey(hkeyDriver
);
4260 FIXME("level 5: incomplete\n");
4265 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
)) {
4267 if (*pcbNeeded
<= cbBuf
)
4268 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
);
4270 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4271 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4274 /* .pDependentFiles */
4275 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
)) {
4277 if (*pcbNeeded
<= cbBuf
)
4278 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
);
4280 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4281 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4283 else if (GetVersion() & 0x80000000) {
4284 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4285 size
= 2 * sizeof(WCHAR
);
4287 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4289 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4290 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4293 /* .pMonitorName is the optional Language Monitor */
4294 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
)) {
4296 if (*pcbNeeded
<= cbBuf
)
4297 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
);
4299 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4300 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4303 /* .pDefaultDataType */
4304 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
)) {
4306 if(*pcbNeeded
<= cbBuf
)
4307 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
);
4309 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4310 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4314 RegCloseKey(hkeyDriver
);
4315 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4319 /* .pszzPreviousNames */
4320 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
)) {
4322 if(*pcbNeeded
<= cbBuf
)
4323 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
);
4325 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4326 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4330 RegCloseKey(hkeyDriver
);
4331 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4335 /* support is missing, but not important enough for a FIXME */
4336 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4339 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
)) {
4341 if(*pcbNeeded
<= cbBuf
)
4342 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
);
4344 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4345 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4349 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
)) {
4351 if(*pcbNeeded
<= cbBuf
)
4352 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
);
4354 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4355 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4358 /* .pszHardwareID */
4359 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
)) {
4361 if(*pcbNeeded
<= cbBuf
)
4362 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
);
4364 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4365 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4369 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
)) {
4371 if(*pcbNeeded
<= cbBuf
)
4372 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
);
4374 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4375 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4379 RegCloseKey(hkeyDriver
);
4383 /* support is missing, but not important enough for a FIXME */
4384 TRACE("level 8: incomplete\n");
4386 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4387 RegCloseKey(hkeyDriver
);
4391 /*****************************************************************************
4392 * GetPrinterDriverW [WINSPOOL.@]
4394 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4395 DWORD Level
, LPBYTE pDriverInfo
,
4396 DWORD cbBuf
, LPDWORD pcbNeeded
)
4399 WCHAR DriverName
[100];
4400 DWORD ret
, type
, size
, needed
= 0;
4402 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4403 const printenv_t
* env
;
4405 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4406 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4409 ZeroMemory(pDriverInfo
, cbBuf
);
4411 if (!(name
= get_opened_printer_name(hPrinter
))) {
4412 SetLastError(ERROR_INVALID_HANDLE
);
4416 if (Level
< 1 || Level
== 7 || Level
> 8) {
4417 SetLastError(ERROR_INVALID_LEVEL
);
4421 env
= validate_envW(pEnvironment
);
4422 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4424 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4426 ERR("Can't create Printers key\n");
4429 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4431 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4432 RegCloseKey(hkeyPrinters
);
4433 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4436 size
= sizeof(DriverName
);
4438 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4439 (LPBYTE
)DriverName
, &size
);
4440 RegCloseKey(hkeyPrinter
);
4441 RegCloseKey(hkeyPrinters
);
4442 if(ret
!= ERROR_SUCCESS
) {
4443 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4447 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4449 ERR("Can't create Drivers key\n");
4453 size
= di_sizeof
[Level
];
4454 if ((size
<= cbBuf
) && pDriverInfo
)
4455 ptr
= pDriverInfo
+ size
;
4457 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4458 env
, Level
, pDriverInfo
, ptr
,
4459 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4461 RegCloseKey(hkeyDrivers
);
4465 RegCloseKey(hkeyDrivers
);
4467 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4468 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4469 if(cbBuf
>= size
+ needed
) return TRUE
;
4470 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4474 /*****************************************************************************
4475 * GetPrinterDriverA [WINSPOOL.@]
4477 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4478 DWORD Level
, LPBYTE pDriverInfo
,
4479 DWORD cbBuf
, LPDWORD pcbNeeded
)
4482 UNICODE_STRING pEnvW
;
4488 ZeroMemory(pDriverInfo
, cbBuf
);
4489 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4492 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4493 ret
= GetPrinterDriverW(hPrinter
, pwstrEnvW
, Level
, buf
,
4496 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, 1);
4498 HeapFree(GetProcessHeap(), 0, buf
);
4500 RtlFreeUnicodeString(&pEnvW
);
4504 /*****************************************************************************
4505 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4507 * Return the PATH for the Printer-Drivers (UNICODE)
4510 * pName [I] Servername (NT only) or NULL (local Computer)
4511 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4512 * Level [I] Structure-Level (must be 1)
4513 * pDriverDirectory [O] PTR to Buffer that receives the Result
4514 * cbBuf [I] Size of Buffer at pDriverDirectory
4515 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4516 * required for pDriverDirectory
4519 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4520 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4521 * if cbBuf is too small
4523 * Native Values returned in pDriverDirectory on Success:
4524 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4525 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4526 *| win9x(Windows 4.0): "%winsysdir%"
4528 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4531 *- Only NULL or "" is supported for pName
4534 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4535 DWORD Level
, LPBYTE pDriverDirectory
,
4536 DWORD cbBuf
, LPDWORD pcbNeeded
)
4538 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4539 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4541 if ((backend
== NULL
) && !load_backend()) return FALSE
;
4544 /* (Level != 1) is ignored in win9x */
4545 SetLastError(ERROR_INVALID_LEVEL
);
4548 if (pcbNeeded
== NULL
) {
4549 /* (pcbNeeded == NULL) is ignored in win9x */
4550 SetLastError(RPC_X_NULL_REF_POINTER
);
4554 return backend
->fpGetPrinterDriverDirectory(pName
, pEnvironment
, Level
,
4555 pDriverDirectory
, cbBuf
, pcbNeeded
);
4560 /*****************************************************************************
4561 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4563 * Return the PATH for the Printer-Drivers (ANSI)
4565 * See GetPrinterDriverDirectoryW.
4568 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4571 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4572 DWORD Level
, LPBYTE pDriverDirectory
,
4573 DWORD cbBuf
, LPDWORD pcbNeeded
)
4575 UNICODE_STRING nameW
, environmentW
;
4578 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4579 WCHAR
*driverDirectoryW
= NULL
;
4581 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4582 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4584 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4586 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4587 else nameW
.Buffer
= NULL
;
4588 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4589 else environmentW
.Buffer
= NULL
;
4591 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4592 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4595 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4596 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4598 *pcbNeeded
= needed
;
4599 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4601 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4603 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4605 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4606 RtlFreeUnicodeString(&environmentW
);
4607 RtlFreeUnicodeString(&nameW
);
4612 /*****************************************************************************
4613 * AddPrinterDriverA [WINSPOOL.@]
4615 * See AddPrinterDriverW.
4618 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4620 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4621 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4624 /******************************************************************************
4625 * AddPrinterDriverW (WINSPOOL.@)
4627 * Install a Printer Driver
4630 * pName [I] Servername or NULL (local Computer)
4631 * level [I] Level for the supplied DRIVER_INFO_*W struct
4632 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4639 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4641 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4642 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4645 /*****************************************************************************
4646 * AddPrintProcessorA [WINSPOOL.@]
4648 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4649 LPSTR pPrintProcessorName
)
4651 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4652 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4656 /*****************************************************************************
4657 * AddPrintProcessorW [WINSPOOL.@]
4659 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
4660 LPWSTR pPrintProcessorName
)
4662 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
4663 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
4667 /*****************************************************************************
4668 * AddPrintProvidorA [WINSPOOL.@]
4670 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4672 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
4676 /*****************************************************************************
4677 * AddPrintProvidorW [WINSPOOL.@]
4679 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
4681 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
4685 /*****************************************************************************
4686 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4688 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
4689 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
4691 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
4692 pDevModeOutput
, pDevModeInput
);
4696 /*****************************************************************************
4697 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4699 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
4700 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
4702 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
4703 pDevModeOutput
, pDevModeInput
);
4707 /*****************************************************************************
4708 * PrinterProperties [WINSPOOL.@]
4710 * Displays a dialog to set the properties of the printer.
4713 * nonzero on success or zero on failure
4716 * implemented as stub only
4718 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
4719 HANDLE hPrinter
/* [in] handle to printer object */
4721 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
4722 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
4726 /*****************************************************************************
4727 * EnumJobsA [WINSPOOL.@]
4730 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4731 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4734 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4735 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4737 if(pcbNeeded
) *pcbNeeded
= 0;
4738 if(pcReturned
) *pcReturned
= 0;
4743 /*****************************************************************************
4744 * EnumJobsW [WINSPOOL.@]
4747 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
4748 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4751 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4752 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
4754 if(pcbNeeded
) *pcbNeeded
= 0;
4755 if(pcReturned
) *pcReturned
= 0;
4759 /*****************************************************************************
4760 * WINSPOOL_EnumPrinterDrivers [internal]
4762 * Delivers information about all printer drivers installed on the
4763 * localhost or a given server
4766 * nonzero on success or zero on failure. If the buffer for the returned
4767 * information is too small the function will return an error
4770 * - only implemented for localhost, foreign hosts will return an error
4772 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
4773 DWORD Level
, LPBYTE pDriverInfo
,
4775 DWORD cbBuf
, LPDWORD pcbNeeded
,
4776 LPDWORD pcFound
, DWORD data_offset
)
4780 const printenv_t
* env
;
4782 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4783 debugstr_w(pName
), debugstr_w(pEnvironment
),
4784 Level
, pDriverInfo
, driver_index
, cbBuf
, data_offset
);
4786 env
= validate_envW(pEnvironment
);
4787 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4791 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
4793 ERR("Can't open Drivers key\n");
4797 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, pcFound
, NULL
, NULL
,
4798 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4799 RegCloseKey(hkeyDrivers
);
4800 ERR("Can't query Drivers key\n");
4803 TRACE("Found %d Drivers\n", *pcFound
);
4805 /* get size of single struct
4806 * unicode and ascii structure have the same size
4808 size
= di_sizeof
[Level
];
4810 if (data_offset
== 0)
4811 data_offset
= size
* (*pcFound
);
4812 *pcbNeeded
= data_offset
;
4814 for( i
= 0; i
< *pcFound
; i
++) {
4815 WCHAR DriverNameW
[255];
4816 PBYTE table_ptr
= NULL
;
4817 PBYTE data_ptr
= NULL
;
4820 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
)/sizeof(DriverNameW
[0]))
4822 ERR("Can't enum key number %d\n", i
);
4823 RegCloseKey(hkeyDrivers
);
4827 if (pDriverInfo
&& ((driver_index
+ i
+ 1) * size
) <= cbBuf
)
4828 table_ptr
= pDriverInfo
+ (driver_index
+ i
) * size
;
4829 if (pDriverInfo
&& *pcbNeeded
<= cbBuf
)
4830 data_ptr
= pDriverInfo
+ *pcbNeeded
;
4832 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
4833 env
, Level
, table_ptr
, data_ptr
,
4834 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
4836 RegCloseKey(hkeyDrivers
);
4840 *pcbNeeded
+= needed
;
4843 RegCloseKey(hkeyDrivers
);
4845 if(cbBuf
< *pcbNeeded
){
4846 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4853 /*****************************************************************************
4854 * EnumPrinterDriversW [WINSPOOL.@]
4856 * see function EnumPrinterDrivers for RETURNS, BUGS
4858 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
4859 LPBYTE pDriverInfo
, DWORD cbBuf
,
4860 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4862 static const WCHAR allW
[] = {'a','l','l',0};
4866 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
))
4868 SetLastError(RPC_X_NULL_REF_POINTER
);
4872 /* check for local drivers */
4873 if((pName
) && (pName
[0])) {
4874 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
4875 SetLastError(ERROR_ACCESS_DENIED
);
4879 /* check input parameter */
4880 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
4881 SetLastError(ERROR_INVALID_LEVEL
);
4885 if(pDriverInfo
&& cbBuf
> 0)
4886 memset( pDriverInfo
, 0, cbBuf
);
4888 /* Exception: pull all printers */
4889 if (pEnvironment
&& !strcmpW(pEnvironment
, allW
))
4891 DWORD i
, needed
, bufsize
= cbBuf
;
4892 DWORD total_needed
= 0;
4893 DWORD total_found
= 0;
4896 /* Precompute the overall total; we need this to know
4897 where pointers end and data begins (i.e. data_offset) */
4898 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4901 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4902 NULL
, 0, 0, &needed
, &found
, 0);
4903 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4904 total_needed
+= needed
;
4905 total_found
+= found
;
4908 data_offset
= di_sizeof
[Level
] * total_found
;
4913 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
4916 ret
= WINSPOOL_EnumPrinterDrivers(pName
, all_printenv
[i
]->envname
, Level
,
4917 pDriverInfo
, total_found
, bufsize
, &needed
, &found
, data_offset
);
4918 if (!ret
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER
) return FALSE
;
4920 *pcReturned
+= found
;
4921 *pcbNeeded
= needed
;
4922 data_offset
= needed
;
4923 total_found
+= found
;
4928 /* Normal behavior */
4929 ret
= WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
4930 0, cbBuf
, pcbNeeded
, &found
, 0);
4932 *pcReturned
= found
;
4937 /*****************************************************************************
4938 * EnumPrinterDriversA [WINSPOOL.@]
4940 * see function EnumPrinterDrivers for RETURNS, BUGS
4942 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
4943 LPBYTE pDriverInfo
, DWORD cbBuf
,
4944 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4947 UNICODE_STRING pNameW
, pEnvironmentW
;
4948 PWSTR pwstrNameW
, pwstrEnvironmentW
;
4952 buf
= HeapAlloc(GetProcessHeap(), 0, cbBuf
);
4954 pwstrNameW
= asciitounicode(&pNameW
, pName
);
4955 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
4957 ret
= EnumPrinterDriversW(pwstrNameW
, pwstrEnvironmentW
, Level
,
4958 buf
, cbBuf
, pcbNeeded
, pcReturned
);
4960 convert_driverinfo_W_to_A(pDriverInfo
, buf
, Level
, cbBuf
, *pcReturned
);
4962 HeapFree(GetProcessHeap(), 0, buf
);
4964 RtlFreeUnicodeString(&pNameW
);
4965 RtlFreeUnicodeString(&pEnvironmentW
);
4970 /******************************************************************************
4971 * EnumPortsA (WINSPOOL.@)
4976 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
4977 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
4980 LPBYTE bufferW
= NULL
;
4981 LPWSTR nameW
= NULL
;
4983 DWORD numentries
= 0;
4986 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
4987 cbBuf
, pcbNeeded
, pcReturned
);
4989 /* convert servername to unicode */
4991 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
4992 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4993 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
4995 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4996 needed
= cbBuf
* sizeof(WCHAR
);
4997 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
4998 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5000 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5001 if (pcbNeeded
) needed
= *pcbNeeded
;
5002 /* HeapReAlloc return NULL, when bufferW was NULL */
5003 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5004 HeapAlloc(GetProcessHeap(), 0, needed
);
5006 /* Try again with the large Buffer */
5007 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5009 needed
= pcbNeeded
? *pcbNeeded
: 0;
5010 numentries
= pcReturned
? *pcReturned
: 0;
5013 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5014 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5017 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5018 DWORD entrysize
= 0;
5021 LPPORT_INFO_2W pi2w
;
5022 LPPORT_INFO_2A pi2a
;
5025 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5027 /* First pass: calculate the size for all Entries */
5028 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5029 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5031 while (index
< numentries
) {
5033 needed
+= entrysize
; /* PORT_INFO_?A */
5034 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5036 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5037 NULL
, 0, NULL
, NULL
);
5039 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5040 NULL
, 0, NULL
, NULL
);
5041 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5042 NULL
, 0, NULL
, NULL
);
5044 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5045 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5046 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5049 /* check for errors and quit on failure */
5050 if (cbBuf
< needed
) {
5051 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5055 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5056 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5057 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5058 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5059 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5061 /* Second Pass: Fill the User Buffer (if we have one) */
5062 while ((index
< numentries
) && pPorts
) {
5064 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5065 pi2a
->pPortName
= ptr
;
5066 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5067 ptr
, cbBuf
, NULL
, NULL
);
5071 pi2a
->pMonitorName
= ptr
;
5072 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5073 ptr
, cbBuf
, NULL
, NULL
);
5077 pi2a
->pDescription
= ptr
;
5078 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5079 ptr
, cbBuf
, NULL
, NULL
);
5083 pi2a
->fPortType
= pi2w
->fPortType
;
5084 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5087 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5088 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5089 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5094 if (pcbNeeded
) *pcbNeeded
= needed
;
5095 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5097 HeapFree(GetProcessHeap(), 0, nameW
);
5098 HeapFree(GetProcessHeap(), 0, bufferW
);
5100 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5101 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5107 /******************************************************************************
5108 * EnumPortsW (WINSPOOL.@)
5110 * Enumerate available Ports
5113 * pName [I] Servername or NULL (local Computer)
5114 * Level [I] Structure-Level (1 or 2)
5115 * pPorts [O] PTR to Buffer that receives the Result
5116 * cbBuf [I] Size of Buffer at pPorts
5117 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5118 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5122 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5125 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5128 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5129 cbBuf
, pcbNeeded
, pcReturned
);
5131 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5133 /* Level is not checked in win9x */
5134 if (!Level
|| (Level
> 2)) {
5135 WARN("level (%d) is ignored in win9x\n", Level
);
5136 SetLastError(ERROR_INVALID_LEVEL
);
5139 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
5140 SetLastError(RPC_X_NULL_REF_POINTER
);
5144 return backend
->fpEnumPorts(pName
, Level
, pPorts
, cbBuf
, pcbNeeded
, pcReturned
);
5147 /******************************************************************************
5148 * GetDefaultPrinterW (WINSPOOL.@)
5151 * This function must read the value from data 'device' of key
5152 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5154 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5158 WCHAR
*buffer
, *ptr
;
5162 SetLastError(ERROR_INVALID_PARAMETER
);
5166 /* make the buffer big enough for the stuff from the profile/registry,
5167 * the content must fit into the local buffer to compute the correct
5168 * size even if the extern buffer is too small or not given.
5169 * (20 for ,driver,port) */
5171 len
= max(100, (insize
+ 20));
5172 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5174 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5176 SetLastError (ERROR_FILE_NOT_FOUND
);
5180 TRACE("%s\n", debugstr_w(buffer
));
5182 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5184 SetLastError(ERROR_INVALID_NAME
);
5190 *namesize
= strlenW(buffer
) + 1;
5191 if(!name
|| (*namesize
> insize
))
5193 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5197 strcpyW(name
, buffer
);
5200 HeapFree( GetProcessHeap(), 0, buffer
);
5205 /******************************************************************************
5206 * GetDefaultPrinterA (WINSPOOL.@)
5208 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5212 WCHAR
*bufferW
= NULL
;
5216 SetLastError(ERROR_INVALID_PARAMETER
);
5220 if(name
&& *namesize
) {
5222 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5225 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5230 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5234 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5237 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5240 HeapFree( GetProcessHeap(), 0, bufferW
);
5245 /******************************************************************************
5246 * SetDefaultPrinterW (WINSPOOL.204)
5248 * Set the Name of the Default Printer
5251 * pszPrinter [I] Name of the Printer or NULL
5258 * When the Parameter is NULL or points to an Empty String and
5259 * a Default Printer was already present, then this Function changes nothing.
5260 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5261 * the First enumerated local Printer is used.
5264 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5267 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5269 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5273 /******************************************************************************
5274 * SetDefaultPrinterA (WINSPOOL.202)
5276 * See SetDefaultPrinterW.
5279 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5282 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5284 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5289 /******************************************************************************
5290 * SetPrinterDataExA (WINSPOOL.@)
5292 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5293 LPCSTR pValueName
, DWORD Type
,
5294 LPBYTE pData
, DWORD cbData
)
5296 HKEY hkeyPrinter
, hkeySubkey
;
5299 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5300 debugstr_a(pValueName
), Type
, pData
, cbData
);
5302 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5306 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5308 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5309 RegCloseKey(hkeyPrinter
);
5312 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5313 RegCloseKey(hkeySubkey
);
5314 RegCloseKey(hkeyPrinter
);
5318 /******************************************************************************
5319 * SetPrinterDataExW (WINSPOOL.@)
5321 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5322 LPCWSTR pValueName
, DWORD Type
,
5323 LPBYTE pData
, DWORD cbData
)
5325 HKEY hkeyPrinter
, hkeySubkey
;
5328 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5329 debugstr_w(pValueName
), Type
, pData
, cbData
);
5331 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5335 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5337 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5338 RegCloseKey(hkeyPrinter
);
5341 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5342 RegCloseKey(hkeySubkey
);
5343 RegCloseKey(hkeyPrinter
);
5347 /******************************************************************************
5348 * SetPrinterDataA (WINSPOOL.@)
5350 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5351 LPBYTE pData
, DWORD cbData
)
5353 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5357 /******************************************************************************
5358 * SetPrinterDataW (WINSPOOL.@)
5360 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5361 LPBYTE pData
, DWORD cbData
)
5363 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5367 /******************************************************************************
5368 * GetPrinterDataExA (WINSPOOL.@)
5370 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5371 LPCSTR pValueName
, LPDWORD pType
,
5372 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5374 opened_printer_t
*printer
;
5375 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5378 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_a(pKeyName
),
5379 debugstr_a(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5381 printer
= get_opened_printer(hPrinter
);
5382 if(!printer
) return ERROR_INVALID_HANDLE
;
5384 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5385 if (ret
) return ret
;
5387 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5389 if (printer
->name
) {
5391 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5393 RegCloseKey(hkeyPrinters
);
5396 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5397 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName
), ret
);
5398 RegCloseKey(hkeyPrinter
);
5399 RegCloseKey(hkeyPrinters
);
5404 ret
= RegQueryValueExA(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5405 0, pType
, pData
, pcbNeeded
);
5407 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5409 RegCloseKey(hkeySubkey
);
5410 RegCloseKey(hkeyPrinter
);
5411 RegCloseKey(hkeyPrinters
);
5413 TRACE("--> %d\n", ret
);
5417 /******************************************************************************
5418 * GetPrinterDataExW (WINSPOOL.@)
5420 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5421 LPCWSTR pValueName
, LPDWORD pType
,
5422 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5424 opened_printer_t
*printer
;
5425 HKEY hkeyPrinters
, hkeyPrinter
= 0, hkeySubkey
= 0;
5428 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter
, debugstr_w(pKeyName
),
5429 debugstr_w(pValueName
), pType
, pData
, nSize
, pcbNeeded
);
5431 printer
= get_opened_printer(hPrinter
);
5432 if(!printer
) return ERROR_INVALID_HANDLE
;
5434 ret
= RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
);
5435 if (ret
) return ret
;
5437 TRACE("printer->name: %s\n", debugstr_w(printer
->name
));
5439 if (printer
->name
) {
5441 ret
= RegOpenKeyW(hkeyPrinters
, printer
->name
, &hkeyPrinter
);
5443 RegCloseKey(hkeyPrinters
);
5446 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
)) != ERROR_SUCCESS
) {
5447 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName
), ret
);
5448 RegCloseKey(hkeyPrinter
);
5449 RegCloseKey(hkeyPrinters
);
5454 ret
= RegQueryValueExW(printer
->name
? hkeySubkey
: hkeyPrinters
, pValueName
,
5455 0, pType
, pData
, pcbNeeded
);
5457 if (!ret
&& !pData
) ret
= ERROR_MORE_DATA
;
5459 RegCloseKey(hkeySubkey
);
5460 RegCloseKey(hkeyPrinter
);
5461 RegCloseKey(hkeyPrinters
);
5463 TRACE("--> %d\n", ret
);
5467 /******************************************************************************
5468 * GetPrinterDataA (WINSPOOL.@)
5470 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5471 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5473 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5474 pData
, nSize
, pcbNeeded
);
5477 /******************************************************************************
5478 * GetPrinterDataW (WINSPOOL.@)
5480 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5481 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5483 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5484 pData
, nSize
, pcbNeeded
);
5487 /*******************************************************************************
5488 * EnumPrinterDataExW [WINSPOOL.@]
5490 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5491 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5492 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5494 HKEY hkPrinter
, hkSubKey
;
5495 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5496 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5501 PPRINTER_ENUM_VALUESW ppev
;
5503 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5505 if (pKeyName
== NULL
|| *pKeyName
== 0)
5506 return ERROR_INVALID_PARAMETER
;
5508 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5509 if (ret
!= ERROR_SUCCESS
)
5511 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5516 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5517 if (ret
!= ERROR_SUCCESS
)
5519 r
= RegCloseKey (hkPrinter
);
5520 if (r
!= ERROR_SUCCESS
)
5521 WARN ("RegCloseKey returned %i\n", r
);
5522 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5523 debugstr_w (pKeyName
), ret
);
5527 ret
= RegCloseKey (hkPrinter
);
5528 if (ret
!= ERROR_SUCCESS
)
5530 ERR ("RegCloseKey returned %i\n", ret
);
5531 r
= RegCloseKey (hkSubKey
);
5532 if (r
!= ERROR_SUCCESS
)
5533 WARN ("RegCloseKey returned %i\n", r
);
5537 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5538 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5539 if (ret
!= ERROR_SUCCESS
)
5541 r
= RegCloseKey (hkSubKey
);
5542 if (r
!= ERROR_SUCCESS
)
5543 WARN ("RegCloseKey returned %i\n", r
);
5544 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5548 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5549 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5551 if (cValues
== 0) /* empty key */
5553 r
= RegCloseKey (hkSubKey
);
5554 if (r
!= ERROR_SUCCESS
)
5555 WARN ("RegCloseKey returned %i\n", r
);
5556 *pcbEnumValues
= *pnEnumValues
= 0;
5557 return ERROR_SUCCESS
;
5560 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5562 hHeap
= GetProcessHeap ();
5565 ERR ("GetProcessHeap failed\n");
5566 r
= RegCloseKey (hkSubKey
);
5567 if (r
!= ERROR_SUCCESS
)
5568 WARN ("RegCloseKey returned %i\n", r
);
5569 return ERROR_OUTOFMEMORY
;
5572 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5573 if (lpValueName
== NULL
)
5575 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5576 r
= RegCloseKey (hkSubKey
);
5577 if (r
!= ERROR_SUCCESS
)
5578 WARN ("RegCloseKey returned %i\n", r
);
5579 return ERROR_OUTOFMEMORY
;
5582 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5583 if (lpValue
== NULL
)
5585 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5586 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5587 WARN ("HeapFree failed with code %i\n", GetLastError ());
5588 r
= RegCloseKey (hkSubKey
);
5589 if (r
!= ERROR_SUCCESS
)
5590 WARN ("RegCloseKey returned %i\n", r
);
5591 return ERROR_OUTOFMEMORY
;
5594 TRACE ("pass 1: calculating buffer required for all names and values\n");
5596 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5598 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5600 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5602 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5603 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5604 NULL
, NULL
, lpValue
, &cbValueLen
);
5605 if (ret
!= ERROR_SUCCESS
)
5607 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5608 WARN ("HeapFree failed with code %i\n", GetLastError ());
5609 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5610 WARN ("HeapFree failed with code %i\n", GetLastError ());
5611 r
= RegCloseKey (hkSubKey
);
5612 if (r
!= ERROR_SUCCESS
)
5613 WARN ("RegCloseKey returned %i\n", r
);
5614 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5618 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5619 debugstr_w (lpValueName
), dwIndex
,
5620 cbValueNameLen
+ 1, cbValueLen
);
5622 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5623 cbBufSize
+= cbValueLen
;
5626 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5628 *pcbEnumValues
= cbBufSize
;
5629 *pnEnumValues
= cValues
;
5631 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5633 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5634 WARN ("HeapFree failed with code %i\n", GetLastError ());
5635 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5636 WARN ("HeapFree failed with code %i\n", GetLastError ());
5637 r
= RegCloseKey (hkSubKey
);
5638 if (r
!= ERROR_SUCCESS
)
5639 WARN ("RegCloseKey returned %i\n", r
);
5640 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5641 return ERROR_MORE_DATA
;
5644 TRACE ("pass 2: copying all names and values to buffer\n");
5646 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5647 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5649 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5651 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5652 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5653 NULL
, &dwType
, lpValue
, &cbValueLen
);
5654 if (ret
!= ERROR_SUCCESS
)
5656 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5657 WARN ("HeapFree failed with code %i\n", GetLastError ());
5658 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5659 WARN ("HeapFree failed with code %i\n", GetLastError ());
5660 r
= RegCloseKey (hkSubKey
);
5661 if (r
!= ERROR_SUCCESS
)
5662 WARN ("RegCloseKey returned %i\n", r
);
5663 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5667 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5668 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5669 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5670 pEnumValues
+= cbValueNameLen
;
5672 /* return # of *bytes* (including trailing \0), not # of chars */
5673 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5675 ppev
[dwIndex
].dwType
= dwType
;
5677 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5678 ppev
[dwIndex
].pData
= pEnumValues
;
5679 pEnumValues
+= cbValueLen
;
5681 ppev
[dwIndex
].cbData
= cbValueLen
;
5683 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5684 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5687 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5689 ret
= GetLastError ();
5690 ERR ("HeapFree failed with code %i\n", ret
);
5691 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5692 WARN ("HeapFree failed with code %i\n", GetLastError ());
5693 r
= RegCloseKey (hkSubKey
);
5694 if (r
!= ERROR_SUCCESS
)
5695 WARN ("RegCloseKey returned %i\n", r
);
5699 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5701 ret
= GetLastError ();
5702 ERR ("HeapFree failed with code %i\n", ret
);
5703 r
= RegCloseKey (hkSubKey
);
5704 if (r
!= ERROR_SUCCESS
)
5705 WARN ("RegCloseKey returned %i\n", r
);
5709 ret
= RegCloseKey (hkSubKey
);
5710 if (ret
!= ERROR_SUCCESS
)
5712 ERR ("RegCloseKey returned %i\n", ret
);
5716 return ERROR_SUCCESS
;
5719 /*******************************************************************************
5720 * EnumPrinterDataExA [WINSPOOL.@]
5722 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5723 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5724 * what Windows 2000 SP1 does.
5727 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5728 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5729 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5733 DWORD ret
, dwIndex
, dwBufSize
;
5737 TRACE ("%p %s\n", hPrinter
, pKeyName
);
5739 if (pKeyName
== NULL
|| *pKeyName
== 0)
5740 return ERROR_INVALID_PARAMETER
;
5742 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
5745 ret
= GetLastError ();
5746 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5750 hHeap
= GetProcessHeap ();
5753 ERR ("GetProcessHeap failed\n");
5754 return ERROR_OUTOFMEMORY
;
5757 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
5758 if (pKeyNameW
== NULL
)
5760 ERR ("Failed to allocate %i bytes from process heap\n",
5761 (LONG
)(len
* sizeof (WCHAR
)));
5762 return ERROR_OUTOFMEMORY
;
5765 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
5767 ret
= GetLastError ();
5768 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
5769 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5770 WARN ("HeapFree failed with code %i\n", GetLastError ());
5774 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
5775 pcbEnumValues
, pnEnumValues
);
5776 if (ret
!= ERROR_SUCCESS
)
5778 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5779 WARN ("HeapFree failed with code %i\n", GetLastError ());
5780 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
5784 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
5786 ret
= GetLastError ();
5787 ERR ("HeapFree failed with code %i\n", ret
);
5791 if (*pnEnumValues
== 0) /* empty key */
5792 return ERROR_SUCCESS
;
5795 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5797 PPRINTER_ENUM_VALUESW ppev
=
5798 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5800 if (dwBufSize
< ppev
->cbValueName
)
5801 dwBufSize
= ppev
->cbValueName
;
5803 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
5804 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
5805 dwBufSize
= ppev
->cbData
;
5808 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
5810 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
5811 if (pBuffer
== NULL
)
5813 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
5814 return ERROR_OUTOFMEMORY
;
5817 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
5819 PPRINTER_ENUM_VALUESW ppev
=
5820 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
5822 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
5823 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
5827 ret
= GetLastError ();
5828 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5829 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5830 WARN ("HeapFree failed with code %i\n", GetLastError ());
5834 memcpy (ppev
->pValueName
, pBuffer
, len
);
5836 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5838 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
5839 ppev
->dwType
!= REG_MULTI_SZ
)
5842 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
5843 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
5846 ret
= GetLastError ();
5847 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
5848 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5849 WARN ("HeapFree failed with code %i\n", GetLastError ());
5853 memcpy (ppev
->pData
, pBuffer
, len
);
5855 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
5856 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5859 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
5861 ret
= GetLastError ();
5862 ERR ("HeapFree failed with code %i\n", ret
);
5866 return ERROR_SUCCESS
;
5869 /******************************************************************************
5870 * AbortPrinter (WINSPOOL.@)
5872 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
5874 FIXME("(%p), stub!\n", hPrinter
);
5878 /******************************************************************************
5879 * AddPortA (WINSPOOL.@)
5884 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
5886 LPWSTR nameW
= NULL
;
5887 LPWSTR monitorW
= NULL
;
5891 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
5894 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5895 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5896 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5900 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5901 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5902 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5904 res
= AddPortW(nameW
, hWnd
, monitorW
);
5905 HeapFree(GetProcessHeap(), 0, nameW
);
5906 HeapFree(GetProcessHeap(), 0, monitorW
);
5910 /******************************************************************************
5911 * AddPortW (WINSPOOL.@)
5913 * Add a Port for a specific Monitor
5916 * pName [I] Servername or NULL (local Computer)
5917 * hWnd [I] Handle to parent Window for the Dialog-Box
5918 * pMonitorName [I] Name of the Monitor that manage the Port
5925 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
5927 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
5929 if ((backend
== NULL
) && !load_backend()) return FALSE
;
5931 if (!pMonitorName
) {
5932 SetLastError(RPC_X_NULL_REF_POINTER
);
5936 return backend
->fpAddPort(pName
, hWnd
, pMonitorName
);
5939 /******************************************************************************
5940 * AddPortExA (WINSPOOL.@)
5945 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
5948 PORT_INFO_2A
* pi2A
;
5949 LPWSTR nameW
= NULL
;
5950 LPWSTR monitorW
= NULL
;
5954 pi2A
= (PORT_INFO_2A
*) pBuffer
;
5956 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
5957 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
5959 if ((level
< 1) || (level
> 2)) {
5960 SetLastError(ERROR_INVALID_LEVEL
);
5965 SetLastError(ERROR_INVALID_PARAMETER
);
5970 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5971 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5972 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5976 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
5977 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5978 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
5981 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
5983 if (pi2A
->pPortName
) {
5984 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
5985 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5986 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
5990 if (pi2A
->pMonitorName
) {
5991 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
5992 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5993 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
5996 if (pi2A
->pDescription
) {
5997 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
5998 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5999 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6001 pi2W
.fPortType
= pi2A
->fPortType
;
6002 pi2W
.Reserved
= pi2A
->Reserved
;
6005 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6007 HeapFree(GetProcessHeap(), 0, nameW
);
6008 HeapFree(GetProcessHeap(), 0, monitorW
);
6009 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6010 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6011 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6016 /******************************************************************************
6017 * AddPortExW (WINSPOOL.@)
6019 * Add a Port for a specific Monitor, without presenting a user interface
6022 * pName [I] Servername or NULL (local Computer)
6023 * level [I] Structure-Level (1 or 2) for pBuffer
6024 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6025 * pMonitorName [I] Name of the Monitor that manage the Port
6032 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6036 pi2
= (PORT_INFO_2W
*) pBuffer
;
6038 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6039 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6040 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6041 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6043 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6045 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6046 SetLastError(ERROR_INVALID_PARAMETER
);
6050 return backend
->fpAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6053 /******************************************************************************
6054 * AddPrinterConnectionA (WINSPOOL.@)
6056 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6058 FIXME("%s\n", debugstr_a(pName
));
6062 /******************************************************************************
6063 * AddPrinterConnectionW (WINSPOOL.@)
6065 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6067 FIXME("%s\n", debugstr_w(pName
));
6071 /******************************************************************************
6072 * AddPrinterDriverExW (WINSPOOL.@)
6074 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6077 * pName [I] Servername or NULL (local Computer)
6078 * level [I] Level for the supplied DRIVER_INFO_*W struct
6079 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6080 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6087 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6089 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6091 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6093 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6094 SetLastError(ERROR_INVALID_LEVEL
);
6099 SetLastError(ERROR_INVALID_PARAMETER
);
6103 return backend
->fpAddPrinterDriverEx(pName
, level
, pDriverInfo
, dwFileCopyFlags
);
6106 /******************************************************************************
6107 * AddPrinterDriverExA (WINSPOOL.@)
6109 * See AddPrinterDriverExW.
6112 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6114 DRIVER_INFO_8A
*diA
;
6116 LPWSTR nameW
= NULL
;
6121 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6123 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6124 ZeroMemory(&diW
, sizeof(diW
));
6126 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6127 SetLastError(ERROR_INVALID_LEVEL
);
6132 SetLastError(ERROR_INVALID_PARAMETER
);
6136 /* convert servername to unicode */
6138 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6139 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6140 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6144 diW
.cVersion
= diA
->cVersion
;
6147 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6148 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6149 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6152 if (diA
->pEnvironment
) {
6153 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6154 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6155 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6158 if (diA
->pDriverPath
) {
6159 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6160 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6161 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6164 if (diA
->pDataFile
) {
6165 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6166 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6167 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6170 if (diA
->pConfigFile
) {
6171 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6172 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6173 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6176 if ((Level
> 2) && diA
->pDependentFiles
) {
6177 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6178 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6179 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6180 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6183 if ((Level
> 2) && diA
->pMonitorName
) {
6184 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6185 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6186 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6189 if ((Level
> 3) && diA
->pDefaultDataType
) {
6190 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6191 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6192 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6195 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6196 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6197 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6198 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6199 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6202 if ((Level
> 5) && diA
->pszMfgName
) {
6203 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6204 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6205 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6208 if ((Level
> 5) && diA
->pszOEMUrl
) {
6209 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6210 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6211 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6214 if ((Level
> 5) && diA
->pszHardwareID
) {
6215 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6216 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6217 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6220 if ((Level
> 5) && diA
->pszProvider
) {
6221 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6222 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6223 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6227 FIXME("level %u is incomplete\n", Level
);
6230 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6231 TRACE("got %u with %u\n", res
, GetLastError());
6232 HeapFree(GetProcessHeap(), 0, nameW
);
6233 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6234 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6235 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6236 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6237 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6238 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6239 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6240 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6241 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6242 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6243 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6244 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6245 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6247 TRACE("=> %u with %u\n", res
, GetLastError());
6251 /******************************************************************************
6252 * ConfigurePortA (WINSPOOL.@)
6254 * See ConfigurePortW.
6257 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6259 LPWSTR nameW
= NULL
;
6260 LPWSTR portW
= NULL
;
6264 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6266 /* convert servername to unicode */
6268 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6269 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6270 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6273 /* convert portname to unicode */
6275 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6276 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6277 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6280 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6281 HeapFree(GetProcessHeap(), 0, nameW
);
6282 HeapFree(GetProcessHeap(), 0, portW
);
6286 /******************************************************************************
6287 * ConfigurePortW (WINSPOOL.@)
6289 * Display the Configuration-Dialog for a specific Port
6292 * pName [I] Servername or NULL (local Computer)
6293 * hWnd [I] Handle to parent Window for the Dialog-Box
6294 * pPortName [I] Name of the Port, that should be configured
6301 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6304 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6306 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6309 SetLastError(RPC_X_NULL_REF_POINTER
);
6313 return backend
->fpConfigurePort(pName
, hWnd
, pPortName
);
6316 /******************************************************************************
6317 * ConnectToPrinterDlg (WINSPOOL.@)
6319 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6321 FIXME("%p %x\n", hWnd
, Flags
);
6325 /******************************************************************************
6326 * DeletePrinterConnectionA (WINSPOOL.@)
6328 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6330 FIXME("%s\n", debugstr_a(pName
));
6334 /******************************************************************************
6335 * DeletePrinterConnectionW (WINSPOOL.@)
6337 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6339 FIXME("%s\n", debugstr_w(pName
));
6343 /******************************************************************************
6344 * DeletePrinterDriverExW (WINSPOOL.@)
6346 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6347 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6352 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6353 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6355 if(pName
&& pName
[0])
6357 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6358 SetLastError(ERROR_INVALID_PARAMETER
);
6364 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6365 SetLastError(ERROR_INVALID_PARAMETER
);
6369 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
);
6373 ERR("Can't open drivers key\n");
6377 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6380 RegCloseKey(hkey_drivers
);
6385 /******************************************************************************
6386 * DeletePrinterDriverExA (WINSPOOL.@)
6388 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6389 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6391 UNICODE_STRING NameW
, EnvW
, DriverW
;
6394 asciitounicode(&NameW
, pName
);
6395 asciitounicode(&EnvW
, pEnvironment
);
6396 asciitounicode(&DriverW
, pDriverName
);
6398 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6400 RtlFreeUnicodeString(&DriverW
);
6401 RtlFreeUnicodeString(&EnvW
);
6402 RtlFreeUnicodeString(&NameW
);
6407 /******************************************************************************
6408 * DeletePrinterDataExW (WINSPOOL.@)
6410 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6413 FIXME("%p %s %s\n", hPrinter
,
6414 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6415 return ERROR_INVALID_PARAMETER
;
6418 /******************************************************************************
6419 * DeletePrinterDataExA (WINSPOOL.@)
6421 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6424 FIXME("%p %s %s\n", hPrinter
,
6425 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6426 return ERROR_INVALID_PARAMETER
;
6429 /******************************************************************************
6430 * DeletePrintProcessorA (WINSPOOL.@)
6432 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6434 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6435 debugstr_a(pPrintProcessorName
));
6439 /******************************************************************************
6440 * DeletePrintProcessorW (WINSPOOL.@)
6442 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6444 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6445 debugstr_w(pPrintProcessorName
));
6449 /******************************************************************************
6450 * DeletePrintProvidorA (WINSPOOL.@)
6452 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6454 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6455 debugstr_a(pPrintProviderName
));
6459 /******************************************************************************
6460 * DeletePrintProvidorW (WINSPOOL.@)
6462 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6464 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6465 debugstr_w(pPrintProviderName
));
6469 /******************************************************************************
6470 * EnumFormsA (WINSPOOL.@)
6472 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6473 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6475 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6476 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6480 /******************************************************************************
6481 * EnumFormsW (WINSPOOL.@)
6483 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6484 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6486 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6487 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
6491 /*****************************************************************************
6492 * EnumMonitorsA [WINSPOOL.@]
6494 * See EnumMonitorsW.
6497 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6498 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6501 LPBYTE bufferW
= NULL
;
6502 LPWSTR nameW
= NULL
;
6504 DWORD numentries
= 0;
6507 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
6508 cbBuf
, pcbNeeded
, pcReturned
);
6510 /* convert servername to unicode */
6512 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6513 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6514 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6516 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6517 needed
= cbBuf
* sizeof(WCHAR
);
6518 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6519 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6521 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6522 if (pcbNeeded
) needed
= *pcbNeeded
;
6523 /* HeapReAlloc return NULL, when bufferW was NULL */
6524 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6525 HeapAlloc(GetProcessHeap(), 0, needed
);
6527 /* Try again with the large Buffer */
6528 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6530 numentries
= pcReturned
? *pcReturned
: 0;
6533 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6534 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6537 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6538 DWORD entrysize
= 0;
6541 LPMONITOR_INFO_2W mi2w
;
6542 LPMONITOR_INFO_2A mi2a
;
6544 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6545 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
6547 /* First pass: calculate the size for all Entries */
6548 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6549 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6551 while (index
< numentries
) {
6553 needed
+= entrysize
; /* MONITOR_INFO_?A */
6554 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
6556 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6557 NULL
, 0, NULL
, NULL
);
6559 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6560 NULL
, 0, NULL
, NULL
);
6561 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6562 NULL
, 0, NULL
, NULL
);
6564 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6565 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6566 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6569 /* check for errors and quit on failure */
6570 if (cbBuf
< needed
) {
6571 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6575 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
6576 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
6577 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6578 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
6579 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
6581 /* Second Pass: Fill the User Buffer (if we have one) */
6582 while ((index
< numentries
) && pMonitors
) {
6584 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
6586 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
6587 ptr
, cbBuf
, NULL
, NULL
);
6591 mi2a
->pEnvironment
= ptr
;
6592 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
6593 ptr
, cbBuf
, NULL
, NULL
);
6597 mi2a
->pDLLName
= ptr
;
6598 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
6599 ptr
, cbBuf
, NULL
, NULL
);
6603 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6604 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
6605 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
6609 if (pcbNeeded
) *pcbNeeded
= needed
;
6610 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6612 HeapFree(GetProcessHeap(), 0, nameW
);
6613 HeapFree(GetProcessHeap(), 0, bufferW
);
6615 TRACE("returning %d with %d (%d byte for %d entries)\n",
6616 (res
), GetLastError(), needed
, numentries
);
6622 /*****************************************************************************
6623 * EnumMonitorsW [WINSPOOL.@]
6625 * Enumerate available Port-Monitors
6628 * pName [I] Servername or NULL (local Computer)
6629 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6630 * pMonitors [O] PTR to Buffer that receives the Result
6631 * cbBuf [I] Size of Buffer at pMonitors
6632 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6633 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6637 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6640 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
6641 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6644 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
6645 cbBuf
, pcbNeeded
, pcReturned
);
6647 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6649 if (!pcbNeeded
|| !pcReturned
|| (!pMonitors
&& (cbBuf
> 0))) {
6650 SetLastError(RPC_X_NULL_REF_POINTER
);
6654 return backend
->fpEnumMonitors(pName
, Level
, pMonitors
, cbBuf
, pcbNeeded
, pcReturned
);
6657 /******************************************************************************
6658 * SpoolerInit (WINSPOOL.@)
6660 * Initialize the Spooler
6667 * The function fails on windows, when the spooler service is not running
6670 BOOL WINAPI
SpoolerInit(void)
6673 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6677 /******************************************************************************
6678 * XcvDataW (WINSPOOL.@)
6680 * Execute commands in the Printmonitor DLL
6683 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6684 * pszDataName [i] Name of the command to execute
6685 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6686 * cbInputData [i] Size in Bytes of Buffer at pInputData
6687 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6688 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6689 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6690 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6697 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6698 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6700 * Minimal List of commands, that a Printmonitor DLL should support:
6702 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6703 *| "AddPort" : Add a Port
6704 *| "DeletePort": Delete a Port
6706 * Many Printmonitors support additional commands. Examples for localspl.dll:
6707 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6708 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6711 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
6712 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
6713 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
6715 opened_printer_t
*printer
;
6717 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
6718 pInputData
, cbInputData
, pOutputData
,
6719 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6721 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6723 printer
= get_opened_printer(hXcv
);
6724 if (!printer
|| (!printer
->backend_printer
)) {
6725 SetLastError(ERROR_INVALID_HANDLE
);
6729 if (!pcbOutputNeeded
) {
6730 SetLastError(ERROR_INVALID_PARAMETER
);
6734 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
6735 SetLastError(RPC_X_NULL_REF_POINTER
);
6739 *pcbOutputNeeded
= 0;
6741 return backend
->fpXcvData(printer
->backend_printer
, pszDataName
, pInputData
,
6742 cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
, pdwStatus
);
6746 /*****************************************************************************
6747 * EnumPrinterDataA [WINSPOOL.@]
6750 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
6751 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6752 DWORD cbData
, LPDWORD pcbData
)
6754 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6755 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6756 return ERROR_NO_MORE_ITEMS
;
6759 /*****************************************************************************
6760 * EnumPrinterDataW [WINSPOOL.@]
6763 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
6764 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
6765 DWORD cbData
, LPDWORD pcbData
)
6767 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
6768 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
6769 return ERROR_NO_MORE_ITEMS
;
6772 /*****************************************************************************
6773 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6776 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
6777 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6778 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6780 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
6781 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6782 pcbNeeded
, pcReturned
);
6786 /*****************************************************************************
6787 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6790 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
6791 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
6792 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6794 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
6795 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
6796 pcbNeeded
, pcReturned
);
6800 /*****************************************************************************
6801 * EnumPrintProcessorsA [WINSPOOL.@]
6803 * See EnumPrintProcessorsW.
6806 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
6807 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6810 LPBYTE bufferW
= NULL
;
6811 LPWSTR nameW
= NULL
;
6814 DWORD numentries
= 0;
6817 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6818 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6820 /* convert names to unicode */
6822 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6823 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6824 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6827 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
6828 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6829 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, envW
, len
);
6832 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6833 needed
= cbBuf
* sizeof(WCHAR
);
6834 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
6835 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6837 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
6838 if (pcbNeeded
) needed
= *pcbNeeded
;
6839 /* HeapReAlloc return NULL, when bufferW was NULL */
6840 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
6841 HeapAlloc(GetProcessHeap(), 0, needed
);
6843 /* Try again with the large Buffer */
6844 res
= EnumPrintProcessorsW(nameW
, envW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
6846 numentries
= pcReturned
? *pcReturned
: 0;
6850 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6853 PPRINTPROCESSOR_INFO_1W ppiw
;
6854 PPRINTPROCESSOR_INFO_1A ppia
;
6856 /* First pass: calculate the size for all Entries */
6857 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
6858 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
6860 while (index
< numentries
) {
6862 needed
+= sizeof(PRINTPROCESSOR_INFO_1A
);
6863 TRACE("%p: parsing #%d (%s)\n", ppiw
, index
, debugstr_w(ppiw
->pName
));
6865 needed
+= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
6866 NULL
, 0, NULL
, NULL
);
6868 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
6869 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
6872 /* check for errors and quit on failure */
6873 if (cbBuf
< needed
) {
6874 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
6879 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1A
); /* room for structs */
6880 ptr
= (LPSTR
) &pPPInfo
[len
]; /* start of strings */
6881 cbBuf
-= len
; /* free Bytes in the user-Buffer */
6882 ppiw
= (PPRINTPROCESSOR_INFO_1W
) bufferW
;
6883 ppia
= (PPRINTPROCESSOR_INFO_1A
) pPPInfo
;
6885 /* Second Pass: Fill the User Buffer (if we have one) */
6886 while ((index
< numentries
) && pPPInfo
) {
6888 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia
, index
);
6890 len
= WideCharToMultiByte(CP_ACP
, 0, ppiw
->pName
, -1,
6891 ptr
, cbBuf
, NULL
, NULL
);
6895 ppiw
= (PPRINTPROCESSOR_INFO_1W
) (((LPBYTE
)ppiw
) + sizeof(PRINTPROCESSOR_INFO_1W
));
6896 ppia
= (PPRINTPROCESSOR_INFO_1A
) (((LPBYTE
)ppia
) + sizeof(PRINTPROCESSOR_INFO_1A
));
6901 if (pcbNeeded
) *pcbNeeded
= needed
;
6902 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
6904 HeapFree(GetProcessHeap(), 0, nameW
);
6905 HeapFree(GetProcessHeap(), 0, envW
);
6906 HeapFree(GetProcessHeap(), 0, bufferW
);
6908 TRACE("returning %d with %d (%d byte for %d entries)\n",
6909 (res
), GetLastError(), needed
, numentries
);
6914 /*****************************************************************************
6915 * EnumPrintProcessorsW [WINSPOOL.@]
6917 * Enumerate available Print Processors
6920 * pName [I] Servername or NULL (local Computer)
6921 * pEnvironment [I] Printing-Environment or NULL (Default)
6922 * Level [I] Structure-Level (Only 1 is allowed)
6923 * pPPInfo [O] PTR to Buffer that receives the Result
6924 * cbBuf [I] Size of Buffer at pPPInfo
6925 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6926 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6930 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6933 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
6934 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6937 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6938 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
6940 if ((backend
== NULL
) && !load_backend()) return FALSE
;
6942 if (!pcbNeeded
|| !pcReturned
) {
6943 SetLastError(RPC_X_NULL_REF_POINTER
);
6947 if (!pPPInfo
&& (cbBuf
> 0)) {
6948 SetLastError(ERROR_INVALID_USER_BUFFER
);
6952 return backend
->fpEnumPrintProcessors(pName
, pEnvironment
, Level
, pPPInfo
,
6953 cbBuf
, pcbNeeded
, pcReturned
);
6956 /*****************************************************************************
6957 * ExtDeviceMode [WINSPOOL.@]
6960 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
6961 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
6964 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
6965 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
6966 debugstr_a(pProfile
), fMode
);
6970 /*****************************************************************************
6971 * FindClosePrinterChangeNotification [WINSPOOL.@]
6974 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
6976 FIXME("Stub: %p\n", hChange
);
6980 /*****************************************************************************
6981 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6984 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
6985 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
6987 FIXME("Stub: %p %x %x %p\n",
6988 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
6989 return INVALID_HANDLE_VALUE
;
6992 /*****************************************************************************
6993 * FindNextPrinterChangeNotification [WINSPOOL.@]
6996 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
6997 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
6999 FIXME("Stub: %p %p %p %p\n",
7000 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7004 /*****************************************************************************
7005 * FreePrinterNotifyInfo [WINSPOOL.@]
7008 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7010 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7014 /*****************************************************************************
7017 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7018 * ansi depending on the unicode parameter.
7020 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7030 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7033 memcpy(ptr
, str
, *size
);
7040 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7043 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7050 /*****************************************************************************
7053 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7054 LPDWORD pcbNeeded
, BOOL unicode
)
7056 DWORD size
, left
= cbBuf
;
7057 BOOL space
= (cbBuf
> 0);
7064 ji1
->JobId
= job
->job_id
;
7067 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7068 if(space
&& size
<= left
)
7070 ji1
->pDocument
= (LPWSTR
)ptr
;
7078 if (job
->printer_name
)
7080 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7081 if(space
&& size
<= left
)
7083 ji1
->pPrinterName
= (LPWSTR
)ptr
;
7095 /*****************************************************************************
7098 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7099 LPDWORD pcbNeeded
, BOOL unicode
)
7101 DWORD size
, left
= cbBuf
;
7102 BOOL space
= (cbBuf
> 0);
7109 ji2
->JobId
= job
->job_id
;
7112 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7113 if(space
&& size
<= left
)
7115 ji2
->pDocument
= (LPWSTR
)ptr
;
7123 if (job
->printer_name
)
7125 string_to_buf(job
->printer_name
, ptr
, left
, &size
, unicode
);
7126 if(space
&& size
<= left
)
7128 ji2
->pPrinterName
= (LPWSTR
)ptr
;
7140 /*****************************************************************************
7143 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7144 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7147 DWORD needed
= 0, size
;
7151 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7153 EnterCriticalSection(&printer_handles_cs
);
7154 job
= get_job(hPrinter
, JobId
);
7161 size
= sizeof(JOB_INFO_1W
);
7166 memset(pJob
, 0, size
);
7170 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7175 size
= sizeof(JOB_INFO_2W
);
7180 memset(pJob
, 0, size
);
7184 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7189 size
= sizeof(JOB_INFO_3
);
7193 memset(pJob
, 0, size
);
7202 SetLastError(ERROR_INVALID_LEVEL
);
7206 *pcbNeeded
= needed
;
7208 LeaveCriticalSection(&printer_handles_cs
);
7212 /*****************************************************************************
7213 * GetJobA [WINSPOOL.@]
7216 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7217 DWORD cbBuf
, LPDWORD pcbNeeded
)
7219 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7222 /*****************************************************************************
7223 * GetJobW [WINSPOOL.@]
7226 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7227 DWORD cbBuf
, LPDWORD pcbNeeded
)
7229 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7232 /*****************************************************************************
7235 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7237 char *unixname
, *queue
, *cmd
;
7238 char fmt
[] = "lpr -P'%s' '%s'";
7242 if(!(unixname
= wine_get_unix_file_name(filename
)))
7245 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7246 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7247 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7249 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7250 sprintf(cmd
, fmt
, queue
, unixname
);
7252 TRACE("printing with: %s\n", cmd
);
7255 HeapFree(GetProcessHeap(), 0, cmd
);
7256 HeapFree(GetProcessHeap(), 0, queue
);
7257 HeapFree(GetProcessHeap(), 0, unixname
);
7261 /*****************************************************************************
7264 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7266 #ifdef SONAME_LIBCUPS
7269 char *unixname
, *queue
, *unix_doc_title
;
7273 if(!(unixname
= wine_get_unix_file_name(filename
)))
7276 len
= WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7277 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7278 WideCharToMultiByte(CP_UNIXCP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7280 len
= WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7281 unix_doc_title
= HeapAlloc(GetProcessHeap(), 0, len
);
7282 WideCharToMultiByte(CP_UNIXCP
, 0, document_title
, -1, unix_doc_title
, len
, NULL
, NULL
);
7284 TRACE("printing via cups\n");
7285 ret
= pcupsPrintFile(queue
, unixname
, unix_doc_title
, 0, NULL
);
7286 HeapFree(GetProcessHeap(), 0, unix_doc_title
);
7287 HeapFree(GetProcessHeap(), 0, queue
);
7288 HeapFree(GetProcessHeap(), 0, unixname
);
7294 return schedule_lpr(printer_name
, filename
);
7298 static INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7305 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7309 if(HIWORD(wparam
) == BN_CLICKED
)
7311 if(LOWORD(wparam
) == IDOK
)
7314 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7317 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7318 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7320 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7322 WCHAR caption
[200], message
[200];
7325 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7326 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7327 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7328 if(mb_ret
== IDCANCEL
)
7330 HeapFree(GetProcessHeap(), 0, filename
);
7334 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7335 if(hf
== INVALID_HANDLE_VALUE
)
7337 WCHAR caption
[200], message
[200];
7339 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7340 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7341 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7342 HeapFree(GetProcessHeap(), 0, filename
);
7346 DeleteFileW(filename
);
7347 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7349 EndDialog(hwnd
, IDOK
);
7352 if(LOWORD(wparam
) == IDCANCEL
)
7354 EndDialog(hwnd
, IDCANCEL
);
7363 /*****************************************************************************
7366 static BOOL
get_filename(LPWSTR
*filename
)
7368 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7369 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7372 /*****************************************************************************
7375 static BOOL
schedule_file(LPCWSTR filename
)
7377 LPWSTR output
= NULL
;
7379 if(get_filename(&output
))
7382 TRACE("copy to %s\n", debugstr_w(output
));
7383 r
= CopyFileW(filename
, output
, FALSE
);
7384 HeapFree(GetProcessHeap(), 0, output
);
7390 /*****************************************************************************
7393 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7396 char *unixname
, *cmdA
;
7398 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7402 if(!(unixname
= wine_get_unix_file_name(filename
)))
7405 len
= WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7406 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7407 WideCharToMultiByte(CP_UNIXCP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7409 TRACE("printing with: %s\n", cmdA
);
7411 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7416 ERR("pipe() failed!\n");
7426 /* reset signals that we previously set to SIG_IGN */
7427 signal(SIGPIPE
, SIG_DFL
);
7428 signal(SIGCHLD
, SIG_DFL
);
7430 execl("/bin/sh", "/bin/sh", "-c", cmdA
, NULL
);
7434 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7435 write(fds
[1], buf
, no_read
);
7440 if(file_fd
!= -1) close(file_fd
);
7441 if(fds
[0] != -1) close(fds
[0]);
7442 if(fds
[1] != -1) close(fds
[1]);
7444 HeapFree(GetProcessHeap(), 0, cmdA
);
7445 HeapFree(GetProcessHeap(), 0, unixname
);
7452 /*****************************************************************************
7455 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7457 int in_fd
, out_fd
, no_read
;
7460 char *unixname
, *outputA
;
7463 if(!(unixname
= wine_get_unix_file_name(filename
)))
7466 len
= WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7467 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7468 WideCharToMultiByte(CP_UNIXCP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7470 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7471 in_fd
= open(unixname
, O_RDONLY
);
7472 if(out_fd
== -1 || in_fd
== -1)
7475 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7476 write(out_fd
, buf
, no_read
);
7480 if(in_fd
!= -1) close(in_fd
);
7481 if(out_fd
!= -1) close(out_fd
);
7482 HeapFree(GetProcessHeap(), 0, outputA
);
7483 HeapFree(GetProcessHeap(), 0, unixname
);
7487 /*****************************************************************************
7488 * ScheduleJob [WINSPOOL.@]
7491 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7493 opened_printer_t
*printer
;
7495 struct list
*cursor
, *cursor2
;
7497 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7498 EnterCriticalSection(&printer_handles_cs
);
7499 printer
= get_opened_printer(hPrinter
);
7503 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7505 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7508 if(job
->job_id
!= dwJobID
) continue;
7510 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7511 if(hf
!= INVALID_HANDLE_VALUE
)
7513 PRINTER_INFO_5W
*pi5
= NULL
;
7514 LPWSTR portname
= job
->portname
;
7518 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7519 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7523 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7524 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7525 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7526 portname
= pi5
->pPortName
;
7528 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7529 debugstr_w(portname
));
7533 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7534 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7536 DWORD type
, count
= sizeof(output
);
7537 RegQueryValueExW(hkey
, portname
, NULL
, &type
, (LPBYTE
)output
, &count
);
7540 if(output
[0] == '|')
7542 ret
= schedule_pipe(output
+ 1, job
->filename
);
7546 ret
= schedule_unixfile(output
, job
->filename
);
7548 else if(!strncmpW(portname
, LPR_Port
, strlenW(LPR_Port
)))
7550 ret
= schedule_lpr(portname
+ strlenW(LPR_Port
), job
->filename
);
7552 else if(!strncmpW(portname
, CUPS_Port
, strlenW(CUPS_Port
)))
7554 ret
= schedule_cups(portname
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7556 else if(!strncmpW(portname
, FILE_Port
, strlenW(FILE_Port
)))
7558 ret
= schedule_file(job
->filename
);
7562 FIXME("can't schedule to port %s\n", debugstr_w(portname
));
7564 HeapFree(GetProcessHeap(), 0, pi5
);
7566 DeleteFileW(job
->filename
);
7568 list_remove(cursor
);
7569 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7570 HeapFree(GetProcessHeap(), 0, job
->printer_name
);
7571 HeapFree(GetProcessHeap(), 0, job
->portname
);
7572 HeapFree(GetProcessHeap(), 0, job
->filename
);
7573 HeapFree(GetProcessHeap(), 0, job
);
7577 LeaveCriticalSection(&printer_handles_cs
);
7581 /*****************************************************************************
7582 * StartDocDlgA [WINSPOOL.@]
7584 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7586 UNICODE_STRING usBuffer
;
7589 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7592 docW
.cbSize
= sizeof(docW
);
7593 if (doc
->lpszDocName
)
7595 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7596 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7598 if (doc
->lpszOutput
)
7600 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7601 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7603 if (doc
->lpszDatatype
)
7605 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7606 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7608 docW
.fwType
= doc
->fwType
;
7610 retW
= StartDocDlgW(hPrinter
, &docW
);
7614 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7615 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7616 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7617 HeapFree(GetProcessHeap(), 0, retW
);
7620 HeapFree(GetProcessHeap(), 0, datatypeW
);
7621 HeapFree(GetProcessHeap(), 0, outputW
);
7622 HeapFree(GetProcessHeap(), 0, docnameW
);
7627 /*****************************************************************************
7628 * StartDocDlgW [WINSPOOL.@]
7630 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7631 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7632 * port is "FILE:". Also returns the full path if passed a relative path.
7634 * The caller should free the returned string from the process heap.
7636 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
7641 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
7643 PRINTER_INFO_5W
*pi5
;
7644 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
7645 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
7647 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
7648 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
7649 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
7651 HeapFree(GetProcessHeap(), 0, pi5
);
7654 HeapFree(GetProcessHeap(), 0, pi5
);
7657 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
7661 if (get_filename(&name
))
7663 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
7665 HeapFree(GetProcessHeap(), 0, name
);
7668 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7669 GetFullPathNameW(name
, len
, ret
, NULL
);
7670 HeapFree(GetProcessHeap(), 0, name
);
7675 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
7678 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7679 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
7681 attr
= GetFileAttributesW(ret
);
7682 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
7684 HeapFree(GetProcessHeap(), 0, ret
);