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
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
40 #ifdef HAVE_CUPS_CUPS_H
41 # include <cups/cups.h>
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
46 #include "wine/library.h"
55 #include "wine/windef16.h"
56 #include "wine/unicode.h"
57 #include "wine/debug.h"
58 #include "wine/list.h"
61 #include "ddk/winsplp.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
66 /* ############################### */
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
77 /* ############################### */
92 HANDLE backend_printer;
102 WCHAR *document_title;
112 LPCWSTR versionregpath;
113 LPCWSTR versionsubdir;
116 /* ############################### */
118 static opened_printer_t **printer_handles;
119 static UINT nb_printer_handles;
120 static LONG next_job_id = 1;
122 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
123 WORD fwCapability, LPSTR lpszOutput,
125 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
126 LPSTR lpszDevice, LPSTR lpszPort,
127 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
130 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'c','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
135 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
137 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
138 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
139 'C','o','n','t','r','o','l','\\',
140 'P','r','i','n','t','\\',
141 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
145 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
146 'M','i','c','r','o','s','o','f','t','\\',
147 'W','i','n','d','o','w','s',' ','N','T','\\',
148 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
149 'W','i','n','d','o','w','s',0};
151 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
152 'M','i','c','r','o','s','o','f','t','\\',
153 'W','i','n','d','o','w','s',' ','N','T','\\',
154 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'D','e','v','i','c','e','s',0};
157 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
158 'M','i','c','r','o','s','o','f','t','\\',
159 'W','i','n','d','o','w','s',' ','N','T','\\',
160 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
161 'P','o','r','t','s',0};
163 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
164 'M','i','c','r','o','s','o','f','t','\\',
165 'W','i','n','d','o','w','s',' ','N','T','\\',
166 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
167 'P','r','i','n','t','e','r','P','o','r','t','s',0};
169 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
170 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
171 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
172 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
173 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
174 static const WCHAR subdir_x64W[] = {'x','6','4',0};
175 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
176 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
177 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
178 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
179 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
181 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
182 static const WCHAR backslashW[] = {'\\',0};
183 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
184 'i','o','n',' ','F','i','l','e',0};
185 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
186 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
187 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
188 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
189 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
190 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
191 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
192 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
193 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
194 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
195 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
196 static const WCHAR NameW[] = {'N','a','m','e',0};
197 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
198 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
199 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
200 static const WCHAR PortW[] = {'P','o','r','t',0};
201 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
202 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
203 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
204 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
205 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
206 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
207 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
208 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
209 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
210 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
211 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
212 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
213 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
214 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
215 static const WCHAR emptyStringW[] = {0};
217 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
219 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
220 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
221 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
223 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
224 'D','o','c','u','m','e','n','t',0};
226 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
227 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
228 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
229 0, sizeof(DRIVER_INFO_8W)};
232 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
233 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
234 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
235 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
236 sizeof(PRINTER_INFO_9W)};
238 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
239 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
240 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
242 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
244 /******************************************************************
245 * validate the user-supplied printing-environment [internal]
248 * env [I] PTR to Environment-String or NULL
252 * Success: PTR to printenv_t
255 * An empty string is handled the same way as NULL.
256 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
260 static const printenv_t * validate_envW(LPCWSTR env)
262 const printenv_t *result = NULL;
265 TRACE("testing %s\n", debugstr_w(env));
268 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
270 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
272 result = all_printenv[i];
277 if (result == NULL) {
278 FIXME("unsupported Environment: %s\n", debugstr_w(env));
279 SetLastError(ERROR_INVALID_ENVIRONMENT);
281 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
285 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
287 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
293 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
294 if passed a NULL string. This returns NULLs to the result.
296 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
300 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
301 return usBufferPtr->Buffer;
303 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
307 static LPWSTR strdupW(LPCWSTR p)
313 len = (strlenW(p) + 1) * sizeof(WCHAR);
314 ret = HeapAlloc(GetProcessHeap(), 0, len);
319 static LPSTR strdupWtoA( LPCWSTR str )
324 if (!str) return NULL;
325 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
326 ret = HeapAlloc( GetProcessHeap(), 0, len );
327 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
331 /******************************************************************
332 * verify, that the filename is a local file
335 static inline BOOL is_local_file(LPWSTR name)
337 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
340 /******************************************************************
341 * Return the number of bytes for an multi_sz string.
342 * The result includes all \0s
343 * (specifically the extra \0, that is needed as multi_sz terminator).
346 static int multi_sz_lenW(const WCHAR *str)
348 const WCHAR *ptr = str;
352 ptr += lstrlenW(ptr) + 1;
355 return (ptr - str + 1) * sizeof(WCHAR);
358 /* ################################ */
360 static int multi_sz_lenA(const char *str)
362 const char *ptr = str;
366 ptr += lstrlenA(ptr) + 1;
369 return ptr - str + 1;
373 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
376 /* If forcing, or no profile string entry for device yet, set the entry
378 * The always change entry if not WINEPS yet is discussable.
381 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
383 !strstr(qbuf,"WINEPS.DRV")
385 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
388 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
389 WriteProfileStringA("windows","device",buf);
390 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
391 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
394 HeapFree(GetProcessHeap(),0,buf);
398 static BOOL add_printer_driver(const char *name)
402 static char driver_9x[] = "wineps16.drv",
403 driver_nt[] = "wineps.drv",
404 env_9x[] = "Windows 4.0",
405 env_nt[] = "Windows NT x86",
406 data_file[] = "generic.ppd",
407 default_data_type[] = "RAW";
409 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
411 di3a.pName = (char *)name;
412 di3a.pEnvironment = env_nt;
413 di3a.pDriverPath = driver_nt;
414 di3a.pDataFile = data_file;
415 di3a.pConfigFile = driver_nt;
416 di3a.pDefaultDataType = default_data_type;
418 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
419 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
422 di3a.pEnvironment = env_9x;
423 di3a.pDriverPath = driver_9x;
424 di3a.pConfigFile = driver_9x;
425 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
426 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
431 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
432 debugstr_a(di3a.pEnvironment), GetLastError());
436 #ifdef SONAME_LIBCUPS
437 static typeof(cupsFreeDests) *pcupsFreeDests;
438 static typeof(cupsGetDests) *pcupsGetDests;
439 static typeof(cupsGetPPD) *pcupsGetPPD;
440 static typeof(cupsPrintFile) *pcupsPrintFile;
441 static void *cupshandle;
443 static BOOL CUPS_LoadPrinters(void)
446 BOOL hadprinter = FALSE, haddefault = FALSE;
448 PRINTER_INFO_2A pinfo2a;
450 HKEY hkeyPrinter, hkeyPrinters, hkey;
453 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
455 TRACE("%s\n", loaderror);
458 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
461 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
462 if (!p##x) return FALSE;
464 DYNCUPS(cupsFreeDests);
466 DYNCUPS(cupsGetDests);
467 DYNCUPS(cupsPrintFile);
470 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
472 ERR("Can't create Printers key\n");
476 nrofdests = pcupsGetDests(&dests);
477 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
478 for (i=0;i<nrofdests;i++) {
479 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
480 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
481 sprintf(port,"LPR:%s", dests[i].name);
482 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
483 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
484 sprintf(devline, "WINEPS.DRV,%s", port);
485 WriteProfileStringA("devices", dests[i].name, devline);
486 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
487 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
491 lstrcatA(devline, ",15,45");
492 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
493 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
494 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
498 HeapFree(GetProcessHeap(), 0, devline);
500 TRACE("Printer %d: %s\n", i, dests[i].name);
501 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
502 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
504 TRACE("Printer already exists\n");
505 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
506 RegCloseKey(hkeyPrinter);
508 static CHAR data_type[] = "RAW",
509 print_proc[] = "WinPrint",
510 comment[] = "WINEPS Printer using CUPS",
511 location[] = "<physical location of printer>",
512 params[] = "<parameters?>",
513 share_name[] = "<share name?>",
514 sep_file[] = "<sep file?>";
516 add_printer_driver(dests[i].name);
518 memset(&pinfo2a,0,sizeof(pinfo2a));
519 pinfo2a.pPrinterName = dests[i].name;
520 pinfo2a.pDatatype = data_type;
521 pinfo2a.pPrintProcessor = print_proc;
522 pinfo2a.pDriverName = dests[i].name;
523 pinfo2a.pComment = comment;
524 pinfo2a.pLocation = location;
525 pinfo2a.pPortName = port;
526 pinfo2a.pParameters = params;
527 pinfo2a.pShareName = share_name;
528 pinfo2a.pSepFile = sep_file;
530 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
531 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
532 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
535 HeapFree(GetProcessHeap(),0,port);
538 if (dests[i].is_default) {
539 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
543 if (hadprinter & !haddefault)
544 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
545 pcupsFreeDests(nrofdests, dests);
546 RegCloseKey(hkeyPrinters);
552 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
553 PRINTER_INFO_2A pinfo2a;
554 char *e,*s,*name,*prettyname,*devname;
555 BOOL ret = FALSE, set_default = FALSE;
556 char *port = NULL, *devline,*env_default;
557 HKEY hkeyPrinter, hkeyPrinters, hkey;
559 while (isspace(*pent)) pent++;
560 s = strchr(pent,':');
562 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
570 TRACE("name=%s entry=%s\n",name, pent);
572 if(ispunct(*name)) { /* a tc entry, not a real printer */
573 TRACE("skipping tc entry\n");
577 if(strstr(pent,":server")) { /* server only version so skip */
578 TRACE("skipping server entry\n");
582 /* Determine whether this is a postscript printer. */
585 env_default = getenv("PRINTER");
587 /* Get longest name, usually the one at the right for later display. */
588 while((s=strchr(prettyname,'|'))) {
591 while(isspace(*--e)) *e = '\0';
592 TRACE("\t%s\n", debugstr_a(prettyname));
593 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
594 for(prettyname = s+1; isspace(*prettyname); prettyname++)
597 e = prettyname + strlen(prettyname);
598 while(isspace(*--e)) *e = '\0';
599 TRACE("\t%s\n", debugstr_a(prettyname));
600 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
602 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
603 * if it is too long, we use it as comment below. */
604 devname = prettyname;
605 if (strlen(devname)>=CCHDEVICENAME-1)
607 if (strlen(devname)>=CCHDEVICENAME-1) {
612 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
613 sprintf(port,"LPR:%s",name);
615 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
616 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
617 sprintf(devline, "WINEPS.DRV,%s", port);
618 WriteProfileStringA("devices", devname, devline);
619 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
620 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
624 lstrcatA(devline, ",15,45");
625 WriteProfileStringA("PrinterPorts", devname, devline);
626 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
627 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
631 HeapFree(GetProcessHeap(),0,devline);
633 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
635 ERR("Can't create Printers key\n");
639 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
640 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
642 TRACE("Printer already exists\n");
643 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
644 RegCloseKey(hkeyPrinter);
646 static CHAR data_type[] = "RAW",
647 print_proc[] = "WinPrint",
648 comment[] = "WINEPS Printer using LPR",
649 params[] = "<parameters?>",
650 share_name[] = "<share name?>",
651 sep_file[] = "<sep file?>";
653 add_printer_driver(devname);
655 memset(&pinfo2a,0,sizeof(pinfo2a));
656 pinfo2a.pPrinterName = devname;
657 pinfo2a.pDatatype = data_type;
658 pinfo2a.pPrintProcessor = print_proc;
659 pinfo2a.pDriverName = devname;
660 pinfo2a.pComment = comment;
661 pinfo2a.pLocation = prettyname;
662 pinfo2a.pPortName = port;
663 pinfo2a.pParameters = params;
664 pinfo2a.pShareName = share_name;
665 pinfo2a.pSepFile = sep_file;
667 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
668 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
669 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
672 RegCloseKey(hkeyPrinters);
674 if (isfirst || set_default)
675 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
678 HeapFree(GetProcessHeap(), 0, port);
679 HeapFree(GetProcessHeap(), 0, name);
684 PRINTCAP_LoadPrinters(void) {
685 BOOL hadprinter = FALSE;
689 BOOL had_bash = FALSE;
691 f = fopen("/etc/printcap","r");
695 while(fgets(buf,sizeof(buf),f)) {
698 end=strchr(buf,'\n');
702 while(isspace(*start)) start++;
703 if(*start == '#' || *start == '\0')
706 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
707 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
708 HeapFree(GetProcessHeap(),0,pent);
712 if (end && *--end == '\\') {
719 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
722 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
728 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
729 HeapFree(GetProcessHeap(),0,pent);
735 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
738 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
739 (lstrlenW(value) + 1) * sizeof(WCHAR));
741 return ERROR_FILE_NOT_FOUND;
744 /******************************************************************
745 * get_servername_from_name (internal)
747 * for an external server, a copy of the serverpart from the full name is returned
750 static LPWSTR get_servername_from_name(LPCWSTR name)
754 WCHAR buffer[MAX_PATH];
757 if (name == NULL) return NULL;
758 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
760 server = strdupW(&name[2]); /* skip over both backslash */
761 if (server == NULL) return NULL;
763 /* strip '\' and the printername */
764 ptr = strchrW(server, '\\');
765 if (ptr) ptr[0] = '\0';
767 TRACE("found %s\n", debugstr_w(server));
769 len = sizeof(buffer)/sizeof(buffer[0]);
770 if (GetComputerNameW(buffer, &len)) {
771 if (lstrcmpW(buffer, server) == 0) {
772 /* The requested Servername is our computername */
773 HeapFree(GetProcessHeap(), 0, server);
780 /******************************************************************
781 * get_basename_from_name (internal)
783 * skip over the serverpart from the full name
786 static LPCWSTR get_basename_from_name(LPCWSTR name)
788 if (name == NULL) return NULL;
789 if ((name[0] == '\\') && (name[1] == '\\')) {
790 /* skip over the servername and search for the following '\' */
791 name = strchrW(&name[2], '\\');
792 if ((name) && (name[1])) {
793 /* found a separator ('\') followed by a name:
794 skip over the separator and return the rest */
799 /* no basename present (we found only a servername) */
806 /******************************************************************
807 * get_opened_printer_entry
808 * Get the first place empty in the opened printer table
811 * - pDefault is ignored
813 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
815 UINT_PTR handle = nb_printer_handles, i;
816 jobqueue_t *queue = NULL;
817 opened_printer_t *printer = NULL;
821 if ((backend == NULL) && !load_backend()) return NULL;
823 servername = get_servername_from_name(name);
825 FIXME("server %s not supported\n", debugstr_w(servername));
826 HeapFree(GetProcessHeap(), 0, servername);
827 SetLastError(ERROR_INVALID_PRINTER_NAME);
831 printername = get_basename_from_name(name);
832 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
834 /* an empty printername is invalid */
835 if (printername && (!printername[0])) {
836 SetLastError(ERROR_INVALID_PARAMETER);
840 EnterCriticalSection(&printer_handles_cs);
842 for (i = 0; i < nb_printer_handles; i++)
844 if (!printer_handles[i])
846 if(handle == nb_printer_handles)
851 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
852 queue = printer_handles[i]->queue;
856 if (handle >= nb_printer_handles)
858 opened_printer_t **new_array;
860 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
861 (nb_printer_handles + 16) * sizeof(*new_array) );
863 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
864 (nb_printer_handles + 16) * sizeof(*new_array) );
871 printer_handles = new_array;
872 nb_printer_handles += 16;
875 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
881 /* get a printer handle from the backend */
882 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
887 /* clone the base name. This is NULL for the printserver */
888 printer->printername = strdupW(printername);
890 /* clone the full name */
891 printer->name = strdupW(name);
892 if (name && (!printer->name)) {
898 printer->queue = queue;
901 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
902 if (!printer->queue) {
906 list_init(&printer->queue->jobs);
907 printer->queue->ref = 0;
909 InterlockedIncrement(&printer->queue->ref);
911 printer_handles[handle] = printer;
914 LeaveCriticalSection(&printer_handles_cs);
915 if (!handle && printer) {
916 /* Something failed: Free all resources */
917 HeapFree(GetProcessHeap(), 0, printer->printername);
918 HeapFree(GetProcessHeap(), 0, printer->name);
919 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
920 HeapFree(GetProcessHeap(), 0, printer);
923 return (HANDLE)handle;
926 /******************************************************************
928 * Get the pointer to the opened printer referred by the handle
930 static opened_printer_t *get_opened_printer(HANDLE hprn)
932 UINT_PTR idx = (UINT_PTR)hprn;
933 opened_printer_t *ret = NULL;
935 EnterCriticalSection(&printer_handles_cs);
937 if ((idx > 0) && (idx <= nb_printer_handles)) {
938 ret = printer_handles[idx - 1];
940 LeaveCriticalSection(&printer_handles_cs);
944 /******************************************************************
945 * get_opened_printer_name
946 * Get the pointer to the opened printer name referred by the handle
948 static LPCWSTR get_opened_printer_name(HANDLE hprn)
950 opened_printer_t *printer = get_opened_printer(hprn);
951 if(!printer) return NULL;
952 return printer->name;
955 /******************************************************************
956 * WINSPOOL_GetOpenedPrinterRegKey
959 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
961 LPCWSTR name = get_opened_printer_name(hPrinter);
965 if(!name) return ERROR_INVALID_HANDLE;
967 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
971 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
973 ERR("Can't find opened printer %s in registry\n",
975 RegCloseKey(hkeyPrinters);
976 return ERROR_INVALID_PRINTER_NAME; /* ? */
978 RegCloseKey(hkeyPrinters);
979 return ERROR_SUCCESS;
982 void WINSPOOL_LoadSystemPrinters(void)
984 HKEY hkey, hkeyPrinters;
986 DWORD needed, num, i;
987 WCHAR PrinterName[256];
990 /* This ensures that all printer entries have a valid Name value. If causes
991 problems later if they don't. If one is found to be missed we create one
992 and set it equal to the name of the key */
993 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
994 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
995 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
996 for(i = 0; i < num; i++) {
997 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
998 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
999 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1000 set_reg_szW(hkey, NameW, PrinterName);
1007 RegCloseKey(hkeyPrinters);
1010 /* We want to avoid calling AddPrinter on printers as much as
1011 possible, because on cups printers this will (eventually) lead
1012 to a call to cupsGetPPD which takes forever, even with non-cups
1013 printers AddPrinter takes a while. So we'll tag all printers that
1014 were automatically added last time around, if they still exist
1015 we'll leave them be otherwise we'll delete them. */
1016 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1018 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1019 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1020 for(i = 0; i < num; i++) {
1021 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1022 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1023 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1025 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1033 HeapFree(GetProcessHeap(), 0, pi);
1037 #ifdef SONAME_LIBCUPS
1038 done = CUPS_LoadPrinters();
1041 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1042 PRINTCAP_LoadPrinters();
1044 /* Now enumerate the list again and delete any printers that are still tagged */
1045 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1047 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1048 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1049 for(i = 0; i < num; i++) {
1050 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1051 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1052 BOOL delete_driver = FALSE;
1053 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1054 DWORD dw, type, size = sizeof(dw);
1055 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1056 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1057 DeletePrinter(hprn);
1058 delete_driver = TRUE;
1064 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1069 HeapFree(GetProcessHeap(), 0, pi);
1076 /******************************************************************
1079 * Get the pointer to the specified job.
1080 * Should hold the printer_handles_cs before calling.
1082 static job_t *get_job(HANDLE hprn, DWORD JobId)
1084 opened_printer_t *printer = get_opened_printer(hprn);
1087 if(!printer) return NULL;
1088 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1090 if(job->job_id == JobId)
1096 /***********************************************************
1099 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1102 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1105 Formname = (dmA->dmSize > off_formname);
1106 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1107 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1108 dmW->dmDeviceName, CCHDEVICENAME);
1110 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1111 dmA->dmSize - CCHDEVICENAME);
1113 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1114 off_formname - CCHDEVICENAME);
1115 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1116 dmW->dmFormName, CCHFORMNAME);
1117 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1118 (off_formname + CCHFORMNAME));
1121 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1122 dmA->dmDriverExtra);
1126 /***********************************************************
1128 * Creates an ansi copy of supplied devmode
1130 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1135 if (!dmW) return NULL;
1136 size = dmW->dmSize - CCHDEVICENAME -
1137 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1139 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1140 if (!dmA) return NULL;
1142 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1143 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1145 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1146 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1147 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1151 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1152 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1153 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1154 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1156 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1160 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1164 /******************************************************************
1165 * convert_printerinfo_W_to_A [internal]
1168 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1169 DWORD level, DWORD outlen, DWORD numentries)
1175 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1177 len = pi_sizeof[level] * numentries;
1178 ptr = (LPSTR) out + len;
1181 /* copy the numbers of all PRINTER_INFO_* first */
1182 memcpy(out, pPrintersW, len);
1184 while (id < numentries) {
1188 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1189 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1191 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1192 if (piW->pDescription) {
1193 piA->pDescription = ptr;
1194 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1195 ptr, outlen, NULL, NULL);
1201 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1202 ptr, outlen, NULL, NULL);
1206 if (piW->pComment) {
1207 piA->pComment = ptr;
1208 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1209 ptr, outlen, NULL, NULL);
1218 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1219 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1222 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1223 if (piW->pServerName) {
1224 piA->pServerName = ptr;
1225 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1226 ptr, outlen, NULL, NULL);
1230 if (piW->pPrinterName) {
1231 piA->pPrinterName = ptr;
1232 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1233 ptr, outlen, NULL, NULL);
1237 if (piW->pShareName) {
1238 piA->pShareName = ptr;
1239 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1240 ptr, outlen, NULL, NULL);
1244 if (piW->pPortName) {
1245 piA->pPortName = ptr;
1246 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1247 ptr, outlen, NULL, NULL);
1251 if (piW->pDriverName) {
1252 piA->pDriverName = ptr;
1253 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1254 ptr, outlen, NULL, NULL);
1258 if (piW->pComment) {
1259 piA->pComment = ptr;
1260 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1261 ptr, outlen, NULL, NULL);
1265 if (piW->pLocation) {
1266 piA->pLocation = ptr;
1267 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1268 ptr, outlen, NULL, NULL);
1273 dmA = DEVMODEdupWtoA(piW->pDevMode);
1275 /* align DEVMODEA to a DWORD boundary */
1276 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1280 piA->pDevMode = (LPDEVMODEA) ptr;
1281 len = dmA->dmSize + dmA->dmDriverExtra;
1282 memcpy(ptr, dmA, len);
1283 HeapFree(GetProcessHeap(), 0, dmA);
1289 if (piW->pSepFile) {
1290 piA->pSepFile = ptr;
1291 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1292 ptr, outlen, NULL, NULL);
1296 if (piW->pPrintProcessor) {
1297 piA->pPrintProcessor = ptr;
1298 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1299 ptr, outlen, NULL, NULL);
1303 if (piW->pDatatype) {
1304 piA->pDatatype = ptr;
1305 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1306 ptr, outlen, NULL, NULL);
1310 if (piW->pParameters) {
1311 piA->pParameters = ptr;
1312 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1313 ptr, outlen, NULL, NULL);
1317 if (piW->pSecurityDescriptor) {
1318 piA->pSecurityDescriptor = NULL;
1319 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1326 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1327 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1329 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1331 if (piW->pPrinterName) {
1332 piA->pPrinterName = ptr;
1333 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1334 ptr, outlen, NULL, NULL);
1338 if (piW->pServerName) {
1339 piA->pServerName = ptr;
1340 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1341 ptr, outlen, NULL, NULL);
1350 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1351 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1353 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1355 if (piW->pPrinterName) {
1356 piA->pPrinterName = ptr;
1357 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1358 ptr, outlen, NULL, NULL);
1362 if (piW->pPortName) {
1363 piA->pPortName = ptr;
1364 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1365 ptr, outlen, NULL, NULL);
1372 case 6: /* 6A and 6W are the same structure */
1377 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1378 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1380 TRACE("(%u) #%u\n", level, id);
1381 if (piW->pszObjectGUID) {
1382 piA->pszObjectGUID = ptr;
1383 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1384 ptr, outlen, NULL, NULL);
1393 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1394 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1397 TRACE("(%u) #%u\n", level, id);
1398 dmA = DEVMODEdupWtoA(piW->pDevMode);
1400 /* align DEVMODEA to a DWORD boundary */
1401 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1405 piA->pDevMode = (LPDEVMODEA) ptr;
1406 len = dmA->dmSize + dmA->dmDriverExtra;
1407 memcpy(ptr, dmA, len);
1408 HeapFree(GetProcessHeap(), 0, dmA);
1418 FIXME("for level %u\n", level);
1420 pPrintersW += pi_sizeof[level];
1421 out += pi_sizeof[level];
1426 /******************************************************************
1427 * convert_driverinfo_W_to_A [internal]
1430 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1431 DWORD level, DWORD outlen, DWORD numentries)
1437 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1439 len = di_sizeof[level] * numentries;
1440 ptr = (LPSTR) out + len;
1443 /* copy the numbers of all PRINTER_INFO_* first */
1444 memcpy(out, pDriversW, len);
1446 #define COPY_STRING(fld) \
1449 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1450 ptr += len; outlen -= len;\
1452 #define COPY_MULTIZ_STRING(fld) \
1453 { LPWSTR p = diW->fld; if (p){ \
1456 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1457 ptr += len; outlen -= len; p += len;\
1459 while(len > 1 && outlen > 0); \
1462 while (id < numentries)
1468 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1469 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1471 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1478 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1479 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1481 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1484 COPY_STRING(pEnvironment);
1485 COPY_STRING(pDriverPath);
1486 COPY_STRING(pDataFile);
1487 COPY_STRING(pConfigFile);
1492 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1493 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1495 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1498 COPY_STRING(pEnvironment);
1499 COPY_STRING(pDriverPath);
1500 COPY_STRING(pDataFile);
1501 COPY_STRING(pConfigFile);
1502 COPY_STRING(pHelpFile);
1503 COPY_MULTIZ_STRING(pDependentFiles);
1504 COPY_STRING(pMonitorName);
1505 COPY_STRING(pDefaultDataType);
1510 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1511 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1513 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1516 COPY_STRING(pEnvironment);
1517 COPY_STRING(pDriverPath);
1518 COPY_STRING(pDataFile);
1519 COPY_STRING(pConfigFile);
1520 COPY_STRING(pHelpFile);
1521 COPY_MULTIZ_STRING(pDependentFiles);
1522 COPY_STRING(pMonitorName);
1523 COPY_STRING(pDefaultDataType);
1524 COPY_MULTIZ_STRING(pszzPreviousNames);
1529 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1530 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1532 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1535 COPY_STRING(pEnvironment);
1536 COPY_STRING(pDriverPath);
1537 COPY_STRING(pDataFile);
1538 COPY_STRING(pConfigFile);
1543 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1544 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1546 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1549 COPY_STRING(pEnvironment);
1550 COPY_STRING(pDriverPath);
1551 COPY_STRING(pDataFile);
1552 COPY_STRING(pConfigFile);
1553 COPY_STRING(pHelpFile);
1554 COPY_MULTIZ_STRING(pDependentFiles);
1555 COPY_STRING(pMonitorName);
1556 COPY_STRING(pDefaultDataType);
1557 COPY_MULTIZ_STRING(pszzPreviousNames);
1558 COPY_STRING(pszMfgName);
1559 COPY_STRING(pszOEMUrl);
1560 COPY_STRING(pszHardwareID);
1561 COPY_STRING(pszProvider);
1566 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1567 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1569 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1572 COPY_STRING(pEnvironment);
1573 COPY_STRING(pDriverPath);
1574 COPY_STRING(pDataFile);
1575 COPY_STRING(pConfigFile);
1576 COPY_STRING(pHelpFile);
1577 COPY_MULTIZ_STRING(pDependentFiles);
1578 COPY_STRING(pMonitorName);
1579 COPY_STRING(pDefaultDataType);
1580 COPY_MULTIZ_STRING(pszzPreviousNames);
1581 COPY_STRING(pszMfgName);
1582 COPY_STRING(pszOEMUrl);
1583 COPY_STRING(pszHardwareID);
1584 COPY_STRING(pszProvider);
1585 COPY_STRING(pszPrintProcessor);
1586 COPY_STRING(pszVendorSetup);
1587 COPY_MULTIZ_STRING(pszzColorProfiles);
1588 COPY_STRING(pszInfPath);
1589 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1595 FIXME("for level %u\n", level);
1598 pDriversW += di_sizeof[level];
1599 out += di_sizeof[level];
1604 #undef COPY_MULTIZ_STRING
1608 /***********************************************************
1609 * PRINTER_INFO_2AtoW
1610 * Creates a unicode copy of PRINTER_INFO_2A on heap
1612 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1614 LPPRINTER_INFO_2W piW;
1615 UNICODE_STRING usBuffer;
1617 if(!piA) return NULL;
1618 piW = HeapAlloc(heap, 0, sizeof(*piW));
1619 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1621 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1622 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1623 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1624 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1625 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1626 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1627 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1628 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1629 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1630 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1631 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1632 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1636 /***********************************************************
1637 * FREE_PRINTER_INFO_2W
1638 * Free PRINTER_INFO_2W and all strings
1640 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1644 HeapFree(heap,0,piW->pServerName);
1645 HeapFree(heap,0,piW->pPrinterName);
1646 HeapFree(heap,0,piW->pShareName);
1647 HeapFree(heap,0,piW->pPortName);
1648 HeapFree(heap,0,piW->pDriverName);
1649 HeapFree(heap,0,piW->pComment);
1650 HeapFree(heap,0,piW->pLocation);
1651 HeapFree(heap,0,piW->pDevMode);
1652 HeapFree(heap,0,piW->pSepFile);
1653 HeapFree(heap,0,piW->pPrintProcessor);
1654 HeapFree(heap,0,piW->pDatatype);
1655 HeapFree(heap,0,piW->pParameters);
1656 HeapFree(heap,0,piW);
1660 /******************************************************************
1661 * DeviceCapabilities [WINSPOOL.@]
1662 * DeviceCapabilitiesA [WINSPOOL.@]
1665 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1666 LPSTR pOutput, LPDEVMODEA lpdm)
1670 if (!GDI_CallDeviceCapabilities16)
1672 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1674 if (!GDI_CallDeviceCapabilities16) return -1;
1676 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1678 /* If DC_PAPERSIZE map POINT16s to POINTs */
1679 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1680 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1681 POINT *pt = (POINT *)pOutput;
1683 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1684 for(i = 0; i < ret; i++, pt++)
1689 HeapFree( GetProcessHeap(), 0, tmp );
1695 /*****************************************************************************
1696 * DeviceCapabilitiesW [WINSPOOL.@]
1698 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1701 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1702 WORD fwCapability, LPWSTR pOutput,
1703 const DEVMODEW *pDevMode)
1705 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1706 LPSTR pDeviceA = strdupWtoA(pDevice);
1707 LPSTR pPortA = strdupWtoA(pPort);
1710 if(pOutput && (fwCapability == DC_BINNAMES ||
1711 fwCapability == DC_FILEDEPENDENCIES ||
1712 fwCapability == DC_PAPERNAMES)) {
1713 /* These need A -> W translation */
1716 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1720 switch(fwCapability) {
1725 case DC_FILEDEPENDENCIES:
1729 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1730 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1732 for(i = 0; i < ret; i++)
1733 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1734 pOutput + (i * size), size);
1735 HeapFree(GetProcessHeap(), 0, pOutputA);
1737 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1738 (LPSTR)pOutput, dmA);
1740 HeapFree(GetProcessHeap(),0,pPortA);
1741 HeapFree(GetProcessHeap(),0,pDeviceA);
1742 HeapFree(GetProcessHeap(),0,dmA);
1746 /******************************************************************
1747 * DocumentPropertiesA [WINSPOOL.@]
1749 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1751 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1752 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1753 LPDEVMODEA pDevModeInput,DWORD fMode )
1755 LPSTR lpName = pDeviceName;
1756 static CHAR port[] = "LPT1:";
1759 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1760 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1764 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1766 ERR("no name from hPrinter?\n");
1767 SetLastError(ERROR_INVALID_HANDLE);
1770 lpName = strdupWtoA(lpNameW);
1773 if (!GDI_CallExtDeviceMode16)
1775 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1777 if (!GDI_CallExtDeviceMode16) {
1778 ERR("No CallExtDeviceMode16?\n");
1782 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1783 pDevModeInput, NULL, fMode);
1786 HeapFree(GetProcessHeap(),0,lpName);
1791 /*****************************************************************************
1792 * DocumentPropertiesW (WINSPOOL.@)
1794 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1796 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1798 LPDEVMODEW pDevModeOutput,
1799 LPDEVMODEW pDevModeInput, DWORD fMode)
1802 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1803 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1804 LPDEVMODEA pDevModeOutputA = NULL;
1807 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1808 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1810 if(pDevModeOutput) {
1811 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1812 if(ret < 0) return ret;
1813 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1815 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1816 pDevModeInputA, fMode);
1817 if(pDevModeOutput) {
1818 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1819 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1821 if(fMode == 0 && ret > 0)
1822 ret += (CCHDEVICENAME + CCHFORMNAME);
1823 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1824 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1828 /******************************************************************
1829 * OpenPrinterA [WINSPOOL.@]
1834 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1835 LPPRINTER_DEFAULTSA pDefault)
1837 UNICODE_STRING lpPrinterNameW;
1838 UNICODE_STRING usBuffer;
1839 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1840 PWSTR pwstrPrinterNameW;
1843 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1846 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1847 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1848 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1849 pDefaultW = &DefaultW;
1851 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1853 RtlFreeUnicodeString(&usBuffer);
1854 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1856 RtlFreeUnicodeString(&lpPrinterNameW);
1860 /******************************************************************
1861 * OpenPrinterW [WINSPOOL.@]
1863 * Open a Printer / Printserver or a Printer-Object
1866 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1867 * phPrinter [O] The resulting Handle is stored here
1868 * pDefault [I] PTR to Default Printer Settings or NULL
1875 * lpPrinterName is one of:
1876 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1877 *| Printer: "PrinterName"
1878 *| Printer-Object: "PrinterName,Job xxx"
1879 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1880 *| XcvPort: "Servername,XcvPort PortName"
1883 *| Printer-Object not supported
1884 *| pDefaults is ignored
1887 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1890 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1892 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1893 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1897 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1898 SetLastError(ERROR_INVALID_PARAMETER);
1902 /* Get the unique handle of the printer or Printserver */
1903 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1904 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1905 return (*phPrinter != 0);
1908 /******************************************************************
1909 * AddMonitorA [WINSPOOL.@]
1914 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1916 LPWSTR nameW = NULL;
1919 LPMONITOR_INFO_2A mi2a;
1920 MONITOR_INFO_2W mi2w;
1922 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1923 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1924 debugstr_a(mi2a ? mi2a->pName : NULL),
1925 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1926 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1929 SetLastError(ERROR_INVALID_LEVEL);
1933 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1939 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1940 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1941 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1944 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1946 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1947 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1948 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1950 if (mi2a->pEnvironment) {
1951 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1952 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1953 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1955 if (mi2a->pDLLName) {
1956 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1957 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1958 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1961 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1963 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1964 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1965 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1967 HeapFree(GetProcessHeap(), 0, nameW);
1971 /******************************************************************************
1972 * AddMonitorW [WINSPOOL.@]
1974 * Install a Printmonitor
1977 * pName [I] Servername or NULL (local Computer)
1978 * Level [I] Structure-Level (Must be 2)
1979 * pMonitors [I] PTR to MONITOR_INFO_2
1986 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1989 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1991 LPMONITOR_INFO_2W mi2w;
1993 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1994 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1995 debugstr_w(mi2w ? mi2w->pName : NULL),
1996 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1997 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1999 if ((backend == NULL) && !load_backend()) return FALSE;
2002 SetLastError(ERROR_INVALID_LEVEL);
2006 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2011 return backend->fpAddMonitor(pName, Level, pMonitors);
2014 /******************************************************************
2015 * DeletePrinterDriverA [WINSPOOL.@]
2018 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2020 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2023 /******************************************************************
2024 * DeletePrinterDriverW [WINSPOOL.@]
2027 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2029 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2032 /******************************************************************
2033 * DeleteMonitorA [WINSPOOL.@]
2035 * See DeleteMonitorW.
2038 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2040 LPWSTR nameW = NULL;
2041 LPWSTR EnvironmentW = NULL;
2042 LPWSTR MonitorNameW = NULL;
2047 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2048 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2049 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2053 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2054 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2055 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2058 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2059 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2060 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2063 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2065 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2066 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2067 HeapFree(GetProcessHeap(), 0, nameW);
2071 /******************************************************************
2072 * DeleteMonitorW [WINSPOOL.@]
2074 * Delete a specific Printmonitor from a Printing-Environment
2077 * pName [I] Servername or NULL (local Computer)
2078 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2079 * pMonitorName [I] Name of the Monitor, that should be deleted
2086 * pEnvironment is ignored in Windows for the local Computer.
2089 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2092 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2093 debugstr_w(pMonitorName));
2095 if ((backend == NULL) && !load_backend()) return FALSE;
2097 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2101 /******************************************************************
2102 * DeletePortA [WINSPOOL.@]
2107 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2109 LPWSTR nameW = NULL;
2110 LPWSTR portW = NULL;
2114 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2116 /* convert servername to unicode */
2118 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2119 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2120 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2123 /* convert portname to unicode */
2125 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2126 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2127 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2130 res = DeletePortW(nameW, hWnd, portW);
2131 HeapFree(GetProcessHeap(), 0, nameW);
2132 HeapFree(GetProcessHeap(), 0, portW);
2136 /******************************************************************
2137 * DeletePortW [WINSPOOL.@]
2139 * Delete a specific Port
2142 * pName [I] Servername or NULL (local Computer)
2143 * hWnd [I] Handle to parent Window for the Dialog-Box
2144 * pPortName [I] Name of the Port, that should be deleted
2151 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2153 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2155 if ((backend == NULL) && !load_backend()) return FALSE;
2158 SetLastError(RPC_X_NULL_REF_POINTER);
2162 return backend->fpDeletePort(pName, hWnd, pPortName);
2165 /******************************************************************************
2166 * SetPrinterW [WINSPOOL.@]
2168 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2170 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2171 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2175 /******************************************************************************
2176 * WritePrinter [WINSPOOL.@]
2178 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2180 opened_printer_t *printer;
2183 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2185 EnterCriticalSection(&printer_handles_cs);
2186 printer = get_opened_printer(hPrinter);
2189 SetLastError(ERROR_INVALID_HANDLE);
2195 SetLastError(ERROR_SPL_NO_STARTDOC);
2199 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2201 LeaveCriticalSection(&printer_handles_cs);
2205 /*****************************************************************************
2206 * AddFormA [WINSPOOL.@]
2208 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2210 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2214 /*****************************************************************************
2215 * AddFormW [WINSPOOL.@]
2217 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2219 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2223 /*****************************************************************************
2224 * AddJobA [WINSPOOL.@]
2226 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2229 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2233 SetLastError(ERROR_INVALID_LEVEL);
2237 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2240 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2241 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2242 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2243 if(*pcbNeeded > cbBuf) {
2244 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2247 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2248 addjobA->JobId = addjobW->JobId;
2249 addjobA->Path = (char *)(addjobA + 1);
2250 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2256 /*****************************************************************************
2257 * AddJobW [WINSPOOL.@]
2259 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2261 opened_printer_t *printer;
2264 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2265 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2266 WCHAR path[MAX_PATH], filename[MAX_PATH];
2268 ADDJOB_INFO_1W *addjob;
2270 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2272 EnterCriticalSection(&printer_handles_cs);
2274 printer = get_opened_printer(hPrinter);
2277 SetLastError(ERROR_INVALID_HANDLE);
2282 SetLastError(ERROR_INVALID_LEVEL);
2286 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2290 job->job_id = InterlockedIncrement(&next_job_id);
2292 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2293 if(path[len - 1] != '\\')
2295 memcpy(path + len, spool_path, sizeof(spool_path));
2296 sprintfW(filename, fmtW, path, job->job_id);
2298 len = strlenW(filename);
2299 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2300 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2301 job->document_title = strdupW(default_doc_title);
2302 job->printer_name = strdupW(printer->name);
2303 job->devmode = NULL;
2304 list_add_tail(&printer->queue->jobs, &job->entry);
2306 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2307 if(*pcbNeeded <= cbBuf) {
2308 addjob = (ADDJOB_INFO_1W*)pData;
2309 addjob->JobId = job->job_id;
2310 addjob->Path = (WCHAR *)(addjob + 1);
2311 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2314 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2317 LeaveCriticalSection(&printer_handles_cs);
2321 /*****************************************************************************
2322 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2324 * Return the PATH for the Print-Processors
2326 * See GetPrintProcessorDirectoryW.
2330 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2331 DWORD level, LPBYTE Info,
2332 DWORD cbBuf, LPDWORD pcbNeeded)
2334 LPWSTR serverW = NULL;
2339 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2340 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2344 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2345 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2346 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2350 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2351 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2352 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2355 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2356 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2358 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2361 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2362 cbBuf, NULL, NULL) > 0;
2365 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2366 HeapFree(GetProcessHeap(), 0, envW);
2367 HeapFree(GetProcessHeap(), 0, serverW);
2371 /*****************************************************************************
2372 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2374 * Return the PATH for the Print-Processors
2377 * server [I] Servername (NT only) or NULL (local Computer)
2378 * env [I] Printing-Environment (see below) or NULL (Default)
2379 * level [I] Structure-Level (must be 1)
2380 * Info [O] PTR to Buffer that receives the Result
2381 * cbBuf [I] Size of Buffer at "Info"
2382 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2383 * required for the Buffer at "Info"
2386 * Success: TRUE and in pcbNeeded the Bytes used in Info
2387 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2388 * if cbBuf is too small
2390 * Native Values returned in Info on Success:
2391 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2392 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2393 *| win9x(Windows 4.0): "%winsysdir%"
2395 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2398 * Only NULL or "" is supported for server
2401 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2402 DWORD level, LPBYTE Info,
2403 DWORD cbBuf, LPDWORD pcbNeeded)
2406 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2407 Info, cbBuf, pcbNeeded);
2409 if ((backend == NULL) && !load_backend()) return FALSE;
2412 /* (Level != 1) is ignored in win9x */
2413 SetLastError(ERROR_INVALID_LEVEL);
2417 if (pcbNeeded == NULL) {
2418 /* (pcbNeeded == NULL) is ignored in win9x */
2419 SetLastError(RPC_X_NULL_REF_POINTER);
2423 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2426 /*****************************************************************************
2427 * WINSPOOL_OpenDriverReg [internal]
2429 * opens the registry for the printer drivers depending on the given input
2430 * variable pEnvironment
2433 * the opened hkey on success
2436 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2440 const printenv_t * env;
2442 TRACE("(%s)\n", debugstr_w(pEnvironment));
2444 env = validate_envW(pEnvironment);
2445 if (!env) return NULL;
2447 buffer = HeapAlloc( GetProcessHeap(), 0,
2448 (strlenW(DriversW) + strlenW(env->envname) +
2449 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2451 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2452 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2453 HeapFree(GetProcessHeap(), 0, buffer);
2458 /*****************************************************************************
2459 * AddPrinterW [WINSPOOL.@]
2461 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2463 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2467 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2469 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2470 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2471 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2472 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2473 statusW[] = {'S','t','a','t','u','s',0},
2474 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2476 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2479 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2480 SetLastError(ERROR_INVALID_PARAMETER);
2484 ERR("Level = %d, unsupported!\n", Level);
2485 SetLastError(ERROR_INVALID_LEVEL);
2489 SetLastError(ERROR_INVALID_PARAMETER);
2492 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2494 ERR("Can't create Printers key\n");
2497 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2498 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2499 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2500 RegCloseKey(hkeyPrinter);
2501 RegCloseKey(hkeyPrinters);
2504 RegCloseKey(hkeyPrinter);
2506 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2508 ERR("Can't create Drivers key\n");
2509 RegCloseKey(hkeyPrinters);
2512 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2514 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2515 RegCloseKey(hkeyPrinters);
2516 RegCloseKey(hkeyDrivers);
2517 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2520 RegCloseKey(hkeyDriver);
2521 RegCloseKey(hkeyDrivers);
2523 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2524 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2525 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2526 RegCloseKey(hkeyPrinters);
2530 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2532 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2533 SetLastError(ERROR_INVALID_PRINTER_NAME);
2534 RegCloseKey(hkeyPrinters);
2537 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2538 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2539 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2541 /* See if we can load the driver. We may need the devmode structure anyway
2544 * Note that DocumentPropertiesW will briefly try to open the printer we
2545 * just create to find a DEVMODEA struct (it will use the WINEPS default
2546 * one in case it is not there, so we are ok).
2548 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2551 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2552 size = sizeof(DEVMODEW);
2558 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2560 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2562 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2563 HeapFree(GetProcessHeap(),0,dmW);
2568 /* set devmode to printer name */
2569 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2573 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2574 and we support these drivers. NT writes DEVMODEW so somehow
2575 we'll need to distinguish between these when we support NT
2579 dmA = DEVMODEdupWtoA(dmW);
2580 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2581 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2582 HeapFree(GetProcessHeap(), 0, dmA);
2584 HeapFree(GetProcessHeap(), 0, dmW);
2586 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2587 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2588 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2589 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2591 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2592 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2593 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2594 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2595 (LPBYTE)&pi->Priority, sizeof(DWORD));
2596 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2597 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2598 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2599 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2600 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2601 (LPBYTE)&pi->Status, sizeof(DWORD));
2602 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2603 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2605 RegCloseKey(hkeyPrinter);
2606 RegCloseKey(hkeyPrinters);
2607 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2608 ERR("OpenPrinter failing\n");
2614 /*****************************************************************************
2615 * AddPrinterA [WINSPOOL.@]
2617 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2619 UNICODE_STRING pNameW;
2621 PRINTER_INFO_2W *piW;
2622 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2625 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2627 ERR("Level = %d, unsupported!\n", Level);
2628 SetLastError(ERROR_INVALID_LEVEL);
2631 pwstrNameW = asciitounicode(&pNameW,pName);
2632 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2634 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2636 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2637 RtlFreeUnicodeString(&pNameW);
2642 /*****************************************************************************
2643 * ClosePrinter [WINSPOOL.@]
2645 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2647 UINT_PTR i = (UINT_PTR)hPrinter;
2648 opened_printer_t *printer = NULL;
2651 TRACE("(%p)\n", hPrinter);
2653 EnterCriticalSection(&printer_handles_cs);
2655 if ((i > 0) && (i <= nb_printer_handles))
2656 printer = printer_handles[i - 1];
2661 struct list *cursor, *cursor2;
2663 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2665 if (printer->backend_printer) {
2666 backend->fpClosePrinter(printer->backend_printer);
2670 EndDocPrinter(hPrinter);
2672 if(InterlockedDecrement(&printer->queue->ref) == 0)
2674 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2676 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2677 ScheduleJob(hPrinter, job->job_id);
2679 HeapFree(GetProcessHeap(), 0, printer->queue);
2682 HeapFree(GetProcessHeap(), 0, printer->printername);
2683 HeapFree(GetProcessHeap(), 0, printer->name);
2684 HeapFree(GetProcessHeap(), 0, printer);
2685 printer_handles[i - 1] = NULL;
2688 LeaveCriticalSection(&printer_handles_cs);
2692 /*****************************************************************************
2693 * DeleteFormA [WINSPOOL.@]
2695 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2697 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2701 /*****************************************************************************
2702 * DeleteFormW [WINSPOOL.@]
2704 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2706 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2710 /*****************************************************************************
2711 * DeletePrinter [WINSPOOL.@]
2713 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2715 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2716 HKEY hkeyPrinters, hkey;
2719 SetLastError(ERROR_INVALID_HANDLE);
2722 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2723 RegDeleteTreeW(hkeyPrinters, lpNameW);
2724 RegCloseKey(hkeyPrinters);
2726 WriteProfileStringW(devicesW, lpNameW, NULL);
2727 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2729 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2730 RegDeleteValueW(hkey, lpNameW);
2734 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2735 RegDeleteValueW(hkey, lpNameW);
2741 /*****************************************************************************
2742 * SetPrinterA [WINSPOOL.@]
2744 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2747 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2751 /*****************************************************************************
2752 * SetJobA [WINSPOOL.@]
2754 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2755 LPBYTE pJob, DWORD Command)
2759 UNICODE_STRING usBuffer;
2761 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2763 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2764 are all ignored by SetJob, so we don't bother copying them */
2772 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2773 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2775 JobW = (LPBYTE)info1W;
2776 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2777 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2778 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2779 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2780 info1W->Status = info1A->Status;
2781 info1W->Priority = info1A->Priority;
2782 info1W->Position = info1A->Position;
2783 info1W->PagesPrinted = info1A->PagesPrinted;
2788 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2789 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2791 JobW = (LPBYTE)info2W;
2792 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2793 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2794 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2795 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2796 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2797 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2798 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2799 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2800 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2801 info2W->Status = info2A->Status;
2802 info2W->Priority = info2A->Priority;
2803 info2W->Position = info2A->Position;
2804 info2W->StartTime = info2A->StartTime;
2805 info2W->UntilTime = info2A->UntilTime;
2806 info2W->PagesPrinted = info2A->PagesPrinted;
2810 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2811 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2814 SetLastError(ERROR_INVALID_LEVEL);
2818 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2824 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2825 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2826 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2827 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2828 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2833 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2834 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2835 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2836 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2837 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2838 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2839 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2840 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2841 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2845 HeapFree(GetProcessHeap(), 0, JobW);
2850 /*****************************************************************************
2851 * SetJobW [WINSPOOL.@]
2853 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2854 LPBYTE pJob, DWORD Command)
2860 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2861 FIXME("Ignoring everything other than document title\n");
2863 EnterCriticalSection(&printer_handles_cs);
2864 job = get_job(hPrinter, JobId);
2874 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2875 HeapFree(GetProcessHeap(), 0, job->document_title);
2876 job->document_title = strdupW(info1->pDocument);
2881 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2882 HeapFree(GetProcessHeap(), 0, job->document_title);
2883 job->document_title = strdupW(info2->pDocument);
2884 HeapFree(GetProcessHeap(), 0, job->devmode);
2885 if (info2->pDevMode)
2887 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2888 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2889 memcpy(job->devmode, info2->pDevMode, size);
2892 job->devmode = NULL;
2898 SetLastError(ERROR_INVALID_LEVEL);
2903 LeaveCriticalSection(&printer_handles_cs);
2907 /*****************************************************************************
2908 * EndDocPrinter [WINSPOOL.@]
2910 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2912 opened_printer_t *printer;
2914 TRACE("(%p)\n", hPrinter);
2916 EnterCriticalSection(&printer_handles_cs);
2918 printer = get_opened_printer(hPrinter);
2921 SetLastError(ERROR_INVALID_HANDLE);
2927 SetLastError(ERROR_SPL_NO_STARTDOC);
2931 CloseHandle(printer->doc->hf);
2932 ScheduleJob(hPrinter, printer->doc->job_id);
2933 HeapFree(GetProcessHeap(), 0, printer->doc);
2934 printer->doc = NULL;
2937 LeaveCriticalSection(&printer_handles_cs);
2941 /*****************************************************************************
2942 * EndPagePrinter [WINSPOOL.@]
2944 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2946 FIXME("(%p): stub\n", hPrinter);
2950 /*****************************************************************************
2951 * StartDocPrinterA [WINSPOOL.@]
2953 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2955 UNICODE_STRING usBuffer;
2957 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2960 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2961 or one (DOC_INFO_3) extra DWORDs */
2965 doc2W.JobId = doc2->JobId;
2968 doc2W.dwMode = doc2->dwMode;
2971 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2972 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2973 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2977 SetLastError(ERROR_INVALID_LEVEL);
2981 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2983 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2984 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2985 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2990 /*****************************************************************************
2991 * StartDocPrinterW [WINSPOOL.@]
2993 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2995 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2996 opened_printer_t *printer;
2997 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2998 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2999 JOB_INFO_1W job_info;
3000 DWORD needed, ret = 0;
3005 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3006 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3007 debugstr_w(doc->pDatatype));
3009 if(Level < 1 || Level > 3)
3011 SetLastError(ERROR_INVALID_LEVEL);
3015 EnterCriticalSection(&printer_handles_cs);
3016 printer = get_opened_printer(hPrinter);
3019 SetLastError(ERROR_INVALID_HANDLE);
3025 SetLastError(ERROR_INVALID_PRINTER_STATE);
3029 /* Even if we're printing to a file we still add a print job, we'll
3030 just ignore the spool file name */
3032 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3034 ERR("AddJob failed gle %u\n", GetLastError());
3038 /* use pOutputFile only, when it is a real filename */
3039 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3040 filename = doc->pOutputFile;
3042 filename = addjob->Path;
3044 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3045 if(hf == INVALID_HANDLE_VALUE)
3048 memset(&job_info, 0, sizeof(job_info));
3049 job_info.pDocument = doc->pDocName;
3050 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3052 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3053 printer->doc->hf = hf;
3054 ret = printer->doc->job_id = addjob->JobId;
3055 job = get_job(hPrinter, ret);
3056 job->portname = strdupW(doc->pOutputFile);
3059 LeaveCriticalSection(&printer_handles_cs);
3064 /*****************************************************************************
3065 * StartPagePrinter [WINSPOOL.@]
3067 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3069 FIXME("(%p): stub\n", hPrinter);
3073 /*****************************************************************************
3074 * GetFormA [WINSPOOL.@]
3076 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3077 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3079 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3080 Level,pForm,cbBuf,pcbNeeded);
3084 /*****************************************************************************
3085 * GetFormW [WINSPOOL.@]
3087 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3088 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3090 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3091 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3095 /*****************************************************************************
3096 * SetFormA [WINSPOOL.@]
3098 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3101 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3105 /*****************************************************************************
3106 * SetFormW [WINSPOOL.@]
3108 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3111 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3115 /*****************************************************************************
3116 * ReadPrinter [WINSPOOL.@]
3118 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3119 LPDWORD pNoBytesRead)
3121 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3125 /*****************************************************************************
3126 * ResetPrinterA [WINSPOOL.@]
3128 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3130 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3134 /*****************************************************************************
3135 * ResetPrinterW [WINSPOOL.@]
3137 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3139 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3143 /*****************************************************************************
3144 * WINSPOOL_GetDWORDFromReg
3146 * Return DWORD associated with ValueName from hkey.
3148 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3150 DWORD sz = sizeof(DWORD), type, value = 0;
3153 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3155 if(ret != ERROR_SUCCESS) {
3156 WARN("Got ret = %d on name %s\n", ret, ValueName);
3159 if(type != REG_DWORD) {
3160 ERR("Got type %d\n", type);
3167 /*****************************************************************************
3168 * get_filename_from_reg [internal]
3170 * Get ValueName from hkey storing result in out
3171 * when the Value in the registry has only a filename, use driverdir as prefix
3172 * outlen is space left in out
3173 * String is stored either as unicode or ascii
3177 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3178 LPBYTE out, DWORD outlen, LPDWORD needed)
3180 WCHAR filename[MAX_PATH];
3184 LPWSTR buffer = filename;
3188 size = sizeof(filename);
3190 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3191 if (ret == ERROR_MORE_DATA) {
3192 TRACE("need dynamic buffer: %u\n", size);
3193 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3195 /* No Memory is bad */
3199 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3202 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3203 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3209 /* do we have a full path ? */
3210 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3211 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3214 /* we must build the full Path */
3216 if ((out) && (outlen > dirlen)) {
3217 lstrcpyW((LPWSTR)out, driverdir);
3225 /* write the filename */
3226 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3227 if ((out) && (outlen >= size)) {
3228 lstrcpyW((LPWSTR)out, ptr);
3235 ptr += lstrlenW(ptr)+1;
3236 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3239 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3241 /* write the multisz-termination */
3242 if (type == REG_MULTI_SZ) {
3243 size = sizeof(WCHAR);
3246 if (out && (outlen >= size)) {
3247 memset (out, 0, size);
3253 /*****************************************************************************
3254 * WINSPOOL_GetStringFromReg
3256 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3257 * String is stored as unicode.
3259 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3260 DWORD buflen, DWORD *needed)
3262 DWORD sz = buflen, type;
3265 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3266 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3267 WARN("Got ret = %d\n", ret);
3271 /* add space for terminating '\0' */
3272 sz += sizeof(WCHAR);
3276 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3281 /*****************************************************************************
3282 * WINSPOOL_GetDefaultDevMode
3284 * Get a default DevMode values for wineps.
3288 static void WINSPOOL_GetDefaultDevMode(
3290 DWORD buflen, DWORD *needed)
3293 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3295 /* fill default DEVMODE - should be read from ppd... */
3296 ZeroMemory( &dm, sizeof(dm) );
3297 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3298 dm.dmSpecVersion = DM_SPECVERSION;
3299 dm.dmDriverVersion = 1;
3300 dm.dmSize = sizeof(DEVMODEW);
3301 dm.dmDriverExtra = 0;
3303 DM_ORIENTATION | DM_PAPERSIZE |
3304 DM_PAPERLENGTH | DM_PAPERWIDTH |
3307 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3308 DM_YRESOLUTION | DM_TTOPTION;
3310 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3311 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3312 dm.u1.s1.dmPaperLength = 2970;
3313 dm.u1.s1.dmPaperWidth = 2100;
3315 dm.u1.s1.dmScale = 100;
3316 dm.u1.s1.dmCopies = 1;
3317 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3318 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3321 dm.dmYResolution = 300; /* 300dpi */
3322 dm.dmTTOption = DMTT_BITMAP;
3325 /* dm.dmLogPixels */
3326 /* dm.dmBitsPerPel */
3327 /* dm.dmPelsWidth */
3328 /* dm.dmPelsHeight */
3329 /* dm.u2.dmDisplayFlags */
3330 /* dm.dmDisplayFrequency */
3331 /* dm.dmICMMethod */
3332 /* dm.dmICMIntent */
3333 /* dm.dmMediaType */
3334 /* dm.dmDitherType */
3335 /* dm.dmReserved1 */
3336 /* dm.dmReserved2 */
3337 /* dm.dmPanningWidth */
3338 /* dm.dmPanningHeight */
3340 if(buflen >= sizeof(DEVMODEW))
3341 memcpy(ptr, &dm, sizeof(DEVMODEW));
3342 *needed = sizeof(DEVMODEW);
3345 /*****************************************************************************
3346 * WINSPOOL_GetDevModeFromReg
3348 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3349 * DevMode is stored either as unicode or ascii.
3351 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3353 DWORD buflen, DWORD *needed)
3355 DWORD sz = buflen, type;
3358 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3359 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3360 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3361 if (sz < sizeof(DEVMODEA))
3363 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3366 /* ensures that dmSize is not erratically bogus if registry is invalid */
3367 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3368 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3369 sz += (CCHDEVICENAME + CCHFORMNAME);
3370 if (ptr && (buflen >= sz)) {
3371 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3372 memcpy(ptr, dmW, sz);
3373 HeapFree(GetProcessHeap(),0,dmW);
3379 /*********************************************************************
3380 * WINSPOOL_GetPrinter_1
3382 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3384 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3385 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3387 DWORD size, left = cbBuf;
3388 BOOL space = (cbBuf > 0);
3393 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3394 if(space && size <= left) {
3395 pi1->pName = (LPWSTR)ptr;
3403 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3404 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3405 if(space && size <= left) {
3406 pi1->pDescription = (LPWSTR)ptr;
3414 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3415 if(space && size <= left) {
3416 pi1->pComment = (LPWSTR)ptr;
3424 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3426 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3427 memset(pi1, 0, sizeof(*pi1));
3431 /*********************************************************************
3432 * WINSPOOL_GetPrinter_2
3434 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3436 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3437 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3439 DWORD size, left = cbBuf;
3440 BOOL space = (cbBuf > 0);
3445 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3446 if(space && size <= left) {
3447 pi2->pPrinterName = (LPWSTR)ptr;
3454 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3455 if(space && size <= left) {
3456 pi2->pShareName = (LPWSTR)ptr;
3463 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3464 if(space && size <= left) {
3465 pi2->pPortName = (LPWSTR)ptr;
3472 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3473 if(space && size <= left) {
3474 pi2->pDriverName = (LPWSTR)ptr;
3481 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3482 if(space && size <= left) {
3483 pi2->pComment = (LPWSTR)ptr;
3490 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3491 if(space && size <= left) {
3492 pi2->pLocation = (LPWSTR)ptr;
3499 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3500 if(space && size <= left) {
3501 pi2->pDevMode = (LPDEVMODEW)ptr;
3510 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3511 if(space && size <= left) {
3512 pi2->pDevMode = (LPDEVMODEW)ptr;
3519 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3520 if(space && size <= left) {
3521 pi2->pSepFile = (LPWSTR)ptr;
3528 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3529 if(space && size <= left) {
3530 pi2->pPrintProcessor = (LPWSTR)ptr;
3537 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3538 if(space && size <= left) {
3539 pi2->pDatatype = (LPWSTR)ptr;
3546 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3547 if(space && size <= left) {
3548 pi2->pParameters = (LPWSTR)ptr;
3556 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3557 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3558 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3559 "Default Priority");
3560 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3561 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3564 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3565 memset(pi2, 0, sizeof(*pi2));
3570 /*********************************************************************
3571 * WINSPOOL_GetPrinter_4
3573 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3575 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3576 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3578 DWORD size, left = cbBuf;
3579 BOOL space = (cbBuf > 0);
3584 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3585 if(space && size <= left) {
3586 pi4->pPrinterName = (LPWSTR)ptr;
3594 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3597 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3598 memset(pi4, 0, sizeof(*pi4));
3603 /*********************************************************************
3604 * WINSPOOL_GetPrinter_5
3606 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3608 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3609 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3611 DWORD size, left = cbBuf;
3612 BOOL space = (cbBuf > 0);
3617 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3618 if(space && size <= left) {
3619 pi5->pPrinterName = (LPWSTR)ptr;
3626 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3627 if(space && size <= left) {
3628 pi5->pPortName = (LPWSTR)ptr;
3636 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3637 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3639 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3643 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3644 memset(pi5, 0, sizeof(*pi5));
3649 /*********************************************************************
3650 * WINSPOOL_GetPrinter_7
3652 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3654 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3655 DWORD cbBuf, LPDWORD pcbNeeded)
3657 DWORD size, left = cbBuf;
3658 BOOL space = (cbBuf > 0);
3663 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3666 size = sizeof(pi7->pszObjectGUID);
3668 if (space && size <= left) {
3669 pi7->pszObjectGUID = (LPWSTR)ptr;
3676 /* We do not have a Directory Service */
3677 pi7->dwAction = DSPRINT_UNPUBLISH;
3680 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3681 memset(pi7, 0, sizeof(*pi7));
3686 /*********************************************************************
3687 * WINSPOOL_GetPrinter_9
3689 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3691 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3692 DWORD cbBuf, LPDWORD pcbNeeded)
3695 BOOL space = (cbBuf > 0);
3699 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3700 if(space && size <= cbBuf) {
3701 pi9->pDevMode = (LPDEVMODEW)buf;
3708 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3709 if(space && size <= cbBuf) {
3710 pi9->pDevMode = (LPDEVMODEW)buf;
3716 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3717 memset(pi9, 0, sizeof(*pi9));
3722 /*****************************************************************************
3723 * GetPrinterW [WINSPOOL.@]
3725 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3726 DWORD cbBuf, LPDWORD pcbNeeded)
3729 DWORD size, needed = 0;
3731 HKEY hkeyPrinter, hkeyPrinters;
3734 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3736 if (!(name = get_opened_printer_name(hPrinter))) {
3737 SetLastError(ERROR_INVALID_HANDLE);
3741 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3743 ERR("Can't create Printers key\n");
3746 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3748 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3749 RegCloseKey(hkeyPrinters);
3750 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3757 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3759 size = sizeof(PRINTER_INFO_2W);
3761 ptr = pPrinter + size;
3763 memset(pPrinter, 0, size);
3768 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3775 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3777 size = sizeof(PRINTER_INFO_4W);
3779 ptr = pPrinter + size;
3781 memset(pPrinter, 0, size);
3786 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3794 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3796 size = sizeof(PRINTER_INFO_5W);
3798 ptr = pPrinter + size;
3800 memset(pPrinter, 0, size);
3806 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3814 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3816 size = sizeof(PRINTER_INFO_6);
3817 if (size <= cbBuf) {
3818 /* FIXME: We do not update the status yet */
3819 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3831 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3833 size = sizeof(PRINTER_INFO_7W);
3834 if (size <= cbBuf) {
3835 ptr = pPrinter + size;
3837 memset(pPrinter, 0, size);
3843 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3851 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3853 size = sizeof(PRINTER_INFO_9W);
3855 ptr = pPrinter + size;
3857 memset(pPrinter, 0, size);
3863 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3870 FIXME("Unimplemented level %d\n", Level);
3871 SetLastError(ERROR_INVALID_LEVEL);
3872 RegCloseKey(hkeyPrinters);
3873 RegCloseKey(hkeyPrinter);
3877 RegCloseKey(hkeyPrinter);
3878 RegCloseKey(hkeyPrinters);
3880 TRACE("returning %d needed = %d\n", ret, needed);
3881 if(pcbNeeded) *pcbNeeded = needed;
3883 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3887 /*****************************************************************************
3888 * GetPrinterA [WINSPOOL.@]
3890 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3891 DWORD cbBuf, LPDWORD pcbNeeded)
3897 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3899 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3901 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3902 HeapFree(GetProcessHeap(), 0, buf);
3907 /*****************************************************************************
3908 * WINSPOOL_EnumPrintersW
3910 * Implementation of EnumPrintersW
3912 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3913 DWORD dwLevel, LPBYTE lpbPrinters,
3914 DWORD cbBuf, LPDWORD lpdwNeeded,
3915 LPDWORD lpdwReturned)
3918 HKEY hkeyPrinters, hkeyPrinter;
3919 WCHAR PrinterName[255];
3920 DWORD needed = 0, number = 0;
3921 DWORD used, i, left;
3925 memset(lpbPrinters, 0, cbBuf);
3931 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3932 if(dwType == PRINTER_ENUM_DEFAULT)
3935 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3936 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3937 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3939 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3945 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3946 FIXME("dwType = %08x\n", dwType);
3947 SetLastError(ERROR_INVALID_FLAGS);
3951 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3953 ERR("Can't create Printers key\n");
3957 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3958 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3959 RegCloseKey(hkeyPrinters);
3960 ERR("Can't query Printers key\n");
3963 TRACE("Found %d printers\n", number);
3967 used = number * sizeof(PRINTER_INFO_1W);
3970 used = number * sizeof(PRINTER_INFO_2W);
3973 used = number * sizeof(PRINTER_INFO_4W);
3976 used = number * sizeof(PRINTER_INFO_5W);
3980 SetLastError(ERROR_INVALID_LEVEL);
3981 RegCloseKey(hkeyPrinters);
3984 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3986 for(i = 0; i < number; i++) {
3987 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3989 ERR("Can't enum key number %d\n", i);
3990 RegCloseKey(hkeyPrinters);
3993 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3994 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3996 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3997 RegCloseKey(hkeyPrinters);
4002 buf = lpbPrinters + used;
4003 left = cbBuf - used;
4011 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4014 if(pi) pi += sizeof(PRINTER_INFO_1W);
4017 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4020 if(pi) pi += sizeof(PRINTER_INFO_2W);
4023 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4026 if(pi) pi += sizeof(PRINTER_INFO_4W);
4029 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4032 if(pi) pi += sizeof(PRINTER_INFO_5W);
4035 ERR("Shouldn't be here!\n");
4036 RegCloseKey(hkeyPrinter);
4037 RegCloseKey(hkeyPrinters);
4040 RegCloseKey(hkeyPrinter);
4042 RegCloseKey(hkeyPrinters);
4049 memset(lpbPrinters, 0, cbBuf);
4050 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4054 *lpdwReturned = number;
4055 SetLastError(ERROR_SUCCESS);
4060 /******************************************************************
4061 * EnumPrintersW [WINSPOOL.@]
4063 * Enumerates the available printers, print servers and print
4064 * providers, depending on the specified flags, name and level.
4068 * If level is set to 1:
4069 * Returns an array of PRINTER_INFO_1 data structures in the
4070 * lpbPrinters buffer.
4072 * If level is set to 2:
4073 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4074 * Returns an array of PRINTER_INFO_2 data structures in the
4075 * lpbPrinters buffer. Note that according to MSDN also an
4076 * OpenPrinter should be performed on every remote printer.
4078 * If level is set to 4 (officially WinNT only):
4079 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4080 * Fast: Only the registry is queried to retrieve printer names,
4081 * no connection to the driver is made.
4082 * Returns an array of PRINTER_INFO_4 data structures in the
4083 * lpbPrinters buffer.
4085 * If level is set to 5 (officially WinNT4/Win9x only):
4086 * Fast: Only the registry is queried to retrieve printer names,
4087 * no connection to the driver is made.
4088 * Returns an array of PRINTER_INFO_5 data structures in the
4089 * lpbPrinters buffer.
4091 * If level set to 3 or 6+:
4092 * returns zero (failure!)
4094 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4098 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4099 * - Only levels 2, 4 and 5 are implemented at the moment.
4100 * - 16-bit printer drivers are not enumerated.
4101 * - Returned amount of bytes used/needed does not match the real Windoze
4102 * implementation (as in this implementation, all strings are part
4103 * of the buffer, whereas Win32 keeps them somewhere else)
4104 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4107 * - In a regular Wine installation, no registry settings for printers
4108 * exist, which makes this function return an empty list.
4110 BOOL WINAPI EnumPrintersW(
4111 DWORD dwType, /* [in] Types of print objects to enumerate */
4112 LPWSTR lpszName, /* [in] name of objects to enumerate */
4113 DWORD dwLevel, /* [in] type of printer info structure */
4114 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4115 DWORD cbBuf, /* [in] max size of buffer in bytes */
4116 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4117 LPDWORD lpdwReturned /* [out] number of entries returned */
4120 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4121 lpdwNeeded, lpdwReturned);
4124 /******************************************************************
4125 * EnumPrintersA [WINSPOOL.@]
4130 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4131 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4134 UNICODE_STRING pNameU;
4138 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4139 pPrinters, cbBuf, pcbNeeded, pcReturned);
4141 pNameW = asciitounicode(&pNameU, pName);
4143 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4144 MS Office need this */
4145 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4147 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4149 RtlFreeUnicodeString(&pNameU);
4151 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4153 HeapFree(GetProcessHeap(), 0, pPrintersW);
4157 /*****************************************************************************
4158 * WINSPOOL_GetDriverInfoFromReg [internal]
4160 * Enters the information from the registry into the DRIVER_INFO struct
4163 * zero if the printer driver does not exist in the registry
4164 * (only if Level > 1) otherwise nonzero
4166 static BOOL WINSPOOL_GetDriverInfoFromReg(
4169 const printenv_t * env,
4171 LPBYTE ptr, /* DRIVER_INFO */
4172 LPBYTE pDriverStrings, /* strings buffer */
4173 DWORD cbBuf, /* size of string buffer */
4174 LPDWORD pcbNeeded) /* space needed for str. */
4178 WCHAR driverdir[MAX_PATH];
4180 LPBYTE strPtr = pDriverStrings;
4181 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4183 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4184 debugstr_w(DriverName), env,
4185 Level, di, pDriverStrings, cbBuf);
4187 if (di) ZeroMemory(di, di_sizeof[Level]);
4189 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4190 if (*pcbNeeded <= cbBuf)
4191 strcpyW((LPWSTR)strPtr, DriverName);
4193 /* pName for level 1 has a different offset! */
4195 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4199 /* .cVersion and .pName for level > 1 */
4201 di->cVersion = env->driverversion;
4202 di->pName = (LPWSTR) strPtr;
4203 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4206 /* Reserve Space for the largest subdir and a Backslash*/
4207 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4208 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4209 /* Should never Fail */
4212 lstrcatW(driverdir, env->versionsubdir);
4213 lstrcatW(driverdir, backslashW);
4215 /* dirlen must not include the terminating zero */
4216 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4218 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4219 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4220 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4225 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4228 if (*pcbNeeded <= cbBuf) {
4229 lstrcpyW((LPWSTR)strPtr, env->envname);
4230 if (di) di->pEnvironment = (LPWSTR)strPtr;
4231 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4234 /* .pDriverPath is the Graphics rendering engine.
4235 The full Path is required to avoid a crash in some apps */
4236 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4238 if (*pcbNeeded <= cbBuf)
4239 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4241 if (di) di->pDriverPath = (LPWSTR)strPtr;
4242 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4245 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4246 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4248 if (*pcbNeeded <= cbBuf)
4249 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4251 if (di) di->pDataFile = (LPWSTR)strPtr;
4252 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4255 /* .pConfigFile is the Driver user Interface */
4256 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4258 if (*pcbNeeded <= cbBuf)
4259 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4261 if (di) di->pConfigFile = (LPWSTR)strPtr;
4262 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4266 RegCloseKey(hkeyDriver);
4267 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4272 RegCloseKey(hkeyDriver);
4273 FIXME("level 5: incomplete\n");
4278 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4280 if (*pcbNeeded <= cbBuf)
4281 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4283 if (di) di->pHelpFile = (LPWSTR)strPtr;
4284 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4287 /* .pDependentFiles */
4288 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4290 if (*pcbNeeded <= cbBuf)
4291 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4293 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4294 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4296 else if (GetVersion() & 0x80000000) {
4297 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4298 size = 2 * sizeof(WCHAR);
4300 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4302 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4303 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4306 /* .pMonitorName is the optional Language Monitor */
4307 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4309 if (*pcbNeeded <= cbBuf)
4310 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4312 if (di) di->pMonitorName = (LPWSTR)strPtr;
4313 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4316 /* .pDefaultDataType */
4317 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4319 if(*pcbNeeded <= cbBuf)
4320 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4322 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4323 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4327 RegCloseKey(hkeyDriver);
4328 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4332 /* .pszzPreviousNames */
4333 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4335 if(*pcbNeeded <= cbBuf)
4336 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4338 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4339 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4343 RegCloseKey(hkeyDriver);
4344 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4348 /* support is missing, but not important enough for a FIXME */
4349 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4352 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4354 if(*pcbNeeded <= cbBuf)
4355 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4357 if (di) di->pszMfgName = (LPWSTR)strPtr;
4358 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4362 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4364 if(*pcbNeeded <= cbBuf)
4365 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4367 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4368 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4371 /* .pszHardwareID */
4372 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4374 if(*pcbNeeded <= cbBuf)
4375 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4377 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4378 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4382 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4384 if(*pcbNeeded <= cbBuf)
4385 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4387 if (di) di->pszProvider = (LPWSTR)strPtr;
4388 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4392 RegCloseKey(hkeyDriver);
4396 /* support is missing, but not important enough for a FIXME */
4397 TRACE("level 8: incomplete\n");
4399 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4400 RegCloseKey(hkeyDriver);
4404 /*****************************************************************************
4405 * GetPrinterDriverW [WINSPOOL.@]
4407 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4408 DWORD Level, LPBYTE pDriverInfo,
4409 DWORD cbBuf, LPDWORD pcbNeeded)
4412 WCHAR DriverName[100];
4413 DWORD ret, type, size, needed = 0;
4415 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4416 const printenv_t * env;
4418 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4419 Level,pDriverInfo,cbBuf, pcbNeeded);
4422 ZeroMemory(pDriverInfo, cbBuf);
4424 if (!(name = get_opened_printer_name(hPrinter))) {
4425 SetLastError(ERROR_INVALID_HANDLE);
4429 if (Level < 1 || Level == 7 || Level > 8) {
4430 SetLastError(ERROR_INVALID_LEVEL);
4434 env = validate_envW(pEnvironment);
4435 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4437 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4439 ERR("Can't create Printers key\n");
4442 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4444 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4445 RegCloseKey(hkeyPrinters);
4446 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4449 size = sizeof(DriverName);
4451 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4452 (LPBYTE)DriverName, &size);
4453 RegCloseKey(hkeyPrinter);
4454 RegCloseKey(hkeyPrinters);
4455 if(ret != ERROR_SUCCESS) {
4456 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4460 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4462 ERR("Can't create Drivers key\n");
4466 size = di_sizeof[Level];
4467 if ((size <= cbBuf) && pDriverInfo)
4468 ptr = pDriverInfo + size;
4470 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4471 env, Level, pDriverInfo, ptr,
4472 (cbBuf < size) ? 0 : cbBuf - size,
4474 RegCloseKey(hkeyDrivers);
4478 RegCloseKey(hkeyDrivers);
4480 if(pcbNeeded) *pcbNeeded = size + needed;
4481 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4482 if(cbBuf >= size + needed) return TRUE;
4483 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4487 /*****************************************************************************
4488 * GetPrinterDriverA [WINSPOOL.@]
4490 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4491 DWORD Level, LPBYTE pDriverInfo,
4492 DWORD cbBuf, LPDWORD pcbNeeded)
4495 UNICODE_STRING pEnvW;
4501 ZeroMemory(pDriverInfo, cbBuf);
4502 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4505 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4506 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4509 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4511 HeapFree(GetProcessHeap(), 0, buf);
4513 RtlFreeUnicodeString(&pEnvW);
4517 /*****************************************************************************
4518 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4520 * Return the PATH for the Printer-Drivers (UNICODE)
4523 * pName [I] Servername (NT only) or NULL (local Computer)
4524 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4525 * Level [I] Structure-Level (must be 1)
4526 * pDriverDirectory [O] PTR to Buffer that receives the Result
4527 * cbBuf [I] Size of Buffer at pDriverDirectory
4528 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4529 * required for pDriverDirectory
4532 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4533 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4534 * if cbBuf is too small
4536 * Native Values returned in pDriverDirectory on Success:
4537 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4538 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4539 *| win9x(Windows 4.0): "%winsysdir%"
4541 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4544 *- Only NULL or "" is supported for pName
4547 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4548 DWORD Level, LPBYTE pDriverDirectory,
4549 DWORD cbBuf, LPDWORD pcbNeeded)
4551 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4552 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4554 if ((backend == NULL) && !load_backend()) return FALSE;
4557 /* (Level != 1) is ignored in win9x */
4558 SetLastError(ERROR_INVALID_LEVEL);
4561 if (pcbNeeded == NULL) {
4562 /* (pcbNeeded == NULL) is ignored in win9x */
4563 SetLastError(RPC_X_NULL_REF_POINTER);
4567 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4568 pDriverDirectory, cbBuf, pcbNeeded);
4573 /*****************************************************************************
4574 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4576 * Return the PATH for the Printer-Drivers (ANSI)
4578 * See GetPrinterDriverDirectoryW.
4581 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4584 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4585 DWORD Level, LPBYTE pDriverDirectory,
4586 DWORD cbBuf, LPDWORD pcbNeeded)
4588 UNICODE_STRING nameW, environmentW;
4591 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4592 WCHAR *driverDirectoryW = NULL;
4594 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4595 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4597 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4599 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4600 else nameW.Buffer = NULL;
4601 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4602 else environmentW.Buffer = NULL;
4604 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4605 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4608 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4609 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4611 *pcbNeeded = needed;
4612 ret = (needed <= cbBuf) ? TRUE : FALSE;
4614 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4616 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4618 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4619 RtlFreeUnicodeString(&environmentW);
4620 RtlFreeUnicodeString(&nameW);
4625 /*****************************************************************************
4626 * AddPrinterDriverA [WINSPOOL.@]
4628 * See AddPrinterDriverW.
4631 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4633 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4634 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4637 /******************************************************************************
4638 * AddPrinterDriverW (WINSPOOL.@)
4640 * Install a Printer Driver
4643 * pName [I] Servername or NULL (local Computer)
4644 * level [I] Level for the supplied DRIVER_INFO_*W struct
4645 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4652 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4654 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4655 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4658 /*****************************************************************************
4659 * AddPrintProcessorA [WINSPOOL.@]
4661 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4662 LPSTR pPrintProcessorName)
4664 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4665 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4669 /*****************************************************************************
4670 * AddPrintProcessorW [WINSPOOL.@]
4672 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4673 LPWSTR pPrintProcessorName)
4675 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4676 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4680 /*****************************************************************************
4681 * AddPrintProvidorA [WINSPOOL.@]
4683 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4685 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4689 /*****************************************************************************
4690 * AddPrintProvidorW [WINSPOOL.@]
4692 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4694 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4698 /*****************************************************************************
4699 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4701 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4702 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4704 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4705 pDevModeOutput, pDevModeInput);
4709 /*****************************************************************************
4710 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4712 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4713 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4715 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4716 pDevModeOutput, pDevModeInput);
4720 /*****************************************************************************
4721 * PrinterProperties [WINSPOOL.@]
4723 * Displays a dialog to set the properties of the printer.
4726 * nonzero on success or zero on failure
4729 * implemented as stub only
4731 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4732 HANDLE hPrinter /* [in] handle to printer object */
4734 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4735 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4739 /*****************************************************************************
4740 * EnumJobsA [WINSPOOL.@]
4743 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4744 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4747 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4748 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4750 if(pcbNeeded) *pcbNeeded = 0;
4751 if(pcReturned) *pcReturned = 0;
4756 /*****************************************************************************
4757 * EnumJobsW [WINSPOOL.@]
4760 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4761 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4764 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4765 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4767 if(pcbNeeded) *pcbNeeded = 0;
4768 if(pcReturned) *pcReturned = 0;
4772 /*****************************************************************************
4773 * WINSPOOL_EnumPrinterDrivers [internal]
4775 * Delivers information about all printer drivers installed on the
4776 * localhost or a given server
4779 * nonzero on success or zero on failure. If the buffer for the returned
4780 * information is too small the function will return an error
4783 * - only implemented for localhost, foreign hosts will return an error
4785 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4786 DWORD Level, LPBYTE pDriverInfo,
4788 DWORD cbBuf, LPDWORD pcbNeeded,
4789 LPDWORD pcFound, DWORD data_offset)
4793 const printenv_t * env;
4795 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4796 debugstr_w(pName), debugstr_w(pEnvironment),
4797 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4799 env = validate_envW(pEnvironment);
4800 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4804 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4806 ERR("Can't open Drivers key\n");
4810 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4811 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4812 RegCloseKey(hkeyDrivers);
4813 ERR("Can't query Drivers key\n");
4816 TRACE("Found %d Drivers\n", *pcFound);
4818 /* get size of single struct
4819 * unicode and ascii structure have the same size
4821 size = di_sizeof[Level];
4823 if (data_offset == 0)
4824 data_offset = size * (*pcFound);
4825 *pcbNeeded = data_offset;
4827 for( i = 0; i < *pcFound; i++) {
4828 WCHAR DriverNameW[255];
4829 PBYTE table_ptr = NULL;
4830 PBYTE data_ptr = NULL;
4833 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4835 ERR("Can't enum key number %d\n", i);
4836 RegCloseKey(hkeyDrivers);
4840 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4841 table_ptr = pDriverInfo + (driver_index + i) * size;
4842 if (pDriverInfo && *pcbNeeded <= cbBuf)
4843 data_ptr = pDriverInfo + *pcbNeeded;
4845 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4846 env, Level, table_ptr, data_ptr,
4847 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4849 RegCloseKey(hkeyDrivers);
4853 *pcbNeeded += needed;
4856 RegCloseKey(hkeyDrivers);
4858 if(cbBuf < *pcbNeeded){
4859 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4866 /*****************************************************************************
4867 * EnumPrinterDriversW [WINSPOOL.@]
4869 * see function EnumPrinterDrivers for RETURNS, BUGS
4871 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4872 LPBYTE pDriverInfo, DWORD cbBuf,
4873 LPDWORD pcbNeeded, LPDWORD pcReturned)
4875 static const WCHAR allW[] = {'a','l','l',0};
4879 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4881 SetLastError(RPC_X_NULL_REF_POINTER);
4885 /* check for local drivers */
4886 if((pName) && (pName[0])) {
4887 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4888 SetLastError(ERROR_ACCESS_DENIED);
4892 /* check input parameter */
4893 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4894 SetLastError(ERROR_INVALID_LEVEL);
4898 if(pDriverInfo && cbBuf > 0)
4899 memset( pDriverInfo, 0, cbBuf);
4901 /* Exception: pull all printers */
4902 if (pEnvironment && !strcmpW(pEnvironment, allW))
4904 DWORD i, needed, bufsize = cbBuf;
4905 DWORD total_needed = 0;
4906 DWORD total_found = 0;
4909 /* Precompute the overall total; we need this to know
4910 where pointers end and data begins (i.e. data_offset) */
4911 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4914 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4915 NULL, 0, 0, &needed, &found, 0);
4916 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4917 total_needed += needed;
4918 total_found += found;
4921 data_offset = di_sizeof[Level] * total_found;
4926 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4929 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4930 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4931 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4933 *pcReturned += found;
4934 *pcbNeeded = needed;
4935 data_offset = needed;
4936 total_found += found;
4941 /* Normal behavior */
4942 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4943 0, cbBuf, pcbNeeded, &found, 0);
4945 *pcReturned = found;
4950 /*****************************************************************************
4951 * EnumPrinterDriversA [WINSPOOL.@]
4953 * see function EnumPrinterDrivers for RETURNS, BUGS
4955 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4956 LPBYTE pDriverInfo, DWORD cbBuf,
4957 LPDWORD pcbNeeded, LPDWORD pcReturned)
4960 UNICODE_STRING pNameW, pEnvironmentW;
4961 PWSTR pwstrNameW, pwstrEnvironmentW;
4965 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4967 pwstrNameW = asciitounicode(&pNameW, pName);
4968 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4970 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4971 buf, cbBuf, pcbNeeded, pcReturned);
4973 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4975 HeapFree(GetProcessHeap(), 0, buf);
4977 RtlFreeUnicodeString(&pNameW);
4978 RtlFreeUnicodeString(&pEnvironmentW);
4983 /******************************************************************************
4984 * EnumPortsA (WINSPOOL.@)
4989 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4990 LPDWORD pcbNeeded, LPDWORD pcReturned)
4993 LPBYTE bufferW = NULL;
4994 LPWSTR nameW = NULL;
4996 DWORD numentries = 0;
4999 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5000 cbBuf, pcbNeeded, pcReturned);
5002 /* convert servername to unicode */
5004 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5005 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5006 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5008 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5009 needed = cbBuf * sizeof(WCHAR);
5010 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5011 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5013 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5014 if (pcbNeeded) needed = *pcbNeeded;
5015 /* HeapReAlloc return NULL, when bufferW was NULL */
5016 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5017 HeapAlloc(GetProcessHeap(), 0, needed);
5019 /* Try again with the large Buffer */
5020 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5022 needed = pcbNeeded ? *pcbNeeded : 0;
5023 numentries = pcReturned ? *pcReturned : 0;
5026 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5027 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5030 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5031 DWORD entrysize = 0;
5034 LPPORT_INFO_2W pi2w;
5035 LPPORT_INFO_2A pi2a;
5038 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5040 /* First pass: calculate the size for all Entries */
5041 pi2w = (LPPORT_INFO_2W) bufferW;
5042 pi2a = (LPPORT_INFO_2A) pPorts;
5044 while (index < numentries) {
5046 needed += entrysize; /* PORT_INFO_?A */
5047 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5049 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5050 NULL, 0, NULL, NULL);
5052 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5053 NULL, 0, NULL, NULL);
5054 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5055 NULL, 0, NULL, NULL);
5057 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5058 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5059 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5062 /* check for errors and quit on failure */
5063 if (cbBuf < needed) {
5064 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5068 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5069 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5070 cbBuf -= len ; /* free Bytes in the user-Buffer */
5071 pi2w = (LPPORT_INFO_2W) bufferW;
5072 pi2a = (LPPORT_INFO_2A) pPorts;
5074 /* Second Pass: Fill the User Buffer (if we have one) */
5075 while ((index < numentries) && pPorts) {
5077 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5078 pi2a->pPortName = ptr;
5079 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5080 ptr, cbBuf , NULL, NULL);
5084 pi2a->pMonitorName = ptr;
5085 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5086 ptr, cbBuf, NULL, NULL);
5090 pi2a->pDescription = ptr;
5091 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5092 ptr, cbBuf, NULL, NULL);
5096 pi2a->fPortType = pi2w->fPortType;
5097 pi2a->Reserved = 0; /* documented: "must be zero" */
5100 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5101 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5102 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5107 if (pcbNeeded) *pcbNeeded = needed;
5108 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5110 HeapFree(GetProcessHeap(), 0, nameW);
5111 HeapFree(GetProcessHeap(), 0, bufferW);
5113 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5114 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5120 /******************************************************************************
5121 * EnumPortsW (WINSPOOL.@)
5123 * Enumerate available Ports
5126 * pName [I] Servername or NULL (local Computer)
5127 * Level [I] Structure-Level (1 or 2)
5128 * pPorts [O] PTR to Buffer that receives the Result
5129 * cbBuf [I] Size of Buffer at pPorts
5130 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5131 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5135 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5138 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5141 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5142 cbBuf, pcbNeeded, pcReturned);
5144 if ((backend == NULL) && !load_backend()) return FALSE;
5146 /* Level is not checked in win9x */
5147 if (!Level || (Level > 2)) {
5148 WARN("level (%d) is ignored in win9x\n", Level);
5149 SetLastError(ERROR_INVALID_LEVEL);
5152 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5153 SetLastError(RPC_X_NULL_REF_POINTER);
5157 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5160 /******************************************************************************
5161 * GetDefaultPrinterW (WINSPOOL.@)
5164 * This function must read the value from data 'device' of key
5165 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5167 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5171 WCHAR *buffer, *ptr;
5175 SetLastError(ERROR_INVALID_PARAMETER);
5179 /* make the buffer big enough for the stuff from the profile/registry,
5180 * the content must fit into the local buffer to compute the correct
5181 * size even if the extern buffer is too small or not given.
5182 * (20 for ,driver,port) */
5184 len = max(100, (insize + 20));
5185 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5187 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5189 SetLastError (ERROR_FILE_NOT_FOUND);
5193 TRACE("%s\n", debugstr_w(buffer));
5195 if ((ptr = strchrW(buffer, ',')) == NULL)
5197 SetLastError(ERROR_INVALID_NAME);
5203 *namesize = strlenW(buffer) + 1;
5204 if(!name || (*namesize > insize))
5206 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5210 strcpyW(name, buffer);
5213 HeapFree( GetProcessHeap(), 0, buffer);
5218 /******************************************************************************
5219 * GetDefaultPrinterA (WINSPOOL.@)
5221 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5225 WCHAR *bufferW = NULL;
5229 SetLastError(ERROR_INVALID_PARAMETER);
5233 if(name && *namesize) {
5235 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5238 if(!GetDefaultPrinterW( bufferW, namesize)) {
5243 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5247 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5250 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5253 HeapFree( GetProcessHeap(), 0, bufferW);
5258 /******************************************************************************
5259 * SetDefaultPrinterW (WINSPOOL.204)
5261 * Set the Name of the Default Printer
5264 * pszPrinter [I] Name of the Printer or NULL
5271 * When the Parameter is NULL or points to an Empty String and
5272 * a Default Printer was already present, then this Function changes nothing.
5273 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5274 * the First enumerated local Printer is used.
5277 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5280 TRACE("(%s)\n", debugstr_w(pszPrinter));
5282 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5286 /******************************************************************************
5287 * SetDefaultPrinterA (WINSPOOL.202)
5289 * See SetDefaultPrinterW.
5292 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5295 TRACE("(%s)\n", debugstr_a(pszPrinter));
5297 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5302 /******************************************************************************
5303 * SetPrinterDataExA (WINSPOOL.@)
5305 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5306 LPCSTR pValueName, DWORD Type,
5307 LPBYTE pData, DWORD cbData)
5309 HKEY hkeyPrinter, hkeySubkey;
5312 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5313 debugstr_a(pValueName), Type, pData, cbData);
5315 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5319 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5321 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5322 RegCloseKey(hkeyPrinter);
5325 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5326 RegCloseKey(hkeySubkey);
5327 RegCloseKey(hkeyPrinter);
5331 /******************************************************************************
5332 * SetPrinterDataExW (WINSPOOL.@)
5334 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5335 LPCWSTR pValueName, DWORD Type,
5336 LPBYTE pData, DWORD cbData)
5338 HKEY hkeyPrinter, hkeySubkey;
5341 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5342 debugstr_w(pValueName), Type, pData, cbData);
5344 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5348 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5350 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5351 RegCloseKey(hkeyPrinter);
5354 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5355 RegCloseKey(hkeySubkey);
5356 RegCloseKey(hkeyPrinter);
5360 /******************************************************************************
5361 * SetPrinterDataA (WINSPOOL.@)
5363 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5364 LPBYTE pData, DWORD cbData)
5366 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5370 /******************************************************************************
5371 * SetPrinterDataW (WINSPOOL.@)
5373 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5374 LPBYTE pData, DWORD cbData)
5376 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5380 /******************************************************************************
5381 * GetPrinterDataExA (WINSPOOL.@)
5383 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5384 LPCSTR pValueName, LPDWORD pType,
5385 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5387 opened_printer_t *printer;
5388 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5391 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5392 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5394 printer = get_opened_printer(hPrinter);
5395 if(!printer) return ERROR_INVALID_HANDLE;
5397 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5398 if (ret) return ret;
5400 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5402 if (printer->name) {
5404 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5406 RegCloseKey(hkeyPrinters);
5409 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5410 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5411 RegCloseKey(hkeyPrinter);
5412 RegCloseKey(hkeyPrinters);
5417 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5418 0, pType, pData, pcbNeeded);
5420 if (!ret && !pData) ret = ERROR_MORE_DATA;
5422 RegCloseKey(hkeySubkey);
5423 RegCloseKey(hkeyPrinter);
5424 RegCloseKey(hkeyPrinters);
5426 TRACE("--> %d\n", ret);
5430 /******************************************************************************
5431 * GetPrinterDataExW (WINSPOOL.@)
5433 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5434 LPCWSTR pValueName, LPDWORD pType,
5435 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5437 opened_printer_t *printer;
5438 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5441 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5442 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5444 printer = get_opened_printer(hPrinter);
5445 if(!printer) return ERROR_INVALID_HANDLE;
5447 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5448 if (ret) return ret;
5450 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5452 if (printer->name) {
5454 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5456 RegCloseKey(hkeyPrinters);
5459 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5460 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5461 RegCloseKey(hkeyPrinter);
5462 RegCloseKey(hkeyPrinters);
5467 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5468 0, pType, pData, pcbNeeded);
5470 if (!ret && !pData) ret = ERROR_MORE_DATA;
5472 RegCloseKey(hkeySubkey);
5473 RegCloseKey(hkeyPrinter);
5474 RegCloseKey(hkeyPrinters);
5476 TRACE("--> %d\n", ret);
5480 /******************************************************************************
5481 * GetPrinterDataA (WINSPOOL.@)
5483 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5484 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5486 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5487 pData, nSize, pcbNeeded);
5490 /******************************************************************************
5491 * GetPrinterDataW (WINSPOOL.@)
5493 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5494 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5496 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5497 pData, nSize, pcbNeeded);
5500 /*******************************************************************************
5501 * EnumPrinterDataExW [WINSPOOL.@]
5503 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5504 LPBYTE pEnumValues, DWORD cbEnumValues,
5505 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5507 HKEY hkPrinter, hkSubKey;
5508 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5509 cbValueNameLen, cbMaxValueLen, cbValueLen,
5514 PPRINTER_ENUM_VALUESW ppev;
5516 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5518 if (pKeyName == NULL || *pKeyName == 0)
5519 return ERROR_INVALID_PARAMETER;
5521 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5522 if (ret != ERROR_SUCCESS)
5524 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5529 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5530 if (ret != ERROR_SUCCESS)
5532 r = RegCloseKey (hkPrinter);
5533 if (r != ERROR_SUCCESS)
5534 WARN ("RegCloseKey returned %i\n", r);
5535 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5536 debugstr_w (pKeyName), ret);
5540 ret = RegCloseKey (hkPrinter);
5541 if (ret != ERROR_SUCCESS)
5543 ERR ("RegCloseKey returned %i\n", ret);
5544 r = RegCloseKey (hkSubKey);
5545 if (r != ERROR_SUCCESS)
5546 WARN ("RegCloseKey returned %i\n", r);
5550 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5551 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5552 if (ret != ERROR_SUCCESS)
5554 r = RegCloseKey (hkSubKey);
5555 if (r != ERROR_SUCCESS)
5556 WARN ("RegCloseKey returned %i\n", r);
5557 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5561 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5562 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5564 if (cValues == 0) /* empty key */
5566 r = RegCloseKey (hkSubKey);
5567 if (r != ERROR_SUCCESS)
5568 WARN ("RegCloseKey returned %i\n", r);
5569 *pcbEnumValues = *pnEnumValues = 0;
5570 return ERROR_SUCCESS;
5573 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5575 hHeap = GetProcessHeap ();
5578 ERR ("GetProcessHeap failed\n");
5579 r = RegCloseKey (hkSubKey);
5580 if (r != ERROR_SUCCESS)
5581 WARN ("RegCloseKey returned %i\n", r);
5582 return ERROR_OUTOFMEMORY;
5585 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5586 if (lpValueName == NULL)
5588 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5589 r = RegCloseKey (hkSubKey);
5590 if (r != ERROR_SUCCESS)
5591 WARN ("RegCloseKey returned %i\n", r);
5592 return ERROR_OUTOFMEMORY;
5595 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5596 if (lpValue == NULL)
5598 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5599 if (HeapFree (hHeap, 0, lpValueName) == 0)
5600 WARN ("HeapFree failed with code %i\n", GetLastError ());
5601 r = RegCloseKey (hkSubKey);
5602 if (r != ERROR_SUCCESS)
5603 WARN ("RegCloseKey returned %i\n", r);
5604 return ERROR_OUTOFMEMORY;
5607 TRACE ("pass 1: calculating buffer required for all names and values\n");
5609 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5611 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5613 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5615 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5616 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5617 NULL, NULL, lpValue, &cbValueLen);
5618 if (ret != ERROR_SUCCESS)
5620 if (HeapFree (hHeap, 0, lpValue) == 0)
5621 WARN ("HeapFree failed with code %i\n", GetLastError ());
5622 if (HeapFree (hHeap, 0, lpValueName) == 0)
5623 WARN ("HeapFree failed with code %i\n", GetLastError ());
5624 r = RegCloseKey (hkSubKey);
5625 if (r != ERROR_SUCCESS)
5626 WARN ("RegCloseKey returned %i\n", r);
5627 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5631 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5632 debugstr_w (lpValueName), dwIndex,
5633 cbValueNameLen + 1, cbValueLen);
5635 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5636 cbBufSize += cbValueLen;
5639 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5641 *pcbEnumValues = cbBufSize;
5642 *pnEnumValues = cValues;
5644 if (cbEnumValues < cbBufSize) /* buffer too small */
5646 if (HeapFree (hHeap, 0, lpValue) == 0)
5647 WARN ("HeapFree failed with code %i\n", GetLastError ());
5648 if (HeapFree (hHeap, 0, lpValueName) == 0)
5649 WARN ("HeapFree failed with code %i\n", GetLastError ());
5650 r = RegCloseKey (hkSubKey);
5651 if (r != ERROR_SUCCESS)
5652 WARN ("RegCloseKey returned %i\n", r);
5653 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5654 return ERROR_MORE_DATA;
5657 TRACE ("pass 2: copying all names and values to buffer\n");
5659 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5660 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5662 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5664 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5665 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5666 NULL, &dwType, lpValue, &cbValueLen);
5667 if (ret != ERROR_SUCCESS)
5669 if (HeapFree (hHeap, 0, lpValue) == 0)
5670 WARN ("HeapFree failed with code %i\n", GetLastError ());
5671 if (HeapFree (hHeap, 0, lpValueName) == 0)
5672 WARN ("HeapFree failed with code %i\n", GetLastError ());
5673 r = RegCloseKey (hkSubKey);
5674 if (r != ERROR_SUCCESS)
5675 WARN ("RegCloseKey returned %i\n", r);
5676 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5680 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5681 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5682 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5683 pEnumValues += cbValueNameLen;
5685 /* return # of *bytes* (including trailing \0), not # of chars */
5686 ppev[dwIndex].cbValueName = cbValueNameLen;
5688 ppev[dwIndex].dwType = dwType;
5690 memcpy (pEnumValues, lpValue, cbValueLen);
5691 ppev[dwIndex].pData = pEnumValues;
5692 pEnumValues += cbValueLen;
5694 ppev[dwIndex].cbData = cbValueLen;
5696 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5697 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5700 if (HeapFree (hHeap, 0, lpValue) == 0)
5702 ret = GetLastError ();
5703 ERR ("HeapFree failed with code %i\n", ret);
5704 if (HeapFree (hHeap, 0, lpValueName) == 0)
5705 WARN ("HeapFree failed with code %i\n", GetLastError ());
5706 r = RegCloseKey (hkSubKey);
5707 if (r != ERROR_SUCCESS)
5708 WARN ("RegCloseKey returned %i\n", r);
5712 if (HeapFree (hHeap, 0, lpValueName) == 0)
5714 ret = GetLastError ();
5715 ERR ("HeapFree failed with code %i\n", ret);
5716 r = RegCloseKey (hkSubKey);
5717 if (r != ERROR_SUCCESS)
5718 WARN ("RegCloseKey returned %i\n", r);
5722 ret = RegCloseKey (hkSubKey);
5723 if (ret != ERROR_SUCCESS)
5725 ERR ("RegCloseKey returned %i\n", ret);
5729 return ERROR_SUCCESS;
5732 /*******************************************************************************
5733 * EnumPrinterDataExA [WINSPOOL.@]
5735 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5736 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5737 * what Windows 2000 SP1 does.
5740 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5741 LPBYTE pEnumValues, DWORD cbEnumValues,
5742 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5746 DWORD ret, dwIndex, dwBufSize;
5750 TRACE ("%p %s\n", hPrinter, pKeyName);
5752 if (pKeyName == NULL || *pKeyName == 0)
5753 return ERROR_INVALID_PARAMETER;
5755 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5758 ret = GetLastError ();
5759 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5763 hHeap = GetProcessHeap ();
5766 ERR ("GetProcessHeap failed\n");
5767 return ERROR_OUTOFMEMORY;
5770 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5771 if (pKeyNameW == NULL)
5773 ERR ("Failed to allocate %i bytes from process heap\n",
5774 (LONG)(len * sizeof (WCHAR)));
5775 return ERROR_OUTOFMEMORY;
5778 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5780 ret = GetLastError ();
5781 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5782 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5783 WARN ("HeapFree failed with code %i\n", GetLastError ());
5787 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5788 pcbEnumValues, pnEnumValues);
5789 if (ret != ERROR_SUCCESS)
5791 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5792 WARN ("HeapFree failed with code %i\n", GetLastError ());
5793 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5797 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5799 ret = GetLastError ();
5800 ERR ("HeapFree failed with code %i\n", ret);
5804 if (*pnEnumValues == 0) /* empty key */
5805 return ERROR_SUCCESS;
5808 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5810 PPRINTER_ENUM_VALUESW ppev =
5811 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5813 if (dwBufSize < ppev->cbValueName)
5814 dwBufSize = ppev->cbValueName;
5816 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5817 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5818 dwBufSize = ppev->cbData;
5821 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5823 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5824 if (pBuffer == NULL)
5826 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5827 return ERROR_OUTOFMEMORY;
5830 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5832 PPRINTER_ENUM_VALUESW ppev =
5833 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5835 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5836 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5840 ret = GetLastError ();
5841 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5842 if (HeapFree (hHeap, 0, pBuffer) == 0)
5843 WARN ("HeapFree failed with code %i\n", GetLastError ());
5847 memcpy (ppev->pValueName, pBuffer, len);
5849 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5851 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5852 ppev->dwType != REG_MULTI_SZ)
5855 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5856 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5859 ret = GetLastError ();
5860 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5861 if (HeapFree (hHeap, 0, pBuffer) == 0)
5862 WARN ("HeapFree failed with code %i\n", GetLastError ());
5866 memcpy (ppev->pData, pBuffer, len);
5868 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5869 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5872 if (HeapFree (hHeap, 0, pBuffer) == 0)
5874 ret = GetLastError ();
5875 ERR ("HeapFree failed with code %i\n", ret);
5879 return ERROR_SUCCESS;
5882 /******************************************************************************
5883 * AbortPrinter (WINSPOOL.@)
5885 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5887 FIXME("(%p), stub!\n", hPrinter);
5891 /******************************************************************************
5892 * AddPortA (WINSPOOL.@)
5897 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5899 LPWSTR nameW = NULL;
5900 LPWSTR monitorW = NULL;
5904 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5907 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5908 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5909 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5913 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5914 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5915 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5917 res = AddPortW(nameW, hWnd, monitorW);
5918 HeapFree(GetProcessHeap(), 0, nameW);
5919 HeapFree(GetProcessHeap(), 0, monitorW);
5923 /******************************************************************************
5924 * AddPortW (WINSPOOL.@)
5926 * Add a Port for a specific Monitor
5929 * pName [I] Servername or NULL (local Computer)
5930 * hWnd [I] Handle to parent Window for the Dialog-Box
5931 * pMonitorName [I] Name of the Monitor that manage the Port
5938 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5940 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5942 if ((backend == NULL) && !load_backend()) return FALSE;
5944 if (!pMonitorName) {
5945 SetLastError(RPC_X_NULL_REF_POINTER);
5949 return backend->fpAddPort(pName, hWnd, pMonitorName);
5952 /******************************************************************************
5953 * AddPortExA (WINSPOOL.@)
5958 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5961 PORT_INFO_2A * pi2A;
5962 LPWSTR nameW = NULL;
5963 LPWSTR monitorW = NULL;
5967 pi2A = (PORT_INFO_2A *) pBuffer;
5969 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5970 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5972 if ((level < 1) || (level > 2)) {
5973 SetLastError(ERROR_INVALID_LEVEL);
5978 SetLastError(ERROR_INVALID_PARAMETER);
5983 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5984 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5985 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5989 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5990 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5991 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5994 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5996 if (pi2A->pPortName) {
5997 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5998 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5999 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6003 if (pi2A->pMonitorName) {
6004 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6005 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6006 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6009 if (pi2A->pDescription) {
6010 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6011 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6012 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6014 pi2W.fPortType = pi2A->fPortType;
6015 pi2W.Reserved = pi2A->Reserved;
6018 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6020 HeapFree(GetProcessHeap(), 0, nameW);
6021 HeapFree(GetProcessHeap(), 0, monitorW);
6022 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6023 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6024 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6029 /******************************************************************************
6030 * AddPortExW (WINSPOOL.@)
6032 * Add a Port for a specific Monitor, without presenting a user interface
6035 * pName [I] Servername or NULL (local Computer)
6036 * level [I] Structure-Level (1 or 2) for pBuffer
6037 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6038 * pMonitorName [I] Name of the Monitor that manage the Port
6045 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6049 pi2 = (PORT_INFO_2W *) pBuffer;
6051 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6052 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6053 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6054 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6056 if ((backend == NULL) && !load_backend()) return FALSE;
6058 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6059 SetLastError(ERROR_INVALID_PARAMETER);
6063 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6066 /******************************************************************************
6067 * AddPrinterConnectionA (WINSPOOL.@)
6069 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6071 FIXME("%s\n", debugstr_a(pName));
6075 /******************************************************************************
6076 * AddPrinterConnectionW (WINSPOOL.@)
6078 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6080 FIXME("%s\n", debugstr_w(pName));
6084 /******************************************************************************
6085 * AddPrinterDriverExW (WINSPOOL.@)
6087 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6090 * pName [I] Servername or NULL (local Computer)
6091 * level [I] Level for the supplied DRIVER_INFO_*W struct
6092 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6093 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6100 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6102 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6104 if ((backend == NULL) && !load_backend()) return FALSE;
6106 if (level < 2 || level == 5 || level == 7 || level > 8) {
6107 SetLastError(ERROR_INVALID_LEVEL);
6112 SetLastError(ERROR_INVALID_PARAMETER);
6116 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6119 /******************************************************************************
6120 * AddPrinterDriverExA (WINSPOOL.@)
6122 * See AddPrinterDriverExW.
6125 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6127 DRIVER_INFO_8A *diA;
6129 LPWSTR nameW = NULL;
6134 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6136 diA = (DRIVER_INFO_8A *) pDriverInfo;
6137 ZeroMemory(&diW, sizeof(diW));
6139 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6140 SetLastError(ERROR_INVALID_LEVEL);
6145 SetLastError(ERROR_INVALID_PARAMETER);
6149 /* convert servername to unicode */
6151 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6152 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6153 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6157 diW.cVersion = diA->cVersion;
6160 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6161 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6162 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6165 if (diA->pEnvironment) {
6166 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6167 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6168 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6171 if (diA->pDriverPath) {
6172 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6173 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6174 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6177 if (diA->pDataFile) {
6178 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6179 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6180 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6183 if (diA->pConfigFile) {
6184 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6185 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6186 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6189 if ((Level > 2) && diA->pDependentFiles) {
6190 lenA = multi_sz_lenA(diA->pDependentFiles);
6191 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6192 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6193 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6196 if ((Level > 2) && diA->pMonitorName) {
6197 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6198 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6199 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6202 if ((Level > 3) && diA->pDefaultDataType) {
6203 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6204 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6205 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6208 if ((Level > 3) && diA->pszzPreviousNames) {
6209 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6210 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6211 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6212 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6215 if ((Level > 5) && diA->pszMfgName) {
6216 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6217 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6218 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6221 if ((Level > 5) && diA->pszOEMUrl) {
6222 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6223 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6224 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6227 if ((Level > 5) && diA->pszHardwareID) {
6228 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6229 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6230 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6233 if ((Level > 5) && diA->pszProvider) {
6234 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6235 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6236 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6240 FIXME("level %u is incomplete\n", Level);
6243 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6244 TRACE("got %u with %u\n", res, GetLastError());
6245 HeapFree(GetProcessHeap(), 0, nameW);
6246 HeapFree(GetProcessHeap(), 0, diW.pName);
6247 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6248 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6249 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6250 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6251 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6252 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6253 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6254 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6255 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6256 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6257 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6258 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6260 TRACE("=> %u with %u\n", res, GetLastError());
6264 /******************************************************************************
6265 * ConfigurePortA (WINSPOOL.@)
6267 * See ConfigurePortW.
6270 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6272 LPWSTR nameW = NULL;
6273 LPWSTR portW = NULL;
6277 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6279 /* convert servername to unicode */
6281 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6282 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6283 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6286 /* convert portname to unicode */
6288 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6289 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6290 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6293 res = ConfigurePortW(nameW, hWnd, portW);
6294 HeapFree(GetProcessHeap(), 0, nameW);
6295 HeapFree(GetProcessHeap(), 0, portW);
6299 /******************************************************************************
6300 * ConfigurePortW (WINSPOOL.@)
6302 * Display the Configuration-Dialog for a specific Port
6305 * pName [I] Servername or NULL (local Computer)
6306 * hWnd [I] Handle to parent Window for the Dialog-Box
6307 * pPortName [I] Name of the Port, that should be configured
6314 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6317 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6319 if ((backend == NULL) && !load_backend()) return FALSE;
6322 SetLastError(RPC_X_NULL_REF_POINTER);
6326 return backend->fpConfigurePort(pName, hWnd, pPortName);
6329 /******************************************************************************
6330 * ConnectToPrinterDlg (WINSPOOL.@)
6332 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6334 FIXME("%p %x\n", hWnd, Flags);
6338 /******************************************************************************
6339 * DeletePrinterConnectionA (WINSPOOL.@)
6341 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6343 FIXME("%s\n", debugstr_a(pName));
6347 /******************************************************************************
6348 * DeletePrinterConnectionW (WINSPOOL.@)
6350 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6352 FIXME("%s\n", debugstr_w(pName));
6356 /******************************************************************************
6357 * DeletePrinterDriverExW (WINSPOOL.@)
6359 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6360 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6365 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6366 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6368 if(pName && pName[0])
6370 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6371 SetLastError(ERROR_INVALID_PARAMETER);
6377 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6378 SetLastError(ERROR_INVALID_PARAMETER);
6382 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6386 ERR("Can't open drivers key\n");
6390 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6393 RegCloseKey(hkey_drivers);
6398 /******************************************************************************
6399 * DeletePrinterDriverExA (WINSPOOL.@)
6401 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6402 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6404 UNICODE_STRING NameW, EnvW, DriverW;
6407 asciitounicode(&NameW, pName);
6408 asciitounicode(&EnvW, pEnvironment);
6409 asciitounicode(&DriverW, pDriverName);
6411 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6413 RtlFreeUnicodeString(&DriverW);
6414 RtlFreeUnicodeString(&EnvW);
6415 RtlFreeUnicodeString(&NameW);
6420 /******************************************************************************
6421 * DeletePrinterDataExW (WINSPOOL.@)
6423 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6426 FIXME("%p %s %s\n", hPrinter,
6427 debugstr_w(pKeyName), debugstr_w(pValueName));
6428 return ERROR_INVALID_PARAMETER;
6431 /******************************************************************************
6432 * DeletePrinterDataExA (WINSPOOL.@)
6434 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6437 FIXME("%p %s %s\n", hPrinter,
6438 debugstr_a(pKeyName), debugstr_a(pValueName));
6439 return ERROR_INVALID_PARAMETER;
6442 /******************************************************************************
6443 * DeletePrintProcessorA (WINSPOOL.@)
6445 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6447 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6448 debugstr_a(pPrintProcessorName));
6452 /******************************************************************************
6453 * DeletePrintProcessorW (WINSPOOL.@)
6455 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6457 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6458 debugstr_w(pPrintProcessorName));
6462 /******************************************************************************
6463 * DeletePrintProvidorA (WINSPOOL.@)
6465 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6467 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6468 debugstr_a(pPrintProviderName));
6472 /******************************************************************************
6473 * DeletePrintProvidorW (WINSPOOL.@)
6475 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6477 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6478 debugstr_w(pPrintProviderName));
6482 /******************************************************************************
6483 * EnumFormsA (WINSPOOL.@)
6485 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6486 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6488 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6489 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6493 /******************************************************************************
6494 * EnumFormsW (WINSPOOL.@)
6496 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6497 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6499 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6500 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6504 /*****************************************************************************
6505 * EnumMonitorsA [WINSPOOL.@]
6507 * See EnumMonitorsW.
6510 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6511 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6514 LPBYTE bufferW = NULL;
6515 LPWSTR nameW = NULL;
6517 DWORD numentries = 0;
6520 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6521 cbBuf, pcbNeeded, pcReturned);
6523 /* convert servername to unicode */
6525 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6526 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6527 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6529 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6530 needed = cbBuf * sizeof(WCHAR);
6531 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6532 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6534 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6535 if (pcbNeeded) needed = *pcbNeeded;
6536 /* HeapReAlloc return NULL, when bufferW was NULL */
6537 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6538 HeapAlloc(GetProcessHeap(), 0, needed);
6540 /* Try again with the large Buffer */
6541 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6543 numentries = pcReturned ? *pcReturned : 0;
6546 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6547 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6550 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6551 DWORD entrysize = 0;
6554 LPMONITOR_INFO_2W mi2w;
6555 LPMONITOR_INFO_2A mi2a;
6557 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6558 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6560 /* First pass: calculate the size for all Entries */
6561 mi2w = (LPMONITOR_INFO_2W) bufferW;
6562 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6564 while (index < numentries) {
6566 needed += entrysize; /* MONITOR_INFO_?A */
6567 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6569 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6570 NULL, 0, NULL, NULL);
6572 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6573 NULL, 0, NULL, NULL);
6574 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6575 NULL, 0, NULL, NULL);
6577 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6578 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6579 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6582 /* check for errors and quit on failure */
6583 if (cbBuf < needed) {
6584 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6588 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6589 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6590 cbBuf -= len ; /* free Bytes in the user-Buffer */
6591 mi2w = (LPMONITOR_INFO_2W) bufferW;
6592 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6594 /* Second Pass: Fill the User Buffer (if we have one) */
6595 while ((index < numentries) && pMonitors) {
6597 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6599 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6600 ptr, cbBuf , NULL, NULL);
6604 mi2a->pEnvironment = ptr;
6605 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6606 ptr, cbBuf, NULL, NULL);
6610 mi2a->pDLLName = ptr;
6611 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6612 ptr, cbBuf, NULL, NULL);
6616 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6617 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6618 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6622 if (pcbNeeded) *pcbNeeded = needed;
6623 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6625 HeapFree(GetProcessHeap(), 0, nameW);
6626 HeapFree(GetProcessHeap(), 0, bufferW);
6628 TRACE("returning %d with %d (%d byte for %d entries)\n",
6629 (res), GetLastError(), needed, numentries);
6635 /*****************************************************************************
6636 * EnumMonitorsW [WINSPOOL.@]
6638 * Enumerate available Port-Monitors
6641 * pName [I] Servername or NULL (local Computer)
6642 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6643 * pMonitors [O] PTR to Buffer that receives the Result
6644 * cbBuf [I] Size of Buffer at pMonitors
6645 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6646 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6650 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6653 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6654 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6657 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6658 cbBuf, pcbNeeded, pcReturned);
6660 if ((backend == NULL) && !load_backend()) return FALSE;
6662 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6663 SetLastError(RPC_X_NULL_REF_POINTER);
6667 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6670 /******************************************************************************
6671 * SpoolerInit (WINSPOOL.@)
6673 * Initialize the Spooler
6680 * The function fails on windows, when the spooler service is not running
6683 BOOL WINAPI SpoolerInit(void)
6686 if ((backend == NULL) && !load_backend()) return FALSE;
6690 /******************************************************************************
6691 * XcvDataW (WINSPOOL.@)
6693 * Execute commands in the Printmonitor DLL
6696 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6697 * pszDataName [i] Name of the command to execute
6698 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6699 * cbInputData [i] Size in Bytes of Buffer at pInputData
6700 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6701 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6702 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6703 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6710 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6711 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6713 * Minimal List of commands, that a Printmonitor DLL should support:
6715 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6716 *| "AddPort" : Add a Port
6717 *| "DeletePort": Delete a Port
6719 * Many Printmonitors support additional commands. Examples for localspl.dll:
6720 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6721 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6724 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6725 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6726 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6728 opened_printer_t *printer;
6730 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6731 pInputData, cbInputData, pOutputData,
6732 cbOutputData, pcbOutputNeeded, pdwStatus);
6734 if ((backend == NULL) && !load_backend()) return FALSE;
6736 printer = get_opened_printer(hXcv);
6737 if (!printer || (!printer->backend_printer)) {
6738 SetLastError(ERROR_INVALID_HANDLE);
6742 if (!pcbOutputNeeded) {
6743 SetLastError(ERROR_INVALID_PARAMETER);
6747 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6748 SetLastError(RPC_X_NULL_REF_POINTER);
6752 *pcbOutputNeeded = 0;
6754 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6755 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6759 /*****************************************************************************
6760 * EnumPrinterDataA [WINSPOOL.@]
6763 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR 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 * EnumPrinterDataW [WINSPOOL.@]
6776 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6777 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6778 DWORD cbData, LPDWORD pcbData )
6780 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6781 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6782 return ERROR_NO_MORE_ITEMS;
6785 /*****************************************************************************
6786 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6789 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6790 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6791 LPDWORD pcbNeeded, LPDWORD pcReturned)
6793 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6794 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6795 pcbNeeded, pcReturned);
6799 /*****************************************************************************
6800 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6803 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6804 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6805 LPDWORD pcbNeeded, LPDWORD pcReturned)
6807 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6808 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6809 pcbNeeded, pcReturned);
6813 /*****************************************************************************
6814 * EnumPrintProcessorsA [WINSPOOL.@]
6816 * See EnumPrintProcessorsW.
6819 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6820 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6823 LPBYTE bufferW = NULL;
6824 LPWSTR nameW = NULL;
6827 DWORD numentries = 0;
6830 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6831 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6833 /* convert names to unicode */
6835 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6836 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6837 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6840 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6841 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6842 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6845 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6846 needed = cbBuf * sizeof(WCHAR);
6847 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6848 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6850 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6851 if (pcbNeeded) needed = *pcbNeeded;
6852 /* HeapReAlloc return NULL, when bufferW was NULL */
6853 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6854 HeapAlloc(GetProcessHeap(), 0, needed);
6856 /* Try again with the large Buffer */
6857 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6859 numentries = pcReturned ? *pcReturned : 0;
6863 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6866 PPRINTPROCESSOR_INFO_1W ppiw;
6867 PPRINTPROCESSOR_INFO_1A ppia;
6869 /* First pass: calculate the size for all Entries */
6870 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6871 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6873 while (index < numentries) {
6875 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6876 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6878 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6879 NULL, 0, NULL, NULL);
6881 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6882 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6885 /* check for errors and quit on failure */
6886 if (cbBuf < needed) {
6887 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6892 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6893 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6894 cbBuf -= len ; /* free Bytes in the user-Buffer */
6895 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6896 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6898 /* Second Pass: Fill the User Buffer (if we have one) */
6899 while ((index < numentries) && pPPInfo) {
6901 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6903 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6904 ptr, cbBuf , NULL, NULL);
6908 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6909 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6914 if (pcbNeeded) *pcbNeeded = needed;
6915 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6917 HeapFree(GetProcessHeap(), 0, nameW);
6918 HeapFree(GetProcessHeap(), 0, envW);
6919 HeapFree(GetProcessHeap(), 0, bufferW);
6921 TRACE("returning %d with %d (%d byte for %d entries)\n",
6922 (res), GetLastError(), needed, numentries);
6927 /*****************************************************************************
6928 * EnumPrintProcessorsW [WINSPOOL.@]
6930 * Enumerate available Print Processors
6933 * pName [I] Servername or NULL (local Computer)
6934 * pEnvironment [I] Printing-Environment or NULL (Default)
6935 * Level [I] Structure-Level (Only 1 is allowed)
6936 * pPPInfo [O] PTR to Buffer that receives the Result
6937 * cbBuf [I] Size of Buffer at pPPInfo
6938 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6939 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6943 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6946 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6947 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6950 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6951 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6953 if ((backend == NULL) && !load_backend()) return FALSE;
6955 if (!pcbNeeded || !pcReturned) {
6956 SetLastError(RPC_X_NULL_REF_POINTER);
6960 if (!pPPInfo && (cbBuf > 0)) {
6961 SetLastError(ERROR_INVALID_USER_BUFFER);
6965 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6966 cbBuf, pcbNeeded, pcReturned);
6969 /*****************************************************************************
6970 * ExtDeviceMode [WINSPOOL.@]
6973 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6974 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6977 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6978 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6979 debugstr_a(pProfile), fMode);
6983 /*****************************************************************************
6984 * FindClosePrinterChangeNotification [WINSPOOL.@]
6987 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6989 FIXME("Stub: %p\n", hChange);
6993 /*****************************************************************************
6994 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6997 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6998 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7000 FIXME("Stub: %p %x %x %p\n",
7001 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7002 return INVALID_HANDLE_VALUE;
7005 /*****************************************************************************
7006 * FindNextPrinterChangeNotification [WINSPOOL.@]
7009 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7010 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7012 FIXME("Stub: %p %p %p %p\n",
7013 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7017 /*****************************************************************************
7018 * FreePrinterNotifyInfo [WINSPOOL.@]
7021 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7023 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7027 /*****************************************************************************
7030 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7031 * ansi depending on the unicode parameter.
7033 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7043 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7046 memcpy(ptr, str, *size);
7053 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7056 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7063 /*****************************************************************************
7066 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7067 LPDWORD pcbNeeded, BOOL unicode)
7069 DWORD size, left = cbBuf;
7070 BOOL space = (cbBuf > 0);
7077 ji1->JobId = job->job_id;
7080 string_to_buf(job->document_title, ptr, left, &size, unicode);
7081 if(space && size <= left)
7083 ji1->pDocument = (LPWSTR)ptr;
7091 if (job->printer_name)
7093 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7094 if(space && size <= left)
7096 ji1->pPrinterName = (LPWSTR)ptr;
7108 /*****************************************************************************
7111 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7112 LPDWORD pcbNeeded, BOOL unicode)
7114 DWORD size, left = cbBuf;
7116 BOOL space = (cbBuf > 0);
7125 ji2->JobId = job->job_id;
7128 string_to_buf(job->document_title, ptr, left, &size, unicode);
7129 if(space && size <= left)
7131 ji2->pDocument = (LPWSTR)ptr;
7139 if (job->printer_name)
7141 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7142 if(space && size <= left)
7144 ji2->pPrinterName = (LPWSTR)ptr;
7157 dmA = DEVMODEdupWtoA(job->devmode);
7158 devmode = (LPDEVMODEW) dmA;
7159 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7163 devmode = job->devmode;
7164 size = devmode->dmSize + devmode->dmDriverExtra;
7168 FIXME("Can't convert DEVMODE W to A\n");
7171 /* align DEVMODE to a DWORD boundary */
7172 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7178 memcpy(ptr, devmode, size-shift);
7179 ji2->pDevMode = (LPDEVMODEW)ptr;
7180 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7193 /*****************************************************************************
7196 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7197 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7200 DWORD needed = 0, size;
7204 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7206 EnterCriticalSection(&printer_handles_cs);
7207 job = get_job(hPrinter, JobId);
7214 size = sizeof(JOB_INFO_1W);
7219 memset(pJob, 0, size);
7223 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7228 size = sizeof(JOB_INFO_2W);
7233 memset(pJob, 0, size);
7237 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7242 size = sizeof(JOB_INFO_3);
7246 memset(pJob, 0, size);
7255 SetLastError(ERROR_INVALID_LEVEL);
7259 *pcbNeeded = needed;
7261 LeaveCriticalSection(&printer_handles_cs);
7265 /*****************************************************************************
7266 * GetJobA [WINSPOOL.@]
7269 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7270 DWORD cbBuf, LPDWORD pcbNeeded)
7272 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7275 /*****************************************************************************
7276 * GetJobW [WINSPOOL.@]
7279 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7280 DWORD cbBuf, LPDWORD pcbNeeded)
7282 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7285 /*****************************************************************************
7288 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7290 char *unixname, *queue, *cmd;
7291 char fmt[] = "lpr -P'%s' '%s'";
7295 if(!(unixname = wine_get_unix_file_name(filename)))
7298 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7299 queue = HeapAlloc(GetProcessHeap(), 0, len);
7300 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7302 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7303 sprintf(cmd, fmt, queue, unixname);
7305 TRACE("printing with: %s\n", cmd);
7308 HeapFree(GetProcessHeap(), 0, cmd);
7309 HeapFree(GetProcessHeap(), 0, queue);
7310 HeapFree(GetProcessHeap(), 0, unixname);
7314 /*****************************************************************************
7317 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7319 #ifdef SONAME_LIBCUPS
7322 char *unixname, *queue, *unix_doc_title;
7326 if(!(unixname = wine_get_unix_file_name(filename)))
7329 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7330 queue = HeapAlloc(GetProcessHeap(), 0, len);
7331 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7333 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7334 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7335 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7337 TRACE("printing via cups\n");
7338 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7339 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7340 HeapFree(GetProcessHeap(), 0, queue);
7341 HeapFree(GetProcessHeap(), 0, unixname);
7347 return schedule_lpr(printer_name, filename);
7351 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7358 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7362 if(HIWORD(wparam) == BN_CLICKED)
7364 if(LOWORD(wparam) == IDOK)
7367 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7370 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7371 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7373 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7375 WCHAR caption[200], message[200];
7378 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7379 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7380 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7381 if(mb_ret == IDCANCEL)
7383 HeapFree(GetProcessHeap(), 0, filename);
7387 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7388 if(hf == INVALID_HANDLE_VALUE)
7390 WCHAR caption[200], message[200];
7392 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7393 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7394 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7395 HeapFree(GetProcessHeap(), 0, filename);
7399 DeleteFileW(filename);
7400 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7402 EndDialog(hwnd, IDOK);
7405 if(LOWORD(wparam) == IDCANCEL)
7407 EndDialog(hwnd, IDCANCEL);
7416 /*****************************************************************************
7419 static BOOL get_filename(LPWSTR *filename)
7421 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7422 file_dlg_proc, (LPARAM)filename) == IDOK;
7425 /*****************************************************************************
7428 static BOOL schedule_file(LPCWSTR filename)
7430 LPWSTR output = NULL;
7432 if(get_filename(&output))
7435 TRACE("copy to %s\n", debugstr_w(output));
7436 r = CopyFileW(filename, output, FALSE);
7437 HeapFree(GetProcessHeap(), 0, output);
7443 /*****************************************************************************
7446 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7449 char *unixname, *cmdA;
7451 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7455 if(!(unixname = wine_get_unix_file_name(filename)))
7458 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7459 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7460 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7462 TRACE("printing with: %s\n", cmdA);
7464 if((file_fd = open(unixname, O_RDONLY)) == -1)
7469 ERR("pipe() failed!\n");
7479 /* reset signals that we previously set to SIG_IGN */
7480 signal(SIGPIPE, SIG_DFL);
7481 signal(SIGCHLD, SIG_DFL);
7483 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7487 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7488 write(fds[1], buf, no_read);
7493 if(file_fd != -1) close(file_fd);
7494 if(fds[0] != -1) close(fds[0]);
7495 if(fds[1] != -1) close(fds[1]);
7497 HeapFree(GetProcessHeap(), 0, cmdA);
7498 HeapFree(GetProcessHeap(), 0, unixname);
7505 /*****************************************************************************
7508 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7510 int in_fd, out_fd, no_read;
7513 char *unixname, *outputA;
7516 if(!(unixname = wine_get_unix_file_name(filename)))
7519 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7520 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7521 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7523 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7524 in_fd = open(unixname, O_RDONLY);
7525 if(out_fd == -1 || in_fd == -1)
7528 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7529 write(out_fd, buf, no_read);
7533 if(in_fd != -1) close(in_fd);
7534 if(out_fd != -1) close(out_fd);
7535 HeapFree(GetProcessHeap(), 0, outputA);
7536 HeapFree(GetProcessHeap(), 0, unixname);
7540 /*****************************************************************************
7541 * ScheduleJob [WINSPOOL.@]
7544 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7546 opened_printer_t *printer;
7548 struct list *cursor, *cursor2;
7550 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7551 EnterCriticalSection(&printer_handles_cs);
7552 printer = get_opened_printer(hPrinter);
7556 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7558 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7561 if(job->job_id != dwJobID) continue;
7563 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7564 if(hf != INVALID_HANDLE_VALUE)
7566 PRINTER_INFO_5W *pi5 = NULL;
7567 LPWSTR portname = job->portname;
7571 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7572 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7576 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7577 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7578 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7579 portname = pi5->pPortName;
7581 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7582 debugstr_w(portname));
7586 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7587 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7589 DWORD type, count = sizeof(output);
7590 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7593 if(output[0] == '|')
7595 ret = schedule_pipe(output + 1, job->filename);
7599 ret = schedule_unixfile(output, job->filename);
7601 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7603 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7605 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7607 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7609 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7611 ret = schedule_file(job->filename);
7615 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7617 HeapFree(GetProcessHeap(), 0, pi5);
7619 DeleteFileW(job->filename);
7621 list_remove(cursor);
7622 HeapFree(GetProcessHeap(), 0, job->document_title);
7623 HeapFree(GetProcessHeap(), 0, job->printer_name);
7624 HeapFree(GetProcessHeap(), 0, job->portname);
7625 HeapFree(GetProcessHeap(), 0, job->filename);
7626 HeapFree(GetProcessHeap(), 0, job->devmode);
7627 HeapFree(GetProcessHeap(), 0, job);
7631 LeaveCriticalSection(&printer_handles_cs);
7635 /*****************************************************************************
7636 * StartDocDlgA [WINSPOOL.@]
7638 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7640 UNICODE_STRING usBuffer;
7643 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7646 docW.cbSize = sizeof(docW);
7647 if (doc->lpszDocName)
7649 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7650 if (!(docW.lpszDocName = docnameW)) return NULL;
7652 if (doc->lpszOutput)
7654 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7655 if (!(docW.lpszOutput = outputW)) return NULL;
7657 if (doc->lpszDatatype)
7659 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7660 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7662 docW.fwType = doc->fwType;
7664 retW = StartDocDlgW(hPrinter, &docW);
7668 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7669 ret = HeapAlloc(GetProcessHeap(), 0, len);
7670 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7671 HeapFree(GetProcessHeap(), 0, retW);
7674 HeapFree(GetProcessHeap(), 0, datatypeW);
7675 HeapFree(GetProcessHeap(), 0, outputW);
7676 HeapFree(GetProcessHeap(), 0, docnameW);
7681 /*****************************************************************************
7682 * StartDocDlgW [WINSPOOL.@]
7684 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7685 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7686 * port is "FILE:". Also returns the full path if passed a relative path.
7688 * The caller should free the returned string from the process heap.
7690 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7695 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7697 PRINTER_INFO_5W *pi5;
7698 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7699 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7701 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7702 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7703 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7705 HeapFree(GetProcessHeap(), 0, pi5);
7708 HeapFree(GetProcessHeap(), 0, pi5);
7711 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7715 if (get_filename(&name))
7717 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7719 HeapFree(GetProcessHeap(), 0, name);
7722 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7723 GetFullPathNameW(name, len, ret, NULL);
7724 HeapFree(GetProcessHeap(), 0, name);
7729 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7732 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7733 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7735 attr = GetFileAttributesW(ret);
7736 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7738 HeapFree(GetProcessHeap(), 0, ret);