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 /* ################################ */
342 static int multi_sz_lenA(const char *str)
344 const char *ptr = str;
348 ptr += lstrlenA(ptr) + 1;
351 return ptr - str + 1;
355 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
358 /* If forcing, or no profile string entry for device yet, set the entry
360 * The always change entry if not WINEPS yet is discussable.
363 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
365 !strstr(qbuf,"WINEPS.DRV")
367 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
370 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
371 WriteProfileStringA("windows","device",buf);
372 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
373 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
376 HeapFree(GetProcessHeap(),0,buf);
380 static BOOL add_printer_driver(const char *name)
384 static char driver_9x[] = "wineps16.drv",
385 driver_nt[] = "wineps.drv",
386 env_9x[] = "Windows 4.0",
387 env_nt[] = "Windows NT x86",
388 data_file[] = "generic.ppd",
389 default_data_type[] = "RAW";
391 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
393 di3a.pName = (char *)name;
394 di3a.pEnvironment = env_nt;
395 di3a.pDriverPath = driver_nt;
396 di3a.pDataFile = data_file;
397 di3a.pConfigFile = driver_nt;
398 di3a.pDefaultDataType = default_data_type;
400 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
401 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
404 di3a.pEnvironment = env_9x;
405 di3a.pDriverPath = driver_9x;
406 di3a.pConfigFile = driver_9x;
407 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
408 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
413 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
414 debugstr_a(di3a.pEnvironment), GetLastError());
418 #ifdef SONAME_LIBCUPS
419 static typeof(cupsFreeDests) *pcupsFreeDests;
420 static typeof(cupsGetDests) *pcupsGetDests;
421 static typeof(cupsGetPPD) *pcupsGetPPD;
422 static typeof(cupsPrintFile) *pcupsPrintFile;
423 static void *cupshandle;
425 static BOOL CUPS_LoadPrinters(void)
428 BOOL hadprinter = FALSE, haddefault = FALSE;
430 PRINTER_INFO_2A pinfo2a;
432 HKEY hkeyPrinter, hkeyPrinters, hkey;
435 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
437 TRACE("%s\n", loaderror);
440 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
443 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
444 if (!p##x) return FALSE;
446 DYNCUPS(cupsFreeDests);
448 DYNCUPS(cupsGetDests);
449 DYNCUPS(cupsPrintFile);
452 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
454 ERR("Can't create Printers key\n");
458 nrofdests = pcupsGetDests(&dests);
459 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
460 for (i=0;i<nrofdests;i++) {
461 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
462 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
463 sprintf(port,"LPR:%s", dests[i].name);
464 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
465 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
466 sprintf(devline, "WINEPS.DRV,%s", port);
467 WriteProfileStringA("devices", dests[i].name, devline);
468 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
469 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
473 lstrcatA(devline, ",15,45");
474 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
475 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
476 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
480 HeapFree(GetProcessHeap(), 0, devline);
482 TRACE("Printer %d: %s\n", i, dests[i].name);
483 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
484 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
486 TRACE("Printer already exists\n");
487 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
488 RegCloseKey(hkeyPrinter);
490 static CHAR data_type[] = "RAW",
491 print_proc[] = "WinPrint",
492 comment[] = "WINEPS Printer using CUPS",
493 location[] = "<physical location of printer>",
494 params[] = "<parameters?>",
495 share_name[] = "<share name?>",
496 sep_file[] = "<sep file?>";
498 add_printer_driver(dests[i].name);
500 memset(&pinfo2a,0,sizeof(pinfo2a));
501 pinfo2a.pPrinterName = dests[i].name;
502 pinfo2a.pDatatype = data_type;
503 pinfo2a.pPrintProcessor = print_proc;
504 pinfo2a.pDriverName = dests[i].name;
505 pinfo2a.pComment = comment;
506 pinfo2a.pLocation = location;
507 pinfo2a.pPortName = port;
508 pinfo2a.pParameters = params;
509 pinfo2a.pShareName = share_name;
510 pinfo2a.pSepFile = sep_file;
512 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
513 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
514 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
517 HeapFree(GetProcessHeap(),0,port);
520 if (dests[i].is_default) {
521 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
525 if (hadprinter & !haddefault)
526 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
527 pcupsFreeDests(nrofdests, dests);
528 RegCloseKey(hkeyPrinters);
534 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
535 PRINTER_INFO_2A pinfo2a;
536 char *e,*s,*name,*prettyname,*devname;
537 BOOL ret = FALSE, set_default = FALSE;
538 char *port = NULL, *devline,*env_default;
539 HKEY hkeyPrinter, hkeyPrinters, hkey;
541 while (isspace(*pent)) pent++;
542 s = strchr(pent,':');
544 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
552 TRACE("name=%s entry=%s\n",name, pent);
554 if(ispunct(*name)) { /* a tc entry, not a real printer */
555 TRACE("skipping tc entry\n");
559 if(strstr(pent,":server")) { /* server only version so skip */
560 TRACE("skipping server entry\n");
564 /* Determine whether this is a postscript printer. */
567 env_default = getenv("PRINTER");
569 /* Get longest name, usually the one at the right for later display. */
570 while((s=strchr(prettyname,'|'))) {
573 while(isspace(*--e)) *e = '\0';
574 TRACE("\t%s\n", debugstr_a(prettyname));
575 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
576 for(prettyname = s+1; isspace(*prettyname); prettyname++)
579 e = prettyname + strlen(prettyname);
580 while(isspace(*--e)) *e = '\0';
581 TRACE("\t%s\n", debugstr_a(prettyname));
582 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
584 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
585 * if it is too long, we use it as comment below. */
586 devname = prettyname;
587 if (strlen(devname)>=CCHDEVICENAME-1)
589 if (strlen(devname)>=CCHDEVICENAME-1) {
594 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
595 sprintf(port,"LPR:%s",name);
597 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
598 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
599 sprintf(devline, "WINEPS.DRV,%s", port);
600 WriteProfileStringA("devices", devname, devline);
601 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
602 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
606 lstrcatA(devline, ",15,45");
607 WriteProfileStringA("PrinterPorts", devname, devline);
608 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
609 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
613 HeapFree(GetProcessHeap(),0,devline);
615 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
617 ERR("Can't create Printers key\n");
621 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
622 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
624 TRACE("Printer already exists\n");
625 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
626 RegCloseKey(hkeyPrinter);
628 static CHAR data_type[] = "RAW",
629 print_proc[] = "WinPrint",
630 comment[] = "WINEPS Printer using LPR",
631 params[] = "<parameters?>",
632 share_name[] = "<share name?>",
633 sep_file[] = "<sep file?>";
635 add_printer_driver(devname);
637 memset(&pinfo2a,0,sizeof(pinfo2a));
638 pinfo2a.pPrinterName = devname;
639 pinfo2a.pDatatype = data_type;
640 pinfo2a.pPrintProcessor = print_proc;
641 pinfo2a.pDriverName = devname;
642 pinfo2a.pComment = comment;
643 pinfo2a.pLocation = prettyname;
644 pinfo2a.pPortName = port;
645 pinfo2a.pParameters = params;
646 pinfo2a.pShareName = share_name;
647 pinfo2a.pSepFile = sep_file;
649 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
650 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
651 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
654 RegCloseKey(hkeyPrinters);
656 if (isfirst || set_default)
657 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
660 HeapFree(GetProcessHeap(), 0, port);
661 HeapFree(GetProcessHeap(), 0, name);
666 PRINTCAP_LoadPrinters(void) {
667 BOOL hadprinter = FALSE;
671 BOOL had_bash = FALSE;
673 f = fopen("/etc/printcap","r");
677 while(fgets(buf,sizeof(buf),f)) {
680 end=strchr(buf,'\n');
684 while(isspace(*start)) start++;
685 if(*start == '#' || *start == '\0')
688 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
689 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
690 HeapFree(GetProcessHeap(),0,pent);
694 if (end && *--end == '\\') {
701 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
704 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
710 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
711 HeapFree(GetProcessHeap(),0,pent);
717 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
720 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
721 (lstrlenW(value) + 1) * sizeof(WCHAR));
723 return ERROR_FILE_NOT_FOUND;
726 /******************************************************************
727 * get_servername_from_name (internal)
729 * for an external server, a copy of the serverpart from the full name is returned
732 static LPWSTR get_servername_from_name(LPCWSTR name)
736 WCHAR buffer[MAX_PATH];
739 if (name == NULL) return NULL;
740 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
742 server = strdupW(&name[2]); /* skip over both backslash */
743 if (server == NULL) return NULL;
745 /* strip '\' and the printername */
746 ptr = strchrW(server, '\\');
747 if (ptr) ptr[0] = '\0';
749 TRACE("found %s\n", debugstr_w(server));
751 len = sizeof(buffer)/sizeof(buffer[0]);
752 if (GetComputerNameW(buffer, &len)) {
753 if (lstrcmpW(buffer, server) == 0) {
754 /* The requested Servername is our computername */
755 HeapFree(GetProcessHeap(), 0, server);
762 /******************************************************************
763 * get_basename_from_name (internal)
765 * skip over the serverpart from the full name
768 static LPCWSTR get_basename_from_name(LPCWSTR name)
770 if (name == NULL) return NULL;
771 if ((name[0] == '\\') && (name[1] == '\\')) {
772 /* skip over the servername and search for the following '\' */
773 name = strchrW(&name[2], '\\');
774 if ((name) && (name[1])) {
775 /* found a separator ('\') followed by a name:
776 skip over the separator and return the rest */
781 /* no basename present (we found only a servername) */
788 /******************************************************************
789 * get_opened_printer_entry
790 * Get the first place empty in the opened printer table
793 * - pDefault is ignored
795 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
797 UINT_PTR handle = nb_printer_handles, i;
798 jobqueue_t *queue = NULL;
799 opened_printer_t *printer = NULL;
803 if ((backend == NULL) && !load_backend()) return NULL;
805 servername = get_servername_from_name(name);
807 FIXME("server %s not supported\n", debugstr_w(servername));
808 HeapFree(GetProcessHeap(), 0, servername);
809 SetLastError(ERROR_INVALID_PRINTER_NAME);
813 printername = get_basename_from_name(name);
814 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
816 /* an empty printername is invalid */
817 if (printername && (!printername[0])) {
818 SetLastError(ERROR_INVALID_PARAMETER);
822 EnterCriticalSection(&printer_handles_cs);
824 for (i = 0; i < nb_printer_handles; i++)
826 if (!printer_handles[i])
828 if(handle == nb_printer_handles)
833 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
834 queue = printer_handles[i]->queue;
838 if (handle >= nb_printer_handles)
840 opened_printer_t **new_array;
842 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
843 (nb_printer_handles + 16) * sizeof(*new_array) );
845 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
846 (nb_printer_handles + 16) * sizeof(*new_array) );
853 printer_handles = new_array;
854 nb_printer_handles += 16;
857 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
863 /* get a printer handle from the backend */
864 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
869 /* clone the base name. This is NULL for the printserver */
870 printer->printername = strdupW(printername);
872 /* clone the full name */
873 printer->name = strdupW(name);
874 if (name && (!printer->name)) {
880 printer->queue = queue;
883 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
884 if (!printer->queue) {
888 list_init(&printer->queue->jobs);
889 printer->queue->ref = 0;
891 InterlockedIncrement(&printer->queue->ref);
893 printer_handles[handle] = printer;
896 LeaveCriticalSection(&printer_handles_cs);
897 if (!handle && printer) {
898 /* Something failed: Free all resources */
899 HeapFree(GetProcessHeap(), 0, printer->printername);
900 HeapFree(GetProcessHeap(), 0, printer->name);
901 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
902 HeapFree(GetProcessHeap(), 0, printer);
905 return (HANDLE)handle;
908 /******************************************************************
910 * Get the pointer to the opened printer referred by the handle
912 static opened_printer_t *get_opened_printer(HANDLE hprn)
914 UINT_PTR idx = (UINT_PTR)hprn;
915 opened_printer_t *ret = NULL;
917 EnterCriticalSection(&printer_handles_cs);
919 if ((idx > 0) && (idx <= nb_printer_handles)) {
920 ret = printer_handles[idx - 1];
922 LeaveCriticalSection(&printer_handles_cs);
926 /******************************************************************
927 * get_opened_printer_name
928 * Get the pointer to the opened printer name referred by the handle
930 static LPCWSTR get_opened_printer_name(HANDLE hprn)
932 opened_printer_t *printer = get_opened_printer(hprn);
933 if(!printer) return NULL;
934 return printer->name;
937 /******************************************************************
938 * WINSPOOL_GetOpenedPrinterRegKey
941 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
943 LPCWSTR name = get_opened_printer_name(hPrinter);
947 if(!name) return ERROR_INVALID_HANDLE;
949 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
953 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
955 ERR("Can't find opened printer %s in registry\n",
957 RegCloseKey(hkeyPrinters);
958 return ERROR_INVALID_PRINTER_NAME; /* ? */
960 RegCloseKey(hkeyPrinters);
961 return ERROR_SUCCESS;
964 void WINSPOOL_LoadSystemPrinters(void)
966 HKEY hkey, hkeyPrinters;
968 DWORD needed, num, i;
969 WCHAR PrinterName[256];
972 /* This ensures that all printer entries have a valid Name value. If causes
973 problems later if they don't. If one is found to be missed we create one
974 and set it equal to the name of the key */
975 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
976 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
977 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
978 for(i = 0; i < num; i++) {
979 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
980 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
981 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
982 set_reg_szW(hkey, NameW, PrinterName);
989 RegCloseKey(hkeyPrinters);
992 /* We want to avoid calling AddPrinter on printers as much as
993 possible, because on cups printers this will (eventually) lead
994 to a call to cupsGetPPD which takes forever, even with non-cups
995 printers AddPrinter takes a while. So we'll tag all printers that
996 were automatically added last time around, if they still exist
997 we'll leave them be otherwise we'll delete them. */
998 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1000 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1001 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1002 for(i = 0; i < num; i++) {
1003 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1004 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1005 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1007 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1015 HeapFree(GetProcessHeap(), 0, pi);
1019 #ifdef SONAME_LIBCUPS
1020 done = CUPS_LoadPrinters();
1023 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1024 PRINTCAP_LoadPrinters();
1026 /* Now enumerate the list again and delete any printers that are still tagged */
1027 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1029 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1030 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1031 for(i = 0; i < num; i++) {
1032 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1033 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1034 BOOL delete_driver = FALSE;
1035 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1036 DWORD dw, type, size = sizeof(dw);
1037 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1038 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1039 DeletePrinter(hprn);
1040 delete_driver = TRUE;
1046 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1051 HeapFree(GetProcessHeap(), 0, pi);
1058 /******************************************************************
1061 * Get the pointer to the specified job.
1062 * Should hold the printer_handles_cs before calling.
1064 static job_t *get_job(HANDLE hprn, DWORD JobId)
1066 opened_printer_t *printer = get_opened_printer(hprn);
1069 if(!printer) return NULL;
1070 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1072 if(job->job_id == JobId)
1078 /***********************************************************
1081 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1084 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1087 Formname = (dmA->dmSize > off_formname);
1088 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1089 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1090 dmW->dmDeviceName, CCHDEVICENAME);
1092 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1093 dmA->dmSize - CCHDEVICENAME);
1095 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1096 off_formname - CCHDEVICENAME);
1097 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1098 dmW->dmFormName, CCHFORMNAME);
1099 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1100 (off_formname + CCHFORMNAME));
1103 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1104 dmA->dmDriverExtra);
1108 /***********************************************************
1110 * Creates an ansi copy of supplied devmode
1112 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1117 if (!dmW) return NULL;
1118 size = dmW->dmSize - CCHDEVICENAME -
1119 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1121 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1122 if (!dmA) return NULL;
1124 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1125 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1127 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1128 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1129 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1133 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1134 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1135 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1136 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1138 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1142 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1146 /******************************************************************
1147 * convert_printerinfo_W_to_A [internal]
1150 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1151 DWORD level, DWORD outlen, DWORD numentries)
1157 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1159 len = pi_sizeof[level] * numentries;
1160 ptr = (LPSTR) out + len;
1163 /* copy the numbers of all PRINTER_INFO_* first */
1164 memcpy(out, pPrintersW, len);
1166 while (id < numentries) {
1170 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1171 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1173 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1174 if (piW->pDescription) {
1175 piA->pDescription = ptr;
1176 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1177 ptr, outlen, NULL, NULL);
1183 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1184 ptr, outlen, NULL, NULL);
1188 if (piW->pComment) {
1189 piA->pComment = ptr;
1190 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1191 ptr, outlen, NULL, NULL);
1200 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1201 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1204 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1205 if (piW->pServerName) {
1206 piA->pServerName = ptr;
1207 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1208 ptr, outlen, NULL, NULL);
1212 if (piW->pPrinterName) {
1213 piA->pPrinterName = ptr;
1214 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1215 ptr, outlen, NULL, NULL);
1219 if (piW->pShareName) {
1220 piA->pShareName = ptr;
1221 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1222 ptr, outlen, NULL, NULL);
1226 if (piW->pPortName) {
1227 piA->pPortName = ptr;
1228 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1229 ptr, outlen, NULL, NULL);
1233 if (piW->pDriverName) {
1234 piA->pDriverName = ptr;
1235 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1236 ptr, outlen, NULL, NULL);
1240 if (piW->pComment) {
1241 piA->pComment = ptr;
1242 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1243 ptr, outlen, NULL, NULL);
1247 if (piW->pLocation) {
1248 piA->pLocation = ptr;
1249 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1250 ptr, outlen, NULL, NULL);
1255 dmA = DEVMODEdupWtoA(piW->pDevMode);
1257 /* align DEVMODEA to a DWORD boundary */
1258 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1262 piA->pDevMode = (LPDEVMODEA) ptr;
1263 len = dmA->dmSize + dmA->dmDriverExtra;
1264 memcpy(ptr, dmA, len);
1265 HeapFree(GetProcessHeap(), 0, dmA);
1271 if (piW->pSepFile) {
1272 piA->pSepFile = ptr;
1273 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1274 ptr, outlen, NULL, NULL);
1278 if (piW->pPrintProcessor) {
1279 piA->pPrintProcessor = ptr;
1280 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1281 ptr, outlen, NULL, NULL);
1285 if (piW->pDatatype) {
1286 piA->pDatatype = ptr;
1287 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1288 ptr, outlen, NULL, NULL);
1292 if (piW->pParameters) {
1293 piA->pParameters = ptr;
1294 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1295 ptr, outlen, NULL, NULL);
1299 if (piW->pSecurityDescriptor) {
1300 piA->pSecurityDescriptor = NULL;
1301 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1308 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1309 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1311 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1313 if (piW->pPrinterName) {
1314 piA->pPrinterName = ptr;
1315 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1316 ptr, outlen, NULL, NULL);
1320 if (piW->pServerName) {
1321 piA->pServerName = ptr;
1322 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1323 ptr, outlen, NULL, NULL);
1332 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1333 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1335 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1337 if (piW->pPrinterName) {
1338 piA->pPrinterName = ptr;
1339 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1340 ptr, outlen, NULL, NULL);
1344 if (piW->pPortName) {
1345 piA->pPortName = ptr;
1346 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1347 ptr, outlen, NULL, NULL);
1354 case 6: /* 6A and 6W are the same structure */
1359 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1360 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1362 TRACE("(%u) #%u\n", level, id);
1363 if (piW->pszObjectGUID) {
1364 piA->pszObjectGUID = ptr;
1365 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1366 ptr, outlen, NULL, NULL);
1375 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1376 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1379 TRACE("(%u) #%u\n", level, id);
1380 dmA = DEVMODEdupWtoA(piW->pDevMode);
1382 /* align DEVMODEA to a DWORD boundary */
1383 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1387 piA->pDevMode = (LPDEVMODEA) ptr;
1388 len = dmA->dmSize + dmA->dmDriverExtra;
1389 memcpy(ptr, dmA, len);
1390 HeapFree(GetProcessHeap(), 0, dmA);
1400 FIXME("for level %u\n", level);
1402 pPrintersW += pi_sizeof[level];
1403 out += pi_sizeof[level];
1408 /******************************************************************
1409 * convert_driverinfo_W_to_A [internal]
1412 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1413 DWORD level, DWORD outlen, DWORD numentries)
1419 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1421 len = di_sizeof[level] * numentries;
1422 ptr = (LPSTR) out + len;
1425 /* copy the numbers of all PRINTER_INFO_* first */
1426 memcpy(out, pDriversW, len);
1428 #define COPY_STRING(fld) \
1431 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1432 ptr += len; outlen -= len;\
1434 #define COPY_MULTIZ_STRING(fld) \
1435 { LPWSTR p = diW->fld; if (p){ \
1438 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1439 ptr += len; outlen -= len; p += len;\
1441 while(len > 1 && outlen > 0); \
1444 while (id < numentries)
1450 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1451 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1453 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1460 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1461 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1463 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1466 COPY_STRING(pEnvironment);
1467 COPY_STRING(pDriverPath);
1468 COPY_STRING(pDataFile);
1469 COPY_STRING(pConfigFile);
1474 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1475 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1477 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1480 COPY_STRING(pEnvironment);
1481 COPY_STRING(pDriverPath);
1482 COPY_STRING(pDataFile);
1483 COPY_STRING(pConfigFile);
1484 COPY_STRING(pHelpFile);
1485 COPY_MULTIZ_STRING(pDependentFiles);
1486 COPY_STRING(pMonitorName);
1487 COPY_STRING(pDefaultDataType);
1492 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1493 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) 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);
1506 COPY_MULTIZ_STRING(pszzPreviousNames);
1511 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1512 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1514 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1517 COPY_STRING(pEnvironment);
1518 COPY_STRING(pDriverPath);
1519 COPY_STRING(pDataFile);
1520 COPY_STRING(pConfigFile);
1525 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1526 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1528 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1531 COPY_STRING(pEnvironment);
1532 COPY_STRING(pDriverPath);
1533 COPY_STRING(pDataFile);
1534 COPY_STRING(pConfigFile);
1535 COPY_STRING(pHelpFile);
1536 COPY_MULTIZ_STRING(pDependentFiles);
1537 COPY_STRING(pMonitorName);
1538 COPY_STRING(pDefaultDataType);
1539 COPY_MULTIZ_STRING(pszzPreviousNames);
1540 COPY_STRING(pszMfgName);
1541 COPY_STRING(pszOEMUrl);
1542 COPY_STRING(pszHardwareID);
1543 COPY_STRING(pszProvider);
1548 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1549 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1551 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1554 COPY_STRING(pEnvironment);
1555 COPY_STRING(pDriverPath);
1556 COPY_STRING(pDataFile);
1557 COPY_STRING(pConfigFile);
1558 COPY_STRING(pHelpFile);
1559 COPY_MULTIZ_STRING(pDependentFiles);
1560 COPY_STRING(pMonitorName);
1561 COPY_STRING(pDefaultDataType);
1562 COPY_MULTIZ_STRING(pszzPreviousNames);
1563 COPY_STRING(pszMfgName);
1564 COPY_STRING(pszOEMUrl);
1565 COPY_STRING(pszHardwareID);
1566 COPY_STRING(pszProvider);
1567 COPY_STRING(pszPrintProcessor);
1568 COPY_STRING(pszVendorSetup);
1569 COPY_MULTIZ_STRING(pszzColorProfiles);
1570 COPY_STRING(pszInfPath);
1571 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1577 FIXME("for level %u\n", level);
1580 pDriversW += di_sizeof[level];
1581 out += di_sizeof[level];
1586 #undef COPY_MULTIZ_STRING
1590 /***********************************************************
1591 * PRINTER_INFO_2AtoW
1592 * Creates a unicode copy of PRINTER_INFO_2A on heap
1594 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1596 LPPRINTER_INFO_2W piW;
1597 UNICODE_STRING usBuffer;
1599 if(!piA) return NULL;
1600 piW = HeapAlloc(heap, 0, sizeof(*piW));
1601 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1603 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1604 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1605 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1606 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1607 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1608 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1609 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1610 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1611 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1612 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1613 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1614 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1618 /***********************************************************
1619 * FREE_PRINTER_INFO_2W
1620 * Free PRINTER_INFO_2W and all strings
1622 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1626 HeapFree(heap,0,piW->pServerName);
1627 HeapFree(heap,0,piW->pPrinterName);
1628 HeapFree(heap,0,piW->pShareName);
1629 HeapFree(heap,0,piW->pPortName);
1630 HeapFree(heap,0,piW->pDriverName);
1631 HeapFree(heap,0,piW->pComment);
1632 HeapFree(heap,0,piW->pLocation);
1633 HeapFree(heap,0,piW->pDevMode);
1634 HeapFree(heap,0,piW->pSepFile);
1635 HeapFree(heap,0,piW->pPrintProcessor);
1636 HeapFree(heap,0,piW->pDatatype);
1637 HeapFree(heap,0,piW->pParameters);
1638 HeapFree(heap,0,piW);
1642 /******************************************************************
1643 * DeviceCapabilities [WINSPOOL.@]
1644 * DeviceCapabilitiesA [WINSPOOL.@]
1647 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1648 LPSTR pOutput, LPDEVMODEA lpdm)
1652 if (!GDI_CallDeviceCapabilities16)
1654 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1656 if (!GDI_CallDeviceCapabilities16) return -1;
1658 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1660 /* If DC_PAPERSIZE map POINT16s to POINTs */
1661 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1662 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1663 POINT *pt = (POINT *)pOutput;
1665 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1666 for(i = 0; i < ret; i++, pt++)
1671 HeapFree( GetProcessHeap(), 0, tmp );
1677 /*****************************************************************************
1678 * DeviceCapabilitiesW [WINSPOOL.@]
1680 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1683 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1684 WORD fwCapability, LPWSTR pOutput,
1685 const DEVMODEW *pDevMode)
1687 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1688 LPSTR pDeviceA = strdupWtoA(pDevice);
1689 LPSTR pPortA = strdupWtoA(pPort);
1692 if(pOutput && (fwCapability == DC_BINNAMES ||
1693 fwCapability == DC_FILEDEPENDENCIES ||
1694 fwCapability == DC_PAPERNAMES)) {
1695 /* These need A -> W translation */
1698 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1702 switch(fwCapability) {
1707 case DC_FILEDEPENDENCIES:
1711 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1712 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1714 for(i = 0; i < ret; i++)
1715 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1716 pOutput + (i * size), size);
1717 HeapFree(GetProcessHeap(), 0, pOutputA);
1719 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1720 (LPSTR)pOutput, dmA);
1722 HeapFree(GetProcessHeap(),0,pPortA);
1723 HeapFree(GetProcessHeap(),0,pDeviceA);
1724 HeapFree(GetProcessHeap(),0,dmA);
1728 /******************************************************************
1729 * DocumentPropertiesA [WINSPOOL.@]
1731 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1733 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1734 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1735 LPDEVMODEA pDevModeInput,DWORD fMode )
1737 LPSTR lpName = pDeviceName;
1738 static CHAR port[] = "LPT1:";
1741 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1742 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1746 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1748 ERR("no name from hPrinter?\n");
1749 SetLastError(ERROR_INVALID_HANDLE);
1752 lpName = strdupWtoA(lpNameW);
1755 if (!GDI_CallExtDeviceMode16)
1757 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1759 if (!GDI_CallExtDeviceMode16) {
1760 ERR("No CallExtDeviceMode16?\n");
1764 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1765 pDevModeInput, NULL, fMode);
1768 HeapFree(GetProcessHeap(),0,lpName);
1773 /*****************************************************************************
1774 * DocumentPropertiesW (WINSPOOL.@)
1776 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1778 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1780 LPDEVMODEW pDevModeOutput,
1781 LPDEVMODEW pDevModeInput, DWORD fMode)
1784 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1785 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1786 LPDEVMODEA pDevModeOutputA = NULL;
1789 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1790 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1792 if(pDevModeOutput) {
1793 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1794 if(ret < 0) return ret;
1795 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1797 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1798 pDevModeInputA, fMode);
1799 if(pDevModeOutput) {
1800 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1801 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1803 if(fMode == 0 && ret > 0)
1804 ret += (CCHDEVICENAME + CCHFORMNAME);
1805 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1806 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1810 /******************************************************************
1811 * OpenPrinterA [WINSPOOL.@]
1816 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1817 LPPRINTER_DEFAULTSA pDefault)
1819 UNICODE_STRING lpPrinterNameW;
1820 UNICODE_STRING usBuffer;
1821 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1822 PWSTR pwstrPrinterNameW;
1825 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1828 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1829 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1830 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1831 pDefaultW = &DefaultW;
1833 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1835 RtlFreeUnicodeString(&usBuffer);
1836 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1838 RtlFreeUnicodeString(&lpPrinterNameW);
1842 /******************************************************************
1843 * OpenPrinterW [WINSPOOL.@]
1845 * Open a Printer / Printserver or a Printer-Object
1848 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1849 * phPrinter [O] The resulting Handle is stored here
1850 * pDefault [I] PTR to Default Printer Settings or NULL
1857 * lpPrinterName is one of:
1858 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1859 *| Printer: "PrinterName"
1860 *| Printer-Object: "PrinterName,Job xxx"
1861 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1862 *| XcvPort: "Servername,XcvPort PortName"
1865 *| Printer-Object not supported
1866 *| pDefaults is ignored
1869 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1872 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1874 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1875 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1879 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1880 SetLastError(ERROR_INVALID_PARAMETER);
1884 /* Get the unique handle of the printer or Printserver */
1885 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1886 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1887 return (*phPrinter != 0);
1890 /******************************************************************
1891 * AddMonitorA [WINSPOOL.@]
1896 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1898 LPWSTR nameW = NULL;
1901 LPMONITOR_INFO_2A mi2a;
1902 MONITOR_INFO_2W mi2w;
1904 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1905 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1906 debugstr_a(mi2a ? mi2a->pName : NULL),
1907 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1908 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1911 SetLastError(ERROR_INVALID_LEVEL);
1915 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1921 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1922 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1923 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1926 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1928 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1929 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1930 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1932 if (mi2a->pEnvironment) {
1933 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1934 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1935 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1937 if (mi2a->pDLLName) {
1938 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1939 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1940 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1943 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1945 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1946 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1947 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1949 HeapFree(GetProcessHeap(), 0, nameW);
1953 /******************************************************************************
1954 * AddMonitorW [WINSPOOL.@]
1956 * Install a Printmonitor
1959 * pName [I] Servername or NULL (local Computer)
1960 * Level [I] Structure-Level (Must be 2)
1961 * pMonitors [I] PTR to MONITOR_INFO_2
1968 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1971 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1973 LPMONITOR_INFO_2W mi2w;
1975 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1976 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1977 debugstr_w(mi2w ? mi2w->pName : NULL),
1978 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1979 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1981 if ((backend == NULL) && !load_backend()) return FALSE;
1984 SetLastError(ERROR_INVALID_LEVEL);
1988 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1993 return backend->fpAddMonitor(pName, Level, pMonitors);
1996 /******************************************************************
1997 * DeletePrinterDriverA [WINSPOOL.@]
2000 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2002 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2005 /******************************************************************
2006 * DeletePrinterDriverW [WINSPOOL.@]
2009 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2011 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2014 /******************************************************************
2015 * DeleteMonitorA [WINSPOOL.@]
2017 * See DeleteMonitorW.
2020 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2022 LPWSTR nameW = NULL;
2023 LPWSTR EnvironmentW = NULL;
2024 LPWSTR MonitorNameW = NULL;
2029 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2030 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2031 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2035 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2036 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2037 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2040 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2041 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2045 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2047 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2048 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2049 HeapFree(GetProcessHeap(), 0, nameW);
2053 /******************************************************************
2054 * DeleteMonitorW [WINSPOOL.@]
2056 * Delete a specific Printmonitor from a Printing-Environment
2059 * pName [I] Servername or NULL (local Computer)
2060 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2061 * pMonitorName [I] Name of the Monitor, that should be deleted
2068 * pEnvironment is ignored in Windows for the local Computer.
2071 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2074 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2075 debugstr_w(pMonitorName));
2077 if ((backend == NULL) && !load_backend()) return FALSE;
2079 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2083 /******************************************************************
2084 * DeletePortA [WINSPOOL.@]
2089 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2091 LPWSTR nameW = NULL;
2092 LPWSTR portW = NULL;
2096 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2098 /* convert servername to unicode */
2100 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2101 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2102 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2105 /* convert portname to unicode */
2107 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2108 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2109 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2112 res = DeletePortW(nameW, hWnd, portW);
2113 HeapFree(GetProcessHeap(), 0, nameW);
2114 HeapFree(GetProcessHeap(), 0, portW);
2118 /******************************************************************
2119 * DeletePortW [WINSPOOL.@]
2121 * Delete a specific Port
2124 * pName [I] Servername or NULL (local Computer)
2125 * hWnd [I] Handle to parent Window for the Dialog-Box
2126 * pPortName [I] Name of the Port, that should be deleted
2133 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2135 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2137 if ((backend == NULL) && !load_backend()) return FALSE;
2140 SetLastError(RPC_X_NULL_REF_POINTER);
2144 return backend->fpDeletePort(pName, hWnd, pPortName);
2147 /******************************************************************************
2148 * SetPrinterW [WINSPOOL.@]
2150 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2152 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2153 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2157 /******************************************************************************
2158 * WritePrinter [WINSPOOL.@]
2160 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2162 opened_printer_t *printer;
2165 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2167 EnterCriticalSection(&printer_handles_cs);
2168 printer = get_opened_printer(hPrinter);
2171 SetLastError(ERROR_INVALID_HANDLE);
2177 SetLastError(ERROR_SPL_NO_STARTDOC);
2181 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2183 LeaveCriticalSection(&printer_handles_cs);
2187 /*****************************************************************************
2188 * AddFormA [WINSPOOL.@]
2190 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2192 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2196 /*****************************************************************************
2197 * AddFormW [WINSPOOL.@]
2199 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2201 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2205 /*****************************************************************************
2206 * AddJobA [WINSPOOL.@]
2208 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2211 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2215 SetLastError(ERROR_INVALID_LEVEL);
2219 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2222 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2223 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2224 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2225 if(*pcbNeeded > cbBuf) {
2226 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2229 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2230 addjobA->JobId = addjobW->JobId;
2231 addjobA->Path = (char *)(addjobA + 1);
2232 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2238 /*****************************************************************************
2239 * AddJobW [WINSPOOL.@]
2241 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2243 opened_printer_t *printer;
2246 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2247 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2248 WCHAR path[MAX_PATH], filename[MAX_PATH];
2250 ADDJOB_INFO_1W *addjob;
2252 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2254 EnterCriticalSection(&printer_handles_cs);
2256 printer = get_opened_printer(hPrinter);
2259 SetLastError(ERROR_INVALID_HANDLE);
2264 SetLastError(ERROR_INVALID_LEVEL);
2268 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2272 job->job_id = InterlockedIncrement(&next_job_id);
2274 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2275 if(path[len - 1] != '\\')
2277 memcpy(path + len, spool_path, sizeof(spool_path));
2278 sprintfW(filename, fmtW, path, job->job_id);
2280 len = strlenW(filename);
2281 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2282 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2283 job->document_title = strdupW(default_doc_title);
2284 job->printer_name = strdupW(printer->name);
2285 job->devmode = NULL;
2286 list_add_tail(&printer->queue->jobs, &job->entry);
2288 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2289 if(*pcbNeeded <= cbBuf) {
2290 addjob = (ADDJOB_INFO_1W*)pData;
2291 addjob->JobId = job->job_id;
2292 addjob->Path = (WCHAR *)(addjob + 1);
2293 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2296 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2299 LeaveCriticalSection(&printer_handles_cs);
2303 /*****************************************************************************
2304 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2306 * Return the PATH for the Print-Processors
2308 * See GetPrintProcessorDirectoryW.
2312 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2313 DWORD level, LPBYTE Info,
2314 DWORD cbBuf, LPDWORD pcbNeeded)
2316 LPWSTR serverW = NULL;
2321 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2322 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2326 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2327 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2328 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2332 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2333 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2334 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2337 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2338 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2340 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2343 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2344 cbBuf, NULL, NULL) > 0;
2347 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2348 HeapFree(GetProcessHeap(), 0, envW);
2349 HeapFree(GetProcessHeap(), 0, serverW);
2353 /*****************************************************************************
2354 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2356 * Return the PATH for the Print-Processors
2359 * server [I] Servername (NT only) or NULL (local Computer)
2360 * env [I] Printing-Environment (see below) or NULL (Default)
2361 * level [I] Structure-Level (must be 1)
2362 * Info [O] PTR to Buffer that receives the Result
2363 * cbBuf [I] Size of Buffer at "Info"
2364 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2365 * required for the Buffer at "Info"
2368 * Success: TRUE and in pcbNeeded the Bytes used in Info
2369 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2370 * if cbBuf is too small
2372 * Native Values returned in Info on Success:
2373 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2374 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2375 *| win9x(Windows 4.0): "%winsysdir%"
2377 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2380 * Only NULL or "" is supported for server
2383 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2384 DWORD level, LPBYTE Info,
2385 DWORD cbBuf, LPDWORD pcbNeeded)
2388 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2389 Info, cbBuf, pcbNeeded);
2391 if ((backend == NULL) && !load_backend()) return FALSE;
2394 /* (Level != 1) is ignored in win9x */
2395 SetLastError(ERROR_INVALID_LEVEL);
2399 if (pcbNeeded == NULL) {
2400 /* (pcbNeeded == NULL) is ignored in win9x */
2401 SetLastError(RPC_X_NULL_REF_POINTER);
2405 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2408 /*****************************************************************************
2409 * WINSPOOL_OpenDriverReg [internal]
2411 * opens the registry for the printer drivers depending on the given input
2412 * variable pEnvironment
2415 * the opened hkey on success
2418 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2422 const printenv_t * env;
2424 TRACE("(%s)\n", debugstr_w(pEnvironment));
2426 env = validate_envW(pEnvironment);
2427 if (!env) return NULL;
2429 buffer = HeapAlloc( GetProcessHeap(), 0,
2430 (strlenW(DriversW) + strlenW(env->envname) +
2431 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2433 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2434 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2435 HeapFree(GetProcessHeap(), 0, buffer);
2440 /*****************************************************************************
2441 * AddPrinterW [WINSPOOL.@]
2443 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2445 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2449 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2451 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2452 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2453 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2454 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2455 statusW[] = {'S','t','a','t','u','s',0},
2456 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2458 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2461 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2462 SetLastError(ERROR_INVALID_PARAMETER);
2466 ERR("Level = %d, unsupported!\n", Level);
2467 SetLastError(ERROR_INVALID_LEVEL);
2471 SetLastError(ERROR_INVALID_PARAMETER);
2474 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2476 ERR("Can't create Printers key\n");
2479 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2480 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2481 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2482 RegCloseKey(hkeyPrinter);
2483 RegCloseKey(hkeyPrinters);
2486 RegCloseKey(hkeyPrinter);
2488 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2490 ERR("Can't create Drivers key\n");
2491 RegCloseKey(hkeyPrinters);
2494 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2496 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2497 RegCloseKey(hkeyPrinters);
2498 RegCloseKey(hkeyDrivers);
2499 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2502 RegCloseKey(hkeyDriver);
2503 RegCloseKey(hkeyDrivers);
2505 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2506 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2507 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2508 RegCloseKey(hkeyPrinters);
2512 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2514 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2515 SetLastError(ERROR_INVALID_PRINTER_NAME);
2516 RegCloseKey(hkeyPrinters);
2519 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2520 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2521 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2523 /* See if we can load the driver. We may need the devmode structure anyway
2526 * Note that DocumentPropertiesW will briefly try to open the printer we
2527 * just create to find a DEVMODEA struct (it will use the WINEPS default
2528 * one in case it is not there, so we are ok).
2530 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2533 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2534 size = sizeof(DEVMODEW);
2540 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2542 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2544 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2545 HeapFree(GetProcessHeap(),0,dmW);
2550 /* set devmode to printer name */
2551 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2555 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2556 and we support these drivers. NT writes DEVMODEW so somehow
2557 we'll need to distinguish between these when we support NT
2561 dmA = DEVMODEdupWtoA(dmW);
2562 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2563 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2564 HeapFree(GetProcessHeap(), 0, dmA);
2566 HeapFree(GetProcessHeap(), 0, dmW);
2568 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2569 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2570 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2571 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2573 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2574 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2575 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2576 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2577 (LPBYTE)&pi->Priority, sizeof(DWORD));
2578 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2579 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2580 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2581 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2582 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2583 (LPBYTE)&pi->Status, sizeof(DWORD));
2584 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2585 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2587 RegCloseKey(hkeyPrinter);
2588 RegCloseKey(hkeyPrinters);
2589 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2590 ERR("OpenPrinter failing\n");
2596 /*****************************************************************************
2597 * AddPrinterA [WINSPOOL.@]
2599 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2601 UNICODE_STRING pNameW;
2603 PRINTER_INFO_2W *piW;
2604 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2607 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2609 ERR("Level = %d, unsupported!\n", Level);
2610 SetLastError(ERROR_INVALID_LEVEL);
2613 pwstrNameW = asciitounicode(&pNameW,pName);
2614 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2616 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2618 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2619 RtlFreeUnicodeString(&pNameW);
2624 /*****************************************************************************
2625 * ClosePrinter [WINSPOOL.@]
2627 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2629 UINT_PTR i = (UINT_PTR)hPrinter;
2630 opened_printer_t *printer = NULL;
2633 TRACE("(%p)\n", hPrinter);
2635 EnterCriticalSection(&printer_handles_cs);
2637 if ((i > 0) && (i <= nb_printer_handles))
2638 printer = printer_handles[i - 1];
2643 struct list *cursor, *cursor2;
2645 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2647 if (printer->backend_printer) {
2648 backend->fpClosePrinter(printer->backend_printer);
2652 EndDocPrinter(hPrinter);
2654 if(InterlockedDecrement(&printer->queue->ref) == 0)
2656 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2658 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2659 ScheduleJob(hPrinter, job->job_id);
2661 HeapFree(GetProcessHeap(), 0, printer->queue);
2664 HeapFree(GetProcessHeap(), 0, printer->printername);
2665 HeapFree(GetProcessHeap(), 0, printer->name);
2666 HeapFree(GetProcessHeap(), 0, printer);
2667 printer_handles[i - 1] = NULL;
2670 LeaveCriticalSection(&printer_handles_cs);
2674 /*****************************************************************************
2675 * DeleteFormA [WINSPOOL.@]
2677 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2679 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2683 /*****************************************************************************
2684 * DeleteFormW [WINSPOOL.@]
2686 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2688 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2692 /*****************************************************************************
2693 * DeletePrinter [WINSPOOL.@]
2695 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2697 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2698 HKEY hkeyPrinters, hkey;
2701 SetLastError(ERROR_INVALID_HANDLE);
2704 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2705 RegDeleteTreeW(hkeyPrinters, lpNameW);
2706 RegCloseKey(hkeyPrinters);
2708 WriteProfileStringW(devicesW, lpNameW, NULL);
2709 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2711 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2712 RegDeleteValueW(hkey, lpNameW);
2716 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2717 RegDeleteValueW(hkey, lpNameW);
2723 /*****************************************************************************
2724 * SetPrinterA [WINSPOOL.@]
2726 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2729 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2733 /*****************************************************************************
2734 * SetJobA [WINSPOOL.@]
2736 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2737 LPBYTE pJob, DWORD Command)
2741 UNICODE_STRING usBuffer;
2743 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2745 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2746 are all ignored by SetJob, so we don't bother copying them */
2754 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2755 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2757 JobW = (LPBYTE)info1W;
2758 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2759 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2760 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2761 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2762 info1W->Status = info1A->Status;
2763 info1W->Priority = info1A->Priority;
2764 info1W->Position = info1A->Position;
2765 info1W->PagesPrinted = info1A->PagesPrinted;
2770 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2771 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2773 JobW = (LPBYTE)info2W;
2774 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2775 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2776 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2777 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2778 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2779 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2780 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2781 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2782 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2783 info2W->Status = info2A->Status;
2784 info2W->Priority = info2A->Priority;
2785 info2W->Position = info2A->Position;
2786 info2W->StartTime = info2A->StartTime;
2787 info2W->UntilTime = info2A->UntilTime;
2788 info2W->PagesPrinted = info2A->PagesPrinted;
2792 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2793 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2796 SetLastError(ERROR_INVALID_LEVEL);
2800 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2806 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2807 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2808 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2809 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2810 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2815 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2816 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2817 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2818 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2819 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2820 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2821 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2822 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2823 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2827 HeapFree(GetProcessHeap(), 0, JobW);
2832 /*****************************************************************************
2833 * SetJobW [WINSPOOL.@]
2835 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2836 LPBYTE pJob, DWORD Command)
2842 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2843 FIXME("Ignoring everything other than document title\n");
2845 EnterCriticalSection(&printer_handles_cs);
2846 job = get_job(hPrinter, JobId);
2856 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2857 HeapFree(GetProcessHeap(), 0, job->document_title);
2858 job->document_title = strdupW(info1->pDocument);
2863 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2864 HeapFree(GetProcessHeap(), 0, job->document_title);
2865 job->document_title = strdupW(info2->pDocument);
2866 HeapFree(GetProcessHeap(), 0, job->devmode);
2867 if (info2->pDevMode)
2869 size = info2->pDevMode->dmSize + info2->pDevMode->dmDriverExtra;
2870 job->devmode = HeapAlloc(GetProcessHeap(), 0, size);
2871 memcpy(job->devmode, info2->pDevMode, size);
2874 job->devmode = NULL;
2880 SetLastError(ERROR_INVALID_LEVEL);
2885 LeaveCriticalSection(&printer_handles_cs);
2889 /*****************************************************************************
2890 * EndDocPrinter [WINSPOOL.@]
2892 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2894 opened_printer_t *printer;
2896 TRACE("(%p)\n", hPrinter);
2898 EnterCriticalSection(&printer_handles_cs);
2900 printer = get_opened_printer(hPrinter);
2903 SetLastError(ERROR_INVALID_HANDLE);
2909 SetLastError(ERROR_SPL_NO_STARTDOC);
2913 CloseHandle(printer->doc->hf);
2914 ScheduleJob(hPrinter, printer->doc->job_id);
2915 HeapFree(GetProcessHeap(), 0, printer->doc);
2916 printer->doc = NULL;
2919 LeaveCriticalSection(&printer_handles_cs);
2923 /*****************************************************************************
2924 * EndPagePrinter [WINSPOOL.@]
2926 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2928 FIXME("(%p): stub\n", hPrinter);
2932 /*****************************************************************************
2933 * StartDocPrinterA [WINSPOOL.@]
2935 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2937 UNICODE_STRING usBuffer;
2939 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2942 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2943 or one (DOC_INFO_3) extra DWORDs */
2947 doc2W.JobId = doc2->JobId;
2950 doc2W.dwMode = doc2->dwMode;
2953 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2954 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2955 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2959 SetLastError(ERROR_INVALID_LEVEL);
2963 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2965 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2966 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2967 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2972 /*****************************************************************************
2973 * StartDocPrinterW [WINSPOOL.@]
2975 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2977 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2978 opened_printer_t *printer;
2979 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2980 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2981 JOB_INFO_1W job_info;
2982 DWORD needed, ret = 0;
2987 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2988 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2989 debugstr_w(doc->pDatatype));
2991 if(Level < 1 || Level > 3)
2993 SetLastError(ERROR_INVALID_LEVEL);
2997 EnterCriticalSection(&printer_handles_cs);
2998 printer = get_opened_printer(hPrinter);
3001 SetLastError(ERROR_INVALID_HANDLE);
3007 SetLastError(ERROR_INVALID_PRINTER_STATE);
3011 /* Even if we're printing to a file we still add a print job, we'll
3012 just ignore the spool file name */
3014 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3016 ERR("AddJob failed gle %u\n", GetLastError());
3020 /* use pOutputFile only, when it is a real filename */
3021 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3022 filename = doc->pOutputFile;
3024 filename = addjob->Path;
3026 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3027 if(hf == INVALID_HANDLE_VALUE)
3030 memset(&job_info, 0, sizeof(job_info));
3031 job_info.pDocument = doc->pDocName;
3032 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3034 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3035 printer->doc->hf = hf;
3036 ret = printer->doc->job_id = addjob->JobId;
3037 job = get_job(hPrinter, ret);
3038 job->portname = strdupW(doc->pOutputFile);
3041 LeaveCriticalSection(&printer_handles_cs);
3046 /*****************************************************************************
3047 * StartPagePrinter [WINSPOOL.@]
3049 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3051 FIXME("(%p): stub\n", hPrinter);
3055 /*****************************************************************************
3056 * GetFormA [WINSPOOL.@]
3058 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3059 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3061 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3062 Level,pForm,cbBuf,pcbNeeded);
3066 /*****************************************************************************
3067 * GetFormW [WINSPOOL.@]
3069 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3070 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3072 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3073 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3077 /*****************************************************************************
3078 * SetFormA [WINSPOOL.@]
3080 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3083 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3087 /*****************************************************************************
3088 * SetFormW [WINSPOOL.@]
3090 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3093 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3097 /*****************************************************************************
3098 * ReadPrinter [WINSPOOL.@]
3100 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3101 LPDWORD pNoBytesRead)
3103 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3107 /*****************************************************************************
3108 * ResetPrinterA [WINSPOOL.@]
3110 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3112 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3116 /*****************************************************************************
3117 * ResetPrinterW [WINSPOOL.@]
3119 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3121 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3125 /*****************************************************************************
3126 * WINSPOOL_GetDWORDFromReg
3128 * Return DWORD associated with ValueName from hkey.
3130 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3132 DWORD sz = sizeof(DWORD), type, value = 0;
3135 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3137 if(ret != ERROR_SUCCESS) {
3138 WARN("Got ret = %d on name %s\n", ret, ValueName);
3141 if(type != REG_DWORD) {
3142 ERR("Got type %d\n", type);
3149 /*****************************************************************************
3150 * get_filename_from_reg [internal]
3152 * Get ValueName from hkey storing result in out
3153 * when the Value in the registry has only a filename, use driverdir as prefix
3154 * outlen is space left in out
3155 * String is stored either as unicode or ascii
3159 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3160 LPBYTE out, DWORD outlen, LPDWORD needed)
3162 WCHAR filename[MAX_PATH];
3166 LPWSTR buffer = filename;
3170 size = sizeof(filename);
3172 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3173 if (ret == ERROR_MORE_DATA) {
3174 TRACE("need dynamic buffer: %u\n", size);
3175 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3177 /* No Memory is bad */
3181 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3184 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3185 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3191 /* do we have a full path ? */
3192 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3193 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3196 /* we must build the full Path */
3198 if ((out) && (outlen > dirlen)) {
3199 lstrcpyW((LPWSTR)out, driverdir);
3207 /* write the filename */
3208 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3209 if ((out) && (outlen >= size)) {
3210 lstrcpyW((LPWSTR)out, ptr);
3217 ptr += lstrlenW(ptr)+1;
3218 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3221 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3223 /* write the multisz-termination */
3224 if (type == REG_MULTI_SZ) {
3225 size = sizeof(WCHAR);
3228 if (out && (outlen >= size)) {
3229 memset (out, 0, size);
3235 /*****************************************************************************
3236 * WINSPOOL_GetStringFromReg
3238 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3239 * String is stored as unicode.
3241 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3242 DWORD buflen, DWORD *needed)
3244 DWORD sz = buflen, type;
3247 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3248 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3249 WARN("Got ret = %d\n", ret);
3253 /* add space for terminating '\0' */
3254 sz += sizeof(WCHAR);
3258 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3263 /*****************************************************************************
3264 * WINSPOOL_GetDefaultDevMode
3266 * Get a default DevMode values for wineps.
3270 static void WINSPOOL_GetDefaultDevMode(
3272 DWORD buflen, DWORD *needed)
3275 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3277 /* fill default DEVMODE - should be read from ppd... */
3278 ZeroMemory( &dm, sizeof(dm) );
3279 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3280 dm.dmSpecVersion = DM_SPECVERSION;
3281 dm.dmDriverVersion = 1;
3282 dm.dmSize = sizeof(DEVMODEW);
3283 dm.dmDriverExtra = 0;
3285 DM_ORIENTATION | DM_PAPERSIZE |
3286 DM_PAPERLENGTH | DM_PAPERWIDTH |
3289 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3290 DM_YRESOLUTION | DM_TTOPTION;
3292 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3293 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3294 dm.u1.s1.dmPaperLength = 2970;
3295 dm.u1.s1.dmPaperWidth = 2100;
3297 dm.u1.s1.dmScale = 100;
3298 dm.u1.s1.dmCopies = 1;
3299 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3300 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3303 dm.dmYResolution = 300; /* 300dpi */
3304 dm.dmTTOption = DMTT_BITMAP;
3307 /* dm.dmLogPixels */
3308 /* dm.dmBitsPerPel */
3309 /* dm.dmPelsWidth */
3310 /* dm.dmPelsHeight */
3311 /* dm.u2.dmDisplayFlags */
3312 /* dm.dmDisplayFrequency */
3313 /* dm.dmICMMethod */
3314 /* dm.dmICMIntent */
3315 /* dm.dmMediaType */
3316 /* dm.dmDitherType */
3317 /* dm.dmReserved1 */
3318 /* dm.dmReserved2 */
3319 /* dm.dmPanningWidth */
3320 /* dm.dmPanningHeight */
3322 if(buflen >= sizeof(DEVMODEW))
3323 memcpy(ptr, &dm, sizeof(DEVMODEW));
3324 *needed = sizeof(DEVMODEW);
3327 /*****************************************************************************
3328 * WINSPOOL_GetDevModeFromReg
3330 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3331 * DevMode is stored either as unicode or ascii.
3333 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3335 DWORD buflen, DWORD *needed)
3337 DWORD sz = buflen, type;
3340 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3341 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3342 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3343 if (sz < sizeof(DEVMODEA))
3345 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3348 /* ensures that dmSize is not erratically bogus if registry is invalid */
3349 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3350 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3351 sz += (CCHDEVICENAME + CCHFORMNAME);
3352 if (ptr && (buflen >= sz)) {
3353 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3354 memcpy(ptr, dmW, sz);
3355 HeapFree(GetProcessHeap(),0,dmW);
3361 /*********************************************************************
3362 * WINSPOOL_GetPrinter_1
3364 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3366 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3367 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3369 DWORD size, left = cbBuf;
3370 BOOL space = (cbBuf > 0);
3375 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3376 if(space && size <= left) {
3377 pi1->pName = (LPWSTR)ptr;
3385 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3386 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3387 if(space && size <= left) {
3388 pi1->pDescription = (LPWSTR)ptr;
3396 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3397 if(space && size <= left) {
3398 pi1->pComment = (LPWSTR)ptr;
3406 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3408 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3409 memset(pi1, 0, sizeof(*pi1));
3413 /*********************************************************************
3414 * WINSPOOL_GetPrinter_2
3416 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3418 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3419 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3421 DWORD size, left = cbBuf;
3422 BOOL space = (cbBuf > 0);
3427 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3428 if(space && size <= left) {
3429 pi2->pPrinterName = (LPWSTR)ptr;
3436 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3437 if(space && size <= left) {
3438 pi2->pShareName = (LPWSTR)ptr;
3445 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3446 if(space && size <= left) {
3447 pi2->pPortName = (LPWSTR)ptr;
3454 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3455 if(space && size <= left) {
3456 pi2->pDriverName = (LPWSTR)ptr;
3463 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3464 if(space && size <= left) {
3465 pi2->pComment = (LPWSTR)ptr;
3472 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3473 if(space && size <= left) {
3474 pi2->pLocation = (LPWSTR)ptr;
3481 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3482 if(space && size <= left) {
3483 pi2->pDevMode = (LPDEVMODEW)ptr;
3492 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3493 if(space && size <= left) {
3494 pi2->pDevMode = (LPDEVMODEW)ptr;
3501 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3502 if(space && size <= left) {
3503 pi2->pSepFile = (LPWSTR)ptr;
3510 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3511 if(space && size <= left) {
3512 pi2->pPrintProcessor = (LPWSTR)ptr;
3519 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3520 if(space && size <= left) {
3521 pi2->pDatatype = (LPWSTR)ptr;
3528 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3529 if(space && size <= left) {
3530 pi2->pParameters = (LPWSTR)ptr;
3538 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3539 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3540 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3541 "Default Priority");
3542 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3543 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3546 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3547 memset(pi2, 0, sizeof(*pi2));
3552 /*********************************************************************
3553 * WINSPOOL_GetPrinter_4
3555 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3557 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3558 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3560 DWORD size, left = cbBuf;
3561 BOOL space = (cbBuf > 0);
3566 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3567 if(space && size <= left) {
3568 pi4->pPrinterName = (LPWSTR)ptr;
3576 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3579 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3580 memset(pi4, 0, sizeof(*pi4));
3585 /*********************************************************************
3586 * WINSPOOL_GetPrinter_5
3588 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3590 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3591 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3593 DWORD size, left = cbBuf;
3594 BOOL space = (cbBuf > 0);
3599 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3600 if(space && size <= left) {
3601 pi5->pPrinterName = (LPWSTR)ptr;
3608 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3609 if(space && size <= left) {
3610 pi5->pPortName = (LPWSTR)ptr;
3618 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3619 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3621 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3625 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3626 memset(pi5, 0, sizeof(*pi5));
3631 /*********************************************************************
3632 * WINSPOOL_GetPrinter_7
3634 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3636 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3637 DWORD cbBuf, LPDWORD pcbNeeded)
3639 DWORD size, left = cbBuf;
3640 BOOL space = (cbBuf > 0);
3645 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3648 size = sizeof(pi7->pszObjectGUID);
3650 if (space && size <= left) {
3651 pi7->pszObjectGUID = (LPWSTR)ptr;
3658 /* We do not have a Directory Service */
3659 pi7->dwAction = DSPRINT_UNPUBLISH;
3662 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3663 memset(pi7, 0, sizeof(*pi7));
3668 /*********************************************************************
3669 * WINSPOOL_GetPrinter_9
3671 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3673 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3674 DWORD cbBuf, LPDWORD pcbNeeded)
3677 BOOL space = (cbBuf > 0);
3681 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3682 if(space && size <= cbBuf) {
3683 pi9->pDevMode = (LPDEVMODEW)buf;
3690 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3691 if(space && size <= cbBuf) {
3692 pi9->pDevMode = (LPDEVMODEW)buf;
3698 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3699 memset(pi9, 0, sizeof(*pi9));
3704 /*****************************************************************************
3705 * GetPrinterW [WINSPOOL.@]
3707 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3708 DWORD cbBuf, LPDWORD pcbNeeded)
3711 DWORD size, needed = 0;
3713 HKEY hkeyPrinter, hkeyPrinters;
3716 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3718 if (!(name = get_opened_printer_name(hPrinter))) {
3719 SetLastError(ERROR_INVALID_HANDLE);
3723 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3725 ERR("Can't create Printers key\n");
3728 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3730 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3731 RegCloseKey(hkeyPrinters);
3732 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3739 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3741 size = sizeof(PRINTER_INFO_2W);
3743 ptr = pPrinter + size;
3745 memset(pPrinter, 0, size);
3750 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3757 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3759 size = sizeof(PRINTER_INFO_4W);
3761 ptr = pPrinter + size;
3763 memset(pPrinter, 0, size);
3768 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3776 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3778 size = sizeof(PRINTER_INFO_5W);
3780 ptr = pPrinter + size;
3782 memset(pPrinter, 0, size);
3788 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3796 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3798 size = sizeof(PRINTER_INFO_6);
3799 if (size <= cbBuf) {
3800 /* FIXME: We do not update the status yet */
3801 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3813 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3815 size = sizeof(PRINTER_INFO_7W);
3816 if (size <= cbBuf) {
3817 ptr = pPrinter + size;
3819 memset(pPrinter, 0, size);
3825 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3833 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3835 size = sizeof(PRINTER_INFO_9W);
3837 ptr = pPrinter + size;
3839 memset(pPrinter, 0, size);
3845 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3852 FIXME("Unimplemented level %d\n", Level);
3853 SetLastError(ERROR_INVALID_LEVEL);
3854 RegCloseKey(hkeyPrinters);
3855 RegCloseKey(hkeyPrinter);
3859 RegCloseKey(hkeyPrinter);
3860 RegCloseKey(hkeyPrinters);
3862 TRACE("returning %d needed = %d\n", ret, needed);
3863 if(pcbNeeded) *pcbNeeded = needed;
3865 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3869 /*****************************************************************************
3870 * GetPrinterA [WINSPOOL.@]
3872 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3873 DWORD cbBuf, LPDWORD pcbNeeded)
3879 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3881 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3883 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3884 HeapFree(GetProcessHeap(), 0, buf);
3889 /*****************************************************************************
3890 * WINSPOOL_EnumPrintersW
3892 * Implementation of EnumPrintersW
3894 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3895 DWORD dwLevel, LPBYTE lpbPrinters,
3896 DWORD cbBuf, LPDWORD lpdwNeeded,
3897 LPDWORD lpdwReturned)
3900 HKEY hkeyPrinters, hkeyPrinter;
3901 WCHAR PrinterName[255];
3902 DWORD needed = 0, number = 0;
3903 DWORD used, i, left;
3907 memset(lpbPrinters, 0, cbBuf);
3913 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3914 if(dwType == PRINTER_ENUM_DEFAULT)
3917 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3918 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3919 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3921 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3927 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3928 FIXME("dwType = %08x\n", dwType);
3929 SetLastError(ERROR_INVALID_FLAGS);
3933 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3935 ERR("Can't create Printers key\n");
3939 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3940 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3941 RegCloseKey(hkeyPrinters);
3942 ERR("Can't query Printers key\n");
3945 TRACE("Found %d printers\n", number);
3949 used = number * sizeof(PRINTER_INFO_1W);
3952 used = number * sizeof(PRINTER_INFO_2W);
3955 used = number * sizeof(PRINTER_INFO_4W);
3958 used = number * sizeof(PRINTER_INFO_5W);
3962 SetLastError(ERROR_INVALID_LEVEL);
3963 RegCloseKey(hkeyPrinters);
3966 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3968 for(i = 0; i < number; i++) {
3969 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3971 ERR("Can't enum key number %d\n", i);
3972 RegCloseKey(hkeyPrinters);
3975 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3976 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3978 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3979 RegCloseKey(hkeyPrinters);
3984 buf = lpbPrinters + used;
3985 left = cbBuf - used;
3993 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3996 if(pi) pi += sizeof(PRINTER_INFO_1W);
3999 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4002 if(pi) pi += sizeof(PRINTER_INFO_2W);
4005 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4008 if(pi) pi += sizeof(PRINTER_INFO_4W);
4011 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4014 if(pi) pi += sizeof(PRINTER_INFO_5W);
4017 ERR("Shouldn't be here!\n");
4018 RegCloseKey(hkeyPrinter);
4019 RegCloseKey(hkeyPrinters);
4022 RegCloseKey(hkeyPrinter);
4024 RegCloseKey(hkeyPrinters);
4031 memset(lpbPrinters, 0, cbBuf);
4032 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4036 *lpdwReturned = number;
4037 SetLastError(ERROR_SUCCESS);
4042 /******************************************************************
4043 * EnumPrintersW [WINSPOOL.@]
4045 * Enumerates the available printers, print servers and print
4046 * providers, depending on the specified flags, name and level.
4050 * If level is set to 1:
4051 * Returns an array of PRINTER_INFO_1 data structures in the
4052 * lpbPrinters buffer.
4054 * If level is set to 2:
4055 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4056 * Returns an array of PRINTER_INFO_2 data structures in the
4057 * lpbPrinters buffer. Note that according to MSDN also an
4058 * OpenPrinter should be performed on every remote printer.
4060 * If level is set to 4 (officially WinNT only):
4061 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4062 * Fast: Only the registry is queried to retrieve printer names,
4063 * no connection to the driver is made.
4064 * Returns an array of PRINTER_INFO_4 data structures in the
4065 * lpbPrinters buffer.
4067 * If level is set to 5 (officially WinNT4/Win9x only):
4068 * Fast: Only the registry is queried to retrieve printer names,
4069 * no connection to the driver is made.
4070 * Returns an array of PRINTER_INFO_5 data structures in the
4071 * lpbPrinters buffer.
4073 * If level set to 3 or 6+:
4074 * returns zero (failure!)
4076 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4080 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4081 * - Only levels 2, 4 and 5 are implemented at the moment.
4082 * - 16-bit printer drivers are not enumerated.
4083 * - Returned amount of bytes used/needed does not match the real Windoze
4084 * implementation (as in this implementation, all strings are part
4085 * of the buffer, whereas Win32 keeps them somewhere else)
4086 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4089 * - In a regular Wine installation, no registry settings for printers
4090 * exist, which makes this function return an empty list.
4092 BOOL WINAPI EnumPrintersW(
4093 DWORD dwType, /* [in] Types of print objects to enumerate */
4094 LPWSTR lpszName, /* [in] name of objects to enumerate */
4095 DWORD dwLevel, /* [in] type of printer info structure */
4096 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4097 DWORD cbBuf, /* [in] max size of buffer in bytes */
4098 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4099 LPDWORD lpdwReturned /* [out] number of entries returned */
4102 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4103 lpdwNeeded, lpdwReturned);
4106 /******************************************************************
4107 * EnumPrintersA [WINSPOOL.@]
4112 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4113 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4116 UNICODE_STRING pNameU;
4120 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4121 pPrinters, cbBuf, pcbNeeded, pcReturned);
4123 pNameW = asciitounicode(&pNameU, pName);
4125 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4126 MS Office need this */
4127 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4129 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4131 RtlFreeUnicodeString(&pNameU);
4133 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4135 HeapFree(GetProcessHeap(), 0, pPrintersW);
4139 /*****************************************************************************
4140 * WINSPOOL_GetDriverInfoFromReg [internal]
4142 * Enters the information from the registry into the DRIVER_INFO struct
4145 * zero if the printer driver does not exist in the registry
4146 * (only if Level > 1) otherwise nonzero
4148 static BOOL WINSPOOL_GetDriverInfoFromReg(
4151 const printenv_t * env,
4153 LPBYTE ptr, /* DRIVER_INFO */
4154 LPBYTE pDriverStrings, /* strings buffer */
4155 DWORD cbBuf, /* size of string buffer */
4156 LPDWORD pcbNeeded) /* space needed for str. */
4160 WCHAR driverdir[MAX_PATH];
4162 LPBYTE strPtr = pDriverStrings;
4163 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4165 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4166 debugstr_w(DriverName), env,
4167 Level, di, pDriverStrings, cbBuf);
4169 if (di) ZeroMemory(di, di_sizeof[Level]);
4171 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4172 if (*pcbNeeded <= cbBuf)
4173 strcpyW((LPWSTR)strPtr, DriverName);
4175 /* pName for level 1 has a different offset! */
4177 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4181 /* .cVersion and .pName for level > 1 */
4183 di->cVersion = env->driverversion;
4184 di->pName = (LPWSTR) strPtr;
4185 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4188 /* Reserve Space for the largest subdir and a Backslash*/
4189 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4190 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4191 /* Should never Fail */
4194 lstrcatW(driverdir, env->versionsubdir);
4195 lstrcatW(driverdir, backslashW);
4197 /* dirlen must not include the terminating zero */
4198 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4200 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4201 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4202 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4207 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4210 if (*pcbNeeded <= cbBuf) {
4211 lstrcpyW((LPWSTR)strPtr, env->envname);
4212 if (di) di->pEnvironment = (LPWSTR)strPtr;
4213 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4216 /* .pDriverPath is the Graphics rendering engine.
4217 The full Path is required to avoid a crash in some apps */
4218 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4220 if (*pcbNeeded <= cbBuf)
4221 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4223 if (di) di->pDriverPath = (LPWSTR)strPtr;
4224 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4227 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4228 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4230 if (*pcbNeeded <= cbBuf)
4231 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4233 if (di) di->pDataFile = (LPWSTR)strPtr;
4234 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4237 /* .pConfigFile is the Driver user Interface */
4238 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4240 if (*pcbNeeded <= cbBuf)
4241 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4243 if (di) di->pConfigFile = (LPWSTR)strPtr;
4244 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4248 RegCloseKey(hkeyDriver);
4249 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4254 RegCloseKey(hkeyDriver);
4255 FIXME("level 5: incomplete\n");
4260 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4262 if (*pcbNeeded <= cbBuf)
4263 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4265 if (di) di->pHelpFile = (LPWSTR)strPtr;
4266 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4269 /* .pDependentFiles */
4270 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4272 if (*pcbNeeded <= cbBuf)
4273 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4275 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4276 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4278 else if (GetVersion() & 0x80000000) {
4279 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4280 size = 2 * sizeof(WCHAR);
4282 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4284 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4285 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4288 /* .pMonitorName is the optional Language Monitor */
4289 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4291 if (*pcbNeeded <= cbBuf)
4292 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4294 if (di) di->pMonitorName = (LPWSTR)strPtr;
4295 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4298 /* .pDefaultDataType */
4299 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4301 if(*pcbNeeded <= cbBuf)
4302 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4304 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4305 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4309 RegCloseKey(hkeyDriver);
4310 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4314 /* .pszzPreviousNames */
4315 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4317 if(*pcbNeeded <= cbBuf)
4318 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4320 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4321 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4325 RegCloseKey(hkeyDriver);
4326 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4330 /* support is missing, but not important enough for a FIXME */
4331 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4334 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4336 if(*pcbNeeded <= cbBuf)
4337 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4339 if (di) di->pszMfgName = (LPWSTR)strPtr;
4340 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4344 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4346 if(*pcbNeeded <= cbBuf)
4347 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4349 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4350 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4353 /* .pszHardwareID */
4354 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4356 if(*pcbNeeded <= cbBuf)
4357 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4359 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4360 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4364 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4366 if(*pcbNeeded <= cbBuf)
4367 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4369 if (di) di->pszProvider = (LPWSTR)strPtr;
4370 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4374 RegCloseKey(hkeyDriver);
4378 /* support is missing, but not important enough for a FIXME */
4379 TRACE("level 8: incomplete\n");
4381 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4382 RegCloseKey(hkeyDriver);
4386 /*****************************************************************************
4387 * GetPrinterDriverW [WINSPOOL.@]
4389 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4390 DWORD Level, LPBYTE pDriverInfo,
4391 DWORD cbBuf, LPDWORD pcbNeeded)
4394 WCHAR DriverName[100];
4395 DWORD ret, type, size, needed = 0;
4397 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4398 const printenv_t * env;
4400 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4401 Level,pDriverInfo,cbBuf, pcbNeeded);
4404 ZeroMemory(pDriverInfo, cbBuf);
4406 if (!(name = get_opened_printer_name(hPrinter))) {
4407 SetLastError(ERROR_INVALID_HANDLE);
4411 if (Level < 1 || Level == 7 || Level > 8) {
4412 SetLastError(ERROR_INVALID_LEVEL);
4416 env = validate_envW(pEnvironment);
4417 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4419 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4421 ERR("Can't create Printers key\n");
4424 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4426 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4427 RegCloseKey(hkeyPrinters);
4428 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4431 size = sizeof(DriverName);
4433 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4434 (LPBYTE)DriverName, &size);
4435 RegCloseKey(hkeyPrinter);
4436 RegCloseKey(hkeyPrinters);
4437 if(ret != ERROR_SUCCESS) {
4438 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4442 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4444 ERR("Can't create Drivers key\n");
4448 size = di_sizeof[Level];
4449 if ((size <= cbBuf) && pDriverInfo)
4450 ptr = pDriverInfo + size;
4452 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4453 env, Level, pDriverInfo, ptr,
4454 (cbBuf < size) ? 0 : cbBuf - size,
4456 RegCloseKey(hkeyDrivers);
4460 RegCloseKey(hkeyDrivers);
4462 if(pcbNeeded) *pcbNeeded = size + needed;
4463 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4464 if(cbBuf >= size + needed) return TRUE;
4465 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4469 /*****************************************************************************
4470 * GetPrinterDriverA [WINSPOOL.@]
4472 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4473 DWORD Level, LPBYTE pDriverInfo,
4474 DWORD cbBuf, LPDWORD pcbNeeded)
4477 UNICODE_STRING pEnvW;
4483 ZeroMemory(pDriverInfo, cbBuf);
4484 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4487 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4488 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4491 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4493 HeapFree(GetProcessHeap(), 0, buf);
4495 RtlFreeUnicodeString(&pEnvW);
4499 /*****************************************************************************
4500 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4502 * Return the PATH for the Printer-Drivers (UNICODE)
4505 * pName [I] Servername (NT only) or NULL (local Computer)
4506 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4507 * Level [I] Structure-Level (must be 1)
4508 * pDriverDirectory [O] PTR to Buffer that receives the Result
4509 * cbBuf [I] Size of Buffer at pDriverDirectory
4510 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4511 * required for pDriverDirectory
4514 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4515 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4516 * if cbBuf is too small
4518 * Native Values returned in pDriverDirectory on Success:
4519 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4520 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4521 *| win9x(Windows 4.0): "%winsysdir%"
4523 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4526 *- Only NULL or "" is supported for pName
4529 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4530 DWORD Level, LPBYTE pDriverDirectory,
4531 DWORD cbBuf, LPDWORD pcbNeeded)
4533 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4534 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4536 if ((backend == NULL) && !load_backend()) return FALSE;
4539 /* (Level != 1) is ignored in win9x */
4540 SetLastError(ERROR_INVALID_LEVEL);
4543 if (pcbNeeded == NULL) {
4544 /* (pcbNeeded == NULL) is ignored in win9x */
4545 SetLastError(RPC_X_NULL_REF_POINTER);
4549 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4550 pDriverDirectory, cbBuf, pcbNeeded);
4555 /*****************************************************************************
4556 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4558 * Return the PATH for the Printer-Drivers (ANSI)
4560 * See GetPrinterDriverDirectoryW.
4563 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4566 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4567 DWORD Level, LPBYTE pDriverDirectory,
4568 DWORD cbBuf, LPDWORD pcbNeeded)
4570 UNICODE_STRING nameW, environmentW;
4573 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4574 WCHAR *driverDirectoryW = NULL;
4576 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4577 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4579 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4581 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4582 else nameW.Buffer = NULL;
4583 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4584 else environmentW.Buffer = NULL;
4586 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4587 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4590 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4591 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4593 *pcbNeeded = needed;
4594 ret = (needed <= cbBuf) ? TRUE : FALSE;
4596 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4598 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4600 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4601 RtlFreeUnicodeString(&environmentW);
4602 RtlFreeUnicodeString(&nameW);
4607 /*****************************************************************************
4608 * AddPrinterDriverA [WINSPOOL.@]
4610 * See AddPrinterDriverW.
4613 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4615 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4616 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4619 /******************************************************************************
4620 * AddPrinterDriverW (WINSPOOL.@)
4622 * Install a Printer Driver
4625 * pName [I] Servername or NULL (local Computer)
4626 * level [I] Level for the supplied DRIVER_INFO_*W struct
4627 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4634 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4636 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4637 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4640 /*****************************************************************************
4641 * AddPrintProcessorA [WINSPOOL.@]
4643 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4644 LPSTR pPrintProcessorName)
4646 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4647 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4651 /*****************************************************************************
4652 * AddPrintProcessorW [WINSPOOL.@]
4654 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4655 LPWSTR pPrintProcessorName)
4657 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4658 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4662 /*****************************************************************************
4663 * AddPrintProvidorA [WINSPOOL.@]
4665 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4667 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4671 /*****************************************************************************
4672 * AddPrintProvidorW [WINSPOOL.@]
4674 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4676 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4680 /*****************************************************************************
4681 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4683 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4684 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4686 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4687 pDevModeOutput, pDevModeInput);
4691 /*****************************************************************************
4692 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4694 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4695 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4697 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4698 pDevModeOutput, pDevModeInput);
4702 /*****************************************************************************
4703 * PrinterProperties [WINSPOOL.@]
4705 * Displays a dialog to set the properties of the printer.
4708 * nonzero on success or zero on failure
4711 * implemented as stub only
4713 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4714 HANDLE hPrinter /* [in] handle to printer object */
4716 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4717 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4721 /*****************************************************************************
4722 * EnumJobsA [WINSPOOL.@]
4725 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4726 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4729 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4730 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4732 if(pcbNeeded) *pcbNeeded = 0;
4733 if(pcReturned) *pcReturned = 0;
4738 /*****************************************************************************
4739 * EnumJobsW [WINSPOOL.@]
4742 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4743 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4746 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4747 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4749 if(pcbNeeded) *pcbNeeded = 0;
4750 if(pcReturned) *pcReturned = 0;
4754 /*****************************************************************************
4755 * WINSPOOL_EnumPrinterDrivers [internal]
4757 * Delivers information about all printer drivers installed on the
4758 * localhost or a given server
4761 * nonzero on success or zero on failure. If the buffer for the returned
4762 * information is too small the function will return an error
4765 * - only implemented for localhost, foreign hosts will return an error
4767 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4768 DWORD Level, LPBYTE pDriverInfo,
4770 DWORD cbBuf, LPDWORD pcbNeeded,
4771 LPDWORD pcFound, DWORD data_offset)
4775 const printenv_t * env;
4777 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4778 debugstr_w(pName), debugstr_w(pEnvironment),
4779 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4781 env = validate_envW(pEnvironment);
4782 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4786 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4788 ERR("Can't open Drivers key\n");
4792 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4793 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4794 RegCloseKey(hkeyDrivers);
4795 ERR("Can't query Drivers key\n");
4798 TRACE("Found %d Drivers\n", *pcFound);
4800 /* get size of single struct
4801 * unicode and ascii structure have the same size
4803 size = di_sizeof[Level];
4805 if (data_offset == 0)
4806 data_offset = size * (*pcFound);
4807 *pcbNeeded = data_offset;
4809 for( i = 0; i < *pcFound; i++) {
4810 WCHAR DriverNameW[255];
4811 PBYTE table_ptr = NULL;
4812 PBYTE data_ptr = NULL;
4815 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4817 ERR("Can't enum key number %d\n", i);
4818 RegCloseKey(hkeyDrivers);
4822 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4823 table_ptr = pDriverInfo + (driver_index + i) * size;
4824 if (pDriverInfo && *pcbNeeded <= cbBuf)
4825 data_ptr = pDriverInfo + *pcbNeeded;
4827 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4828 env, Level, table_ptr, data_ptr,
4829 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4831 RegCloseKey(hkeyDrivers);
4835 *pcbNeeded += needed;
4838 RegCloseKey(hkeyDrivers);
4840 if(cbBuf < *pcbNeeded){
4841 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4848 /*****************************************************************************
4849 * EnumPrinterDriversW [WINSPOOL.@]
4851 * see function EnumPrinterDrivers for RETURNS, BUGS
4853 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4854 LPBYTE pDriverInfo, DWORD cbBuf,
4855 LPDWORD pcbNeeded, LPDWORD pcReturned)
4857 static const WCHAR allW[] = {'a','l','l',0};
4861 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4863 SetLastError(RPC_X_NULL_REF_POINTER);
4867 /* check for local drivers */
4868 if((pName) && (pName[0])) {
4869 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4870 SetLastError(ERROR_ACCESS_DENIED);
4874 /* check input parameter */
4875 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4876 SetLastError(ERROR_INVALID_LEVEL);
4880 if(pDriverInfo && cbBuf > 0)
4881 memset( pDriverInfo, 0, cbBuf);
4883 /* Exception: pull all printers */
4884 if (pEnvironment && !strcmpW(pEnvironment, allW))
4886 DWORD i, needed, bufsize = cbBuf;
4887 DWORD total_needed = 0;
4888 DWORD total_found = 0;
4891 /* Precompute the overall total; we need this to know
4892 where pointers end and data begins (i.e. data_offset) */
4893 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4896 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4897 NULL, 0, 0, &needed, &found, 0);
4898 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4899 total_needed += needed;
4900 total_found += found;
4903 data_offset = di_sizeof[Level] * total_found;
4908 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4911 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4912 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4913 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4915 *pcReturned += found;
4916 *pcbNeeded = needed;
4917 data_offset = needed;
4918 total_found += found;
4923 /* Normal behavior */
4924 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4925 0, cbBuf, pcbNeeded, &found, 0);
4927 *pcReturned = found;
4932 /*****************************************************************************
4933 * EnumPrinterDriversA [WINSPOOL.@]
4935 * see function EnumPrinterDrivers for RETURNS, BUGS
4937 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4938 LPBYTE pDriverInfo, DWORD cbBuf,
4939 LPDWORD pcbNeeded, LPDWORD pcReturned)
4942 UNICODE_STRING pNameW, pEnvironmentW;
4943 PWSTR pwstrNameW, pwstrEnvironmentW;
4947 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4949 pwstrNameW = asciitounicode(&pNameW, pName);
4950 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4952 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4953 buf, cbBuf, pcbNeeded, pcReturned);
4955 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4957 HeapFree(GetProcessHeap(), 0, buf);
4959 RtlFreeUnicodeString(&pNameW);
4960 RtlFreeUnicodeString(&pEnvironmentW);
4965 /******************************************************************************
4966 * EnumPortsA (WINSPOOL.@)
4971 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4972 LPDWORD pcbNeeded, LPDWORD pcReturned)
4975 LPBYTE bufferW = NULL;
4976 LPWSTR nameW = NULL;
4978 DWORD numentries = 0;
4981 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4982 cbBuf, pcbNeeded, pcReturned);
4984 /* convert servername to unicode */
4986 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4987 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4988 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4990 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4991 needed = cbBuf * sizeof(WCHAR);
4992 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4993 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4995 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4996 if (pcbNeeded) needed = *pcbNeeded;
4997 /* HeapReAlloc return NULL, when bufferW was NULL */
4998 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4999 HeapAlloc(GetProcessHeap(), 0, needed);
5001 /* Try again with the large Buffer */
5002 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5004 needed = pcbNeeded ? *pcbNeeded : 0;
5005 numentries = pcReturned ? *pcReturned : 0;
5008 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5009 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5012 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5013 DWORD entrysize = 0;
5016 LPPORT_INFO_2W pi2w;
5017 LPPORT_INFO_2A pi2a;
5020 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5022 /* First pass: calculate the size for all Entries */
5023 pi2w = (LPPORT_INFO_2W) bufferW;
5024 pi2a = (LPPORT_INFO_2A) pPorts;
5026 while (index < numentries) {
5028 needed += entrysize; /* PORT_INFO_?A */
5029 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5031 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5032 NULL, 0, NULL, NULL);
5034 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5035 NULL, 0, NULL, NULL);
5036 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5037 NULL, 0, NULL, NULL);
5039 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5040 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5041 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5044 /* check for errors and quit on failure */
5045 if (cbBuf < needed) {
5046 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5050 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5051 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5052 cbBuf -= len ; /* free Bytes in the user-Buffer */
5053 pi2w = (LPPORT_INFO_2W) bufferW;
5054 pi2a = (LPPORT_INFO_2A) pPorts;
5056 /* Second Pass: Fill the User Buffer (if we have one) */
5057 while ((index < numentries) && pPorts) {
5059 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5060 pi2a->pPortName = ptr;
5061 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5062 ptr, cbBuf , NULL, NULL);
5066 pi2a->pMonitorName = ptr;
5067 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5068 ptr, cbBuf, NULL, NULL);
5072 pi2a->pDescription = ptr;
5073 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5074 ptr, cbBuf, NULL, NULL);
5078 pi2a->fPortType = pi2w->fPortType;
5079 pi2a->Reserved = 0; /* documented: "must be zero" */
5082 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5083 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5084 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5089 if (pcbNeeded) *pcbNeeded = needed;
5090 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5092 HeapFree(GetProcessHeap(), 0, nameW);
5093 HeapFree(GetProcessHeap(), 0, bufferW);
5095 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5096 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5102 /******************************************************************************
5103 * EnumPortsW (WINSPOOL.@)
5105 * Enumerate available Ports
5108 * pName [I] Servername or NULL (local Computer)
5109 * Level [I] Structure-Level (1 or 2)
5110 * pPorts [O] PTR to Buffer that receives the Result
5111 * cbBuf [I] Size of Buffer at pPorts
5112 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5113 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5117 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5120 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5123 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5124 cbBuf, pcbNeeded, pcReturned);
5126 if ((backend == NULL) && !load_backend()) return FALSE;
5128 /* Level is not checked in win9x */
5129 if (!Level || (Level > 2)) {
5130 WARN("level (%d) is ignored in win9x\n", Level);
5131 SetLastError(ERROR_INVALID_LEVEL);
5134 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5135 SetLastError(RPC_X_NULL_REF_POINTER);
5139 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5142 /******************************************************************************
5143 * GetDefaultPrinterW (WINSPOOL.@)
5146 * This function must read the value from data 'device' of key
5147 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5149 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5153 WCHAR *buffer, *ptr;
5157 SetLastError(ERROR_INVALID_PARAMETER);
5161 /* make the buffer big enough for the stuff from the profile/registry,
5162 * the content must fit into the local buffer to compute the correct
5163 * size even if the extern buffer is too small or not given.
5164 * (20 for ,driver,port) */
5166 len = max(100, (insize + 20));
5167 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5169 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5171 SetLastError (ERROR_FILE_NOT_FOUND);
5175 TRACE("%s\n", debugstr_w(buffer));
5177 if ((ptr = strchrW(buffer, ',')) == NULL)
5179 SetLastError(ERROR_INVALID_NAME);
5185 *namesize = strlenW(buffer) + 1;
5186 if(!name || (*namesize > insize))
5188 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5192 strcpyW(name, buffer);
5195 HeapFree( GetProcessHeap(), 0, buffer);
5200 /******************************************************************************
5201 * GetDefaultPrinterA (WINSPOOL.@)
5203 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5207 WCHAR *bufferW = NULL;
5211 SetLastError(ERROR_INVALID_PARAMETER);
5215 if(name && *namesize) {
5217 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5220 if(!GetDefaultPrinterW( bufferW, namesize)) {
5225 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5229 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5232 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5235 HeapFree( GetProcessHeap(), 0, bufferW);
5240 /******************************************************************************
5241 * SetDefaultPrinterW (WINSPOOL.204)
5243 * Set the Name of the Default Printer
5246 * pszPrinter [I] Name of the Printer or NULL
5253 * When the Parameter is NULL or points to an Empty String and
5254 * a Default Printer was already present, then this Function changes nothing.
5255 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5256 * the First enumerated local Printer is used.
5259 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5262 TRACE("(%s)\n", debugstr_w(pszPrinter));
5264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5268 /******************************************************************************
5269 * SetDefaultPrinterA (WINSPOOL.202)
5271 * See SetDefaultPrinterW.
5274 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5277 TRACE("(%s)\n", debugstr_a(pszPrinter));
5279 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5284 /******************************************************************************
5285 * SetPrinterDataExA (WINSPOOL.@)
5287 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5288 LPCSTR pValueName, DWORD Type,
5289 LPBYTE pData, DWORD cbData)
5291 HKEY hkeyPrinter, hkeySubkey;
5294 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5295 debugstr_a(pValueName), Type, pData, cbData);
5297 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5301 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5303 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5304 RegCloseKey(hkeyPrinter);
5307 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5308 RegCloseKey(hkeySubkey);
5309 RegCloseKey(hkeyPrinter);
5313 /******************************************************************************
5314 * SetPrinterDataExW (WINSPOOL.@)
5316 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5317 LPCWSTR pValueName, DWORD Type,
5318 LPBYTE pData, DWORD cbData)
5320 HKEY hkeyPrinter, hkeySubkey;
5323 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5324 debugstr_w(pValueName), Type, pData, cbData);
5326 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5330 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5332 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5333 RegCloseKey(hkeyPrinter);
5336 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5337 RegCloseKey(hkeySubkey);
5338 RegCloseKey(hkeyPrinter);
5342 /******************************************************************************
5343 * SetPrinterDataA (WINSPOOL.@)
5345 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5346 LPBYTE pData, DWORD cbData)
5348 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5352 /******************************************************************************
5353 * SetPrinterDataW (WINSPOOL.@)
5355 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5356 LPBYTE pData, DWORD cbData)
5358 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5362 /******************************************************************************
5363 * GetPrinterDataExA (WINSPOOL.@)
5365 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5366 LPCSTR pValueName, LPDWORD pType,
5367 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5369 opened_printer_t *printer;
5370 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5373 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5374 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5376 printer = get_opened_printer(hPrinter);
5377 if(!printer) return ERROR_INVALID_HANDLE;
5379 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5380 if (ret) return ret;
5382 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5384 if (printer->name) {
5386 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5388 RegCloseKey(hkeyPrinters);
5391 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5392 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5393 RegCloseKey(hkeyPrinter);
5394 RegCloseKey(hkeyPrinters);
5399 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5400 0, pType, pData, pcbNeeded);
5402 if (!ret && !pData) ret = ERROR_MORE_DATA;
5404 RegCloseKey(hkeySubkey);
5405 RegCloseKey(hkeyPrinter);
5406 RegCloseKey(hkeyPrinters);
5408 TRACE("--> %d\n", ret);
5412 /******************************************************************************
5413 * GetPrinterDataExW (WINSPOOL.@)
5415 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5416 LPCWSTR pValueName, LPDWORD pType,
5417 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5419 opened_printer_t *printer;
5420 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5423 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5424 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5426 printer = get_opened_printer(hPrinter);
5427 if(!printer) return ERROR_INVALID_HANDLE;
5429 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5430 if (ret) return ret;
5432 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5434 if (printer->name) {
5436 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5438 RegCloseKey(hkeyPrinters);
5441 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5442 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5443 RegCloseKey(hkeyPrinter);
5444 RegCloseKey(hkeyPrinters);
5449 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5450 0, pType, pData, pcbNeeded);
5452 if (!ret && !pData) ret = ERROR_MORE_DATA;
5454 RegCloseKey(hkeySubkey);
5455 RegCloseKey(hkeyPrinter);
5456 RegCloseKey(hkeyPrinters);
5458 TRACE("--> %d\n", ret);
5462 /******************************************************************************
5463 * GetPrinterDataA (WINSPOOL.@)
5465 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5466 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5468 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5469 pData, nSize, pcbNeeded);
5472 /******************************************************************************
5473 * GetPrinterDataW (WINSPOOL.@)
5475 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5476 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5478 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5479 pData, nSize, pcbNeeded);
5482 /*******************************************************************************
5483 * EnumPrinterDataExW [WINSPOOL.@]
5485 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5486 LPBYTE pEnumValues, DWORD cbEnumValues,
5487 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5489 HKEY hkPrinter, hkSubKey;
5490 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5491 cbValueNameLen, cbMaxValueLen, cbValueLen,
5496 PPRINTER_ENUM_VALUESW ppev;
5498 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5500 if (pKeyName == NULL || *pKeyName == 0)
5501 return ERROR_INVALID_PARAMETER;
5503 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5504 if (ret != ERROR_SUCCESS)
5506 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5511 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5512 if (ret != ERROR_SUCCESS)
5514 r = RegCloseKey (hkPrinter);
5515 if (r != ERROR_SUCCESS)
5516 WARN ("RegCloseKey returned %i\n", r);
5517 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5518 debugstr_w (pKeyName), ret);
5522 ret = RegCloseKey (hkPrinter);
5523 if (ret != ERROR_SUCCESS)
5525 ERR ("RegCloseKey returned %i\n", ret);
5526 r = RegCloseKey (hkSubKey);
5527 if (r != ERROR_SUCCESS)
5528 WARN ("RegCloseKey returned %i\n", r);
5532 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5533 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5534 if (ret != ERROR_SUCCESS)
5536 r = RegCloseKey (hkSubKey);
5537 if (r != ERROR_SUCCESS)
5538 WARN ("RegCloseKey returned %i\n", r);
5539 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5543 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5544 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5546 if (cValues == 0) /* empty key */
5548 r = RegCloseKey (hkSubKey);
5549 if (r != ERROR_SUCCESS)
5550 WARN ("RegCloseKey returned %i\n", r);
5551 *pcbEnumValues = *pnEnumValues = 0;
5552 return ERROR_SUCCESS;
5555 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5557 hHeap = GetProcessHeap ();
5560 ERR ("GetProcessHeap failed\n");
5561 r = RegCloseKey (hkSubKey);
5562 if (r != ERROR_SUCCESS)
5563 WARN ("RegCloseKey returned %i\n", r);
5564 return ERROR_OUTOFMEMORY;
5567 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5568 if (lpValueName == NULL)
5570 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5571 r = RegCloseKey (hkSubKey);
5572 if (r != ERROR_SUCCESS)
5573 WARN ("RegCloseKey returned %i\n", r);
5574 return ERROR_OUTOFMEMORY;
5577 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5578 if (lpValue == NULL)
5580 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5581 if (HeapFree (hHeap, 0, lpValueName) == 0)
5582 WARN ("HeapFree failed with code %i\n", GetLastError ());
5583 r = RegCloseKey (hkSubKey);
5584 if (r != ERROR_SUCCESS)
5585 WARN ("RegCloseKey returned %i\n", r);
5586 return ERROR_OUTOFMEMORY;
5589 TRACE ("pass 1: calculating buffer required for all names and values\n");
5591 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5593 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5595 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5597 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5598 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5599 NULL, NULL, lpValue, &cbValueLen);
5600 if (ret != ERROR_SUCCESS)
5602 if (HeapFree (hHeap, 0, lpValue) == 0)
5603 WARN ("HeapFree failed with code %i\n", GetLastError ());
5604 if (HeapFree (hHeap, 0, lpValueName) == 0)
5605 WARN ("HeapFree failed with code %i\n", GetLastError ());
5606 r = RegCloseKey (hkSubKey);
5607 if (r != ERROR_SUCCESS)
5608 WARN ("RegCloseKey returned %i\n", r);
5609 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5613 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5614 debugstr_w (lpValueName), dwIndex,
5615 cbValueNameLen + 1, cbValueLen);
5617 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5618 cbBufSize += cbValueLen;
5621 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5623 *pcbEnumValues = cbBufSize;
5624 *pnEnumValues = cValues;
5626 if (cbEnumValues < cbBufSize) /* buffer too small */
5628 if (HeapFree (hHeap, 0, lpValue) == 0)
5629 WARN ("HeapFree failed with code %i\n", GetLastError ());
5630 if (HeapFree (hHeap, 0, lpValueName) == 0)
5631 WARN ("HeapFree failed with code %i\n", GetLastError ());
5632 r = RegCloseKey (hkSubKey);
5633 if (r != ERROR_SUCCESS)
5634 WARN ("RegCloseKey returned %i\n", r);
5635 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5636 return ERROR_MORE_DATA;
5639 TRACE ("pass 2: copying all names and values to buffer\n");
5641 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5642 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5644 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5646 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5647 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5648 NULL, &dwType, lpValue, &cbValueLen);
5649 if (ret != ERROR_SUCCESS)
5651 if (HeapFree (hHeap, 0, lpValue) == 0)
5652 WARN ("HeapFree failed with code %i\n", GetLastError ());
5653 if (HeapFree (hHeap, 0, lpValueName) == 0)
5654 WARN ("HeapFree failed with code %i\n", GetLastError ());
5655 r = RegCloseKey (hkSubKey);
5656 if (r != ERROR_SUCCESS)
5657 WARN ("RegCloseKey returned %i\n", r);
5658 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5662 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5663 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5664 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5665 pEnumValues += cbValueNameLen;
5667 /* return # of *bytes* (including trailing \0), not # of chars */
5668 ppev[dwIndex].cbValueName = cbValueNameLen;
5670 ppev[dwIndex].dwType = dwType;
5672 memcpy (pEnumValues, lpValue, cbValueLen);
5673 ppev[dwIndex].pData = pEnumValues;
5674 pEnumValues += cbValueLen;
5676 ppev[dwIndex].cbData = cbValueLen;
5678 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5679 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5682 if (HeapFree (hHeap, 0, lpValue) == 0)
5684 ret = GetLastError ();
5685 ERR ("HeapFree failed with code %i\n", ret);
5686 if (HeapFree (hHeap, 0, lpValueName) == 0)
5687 WARN ("HeapFree failed with code %i\n", GetLastError ());
5688 r = RegCloseKey (hkSubKey);
5689 if (r != ERROR_SUCCESS)
5690 WARN ("RegCloseKey returned %i\n", r);
5694 if (HeapFree (hHeap, 0, lpValueName) == 0)
5696 ret = GetLastError ();
5697 ERR ("HeapFree failed with code %i\n", ret);
5698 r = RegCloseKey (hkSubKey);
5699 if (r != ERROR_SUCCESS)
5700 WARN ("RegCloseKey returned %i\n", r);
5704 ret = RegCloseKey (hkSubKey);
5705 if (ret != ERROR_SUCCESS)
5707 ERR ("RegCloseKey returned %i\n", ret);
5711 return ERROR_SUCCESS;
5714 /*******************************************************************************
5715 * EnumPrinterDataExA [WINSPOOL.@]
5717 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5718 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5719 * what Windows 2000 SP1 does.
5722 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5723 LPBYTE pEnumValues, DWORD cbEnumValues,
5724 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5728 DWORD ret, dwIndex, dwBufSize;
5732 TRACE ("%p %s\n", hPrinter, pKeyName);
5734 if (pKeyName == NULL || *pKeyName == 0)
5735 return ERROR_INVALID_PARAMETER;
5737 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5740 ret = GetLastError ();
5741 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5745 hHeap = GetProcessHeap ();
5748 ERR ("GetProcessHeap failed\n");
5749 return ERROR_OUTOFMEMORY;
5752 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5753 if (pKeyNameW == NULL)
5755 ERR ("Failed to allocate %i bytes from process heap\n",
5756 (LONG)(len * sizeof (WCHAR)));
5757 return ERROR_OUTOFMEMORY;
5760 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5762 ret = GetLastError ();
5763 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5764 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5765 WARN ("HeapFree failed with code %i\n", GetLastError ());
5769 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5770 pcbEnumValues, pnEnumValues);
5771 if (ret != ERROR_SUCCESS)
5773 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5774 WARN ("HeapFree failed with code %i\n", GetLastError ());
5775 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5779 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5781 ret = GetLastError ();
5782 ERR ("HeapFree failed with code %i\n", ret);
5786 if (*pnEnumValues == 0) /* empty key */
5787 return ERROR_SUCCESS;
5790 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5792 PPRINTER_ENUM_VALUESW ppev =
5793 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5795 if (dwBufSize < ppev->cbValueName)
5796 dwBufSize = ppev->cbValueName;
5798 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5799 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5800 dwBufSize = ppev->cbData;
5803 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5805 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5806 if (pBuffer == NULL)
5808 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5809 return ERROR_OUTOFMEMORY;
5812 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5814 PPRINTER_ENUM_VALUESW ppev =
5815 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5817 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5818 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5822 ret = GetLastError ();
5823 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5824 if (HeapFree (hHeap, 0, pBuffer) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5829 memcpy (ppev->pValueName, pBuffer, len);
5831 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5833 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5834 ppev->dwType != REG_MULTI_SZ)
5837 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5838 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5841 ret = GetLastError ();
5842 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5843 if (HeapFree (hHeap, 0, pBuffer) == 0)
5844 WARN ("HeapFree failed with code %i\n", GetLastError ());
5848 memcpy (ppev->pData, pBuffer, len);
5850 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5851 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5854 if (HeapFree (hHeap, 0, pBuffer) == 0)
5856 ret = GetLastError ();
5857 ERR ("HeapFree failed with code %i\n", ret);
5861 return ERROR_SUCCESS;
5864 /******************************************************************************
5865 * AbortPrinter (WINSPOOL.@)
5867 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5869 FIXME("(%p), stub!\n", hPrinter);
5873 /******************************************************************************
5874 * AddPortA (WINSPOOL.@)
5879 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5881 LPWSTR nameW = NULL;
5882 LPWSTR monitorW = NULL;
5886 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5889 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5890 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5891 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5895 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5896 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5897 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5899 res = AddPortW(nameW, hWnd, monitorW);
5900 HeapFree(GetProcessHeap(), 0, nameW);
5901 HeapFree(GetProcessHeap(), 0, monitorW);
5905 /******************************************************************************
5906 * AddPortW (WINSPOOL.@)
5908 * Add a Port for a specific Monitor
5911 * pName [I] Servername or NULL (local Computer)
5912 * hWnd [I] Handle to parent Window for the Dialog-Box
5913 * pMonitorName [I] Name of the Monitor that manage the Port
5920 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5922 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5924 if ((backend == NULL) && !load_backend()) return FALSE;
5926 if (!pMonitorName) {
5927 SetLastError(RPC_X_NULL_REF_POINTER);
5931 return backend->fpAddPort(pName, hWnd, pMonitorName);
5934 /******************************************************************************
5935 * AddPortExA (WINSPOOL.@)
5940 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5943 PORT_INFO_2A * pi2A;
5944 LPWSTR nameW = NULL;
5945 LPWSTR monitorW = NULL;
5949 pi2A = (PORT_INFO_2A *) pBuffer;
5951 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5952 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5954 if ((level < 1) || (level > 2)) {
5955 SetLastError(ERROR_INVALID_LEVEL);
5960 SetLastError(ERROR_INVALID_PARAMETER);
5965 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5966 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5967 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5971 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5972 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5973 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5976 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5978 if (pi2A->pPortName) {
5979 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5980 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5981 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5985 if (pi2A->pMonitorName) {
5986 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5987 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5988 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5991 if (pi2A->pDescription) {
5992 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5993 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5994 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5996 pi2W.fPortType = pi2A->fPortType;
5997 pi2W.Reserved = pi2A->Reserved;
6000 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6002 HeapFree(GetProcessHeap(), 0, nameW);
6003 HeapFree(GetProcessHeap(), 0, monitorW);
6004 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6005 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6006 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6011 /******************************************************************************
6012 * AddPortExW (WINSPOOL.@)
6014 * Add a Port for a specific Monitor, without presenting a user interface
6017 * pName [I] Servername or NULL (local Computer)
6018 * level [I] Structure-Level (1 or 2) for pBuffer
6019 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6020 * pMonitorName [I] Name of the Monitor that manage the Port
6027 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6031 pi2 = (PORT_INFO_2W *) pBuffer;
6033 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6034 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6035 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6036 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6038 if ((backend == NULL) && !load_backend()) return FALSE;
6040 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6041 SetLastError(ERROR_INVALID_PARAMETER);
6045 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6048 /******************************************************************************
6049 * AddPrinterConnectionA (WINSPOOL.@)
6051 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6053 FIXME("%s\n", debugstr_a(pName));
6057 /******************************************************************************
6058 * AddPrinterConnectionW (WINSPOOL.@)
6060 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6062 FIXME("%s\n", debugstr_w(pName));
6066 /******************************************************************************
6067 * AddPrinterDriverExW (WINSPOOL.@)
6069 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6072 * pName [I] Servername or NULL (local Computer)
6073 * level [I] Level for the supplied DRIVER_INFO_*W struct
6074 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6075 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6082 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6084 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6086 if ((backend == NULL) && !load_backend()) return FALSE;
6088 if (level < 2 || level == 5 || level == 7 || level > 8) {
6089 SetLastError(ERROR_INVALID_LEVEL);
6094 SetLastError(ERROR_INVALID_PARAMETER);
6098 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6101 /******************************************************************************
6102 * AddPrinterDriverExA (WINSPOOL.@)
6104 * See AddPrinterDriverExW.
6107 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6109 DRIVER_INFO_8A *diA;
6111 LPWSTR nameW = NULL;
6116 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6118 diA = (DRIVER_INFO_8A *) pDriverInfo;
6119 ZeroMemory(&diW, sizeof(diW));
6121 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6122 SetLastError(ERROR_INVALID_LEVEL);
6127 SetLastError(ERROR_INVALID_PARAMETER);
6131 /* convert servername to unicode */
6133 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6134 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6135 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6139 diW.cVersion = diA->cVersion;
6142 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6143 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6144 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6147 if (diA->pEnvironment) {
6148 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6149 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6150 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6153 if (diA->pDriverPath) {
6154 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6155 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6156 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6159 if (diA->pDataFile) {
6160 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6161 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6162 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6165 if (diA->pConfigFile) {
6166 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6167 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6168 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6171 if ((Level > 2) && diA->pDependentFiles) {
6172 lenA = multi_sz_lenA(diA->pDependentFiles);
6173 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6174 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6175 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6178 if ((Level > 2) && diA->pMonitorName) {
6179 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6180 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6181 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6184 if ((Level > 3) && diA->pDefaultDataType) {
6185 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6186 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6187 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6190 if ((Level > 3) && diA->pszzPreviousNames) {
6191 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6192 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6193 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6194 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6197 if ((Level > 5) && diA->pszMfgName) {
6198 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6199 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6200 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6203 if ((Level > 5) && diA->pszOEMUrl) {
6204 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6205 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6206 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6209 if ((Level > 5) && diA->pszHardwareID) {
6210 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6211 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6212 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6215 if ((Level > 5) && diA->pszProvider) {
6216 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6217 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6218 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6222 FIXME("level %u is incomplete\n", Level);
6225 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6226 TRACE("got %u with %u\n", res, GetLastError());
6227 HeapFree(GetProcessHeap(), 0, nameW);
6228 HeapFree(GetProcessHeap(), 0, diW.pName);
6229 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6230 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6231 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6232 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6233 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6234 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6235 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6236 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6237 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6238 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6239 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6240 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6242 TRACE("=> %u with %u\n", res, GetLastError());
6246 /******************************************************************************
6247 * ConfigurePortA (WINSPOOL.@)
6249 * See ConfigurePortW.
6252 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6254 LPWSTR nameW = NULL;
6255 LPWSTR portW = NULL;
6259 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6261 /* convert servername to unicode */
6263 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6264 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6265 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6268 /* convert portname to unicode */
6270 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6271 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6272 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6275 res = ConfigurePortW(nameW, hWnd, portW);
6276 HeapFree(GetProcessHeap(), 0, nameW);
6277 HeapFree(GetProcessHeap(), 0, portW);
6281 /******************************************************************************
6282 * ConfigurePortW (WINSPOOL.@)
6284 * Display the Configuration-Dialog for a specific Port
6287 * pName [I] Servername or NULL (local Computer)
6288 * hWnd [I] Handle to parent Window for the Dialog-Box
6289 * pPortName [I] Name of the Port, that should be configured
6296 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6299 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6301 if ((backend == NULL) && !load_backend()) return FALSE;
6304 SetLastError(RPC_X_NULL_REF_POINTER);
6308 return backend->fpConfigurePort(pName, hWnd, pPortName);
6311 /******************************************************************************
6312 * ConnectToPrinterDlg (WINSPOOL.@)
6314 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6316 FIXME("%p %x\n", hWnd, Flags);
6320 /******************************************************************************
6321 * DeletePrinterConnectionA (WINSPOOL.@)
6323 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6325 FIXME("%s\n", debugstr_a(pName));
6329 /******************************************************************************
6330 * DeletePrinterConnectionW (WINSPOOL.@)
6332 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6334 FIXME("%s\n", debugstr_w(pName));
6338 /******************************************************************************
6339 * DeletePrinterDriverExW (WINSPOOL.@)
6341 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6342 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6347 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6348 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6350 if(pName && pName[0])
6352 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6353 SetLastError(ERROR_INVALID_PARAMETER);
6359 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6360 SetLastError(ERROR_INVALID_PARAMETER);
6364 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6368 ERR("Can't open drivers key\n");
6372 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6375 RegCloseKey(hkey_drivers);
6380 /******************************************************************************
6381 * DeletePrinterDriverExA (WINSPOOL.@)
6383 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6384 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6386 UNICODE_STRING NameW, EnvW, DriverW;
6389 asciitounicode(&NameW, pName);
6390 asciitounicode(&EnvW, pEnvironment);
6391 asciitounicode(&DriverW, pDriverName);
6393 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6395 RtlFreeUnicodeString(&DriverW);
6396 RtlFreeUnicodeString(&EnvW);
6397 RtlFreeUnicodeString(&NameW);
6402 /******************************************************************************
6403 * DeletePrinterDataExW (WINSPOOL.@)
6405 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6408 FIXME("%p %s %s\n", hPrinter,
6409 debugstr_w(pKeyName), debugstr_w(pValueName));
6410 return ERROR_INVALID_PARAMETER;
6413 /******************************************************************************
6414 * DeletePrinterDataExA (WINSPOOL.@)
6416 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6419 FIXME("%p %s %s\n", hPrinter,
6420 debugstr_a(pKeyName), debugstr_a(pValueName));
6421 return ERROR_INVALID_PARAMETER;
6424 /******************************************************************************
6425 * DeletePrintProcessorA (WINSPOOL.@)
6427 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6429 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6430 debugstr_a(pPrintProcessorName));
6434 /******************************************************************************
6435 * DeletePrintProcessorW (WINSPOOL.@)
6437 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6439 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6440 debugstr_w(pPrintProcessorName));
6444 /******************************************************************************
6445 * DeletePrintProvidorA (WINSPOOL.@)
6447 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6449 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6450 debugstr_a(pPrintProviderName));
6454 /******************************************************************************
6455 * DeletePrintProvidorW (WINSPOOL.@)
6457 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6459 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6460 debugstr_w(pPrintProviderName));
6464 /******************************************************************************
6465 * EnumFormsA (WINSPOOL.@)
6467 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6468 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6470 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6471 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6475 /******************************************************************************
6476 * EnumFormsW (WINSPOOL.@)
6478 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6479 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6481 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6482 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6486 /*****************************************************************************
6487 * EnumMonitorsA [WINSPOOL.@]
6489 * See EnumMonitorsW.
6492 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6493 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6496 LPBYTE bufferW = NULL;
6497 LPWSTR nameW = NULL;
6499 DWORD numentries = 0;
6502 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6503 cbBuf, pcbNeeded, pcReturned);
6505 /* convert servername to unicode */
6507 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6508 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6509 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6511 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6512 needed = cbBuf * sizeof(WCHAR);
6513 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6514 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6516 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6517 if (pcbNeeded) needed = *pcbNeeded;
6518 /* HeapReAlloc return NULL, when bufferW was NULL */
6519 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6520 HeapAlloc(GetProcessHeap(), 0, needed);
6522 /* Try again with the large Buffer */
6523 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6525 numentries = pcReturned ? *pcReturned : 0;
6528 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6529 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6532 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6533 DWORD entrysize = 0;
6536 LPMONITOR_INFO_2W mi2w;
6537 LPMONITOR_INFO_2A mi2a;
6539 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6540 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6542 /* First pass: calculate the size for all Entries */
6543 mi2w = (LPMONITOR_INFO_2W) bufferW;
6544 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6546 while (index < numentries) {
6548 needed += entrysize; /* MONITOR_INFO_?A */
6549 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6551 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6552 NULL, 0, NULL, NULL);
6554 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6555 NULL, 0, NULL, NULL);
6556 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6557 NULL, 0, NULL, NULL);
6559 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6560 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6561 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6564 /* check for errors and quit on failure */
6565 if (cbBuf < needed) {
6566 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6570 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6571 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6572 cbBuf -= len ; /* free Bytes in the user-Buffer */
6573 mi2w = (LPMONITOR_INFO_2W) bufferW;
6574 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6576 /* Second Pass: Fill the User Buffer (if we have one) */
6577 while ((index < numentries) && pMonitors) {
6579 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6581 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6582 ptr, cbBuf , NULL, NULL);
6586 mi2a->pEnvironment = ptr;
6587 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6588 ptr, cbBuf, NULL, NULL);
6592 mi2a->pDLLName = ptr;
6593 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6594 ptr, cbBuf, NULL, NULL);
6598 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6599 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6600 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6604 if (pcbNeeded) *pcbNeeded = needed;
6605 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6607 HeapFree(GetProcessHeap(), 0, nameW);
6608 HeapFree(GetProcessHeap(), 0, bufferW);
6610 TRACE("returning %d with %d (%d byte for %d entries)\n",
6611 (res), GetLastError(), needed, numentries);
6617 /*****************************************************************************
6618 * EnumMonitorsW [WINSPOOL.@]
6620 * Enumerate available Port-Monitors
6623 * pName [I] Servername or NULL (local Computer)
6624 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6625 * pMonitors [O] PTR to Buffer that receives the Result
6626 * cbBuf [I] Size of Buffer at pMonitors
6627 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6628 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6632 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6635 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6636 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6639 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6640 cbBuf, pcbNeeded, pcReturned);
6642 if ((backend == NULL) && !load_backend()) return FALSE;
6644 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6645 SetLastError(RPC_X_NULL_REF_POINTER);
6649 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6652 /******************************************************************************
6653 * SpoolerInit (WINSPOOL.@)
6655 * Initialize the Spooler
6662 * The function fails on windows, when the spooler service is not running
6665 BOOL WINAPI SpoolerInit(void)
6668 if ((backend == NULL) && !load_backend()) return FALSE;
6672 /******************************************************************************
6673 * XcvDataW (WINSPOOL.@)
6675 * Execute commands in the Printmonitor DLL
6678 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6679 * pszDataName [i] Name of the command to execute
6680 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6681 * cbInputData [i] Size in Bytes of Buffer at pInputData
6682 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6683 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6684 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6685 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6692 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6693 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6695 * Minimal List of commands, that a Printmonitor DLL should support:
6697 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6698 *| "AddPort" : Add a Port
6699 *| "DeletePort": Delete a Port
6701 * Many Printmonitors support additional commands. Examples for localspl.dll:
6702 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6703 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6706 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6707 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6708 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6710 opened_printer_t *printer;
6712 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6713 pInputData, cbInputData, pOutputData,
6714 cbOutputData, pcbOutputNeeded, pdwStatus);
6716 if ((backend == NULL) && !load_backend()) return FALSE;
6718 printer = get_opened_printer(hXcv);
6719 if (!printer || (!printer->backend_printer)) {
6720 SetLastError(ERROR_INVALID_HANDLE);
6724 if (!pcbOutputNeeded) {
6725 SetLastError(ERROR_INVALID_PARAMETER);
6729 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6730 SetLastError(RPC_X_NULL_REF_POINTER);
6734 *pcbOutputNeeded = 0;
6736 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6737 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6741 /*****************************************************************************
6742 * EnumPrinterDataA [WINSPOOL.@]
6745 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6746 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6747 DWORD cbData, LPDWORD pcbData )
6749 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6750 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6751 return ERROR_NO_MORE_ITEMS;
6754 /*****************************************************************************
6755 * EnumPrinterDataW [WINSPOOL.@]
6758 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6759 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6760 DWORD cbData, LPDWORD pcbData )
6762 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6763 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6764 return ERROR_NO_MORE_ITEMS;
6767 /*****************************************************************************
6768 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6771 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6772 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6773 LPDWORD pcbNeeded, LPDWORD pcReturned)
6775 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6776 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6777 pcbNeeded, pcReturned);
6781 /*****************************************************************************
6782 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6785 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6786 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6787 LPDWORD pcbNeeded, LPDWORD pcReturned)
6789 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6790 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6791 pcbNeeded, pcReturned);
6795 /*****************************************************************************
6796 * EnumPrintProcessorsA [WINSPOOL.@]
6798 * See EnumPrintProcessorsW.
6801 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6802 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6805 LPBYTE bufferW = NULL;
6806 LPWSTR nameW = NULL;
6809 DWORD numentries = 0;
6812 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6813 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6815 /* convert names to unicode */
6817 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6818 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6819 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6822 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6823 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6824 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6827 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6828 needed = cbBuf * sizeof(WCHAR);
6829 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6830 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6832 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6833 if (pcbNeeded) needed = *pcbNeeded;
6834 /* HeapReAlloc return NULL, when bufferW was NULL */
6835 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6836 HeapAlloc(GetProcessHeap(), 0, needed);
6838 /* Try again with the large Buffer */
6839 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6841 numentries = pcReturned ? *pcReturned : 0;
6845 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6848 PPRINTPROCESSOR_INFO_1W ppiw;
6849 PPRINTPROCESSOR_INFO_1A ppia;
6851 /* First pass: calculate the size for all Entries */
6852 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6853 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6855 while (index < numentries) {
6857 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6858 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6860 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6861 NULL, 0, NULL, NULL);
6863 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6864 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6867 /* check for errors and quit on failure */
6868 if (cbBuf < needed) {
6869 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6874 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6875 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6876 cbBuf -= len ; /* free Bytes in the user-Buffer */
6877 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6878 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6880 /* Second Pass: Fill the User Buffer (if we have one) */
6881 while ((index < numentries) && pPPInfo) {
6883 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6885 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6886 ptr, cbBuf , NULL, NULL);
6890 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6891 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6896 if (pcbNeeded) *pcbNeeded = needed;
6897 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6899 HeapFree(GetProcessHeap(), 0, nameW);
6900 HeapFree(GetProcessHeap(), 0, envW);
6901 HeapFree(GetProcessHeap(), 0, bufferW);
6903 TRACE("returning %d with %d (%d byte for %d entries)\n",
6904 (res), GetLastError(), needed, numentries);
6909 /*****************************************************************************
6910 * EnumPrintProcessorsW [WINSPOOL.@]
6912 * Enumerate available Print Processors
6915 * pName [I] Servername or NULL (local Computer)
6916 * pEnvironment [I] Printing-Environment or NULL (Default)
6917 * Level [I] Structure-Level (Only 1 is allowed)
6918 * pPPInfo [O] PTR to Buffer that receives the Result
6919 * cbBuf [I] Size of Buffer at pPPInfo
6920 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6921 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6925 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6928 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6929 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6932 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6933 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6935 if ((backend == NULL) && !load_backend()) return FALSE;
6937 if (!pcbNeeded || !pcReturned) {
6938 SetLastError(RPC_X_NULL_REF_POINTER);
6942 if (!pPPInfo && (cbBuf > 0)) {
6943 SetLastError(ERROR_INVALID_USER_BUFFER);
6947 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6948 cbBuf, pcbNeeded, pcReturned);
6951 /*****************************************************************************
6952 * ExtDeviceMode [WINSPOOL.@]
6955 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6956 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6959 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6960 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6961 debugstr_a(pProfile), fMode);
6965 /*****************************************************************************
6966 * FindClosePrinterChangeNotification [WINSPOOL.@]
6969 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6971 FIXME("Stub: %p\n", hChange);
6975 /*****************************************************************************
6976 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6979 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6980 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6982 FIXME("Stub: %p %x %x %p\n",
6983 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6984 return INVALID_HANDLE_VALUE;
6987 /*****************************************************************************
6988 * FindNextPrinterChangeNotification [WINSPOOL.@]
6991 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6992 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6994 FIXME("Stub: %p %p %p %p\n",
6995 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6999 /*****************************************************************************
7000 * FreePrinterNotifyInfo [WINSPOOL.@]
7003 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7005 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7009 /*****************************************************************************
7012 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7013 * ansi depending on the unicode parameter.
7015 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7025 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7028 memcpy(ptr, str, *size);
7035 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7038 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7045 /*****************************************************************************
7048 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7049 LPDWORD pcbNeeded, BOOL unicode)
7051 DWORD size, left = cbBuf;
7052 BOOL space = (cbBuf > 0);
7059 ji1->JobId = job->job_id;
7062 string_to_buf(job->document_title, ptr, left, &size, unicode);
7063 if(space && size <= left)
7065 ji1->pDocument = (LPWSTR)ptr;
7073 if (job->printer_name)
7075 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7076 if(space && size <= left)
7078 ji1->pPrinterName = (LPWSTR)ptr;
7090 /*****************************************************************************
7093 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7094 LPDWORD pcbNeeded, BOOL unicode)
7096 DWORD size, left = cbBuf;
7098 BOOL space = (cbBuf > 0);
7107 ji2->JobId = job->job_id;
7110 string_to_buf(job->document_title, ptr, left, &size, unicode);
7111 if(space && size <= left)
7113 ji2->pDocument = (LPWSTR)ptr;
7121 if (job->printer_name)
7123 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7124 if(space && size <= left)
7126 ji2->pPrinterName = (LPWSTR)ptr;
7139 dmA = DEVMODEdupWtoA(job->devmode);
7140 devmode = (LPDEVMODEW) dmA;
7141 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7145 devmode = job->devmode;
7146 size = devmode->dmSize + devmode->dmDriverExtra;
7150 FIXME("Can't convert DEVMODE W to A\n");
7153 /* align DEVMODE to a DWORD boundary */
7154 shift= (4 - ( (DWORD_PTR) ptr & 3)) & 3;
7160 memcpy(ptr, devmode, size-shift);
7161 ji2->pDevMode = (LPDEVMODEW)ptr;
7162 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7175 /*****************************************************************************
7178 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7179 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7182 DWORD needed = 0, size;
7186 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7188 EnterCriticalSection(&printer_handles_cs);
7189 job = get_job(hPrinter, JobId);
7196 size = sizeof(JOB_INFO_1W);
7201 memset(pJob, 0, size);
7205 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7210 size = sizeof(JOB_INFO_2W);
7215 memset(pJob, 0, size);
7219 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7224 size = sizeof(JOB_INFO_3);
7228 memset(pJob, 0, size);
7237 SetLastError(ERROR_INVALID_LEVEL);
7241 *pcbNeeded = needed;
7243 LeaveCriticalSection(&printer_handles_cs);
7247 /*****************************************************************************
7248 * GetJobA [WINSPOOL.@]
7251 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7252 DWORD cbBuf, LPDWORD pcbNeeded)
7254 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7257 /*****************************************************************************
7258 * GetJobW [WINSPOOL.@]
7261 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7262 DWORD cbBuf, LPDWORD pcbNeeded)
7264 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7267 /*****************************************************************************
7270 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7272 char *unixname, *queue, *cmd;
7273 char fmt[] = "lpr -P'%s' '%s'";
7277 if(!(unixname = wine_get_unix_file_name(filename)))
7280 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7281 queue = HeapAlloc(GetProcessHeap(), 0, len);
7282 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7284 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7285 sprintf(cmd, fmt, queue, unixname);
7287 TRACE("printing with: %s\n", cmd);
7290 HeapFree(GetProcessHeap(), 0, cmd);
7291 HeapFree(GetProcessHeap(), 0, queue);
7292 HeapFree(GetProcessHeap(), 0, unixname);
7296 /*****************************************************************************
7299 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7301 #ifdef SONAME_LIBCUPS
7304 char *unixname, *queue, *unix_doc_title;
7308 if(!(unixname = wine_get_unix_file_name(filename)))
7311 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7312 queue = HeapAlloc(GetProcessHeap(), 0, len);
7313 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7315 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7316 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7317 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7319 TRACE("printing via cups\n");
7320 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7321 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7322 HeapFree(GetProcessHeap(), 0, queue);
7323 HeapFree(GetProcessHeap(), 0, unixname);
7329 return schedule_lpr(printer_name, filename);
7333 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7340 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7344 if(HIWORD(wparam) == BN_CLICKED)
7346 if(LOWORD(wparam) == IDOK)
7349 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7352 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7353 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7355 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7357 WCHAR caption[200], message[200];
7360 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7361 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7362 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7363 if(mb_ret == IDCANCEL)
7365 HeapFree(GetProcessHeap(), 0, filename);
7369 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7370 if(hf == INVALID_HANDLE_VALUE)
7372 WCHAR caption[200], message[200];
7374 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7375 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7376 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7377 HeapFree(GetProcessHeap(), 0, filename);
7381 DeleteFileW(filename);
7382 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7384 EndDialog(hwnd, IDOK);
7387 if(LOWORD(wparam) == IDCANCEL)
7389 EndDialog(hwnd, IDCANCEL);
7398 /*****************************************************************************
7401 static BOOL get_filename(LPWSTR *filename)
7403 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7404 file_dlg_proc, (LPARAM)filename) == IDOK;
7407 /*****************************************************************************
7410 static BOOL schedule_file(LPCWSTR filename)
7412 LPWSTR output = NULL;
7414 if(get_filename(&output))
7417 TRACE("copy to %s\n", debugstr_w(output));
7418 r = CopyFileW(filename, output, FALSE);
7419 HeapFree(GetProcessHeap(), 0, output);
7425 /*****************************************************************************
7428 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7431 char *unixname, *cmdA;
7433 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7437 if(!(unixname = wine_get_unix_file_name(filename)))
7440 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7441 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7442 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7444 TRACE("printing with: %s\n", cmdA);
7446 if((file_fd = open(unixname, O_RDONLY)) == -1)
7451 ERR("pipe() failed!\n");
7461 /* reset signals that we previously set to SIG_IGN */
7462 signal(SIGPIPE, SIG_DFL);
7463 signal(SIGCHLD, SIG_DFL);
7465 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7469 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7470 write(fds[1], buf, no_read);
7475 if(file_fd != -1) close(file_fd);
7476 if(fds[0] != -1) close(fds[0]);
7477 if(fds[1] != -1) close(fds[1]);
7479 HeapFree(GetProcessHeap(), 0, cmdA);
7480 HeapFree(GetProcessHeap(), 0, unixname);
7487 /*****************************************************************************
7490 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7492 int in_fd, out_fd, no_read;
7495 char *unixname, *outputA;
7498 if(!(unixname = wine_get_unix_file_name(filename)))
7501 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7502 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7503 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7505 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7506 in_fd = open(unixname, O_RDONLY);
7507 if(out_fd == -1 || in_fd == -1)
7510 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7511 write(out_fd, buf, no_read);
7515 if(in_fd != -1) close(in_fd);
7516 if(out_fd != -1) close(out_fd);
7517 HeapFree(GetProcessHeap(), 0, outputA);
7518 HeapFree(GetProcessHeap(), 0, unixname);
7522 /*****************************************************************************
7523 * ScheduleJob [WINSPOOL.@]
7526 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7528 opened_printer_t *printer;
7530 struct list *cursor, *cursor2;
7532 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7533 EnterCriticalSection(&printer_handles_cs);
7534 printer = get_opened_printer(hPrinter);
7538 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7540 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7543 if(job->job_id != dwJobID) continue;
7545 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7546 if(hf != INVALID_HANDLE_VALUE)
7548 PRINTER_INFO_5W *pi5 = NULL;
7549 LPWSTR portname = job->portname;
7553 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7554 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7558 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7559 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7560 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7561 portname = pi5->pPortName;
7563 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7564 debugstr_w(portname));
7568 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7569 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7571 DWORD type, count = sizeof(output);
7572 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7575 if(output[0] == '|')
7577 ret = schedule_pipe(output + 1, job->filename);
7581 ret = schedule_unixfile(output, job->filename);
7583 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7585 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7587 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7589 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7591 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7593 ret = schedule_file(job->filename);
7597 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7599 HeapFree(GetProcessHeap(), 0, pi5);
7601 DeleteFileW(job->filename);
7603 list_remove(cursor);
7604 HeapFree(GetProcessHeap(), 0, job->document_title);
7605 HeapFree(GetProcessHeap(), 0, job->printer_name);
7606 HeapFree(GetProcessHeap(), 0, job->portname);
7607 HeapFree(GetProcessHeap(), 0, job->filename);
7608 HeapFree(GetProcessHeap(), 0, job->devmode);
7609 HeapFree(GetProcessHeap(), 0, job);
7613 LeaveCriticalSection(&printer_handles_cs);
7617 /*****************************************************************************
7618 * StartDocDlgA [WINSPOOL.@]
7620 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7622 UNICODE_STRING usBuffer;
7625 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7628 docW.cbSize = sizeof(docW);
7629 if (doc->lpszDocName)
7631 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7632 if (!(docW.lpszDocName = docnameW)) return NULL;
7634 if (doc->lpszOutput)
7636 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7637 if (!(docW.lpszOutput = outputW)) return NULL;
7639 if (doc->lpszDatatype)
7641 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7642 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7644 docW.fwType = doc->fwType;
7646 retW = StartDocDlgW(hPrinter, &docW);
7650 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7651 ret = HeapAlloc(GetProcessHeap(), 0, len);
7652 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7653 HeapFree(GetProcessHeap(), 0, retW);
7656 HeapFree(GetProcessHeap(), 0, datatypeW);
7657 HeapFree(GetProcessHeap(), 0, outputW);
7658 HeapFree(GetProcessHeap(), 0, docnameW);
7663 /*****************************************************************************
7664 * StartDocDlgW [WINSPOOL.@]
7666 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7667 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7668 * port is "FILE:". Also returns the full path if passed a relative path.
7670 * The caller should free the returned string from the process heap.
7672 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7677 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7679 PRINTER_INFO_5W *pi5;
7680 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7681 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7683 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7684 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7685 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7687 HeapFree(GetProcessHeap(), 0, pi5);
7690 HeapFree(GetProcessHeap(), 0, pi5);
7693 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7697 if (get_filename(&name))
7699 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7701 HeapFree(GetProcessHeap(), 0, name);
7704 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7705 GetFullPathNameW(name, len, ret, NULL);
7706 HeapFree(GetProcessHeap(), 0, name);
7711 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7714 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7715 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7717 attr = GetFileAttributesW(ret);
7718 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7720 HeapFree(GetProcessHeap(), 0, ret);