4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2009 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
76 /* ############################### */
91 HANDLE backend_printer;
100 WCHAR *document_title;
108 LPCWSTR versionregpath;
109 LPCWSTR versionsubdir;
112 /* ############################### */
114 static opened_printer_t **printer_handles;
115 static UINT nb_printer_handles;
116 static LONG next_job_id = 1;
118 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
119 WORD fwCapability, LPSTR lpszOutput,
121 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
122 LPSTR lpszDevice, LPSTR lpszPort,
123 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
126 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
127 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
128 'c','o','n','t','r','o','l','\\',
129 'P','r','i','n','t','\\',
130 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
131 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
133 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
134 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
135 'C','o','n','t','r','o','l','\\',
136 'P','r','i','n','t','\\',
137 'P','r','i','n','t','e','r','s',0};
139 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
141 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
142 'M','i','c','r','o','s','o','f','t','\\',
143 'W','i','n','d','o','w','s',' ','N','T','\\',
144 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
145 'W','i','n','d','o','w','s',0};
147 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
148 'M','i','c','r','o','s','o','f','t','\\',
149 'W','i','n','d','o','w','s',' ','N','T','\\',
150 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
151 'D','e','v','i','c','e','s',0};
153 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
154 'M','i','c','r','o','s','o','f','t','\\',
155 'W','i','n','d','o','w','s',' ','N','T','\\',
156 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
157 'P','o','r','t','s',0};
159 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
160 'M','i','c','r','o','s','o','f','t','\\',
161 'W','i','n','d','o','w','s',' ','N','T','\\',
162 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
163 'P','r','i','n','t','e','r','P','o','r','t','s',0};
165 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
166 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
167 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
168 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
169 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
170 static const WCHAR subdir_x64W[] = {'x','6','4',0};
171 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
172 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
173 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
174 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
175 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
177 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
178 static const WCHAR backslashW[] = {'\\',0};
179 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
180 'i','o','n',' ','F','i','l','e',0};
181 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
182 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
183 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
184 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
185 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
186 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
187 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
188 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
189 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
190 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
191 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
192 static const WCHAR NameW[] = {'N','a','m','e',0};
193 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
194 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
195 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
196 static const WCHAR PortW[] = {'P','o','r','t',0};
197 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
198 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
199 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
200 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
201 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
202 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
203 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
204 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
205 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
206 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
207 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
208 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
209 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
210 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
211 static const WCHAR emptyStringW[] = {0};
213 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
215 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
216 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
217 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
219 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
220 'D','o','c','u','m','e','n','t',0};
222 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
223 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
224 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
225 0, sizeof(DRIVER_INFO_8W)};
228 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
229 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
230 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
231 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
232 sizeof(PRINTER_INFO_9W)};
234 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
235 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
236 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
238 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
240 /******************************************************************
241 * validate the user-supplied printing-environment [internal]
244 * env [I] PTR to Environment-String or NULL
248 * Success: PTR to printenv_t
251 * An empty string is handled the same way as NULL.
252 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
256 static const printenv_t * validate_envW(LPCWSTR env)
258 const printenv_t *result = NULL;
261 TRACE("testing %s\n", debugstr_w(env));
264 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
266 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
268 result = all_printenv[i];
273 if (result == NULL) {
274 FIXME("unsupported Environment: %s\n", debugstr_w(env));
275 SetLastError(ERROR_INVALID_ENVIRONMENT);
277 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
281 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
283 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
289 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
290 if passed a NULL string. This returns NULLs to the result.
292 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
296 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
297 return usBufferPtr->Buffer;
299 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
303 static LPWSTR strdupW(LPCWSTR p)
309 len = (strlenW(p) + 1) * sizeof(WCHAR);
310 ret = HeapAlloc(GetProcessHeap(), 0, len);
315 static LPSTR strdupWtoA( LPCWSTR str )
320 if (!str) return NULL;
321 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
322 ret = HeapAlloc( GetProcessHeap(), 0, len );
323 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
327 /******************************************************************
328 * Return the number of bytes for an multi_sz string.
329 * The result includes all \0s
330 * (specifically the extra \0, that is needed as multi_sz terminator).
333 static int multi_sz_lenW(const WCHAR *str)
335 const WCHAR *ptr = str;
339 ptr += lstrlenW(ptr) + 1;
342 return (ptr - str + 1) * sizeof(WCHAR);
345 /* ################################ */
347 static int multi_sz_lenA(const char *str)
349 const char *ptr = str;
353 ptr += lstrlenA(ptr) + 1;
356 return ptr - str + 1;
360 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
363 /* If forcing, or no profile string entry for device yet, set the entry
365 * The always change entry if not WINEPS yet is discussable.
368 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
370 !strstr(qbuf,"WINEPS.DRV")
372 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
375 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
376 WriteProfileStringA("windows","device",buf);
377 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
378 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
381 HeapFree(GetProcessHeap(),0,buf);
385 static BOOL add_printer_driver(const char *name)
389 static char driver_9x[] = "wineps16.drv",
390 driver_nt[] = "wineps.drv",
391 env_9x[] = "Windows 4.0",
392 env_nt[] = "Windows NT x86",
393 data_file[] = "generic.ppd",
394 default_data_type[] = "RAW";
396 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
398 di3a.pName = (char *)name;
399 di3a.pEnvironment = env_nt;
400 di3a.pDriverPath = driver_nt;
401 di3a.pDataFile = data_file;
402 di3a.pConfigFile = driver_nt;
403 di3a.pDefaultDataType = default_data_type;
405 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
406 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
409 di3a.pEnvironment = env_9x;
410 di3a.pDriverPath = driver_9x;
411 di3a.pConfigFile = driver_9x;
412 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
413 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
418 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
419 debugstr_a(di3a.pEnvironment), GetLastError());
423 #ifdef SONAME_LIBCUPS
424 static typeof(cupsFreeDests) *pcupsFreeDests;
425 static typeof(cupsGetDests) *pcupsGetDests;
426 static typeof(cupsGetPPD) *pcupsGetPPD;
427 static typeof(cupsPrintFile) *pcupsPrintFile;
428 static void *cupshandle;
430 static BOOL CUPS_LoadPrinters(void)
433 BOOL hadprinter = FALSE, haddefault = FALSE;
435 PRINTER_INFO_2A pinfo2a;
437 HKEY hkeyPrinter, hkeyPrinters, hkey;
440 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
442 TRACE("%s\n", loaderror);
445 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
448 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
449 if (!p##x) return FALSE;
451 DYNCUPS(cupsFreeDests);
453 DYNCUPS(cupsGetDests);
454 DYNCUPS(cupsPrintFile);
457 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
459 ERR("Can't create Printers key\n");
463 nrofdests = pcupsGetDests(&dests);
464 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
465 for (i=0;i<nrofdests;i++) {
466 /* FIXME: replace "LPR:" with "CUPS:". Fix printing output first */
467 port = HeapAlloc(GetProcessHeap(), 0, strlen("LPR:") + strlen(dests[i].name)+1);
468 sprintf(port,"LPR:%s", dests[i].name);
469 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
470 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
471 sprintf(devline, "WINEPS.DRV,%s", port);
472 WriteProfileStringA("devices", dests[i].name, devline);
473 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
474 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
478 lstrcatA(devline, ",15,45");
479 WriteProfileStringA("PrinterPorts", dests[i].name, devline);
480 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
481 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
485 HeapFree(GetProcessHeap(), 0, devline);
487 TRACE("Printer %d: %s\n", i, dests[i].name);
488 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
489 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
491 TRACE("Printer already exists\n");
492 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
493 RegCloseKey(hkeyPrinter);
495 static CHAR data_type[] = "RAW",
496 print_proc[] = "WinPrint",
497 comment[] = "WINEPS Printer using CUPS",
498 location[] = "<physical location of printer>",
499 params[] = "<parameters?>",
500 share_name[] = "<share name?>",
501 sep_file[] = "<sep file?>";
503 add_printer_driver(dests[i].name);
505 memset(&pinfo2a,0,sizeof(pinfo2a));
506 pinfo2a.pPrinterName = dests[i].name;
507 pinfo2a.pDatatype = data_type;
508 pinfo2a.pPrintProcessor = print_proc;
509 pinfo2a.pDriverName = dests[i].name;
510 pinfo2a.pComment = comment;
511 pinfo2a.pLocation = location;
512 pinfo2a.pPortName = port;
513 pinfo2a.pParameters = params;
514 pinfo2a.pShareName = share_name;
515 pinfo2a.pSepFile = sep_file;
517 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
518 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
519 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
522 HeapFree(GetProcessHeap(),0,port);
525 if (dests[i].is_default) {
526 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
530 if (hadprinter & !haddefault)
531 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
532 pcupsFreeDests(nrofdests, dests);
533 RegCloseKey(hkeyPrinters);
539 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
540 PRINTER_INFO_2A pinfo2a;
541 char *e,*s,*name,*prettyname,*devname;
542 BOOL ret = FALSE, set_default = FALSE;
543 char *port = NULL, *devline,*env_default;
544 HKEY hkeyPrinter, hkeyPrinters, hkey;
546 while (isspace(*pent)) pent++;
547 s = strchr(pent,':');
549 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
557 TRACE("name=%s entry=%s\n",name, pent);
559 if(ispunct(*name)) { /* a tc entry, not a real printer */
560 TRACE("skipping tc entry\n");
564 if(strstr(pent,":server")) { /* server only version so skip */
565 TRACE("skipping server entry\n");
569 /* Determine whether this is a postscript printer. */
572 env_default = getenv("PRINTER");
574 /* Get longest name, usually the one at the right for later display. */
575 while((s=strchr(prettyname,'|'))) {
578 while(isspace(*--e)) *e = '\0';
579 TRACE("\t%s\n", debugstr_a(prettyname));
580 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
581 for(prettyname = s+1; isspace(*prettyname); prettyname++)
584 e = prettyname + strlen(prettyname);
585 while(isspace(*--e)) *e = '\0';
586 TRACE("\t%s\n", debugstr_a(prettyname));
587 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
589 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
590 * if it is too long, we use it as comment below. */
591 devname = prettyname;
592 if (strlen(devname)>=CCHDEVICENAME-1)
594 if (strlen(devname)>=CCHDEVICENAME-1) {
599 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
600 sprintf(port,"LPR:%s",name);
602 /* FIXME: remove extension. Fix gdi32/drivers and comdlg32/printdlg first */
603 devline = HeapAlloc(GetProcessHeap(), 0, sizeof("WINEPS.DRV,,15,45") + strlen(port));
604 sprintf(devline, "WINEPS.DRV,%s", port);
605 WriteProfileStringA("devices", devname, devline);
606 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
607 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
611 lstrcatA(devline, ",15,45");
612 WriteProfileStringA("PrinterPorts", devname, devline);
613 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
614 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
618 HeapFree(GetProcessHeap(),0,devline);
620 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
622 ERR("Can't create Printers key\n");
626 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
627 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
629 TRACE("Printer already exists\n");
630 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
631 RegCloseKey(hkeyPrinter);
633 static CHAR data_type[] = "RAW",
634 print_proc[] = "WinPrint",
635 comment[] = "WINEPS Printer using LPR",
636 params[] = "<parameters?>",
637 share_name[] = "<share name?>",
638 sep_file[] = "<sep file?>";
640 add_printer_driver(devname);
642 memset(&pinfo2a,0,sizeof(pinfo2a));
643 pinfo2a.pPrinterName = devname;
644 pinfo2a.pDatatype = data_type;
645 pinfo2a.pPrintProcessor = print_proc;
646 pinfo2a.pDriverName = devname;
647 pinfo2a.pComment = comment;
648 pinfo2a.pLocation = prettyname;
649 pinfo2a.pPortName = port;
650 pinfo2a.pParameters = params;
651 pinfo2a.pShareName = share_name;
652 pinfo2a.pSepFile = sep_file;
654 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
655 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
656 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
659 RegCloseKey(hkeyPrinters);
661 if (isfirst || set_default)
662 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
665 HeapFree(GetProcessHeap(), 0, port);
666 HeapFree(GetProcessHeap(), 0, name);
671 PRINTCAP_LoadPrinters(void) {
672 BOOL hadprinter = FALSE;
676 BOOL had_bash = FALSE;
678 f = fopen("/etc/printcap","r");
682 while(fgets(buf,sizeof(buf),f)) {
685 end=strchr(buf,'\n');
689 while(isspace(*start)) start++;
690 if(*start == '#' || *start == '\0')
693 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
694 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
695 HeapFree(GetProcessHeap(),0,pent);
699 if (end && *--end == '\\') {
706 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
709 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
715 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
716 HeapFree(GetProcessHeap(),0,pent);
722 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
725 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
726 (lstrlenW(value) + 1) * sizeof(WCHAR));
728 return ERROR_FILE_NOT_FOUND;
731 /******************************************************************
732 * get_servername_from_name (internal)
734 * for an external server, a copy of the serverpart from the full name is returned
737 static LPWSTR get_servername_from_name(LPCWSTR name)
741 WCHAR buffer[MAX_PATH];
744 if (name == NULL) return NULL;
745 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
747 server = strdupW(&name[2]); /* skip over both backslash */
748 if (server == NULL) return NULL;
750 /* strip '\' and the printername */
751 ptr = strchrW(server, '\\');
752 if (ptr) ptr[0] = '\0';
754 TRACE("found %s\n", debugstr_w(server));
756 len = sizeof(buffer)/sizeof(buffer[0]);
757 if (GetComputerNameW(buffer, &len)) {
758 if (lstrcmpW(buffer, server) == 0) {
759 /* The requested Servername is our computername */
760 HeapFree(GetProcessHeap(), 0, server);
767 /******************************************************************
768 * get_basename_from_name (internal)
770 * skip over the serverpart from the full name
773 static LPCWSTR get_basename_from_name(LPCWSTR name)
775 if (name == NULL) return NULL;
776 if ((name[0] == '\\') && (name[1] == '\\')) {
777 /* skip over the servername and search for the following '\' */
778 name = strchrW(&name[2], '\\');
779 if ((name) && (name[1])) {
780 /* found a separator ('\') followed by a name:
781 skip over the separator and return the rest */
786 /* no basename present (we found only a servername) */
793 /******************************************************************
794 * get_opened_printer_entry
795 * Get the first place empty in the opened printer table
798 * - pDefault is ignored
800 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
802 UINT_PTR handle = nb_printer_handles, i;
803 jobqueue_t *queue = NULL;
804 opened_printer_t *printer = NULL;
808 if ((backend == NULL) && !load_backend()) return NULL;
810 servername = get_servername_from_name(name);
812 FIXME("server %s not supported\n", debugstr_w(servername));
813 HeapFree(GetProcessHeap(), 0, servername);
814 SetLastError(ERROR_INVALID_PRINTER_NAME);
818 printername = get_basename_from_name(name);
819 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
821 /* an empty printername is invalid */
822 if (printername && (!printername[0])) {
823 SetLastError(ERROR_INVALID_PARAMETER);
827 EnterCriticalSection(&printer_handles_cs);
829 for (i = 0; i < nb_printer_handles; i++)
831 if (!printer_handles[i])
833 if(handle == nb_printer_handles)
838 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
839 queue = printer_handles[i]->queue;
843 if (handle >= nb_printer_handles)
845 opened_printer_t **new_array;
847 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
848 (nb_printer_handles + 16) * sizeof(*new_array) );
850 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
851 (nb_printer_handles + 16) * sizeof(*new_array) );
858 printer_handles = new_array;
859 nb_printer_handles += 16;
862 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
868 /* get a printer handle from the backend */
869 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
874 /* clone the base name. This is NULL for the printserver */
875 printer->printername = strdupW(printername);
877 /* clone the full name */
878 printer->name = strdupW(name);
879 if (name && (!printer->name)) {
885 printer->queue = queue;
888 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
889 if (!printer->queue) {
893 list_init(&printer->queue->jobs);
894 printer->queue->ref = 0;
896 InterlockedIncrement(&printer->queue->ref);
898 printer_handles[handle] = printer;
901 LeaveCriticalSection(&printer_handles_cs);
902 if (!handle && printer) {
903 /* Something failed: Free all resources */
904 HeapFree(GetProcessHeap(), 0, printer->printername);
905 HeapFree(GetProcessHeap(), 0, printer->name);
906 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
907 HeapFree(GetProcessHeap(), 0, printer);
910 return (HANDLE)handle;
913 /******************************************************************
915 * Get the pointer to the opened printer referred by the handle
917 static opened_printer_t *get_opened_printer(HANDLE hprn)
919 UINT_PTR idx = (UINT_PTR)hprn;
920 opened_printer_t *ret = NULL;
922 EnterCriticalSection(&printer_handles_cs);
924 if ((idx > 0) && (idx <= nb_printer_handles)) {
925 ret = printer_handles[idx - 1];
927 LeaveCriticalSection(&printer_handles_cs);
931 /******************************************************************
932 * get_opened_printer_name
933 * Get the pointer to the opened printer name referred by the handle
935 static LPCWSTR get_opened_printer_name(HANDLE hprn)
937 opened_printer_t *printer = get_opened_printer(hprn);
938 if(!printer) return NULL;
939 return printer->name;
942 /******************************************************************
943 * WINSPOOL_GetOpenedPrinterRegKey
946 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
948 LPCWSTR name = get_opened_printer_name(hPrinter);
952 if(!name) return ERROR_INVALID_HANDLE;
954 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
958 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
960 ERR("Can't find opened printer %s in registry\n",
962 RegCloseKey(hkeyPrinters);
963 return ERROR_INVALID_PRINTER_NAME; /* ? */
965 RegCloseKey(hkeyPrinters);
966 return ERROR_SUCCESS;
969 void WINSPOOL_LoadSystemPrinters(void)
971 HKEY hkey, hkeyPrinters;
973 DWORD needed, num, i;
974 WCHAR PrinterName[256];
977 /* This ensures that all printer entries have a valid Name value. If causes
978 problems later if they don't. If one is found to be missed we create one
979 and set it equal to the name of the key */
980 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
981 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
982 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
983 for(i = 0; i < num; i++) {
984 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
985 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
986 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
987 set_reg_szW(hkey, NameW, PrinterName);
994 RegCloseKey(hkeyPrinters);
997 /* We want to avoid calling AddPrinter on printers as much as
998 possible, because on cups printers this will (eventually) lead
999 to a call to cupsGetPPD which takes forever, even with non-cups
1000 printers AddPrinter takes a while. So we'll tag all printers that
1001 were automatically added last time around, if they still exist
1002 we'll leave them be otherwise we'll delete them. */
1003 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1005 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1006 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1007 for(i = 0; i < num; i++) {
1008 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1009 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1010 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1012 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1020 HeapFree(GetProcessHeap(), 0, pi);
1024 #ifdef SONAME_LIBCUPS
1025 done = CUPS_LoadPrinters();
1028 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1029 PRINTCAP_LoadPrinters();
1031 /* Now enumerate the list again and delete any printers that are still tagged */
1032 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1034 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1035 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1036 for(i = 0; i < num; i++) {
1037 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1038 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1039 BOOL delete_driver = FALSE;
1040 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1041 DWORD dw, type, size = sizeof(dw);
1042 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1043 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1044 DeletePrinter(hprn);
1045 delete_driver = TRUE;
1051 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1056 HeapFree(GetProcessHeap(), 0, pi);
1063 /******************************************************************
1066 * Get the pointer to the specified job.
1067 * Should hold the printer_handles_cs before calling.
1069 static job_t *get_job(HANDLE hprn, DWORD JobId)
1071 opened_printer_t *printer = get_opened_printer(hprn);
1074 if(!printer) return NULL;
1075 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1077 if(job->job_id == JobId)
1083 /***********************************************************
1086 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1089 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1092 Formname = (dmA->dmSize > off_formname);
1093 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1094 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1095 dmW->dmDeviceName, CCHDEVICENAME);
1097 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1098 dmA->dmSize - CCHDEVICENAME);
1100 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1101 off_formname - CCHDEVICENAME);
1102 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1103 dmW->dmFormName, CCHFORMNAME);
1104 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1105 (off_formname + CCHFORMNAME));
1108 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1109 dmA->dmDriverExtra);
1113 /***********************************************************
1115 * Creates an ansi copy of supplied devmode
1117 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1122 if (!dmW) return NULL;
1123 size = dmW->dmSize - CCHDEVICENAME -
1124 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1126 dmA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1127 if (!dmA) return NULL;
1129 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1130 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1132 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1133 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1134 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1138 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1139 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1140 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1141 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1143 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1147 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1151 /******************************************************************
1152 * convert_printerinfo_W_to_A [internal]
1155 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1156 DWORD level, DWORD outlen, DWORD numentries)
1162 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1164 len = pi_sizeof[level] * numentries;
1165 ptr = (LPSTR) out + len;
1168 /* copy the numbers of all PRINTER_INFO_* first */
1169 memcpy(out, pPrintersW, len);
1171 while (id < numentries) {
1175 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1176 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1178 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1179 if (piW->pDescription) {
1180 piA->pDescription = ptr;
1181 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1182 ptr, outlen, NULL, NULL);
1188 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1189 ptr, outlen, NULL, NULL);
1193 if (piW->pComment) {
1194 piA->pComment = ptr;
1195 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1196 ptr, outlen, NULL, NULL);
1205 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1206 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1209 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1210 if (piW->pServerName) {
1211 piA->pServerName = ptr;
1212 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1213 ptr, outlen, NULL, NULL);
1217 if (piW->pPrinterName) {
1218 piA->pPrinterName = ptr;
1219 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1220 ptr, outlen, NULL, NULL);
1224 if (piW->pShareName) {
1225 piA->pShareName = ptr;
1226 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1227 ptr, outlen, NULL, NULL);
1231 if (piW->pPortName) {
1232 piA->pPortName = ptr;
1233 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1234 ptr, outlen, NULL, NULL);
1238 if (piW->pDriverName) {
1239 piA->pDriverName = ptr;
1240 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1241 ptr, outlen, NULL, NULL);
1245 if (piW->pComment) {
1246 piA->pComment = ptr;
1247 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1248 ptr, outlen, NULL, NULL);
1252 if (piW->pLocation) {
1253 piA->pLocation = ptr;
1254 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1255 ptr, outlen, NULL, NULL);
1260 dmA = DEVMODEdupWtoA(piW->pDevMode);
1262 /* align DEVMODEA to a DWORD boundary */
1263 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1267 piA->pDevMode = (LPDEVMODEA) ptr;
1268 len = dmA->dmSize + dmA->dmDriverExtra;
1269 memcpy(ptr, dmA, len);
1270 HeapFree(GetProcessHeap(), 0, dmA);
1276 if (piW->pSepFile) {
1277 piA->pSepFile = ptr;
1278 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1279 ptr, outlen, NULL, NULL);
1283 if (piW->pPrintProcessor) {
1284 piA->pPrintProcessor = ptr;
1285 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1286 ptr, outlen, NULL, NULL);
1290 if (piW->pDatatype) {
1291 piA->pDatatype = ptr;
1292 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1293 ptr, outlen, NULL, NULL);
1297 if (piW->pParameters) {
1298 piA->pParameters = ptr;
1299 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1300 ptr, outlen, NULL, NULL);
1304 if (piW->pSecurityDescriptor) {
1305 piA->pSecurityDescriptor = NULL;
1306 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1313 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1314 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1316 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1318 if (piW->pPrinterName) {
1319 piA->pPrinterName = ptr;
1320 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1321 ptr, outlen, NULL, NULL);
1325 if (piW->pServerName) {
1326 piA->pServerName = ptr;
1327 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1328 ptr, outlen, NULL, NULL);
1337 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1338 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1340 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1342 if (piW->pPrinterName) {
1343 piA->pPrinterName = ptr;
1344 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1345 ptr, outlen, NULL, NULL);
1349 if (piW->pPortName) {
1350 piA->pPortName = ptr;
1351 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1352 ptr, outlen, NULL, NULL);
1359 case 6: /* 6A and 6W are the same structure */
1364 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1365 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1367 TRACE("(%u) #%u\n", level, id);
1368 if (piW->pszObjectGUID) {
1369 piA->pszObjectGUID = ptr;
1370 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1371 ptr, outlen, NULL, NULL);
1380 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1381 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1384 TRACE("(%u) #%u\n", level, id);
1385 dmA = DEVMODEdupWtoA(piW->pDevMode);
1387 /* align DEVMODEA to a DWORD boundary */
1388 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1392 piA->pDevMode = (LPDEVMODEA) ptr;
1393 len = dmA->dmSize + dmA->dmDriverExtra;
1394 memcpy(ptr, dmA, len);
1395 HeapFree(GetProcessHeap(), 0, dmA);
1405 FIXME("for level %u\n", level);
1407 pPrintersW += pi_sizeof[level];
1408 out += pi_sizeof[level];
1413 /******************************************************************
1414 * convert_driverinfo_W_to_A [internal]
1417 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1418 DWORD level, DWORD outlen, DWORD numentries)
1424 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1426 len = di_sizeof[level] * numentries;
1427 ptr = (LPSTR) out + len;
1430 /* copy the numbers of all PRINTER_INFO_* first */
1431 memcpy(out, pDriversW, len);
1433 #define COPY_STRING(fld) \
1436 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1437 ptr += len; outlen -= len;\
1439 #define COPY_MULTIZ_STRING(fld) \
1440 { LPWSTR p = diW->fld; if (p){ \
1443 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1444 ptr += len; outlen -= len; p += len;\
1446 while(len > 1 && outlen > 0); \
1449 while (id < numentries)
1455 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1456 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1458 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1465 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1466 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1468 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1471 COPY_STRING(pEnvironment);
1472 COPY_STRING(pDriverPath);
1473 COPY_STRING(pDataFile);
1474 COPY_STRING(pConfigFile);
1479 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1480 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1482 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1485 COPY_STRING(pEnvironment);
1486 COPY_STRING(pDriverPath);
1487 COPY_STRING(pDataFile);
1488 COPY_STRING(pConfigFile);
1489 COPY_STRING(pHelpFile);
1490 COPY_MULTIZ_STRING(pDependentFiles);
1491 COPY_STRING(pMonitorName);
1492 COPY_STRING(pDefaultDataType);
1497 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1498 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1500 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1503 COPY_STRING(pEnvironment);
1504 COPY_STRING(pDriverPath);
1505 COPY_STRING(pDataFile);
1506 COPY_STRING(pConfigFile);
1507 COPY_STRING(pHelpFile);
1508 COPY_MULTIZ_STRING(pDependentFiles);
1509 COPY_STRING(pMonitorName);
1510 COPY_STRING(pDefaultDataType);
1511 COPY_MULTIZ_STRING(pszzPreviousNames);
1516 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1517 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1519 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1522 COPY_STRING(pEnvironment);
1523 COPY_STRING(pDriverPath);
1524 COPY_STRING(pDataFile);
1525 COPY_STRING(pConfigFile);
1530 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1531 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1533 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1536 COPY_STRING(pEnvironment);
1537 COPY_STRING(pDriverPath);
1538 COPY_STRING(pDataFile);
1539 COPY_STRING(pConfigFile);
1540 COPY_STRING(pHelpFile);
1541 COPY_MULTIZ_STRING(pDependentFiles);
1542 COPY_STRING(pMonitorName);
1543 COPY_STRING(pDefaultDataType);
1544 COPY_MULTIZ_STRING(pszzPreviousNames);
1545 COPY_STRING(pszMfgName);
1546 COPY_STRING(pszOEMUrl);
1547 COPY_STRING(pszHardwareID);
1548 COPY_STRING(pszProvider);
1553 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1554 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1556 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1559 COPY_STRING(pEnvironment);
1560 COPY_STRING(pDriverPath);
1561 COPY_STRING(pDataFile);
1562 COPY_STRING(pConfigFile);
1563 COPY_STRING(pHelpFile);
1564 COPY_MULTIZ_STRING(pDependentFiles);
1565 COPY_STRING(pMonitorName);
1566 COPY_STRING(pDefaultDataType);
1567 COPY_MULTIZ_STRING(pszzPreviousNames);
1568 COPY_STRING(pszMfgName);
1569 COPY_STRING(pszOEMUrl);
1570 COPY_STRING(pszHardwareID);
1571 COPY_STRING(pszProvider);
1572 COPY_STRING(pszPrintProcessor);
1573 COPY_STRING(pszVendorSetup);
1574 COPY_MULTIZ_STRING(pszzColorProfiles);
1575 COPY_STRING(pszInfPath);
1576 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1582 FIXME("for level %u\n", level);
1585 pDriversW += di_sizeof[level];
1586 out += di_sizeof[level];
1591 #undef COPY_MULTIZ_STRING
1595 /***********************************************************
1596 * PRINTER_INFO_2AtoW
1597 * Creates a unicode copy of PRINTER_INFO_2A on heap
1599 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1601 LPPRINTER_INFO_2W piW;
1602 UNICODE_STRING usBuffer;
1604 if(!piA) return NULL;
1605 piW = HeapAlloc(heap, 0, sizeof(*piW));
1606 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1608 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1609 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1610 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1611 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1612 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1613 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1614 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1615 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1616 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1617 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1618 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1619 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1623 /***********************************************************
1624 * FREE_PRINTER_INFO_2W
1625 * Free PRINTER_INFO_2W and all strings
1627 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1631 HeapFree(heap,0,piW->pServerName);
1632 HeapFree(heap,0,piW->pPrinterName);
1633 HeapFree(heap,0,piW->pShareName);
1634 HeapFree(heap,0,piW->pPortName);
1635 HeapFree(heap,0,piW->pDriverName);
1636 HeapFree(heap,0,piW->pComment);
1637 HeapFree(heap,0,piW->pLocation);
1638 HeapFree(heap,0,piW->pDevMode);
1639 HeapFree(heap,0,piW->pSepFile);
1640 HeapFree(heap,0,piW->pPrintProcessor);
1641 HeapFree(heap,0,piW->pDatatype);
1642 HeapFree(heap,0,piW->pParameters);
1643 HeapFree(heap,0,piW);
1647 /******************************************************************
1648 * DeviceCapabilities [WINSPOOL.@]
1649 * DeviceCapabilitiesA [WINSPOOL.@]
1652 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1653 LPSTR pOutput, LPDEVMODEA lpdm)
1657 if (!GDI_CallDeviceCapabilities16)
1659 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1661 if (!GDI_CallDeviceCapabilities16) return -1;
1663 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1665 /* If DC_PAPERSIZE map POINT16s to POINTs */
1666 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1667 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1668 POINT *pt = (POINT *)pOutput;
1670 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1671 for(i = 0; i < ret; i++, pt++)
1676 HeapFree( GetProcessHeap(), 0, tmp );
1682 /*****************************************************************************
1683 * DeviceCapabilitiesW [WINSPOOL.@]
1685 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1688 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1689 WORD fwCapability, LPWSTR pOutput,
1690 const DEVMODEW *pDevMode)
1692 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1693 LPSTR pDeviceA = strdupWtoA(pDevice);
1694 LPSTR pPortA = strdupWtoA(pPort);
1697 if(pOutput && (fwCapability == DC_BINNAMES ||
1698 fwCapability == DC_FILEDEPENDENCIES ||
1699 fwCapability == DC_PAPERNAMES)) {
1700 /* These need A -> W translation */
1703 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1707 switch(fwCapability) {
1712 case DC_FILEDEPENDENCIES:
1716 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1717 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1719 for(i = 0; i < ret; i++)
1720 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1721 pOutput + (i * size), size);
1722 HeapFree(GetProcessHeap(), 0, pOutputA);
1724 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1725 (LPSTR)pOutput, dmA);
1727 HeapFree(GetProcessHeap(),0,pPortA);
1728 HeapFree(GetProcessHeap(),0,pDeviceA);
1729 HeapFree(GetProcessHeap(),0,dmA);
1733 /******************************************************************
1734 * DocumentPropertiesA [WINSPOOL.@]
1736 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1738 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1739 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1740 LPDEVMODEA pDevModeInput,DWORD fMode )
1742 LPSTR lpName = pDeviceName;
1743 static CHAR port[] = "LPT1:";
1746 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1747 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1751 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1753 ERR("no name from hPrinter?\n");
1754 SetLastError(ERROR_INVALID_HANDLE);
1757 lpName = strdupWtoA(lpNameW);
1760 if (!GDI_CallExtDeviceMode16)
1762 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1764 if (!GDI_CallExtDeviceMode16) {
1765 ERR("No CallExtDeviceMode16?\n");
1769 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1770 pDevModeInput, NULL, fMode);
1773 HeapFree(GetProcessHeap(),0,lpName);
1778 /*****************************************************************************
1779 * DocumentPropertiesW (WINSPOOL.@)
1781 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1783 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1785 LPDEVMODEW pDevModeOutput,
1786 LPDEVMODEW pDevModeInput, DWORD fMode)
1789 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1790 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1791 LPDEVMODEA pDevModeOutputA = NULL;
1794 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1795 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1797 if(pDevModeOutput) {
1798 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1799 if(ret < 0) return ret;
1800 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1802 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1803 pDevModeInputA, fMode);
1804 if(pDevModeOutput) {
1805 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1806 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1808 if(fMode == 0 && ret > 0)
1809 ret += (CCHDEVICENAME + CCHFORMNAME);
1810 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1811 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1815 /******************************************************************
1816 * OpenPrinterA [WINSPOOL.@]
1821 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1822 LPPRINTER_DEFAULTSA pDefault)
1824 UNICODE_STRING lpPrinterNameW;
1825 UNICODE_STRING usBuffer;
1826 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1827 PWSTR pwstrPrinterNameW;
1830 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1833 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1834 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1835 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1836 pDefaultW = &DefaultW;
1838 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1840 RtlFreeUnicodeString(&usBuffer);
1841 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1843 RtlFreeUnicodeString(&lpPrinterNameW);
1847 /******************************************************************
1848 * OpenPrinterW [WINSPOOL.@]
1850 * Open a Printer / Printserver or a Printer-Object
1853 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1854 * phPrinter [O] The resulting Handle is stored here
1855 * pDefault [I] PTR to Default Printer Settings or NULL
1862 * lpPrinterName is one of:
1863 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1864 *| Printer: "PrinterName"
1865 *| Printer-Object: "PrinterName,Job xxx"
1866 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1867 *| XcvPort: "Servername,XcvPort PortName"
1870 *| Printer-Object not supported
1871 *| pDefaults is ignored
1874 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1877 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1879 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1880 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1884 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1885 SetLastError(ERROR_INVALID_PARAMETER);
1889 /* Get the unique handle of the printer or Printserver */
1890 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1891 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1892 return (*phPrinter != 0);
1895 /******************************************************************
1896 * AddMonitorA [WINSPOOL.@]
1901 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1903 LPWSTR nameW = NULL;
1906 LPMONITOR_INFO_2A mi2a;
1907 MONITOR_INFO_2W mi2w;
1909 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1910 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1911 debugstr_a(mi2a ? mi2a->pName : NULL),
1912 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1913 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1916 SetLastError(ERROR_INVALID_LEVEL);
1920 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1926 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1927 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1928 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1931 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1933 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1934 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1935 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1937 if (mi2a->pEnvironment) {
1938 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1939 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1940 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1942 if (mi2a->pDLLName) {
1943 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1944 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1945 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1948 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1950 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1951 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1952 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1954 HeapFree(GetProcessHeap(), 0, nameW);
1958 /******************************************************************************
1959 * AddMonitorW [WINSPOOL.@]
1961 * Install a Printmonitor
1964 * pName [I] Servername or NULL (local Computer)
1965 * Level [I] Structure-Level (Must be 2)
1966 * pMonitors [I] PTR to MONITOR_INFO_2
1973 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1976 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1978 LPMONITOR_INFO_2W mi2w;
1980 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1981 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1982 debugstr_w(mi2w ? mi2w->pName : NULL),
1983 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1984 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1986 if ((backend == NULL) && !load_backend()) return FALSE;
1989 SetLastError(ERROR_INVALID_LEVEL);
1993 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1998 return backend->fpAddMonitor(pName, Level, pMonitors);
2001 /******************************************************************
2002 * DeletePrinterDriverA [WINSPOOL.@]
2005 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2007 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2010 /******************************************************************
2011 * DeletePrinterDriverW [WINSPOOL.@]
2014 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2016 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2019 /******************************************************************
2020 * DeleteMonitorA [WINSPOOL.@]
2022 * See DeleteMonitorW.
2025 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2027 LPWSTR nameW = NULL;
2028 LPWSTR EnvironmentW = NULL;
2029 LPWSTR MonitorNameW = NULL;
2034 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2035 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2036 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2040 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2041 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2042 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2045 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2046 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2047 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2050 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2052 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2053 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2054 HeapFree(GetProcessHeap(), 0, nameW);
2058 /******************************************************************
2059 * DeleteMonitorW [WINSPOOL.@]
2061 * Delete a specific Printmonitor from a Printing-Environment
2064 * pName [I] Servername or NULL (local Computer)
2065 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2066 * pMonitorName [I] Name of the Monitor, that should be deleted
2073 * pEnvironment is ignored in Windows for the local Computer.
2076 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2079 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2080 debugstr_w(pMonitorName));
2082 if ((backend == NULL) && !load_backend()) return FALSE;
2084 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2088 /******************************************************************
2089 * DeletePortA [WINSPOOL.@]
2094 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2096 LPWSTR nameW = NULL;
2097 LPWSTR portW = NULL;
2101 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2103 /* convert servername to unicode */
2105 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2106 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2107 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2110 /* convert portname to unicode */
2112 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2113 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2114 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2117 res = DeletePortW(nameW, hWnd, portW);
2118 HeapFree(GetProcessHeap(), 0, nameW);
2119 HeapFree(GetProcessHeap(), 0, portW);
2123 /******************************************************************
2124 * DeletePortW [WINSPOOL.@]
2126 * Delete a specific Port
2129 * pName [I] Servername or NULL (local Computer)
2130 * hWnd [I] Handle to parent Window for the Dialog-Box
2131 * pPortName [I] Name of the Port, that should be deleted
2138 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2140 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2142 if ((backend == NULL) && !load_backend()) return FALSE;
2145 SetLastError(RPC_X_NULL_REF_POINTER);
2149 return backend->fpDeletePort(pName, hWnd, pPortName);
2152 /******************************************************************************
2153 * SetPrinterW [WINSPOOL.@]
2155 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2157 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2158 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2162 /******************************************************************************
2163 * WritePrinter [WINSPOOL.@]
2165 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2167 opened_printer_t *printer;
2170 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2172 EnterCriticalSection(&printer_handles_cs);
2173 printer = get_opened_printer(hPrinter);
2176 SetLastError(ERROR_INVALID_HANDLE);
2182 SetLastError(ERROR_SPL_NO_STARTDOC);
2186 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2188 LeaveCriticalSection(&printer_handles_cs);
2192 /*****************************************************************************
2193 * AddFormA [WINSPOOL.@]
2195 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2197 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2201 /*****************************************************************************
2202 * AddFormW [WINSPOOL.@]
2204 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2206 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2210 /*****************************************************************************
2211 * AddJobA [WINSPOOL.@]
2213 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2216 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2220 SetLastError(ERROR_INVALID_LEVEL);
2224 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2227 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2228 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2229 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2230 if(*pcbNeeded > cbBuf) {
2231 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2234 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2235 addjobA->JobId = addjobW->JobId;
2236 addjobA->Path = (char *)(addjobA + 1);
2237 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2243 /*****************************************************************************
2244 * AddJobW [WINSPOOL.@]
2246 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2248 opened_printer_t *printer;
2251 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2252 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2253 WCHAR path[MAX_PATH], filename[MAX_PATH];
2255 ADDJOB_INFO_1W *addjob;
2257 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2259 EnterCriticalSection(&printer_handles_cs);
2261 printer = get_opened_printer(hPrinter);
2264 SetLastError(ERROR_INVALID_HANDLE);
2269 SetLastError(ERROR_INVALID_LEVEL);
2273 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2277 job->job_id = InterlockedIncrement(&next_job_id);
2279 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2280 if(path[len - 1] != '\\')
2282 memcpy(path + len, spool_path, sizeof(spool_path));
2283 sprintfW(filename, fmtW, path, job->job_id);
2285 len = strlenW(filename);
2286 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2287 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2288 job->document_title = strdupW(default_doc_title);
2289 list_add_tail(&printer->queue->jobs, &job->entry);
2291 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2292 if(*pcbNeeded <= cbBuf) {
2293 addjob = (ADDJOB_INFO_1W*)pData;
2294 addjob->JobId = job->job_id;
2295 addjob->Path = (WCHAR *)(addjob + 1);
2296 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2299 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2302 LeaveCriticalSection(&printer_handles_cs);
2306 /*****************************************************************************
2307 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2309 * Return the PATH for the Print-Processors
2311 * See GetPrintProcessorDirectoryW.
2315 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2316 DWORD level, LPBYTE Info,
2317 DWORD cbBuf, LPDWORD pcbNeeded)
2319 LPWSTR serverW = NULL;
2324 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2325 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2329 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2330 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2331 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2335 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2336 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2337 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2340 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2341 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2343 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2346 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2347 cbBuf, NULL, NULL) > 0;
2350 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2351 HeapFree(GetProcessHeap(), 0, envW);
2352 HeapFree(GetProcessHeap(), 0, serverW);
2356 /*****************************************************************************
2357 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2359 * Return the PATH for the Print-Processors
2362 * server [I] Servername (NT only) or NULL (local Computer)
2363 * env [I] Printing-Environment (see below) or NULL (Default)
2364 * level [I] Structure-Level (must be 1)
2365 * Info [O] PTR to Buffer that receives the Result
2366 * cbBuf [I] Size of Buffer at "Info"
2367 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2368 * required for the Buffer at "Info"
2371 * Success: TRUE and in pcbNeeded the Bytes used in Info
2372 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2373 * if cbBuf is too small
2375 * Native Values returned in Info on Success:
2376 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2377 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2378 *| win9x(Windows 4.0): "%winsysdir%"
2380 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2383 * Only NULL or "" is supported for server
2386 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2387 DWORD level, LPBYTE Info,
2388 DWORD cbBuf, LPDWORD pcbNeeded)
2391 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2392 Info, cbBuf, pcbNeeded);
2394 if ((backend == NULL) && !load_backend()) return FALSE;
2397 /* (Level != 1) is ignored in win9x */
2398 SetLastError(ERROR_INVALID_LEVEL);
2402 if (pcbNeeded == NULL) {
2403 /* (pcbNeeded == NULL) is ignored in win9x */
2404 SetLastError(RPC_X_NULL_REF_POINTER);
2408 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2411 /*****************************************************************************
2412 * WINSPOOL_OpenDriverReg [internal]
2414 * opens the registry for the printer drivers depending on the given input
2415 * variable pEnvironment
2418 * the opened hkey on success
2421 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2425 const printenv_t * env;
2427 TRACE("(%s)\n", debugstr_w(pEnvironment));
2429 env = validate_envW(pEnvironment);
2430 if (!env) return NULL;
2432 buffer = HeapAlloc( GetProcessHeap(), 0,
2433 (strlenW(DriversW) + strlenW(env->envname) +
2434 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2436 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2437 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2438 HeapFree(GetProcessHeap(), 0, buffer);
2443 /*****************************************************************************
2444 * AddPrinterW [WINSPOOL.@]
2446 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2448 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2452 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2454 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2455 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2456 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2457 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2458 statusW[] = {'S','t','a','t','u','s',0},
2459 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2461 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2464 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2465 SetLastError(ERROR_INVALID_PARAMETER);
2469 ERR("Level = %d, unsupported!\n", Level);
2470 SetLastError(ERROR_INVALID_LEVEL);
2474 SetLastError(ERROR_INVALID_PARAMETER);
2477 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2479 ERR("Can't create Printers key\n");
2482 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2483 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2484 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2485 RegCloseKey(hkeyPrinter);
2486 RegCloseKey(hkeyPrinters);
2489 RegCloseKey(hkeyPrinter);
2491 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2493 ERR("Can't create Drivers key\n");
2494 RegCloseKey(hkeyPrinters);
2497 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2499 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2500 RegCloseKey(hkeyPrinters);
2501 RegCloseKey(hkeyDrivers);
2502 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2505 RegCloseKey(hkeyDriver);
2506 RegCloseKey(hkeyDrivers);
2508 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2509 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2510 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2511 RegCloseKey(hkeyPrinters);
2515 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2517 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2518 SetLastError(ERROR_INVALID_PRINTER_NAME);
2519 RegCloseKey(hkeyPrinters);
2522 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2523 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2524 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2526 /* See if we can load the driver. We may need the devmode structure anyway
2529 * Note that DocumentPropertiesW will briefly try to open the printer we
2530 * just create to find a DEVMODEA struct (it will use the WINEPS default
2531 * one in case it is not there, so we are ok).
2533 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2536 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2537 size = sizeof(DEVMODEW);
2543 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2545 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2547 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2548 HeapFree(GetProcessHeap(),0,dmW);
2553 /* set devmode to printer name */
2554 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2558 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2559 and we support these drivers. NT writes DEVMODEW so somehow
2560 we'll need to distinguish between these when we support NT
2564 dmA = DEVMODEdupWtoA(dmW);
2565 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2566 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2567 HeapFree(GetProcessHeap(), 0, dmA);
2569 HeapFree(GetProcessHeap(), 0, dmW);
2571 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2572 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2573 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2574 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2576 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2577 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2578 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2579 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2580 (LPBYTE)&pi->Priority, sizeof(DWORD));
2581 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2582 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2583 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2584 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2585 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2586 (LPBYTE)&pi->Status, sizeof(DWORD));
2587 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2588 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2590 RegCloseKey(hkeyPrinter);
2591 RegCloseKey(hkeyPrinters);
2592 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2593 ERR("OpenPrinter failing\n");
2599 /*****************************************************************************
2600 * AddPrinterA [WINSPOOL.@]
2602 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2604 UNICODE_STRING pNameW;
2606 PRINTER_INFO_2W *piW;
2607 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2610 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2612 ERR("Level = %d, unsupported!\n", Level);
2613 SetLastError(ERROR_INVALID_LEVEL);
2616 pwstrNameW = asciitounicode(&pNameW,pName);
2617 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2619 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2621 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2622 RtlFreeUnicodeString(&pNameW);
2627 /*****************************************************************************
2628 * ClosePrinter [WINSPOOL.@]
2630 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2632 UINT_PTR i = (UINT_PTR)hPrinter;
2633 opened_printer_t *printer = NULL;
2636 TRACE("(%p)\n", hPrinter);
2638 EnterCriticalSection(&printer_handles_cs);
2640 if ((i > 0) && (i <= nb_printer_handles))
2641 printer = printer_handles[i - 1];
2646 struct list *cursor, *cursor2;
2648 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2650 if (printer->backend_printer) {
2651 backend->fpClosePrinter(printer->backend_printer);
2655 EndDocPrinter(hPrinter);
2657 if(InterlockedDecrement(&printer->queue->ref) == 0)
2659 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2661 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2662 ScheduleJob(hPrinter, job->job_id);
2664 HeapFree(GetProcessHeap(), 0, printer->queue);
2667 HeapFree(GetProcessHeap(), 0, printer->printername);
2668 HeapFree(GetProcessHeap(), 0, printer->name);
2669 HeapFree(GetProcessHeap(), 0, printer);
2670 printer_handles[i - 1] = NULL;
2673 LeaveCriticalSection(&printer_handles_cs);
2677 /*****************************************************************************
2678 * DeleteFormA [WINSPOOL.@]
2680 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2682 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2686 /*****************************************************************************
2687 * DeleteFormW [WINSPOOL.@]
2689 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2691 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2695 /*****************************************************************************
2696 * DeletePrinter [WINSPOOL.@]
2698 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2700 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2701 HKEY hkeyPrinters, hkey;
2704 SetLastError(ERROR_INVALID_HANDLE);
2707 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2708 RegDeleteTreeW(hkeyPrinters, lpNameW);
2709 RegCloseKey(hkeyPrinters);
2711 WriteProfileStringW(devicesW, lpNameW, NULL);
2712 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2714 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2715 RegDeleteValueW(hkey, lpNameW);
2719 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2720 RegDeleteValueW(hkey, lpNameW);
2726 /*****************************************************************************
2727 * SetPrinterA [WINSPOOL.@]
2729 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2732 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2736 /*****************************************************************************
2737 * SetJobA [WINSPOOL.@]
2739 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2740 LPBYTE pJob, DWORD Command)
2744 UNICODE_STRING usBuffer;
2746 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2748 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2749 are all ignored by SetJob, so we don't bother copying them */
2757 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2758 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2760 JobW = (LPBYTE)info1W;
2761 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2762 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2763 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2764 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2765 info1W->Status = info1A->Status;
2766 info1W->Priority = info1A->Priority;
2767 info1W->Position = info1A->Position;
2768 info1W->PagesPrinted = info1A->PagesPrinted;
2773 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2774 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2776 JobW = (LPBYTE)info2W;
2777 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2778 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2779 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2780 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2781 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2782 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2783 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2784 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2785 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2786 info2W->Status = info2A->Status;
2787 info2W->Priority = info2A->Priority;
2788 info2W->Position = info2A->Position;
2789 info2W->StartTime = info2A->StartTime;
2790 info2W->UntilTime = info2A->UntilTime;
2791 info2W->PagesPrinted = info2A->PagesPrinted;
2795 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2796 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2799 SetLastError(ERROR_INVALID_LEVEL);
2803 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2809 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2810 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2811 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2812 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2813 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2818 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2819 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2820 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2821 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2822 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2823 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2824 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2825 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2826 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2830 HeapFree(GetProcessHeap(), 0, JobW);
2835 /*****************************************************************************
2836 * SetJobW [WINSPOOL.@]
2838 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2839 LPBYTE pJob, DWORD Command)
2844 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2845 FIXME("Ignoring everything other than document title\n");
2847 EnterCriticalSection(&printer_handles_cs);
2848 job = get_job(hPrinter, JobId);
2858 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2859 HeapFree(GetProcessHeap(), 0, job->document_title);
2860 job->document_title = strdupW(info1->pDocument);
2865 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2866 HeapFree(GetProcessHeap(), 0, job->document_title);
2867 job->document_title = strdupW(info2->pDocument);
2873 SetLastError(ERROR_INVALID_LEVEL);
2878 LeaveCriticalSection(&printer_handles_cs);
2882 /*****************************************************************************
2883 * EndDocPrinter [WINSPOOL.@]
2885 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2887 opened_printer_t *printer;
2889 TRACE("(%p)\n", hPrinter);
2891 EnterCriticalSection(&printer_handles_cs);
2893 printer = get_opened_printer(hPrinter);
2896 SetLastError(ERROR_INVALID_HANDLE);
2902 SetLastError(ERROR_SPL_NO_STARTDOC);
2906 CloseHandle(printer->doc->hf);
2907 ScheduleJob(hPrinter, printer->doc->job_id);
2908 HeapFree(GetProcessHeap(), 0, printer->doc);
2909 printer->doc = NULL;
2912 LeaveCriticalSection(&printer_handles_cs);
2916 /*****************************************************************************
2917 * EndPagePrinter [WINSPOOL.@]
2919 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2921 FIXME("(%p): stub\n", hPrinter);
2925 /*****************************************************************************
2926 * StartDocPrinterA [WINSPOOL.@]
2928 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2930 UNICODE_STRING usBuffer;
2932 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2935 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2936 or one (DOC_INFO_3) extra DWORDs */
2940 doc2W.JobId = doc2->JobId;
2943 doc2W.dwMode = doc2->dwMode;
2946 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2947 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2948 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2952 SetLastError(ERROR_INVALID_LEVEL);
2956 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2958 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2959 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2960 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2965 /*****************************************************************************
2966 * StartDocPrinterW [WINSPOOL.@]
2968 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2970 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2971 opened_printer_t *printer;
2972 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2973 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2974 JOB_INFO_1W job_info;
2975 DWORD needed, ret = 0;
2979 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2980 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2981 debugstr_w(doc->pDatatype));
2983 if(Level < 1 || Level > 3)
2985 SetLastError(ERROR_INVALID_LEVEL);
2989 EnterCriticalSection(&printer_handles_cs);
2990 printer = get_opened_printer(hPrinter);
2993 SetLastError(ERROR_INVALID_HANDLE);
2999 SetLastError(ERROR_INVALID_PRINTER_STATE);
3003 /* Even if we're printing to a file we still add a print job, we'll
3004 just ignore the spool file name */
3006 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3008 ERR("AddJob failed gle %u\n", GetLastError());
3012 if(doc->pOutputFile)
3013 filename = doc->pOutputFile;
3015 filename = addjob->Path;
3017 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3018 if(hf == INVALID_HANDLE_VALUE)
3021 memset(&job_info, 0, sizeof(job_info));
3022 job_info.pDocument = doc->pDocName;
3023 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3025 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3026 printer->doc->hf = hf;
3027 ret = printer->doc->job_id = addjob->JobId;
3029 LeaveCriticalSection(&printer_handles_cs);
3034 /*****************************************************************************
3035 * StartPagePrinter [WINSPOOL.@]
3037 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3039 FIXME("(%p): stub\n", hPrinter);
3043 /*****************************************************************************
3044 * GetFormA [WINSPOOL.@]
3046 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3047 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3049 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3050 Level,pForm,cbBuf,pcbNeeded);
3054 /*****************************************************************************
3055 * GetFormW [WINSPOOL.@]
3057 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3058 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3060 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3061 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3065 /*****************************************************************************
3066 * SetFormA [WINSPOOL.@]
3068 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3071 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3075 /*****************************************************************************
3076 * SetFormW [WINSPOOL.@]
3078 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3081 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3085 /*****************************************************************************
3086 * ReadPrinter [WINSPOOL.@]
3088 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3089 LPDWORD pNoBytesRead)
3091 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3095 /*****************************************************************************
3096 * ResetPrinterA [WINSPOOL.@]
3098 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3100 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3104 /*****************************************************************************
3105 * ResetPrinterW [WINSPOOL.@]
3107 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3109 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3113 /*****************************************************************************
3114 * WINSPOOL_GetDWORDFromReg
3116 * Return DWORD associated with ValueName from hkey.
3118 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3120 DWORD sz = sizeof(DWORD), type, value = 0;
3123 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3125 if(ret != ERROR_SUCCESS) {
3126 WARN("Got ret = %d on name %s\n", ret, ValueName);
3129 if(type != REG_DWORD) {
3130 ERR("Got type %d\n", type);
3137 /*****************************************************************************
3138 * get_filename_from_reg [internal]
3140 * Get ValueName from hkey storing result in out
3141 * when the Value in the registry has only a filename, use driverdir as prefix
3142 * outlen is space left in out
3143 * String is stored either as unicode or ascii
3147 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3148 LPBYTE out, DWORD outlen, LPDWORD needed)
3150 WCHAR filename[MAX_PATH];
3154 LPWSTR buffer = filename;
3158 size = sizeof(filename);
3160 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3161 if (ret == ERROR_MORE_DATA) {
3162 TRACE("need dynamic buffer: %u\n", size);
3163 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3165 /* No Memory is bad */
3169 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3172 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3173 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3179 /* do we have a full path ? */
3180 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3181 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3184 /* we must build the full Path */
3186 if ((out) && (outlen > dirlen)) {
3187 lstrcpyW((LPWSTR)out, driverdir);
3195 /* write the filename */
3196 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3197 if ((out) && (outlen >= size)) {
3198 lstrcpyW((LPWSTR)out, ptr);
3205 ptr += lstrlenW(ptr)+1;
3206 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3209 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3211 /* write the multisz-termination */
3212 if (type == REG_MULTI_SZ) {
3213 size = sizeof(WCHAR);
3216 if (out && (outlen >= size)) {
3217 memset (out, 0, size);
3223 /*****************************************************************************
3224 * WINSPOOL_GetStringFromReg
3226 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3227 * String is stored as unicode.
3229 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3230 DWORD buflen, DWORD *needed)
3232 DWORD sz = buflen, type;
3235 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3236 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3237 WARN("Got ret = %d\n", ret);
3241 /* add space for terminating '\0' */
3242 sz += sizeof(WCHAR);
3246 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3251 /*****************************************************************************
3252 * WINSPOOL_GetDefaultDevMode
3254 * Get a default DevMode values for wineps.
3258 static void WINSPOOL_GetDefaultDevMode(
3260 DWORD buflen, DWORD *needed)
3263 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3265 /* fill default DEVMODE - should be read from ppd... */
3266 ZeroMemory( &dm, sizeof(dm) );
3267 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3268 dm.dmSpecVersion = DM_SPECVERSION;
3269 dm.dmDriverVersion = 1;
3270 dm.dmSize = sizeof(DEVMODEW);
3271 dm.dmDriverExtra = 0;
3273 DM_ORIENTATION | DM_PAPERSIZE |
3274 DM_PAPERLENGTH | DM_PAPERWIDTH |
3277 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3278 DM_YRESOLUTION | DM_TTOPTION;
3280 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3281 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3282 dm.u1.s1.dmPaperLength = 2970;
3283 dm.u1.s1.dmPaperWidth = 2100;
3285 dm.u1.s1.dmScale = 100;
3286 dm.u1.s1.dmCopies = 1;
3287 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3288 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3291 dm.dmYResolution = 300; /* 300dpi */
3292 dm.dmTTOption = DMTT_BITMAP;
3295 /* dm.dmLogPixels */
3296 /* dm.dmBitsPerPel */
3297 /* dm.dmPelsWidth */
3298 /* dm.dmPelsHeight */
3299 /* dm.u2.dmDisplayFlags */
3300 /* dm.dmDisplayFrequency */
3301 /* dm.dmICMMethod */
3302 /* dm.dmICMIntent */
3303 /* dm.dmMediaType */
3304 /* dm.dmDitherType */
3305 /* dm.dmReserved1 */
3306 /* dm.dmReserved2 */
3307 /* dm.dmPanningWidth */
3308 /* dm.dmPanningHeight */
3310 if(buflen >= sizeof(DEVMODEW))
3311 memcpy(ptr, &dm, sizeof(DEVMODEW));
3312 *needed = sizeof(DEVMODEW);
3315 /*****************************************************************************
3316 * WINSPOOL_GetDevModeFromReg
3318 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3319 * DevMode is stored either as unicode or ascii.
3321 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3323 DWORD buflen, DWORD *needed)
3325 DWORD sz = buflen, type;
3328 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3329 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3330 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3331 if (sz < sizeof(DEVMODEA))
3333 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3336 /* ensures that dmSize is not erratically bogus if registry is invalid */
3337 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3338 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3339 sz += (CCHDEVICENAME + CCHFORMNAME);
3340 if (ptr && (buflen >= sz)) {
3341 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3342 memcpy(ptr, dmW, sz);
3343 HeapFree(GetProcessHeap(),0,dmW);
3349 /*********************************************************************
3350 * WINSPOOL_GetPrinter_1
3352 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3354 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3355 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3357 DWORD size, left = cbBuf;
3358 BOOL space = (cbBuf > 0);
3363 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3364 if(space && size <= left) {
3365 pi1->pName = (LPWSTR)ptr;
3373 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3374 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3375 if(space && size <= left) {
3376 pi1->pDescription = (LPWSTR)ptr;
3384 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3385 if(space && size <= left) {
3386 pi1->pComment = (LPWSTR)ptr;
3394 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3396 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3397 memset(pi1, 0, sizeof(*pi1));
3401 /*********************************************************************
3402 * WINSPOOL_GetPrinter_2
3404 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3406 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3407 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3409 DWORD size, left = cbBuf;
3410 BOOL space = (cbBuf > 0);
3415 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3416 if(space && size <= left) {
3417 pi2->pPrinterName = (LPWSTR)ptr;
3424 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3425 if(space && size <= left) {
3426 pi2->pShareName = (LPWSTR)ptr;
3433 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3434 if(space && size <= left) {
3435 pi2->pPortName = (LPWSTR)ptr;
3442 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3443 if(space && size <= left) {
3444 pi2->pDriverName = (LPWSTR)ptr;
3451 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3452 if(space && size <= left) {
3453 pi2->pComment = (LPWSTR)ptr;
3460 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3461 if(space && size <= left) {
3462 pi2->pLocation = (LPWSTR)ptr;
3469 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3470 if(space && size <= left) {
3471 pi2->pDevMode = (LPDEVMODEW)ptr;
3480 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3481 if(space && size <= left) {
3482 pi2->pDevMode = (LPDEVMODEW)ptr;
3489 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3490 if(space && size <= left) {
3491 pi2->pSepFile = (LPWSTR)ptr;
3498 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3499 if(space && size <= left) {
3500 pi2->pPrintProcessor = (LPWSTR)ptr;
3507 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3508 if(space && size <= left) {
3509 pi2->pDatatype = (LPWSTR)ptr;
3516 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3517 if(space && size <= left) {
3518 pi2->pParameters = (LPWSTR)ptr;
3526 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3527 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3528 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3529 "Default Priority");
3530 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3531 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3534 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3535 memset(pi2, 0, sizeof(*pi2));
3540 /*********************************************************************
3541 * WINSPOOL_GetPrinter_4
3543 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3545 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3546 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3548 DWORD size, left = cbBuf;
3549 BOOL space = (cbBuf > 0);
3554 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3555 if(space && size <= left) {
3556 pi4->pPrinterName = (LPWSTR)ptr;
3564 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3567 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3568 memset(pi4, 0, sizeof(*pi4));
3573 /*********************************************************************
3574 * WINSPOOL_GetPrinter_5
3576 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3578 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3579 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3581 DWORD size, left = cbBuf;
3582 BOOL space = (cbBuf > 0);
3587 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3588 if(space && size <= left) {
3589 pi5->pPrinterName = (LPWSTR)ptr;
3596 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3597 if(space && size <= left) {
3598 pi5->pPortName = (LPWSTR)ptr;
3606 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3607 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3609 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3613 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3614 memset(pi5, 0, sizeof(*pi5));
3619 /*********************************************************************
3620 * WINSPOOL_GetPrinter_7
3622 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3624 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3625 DWORD cbBuf, LPDWORD pcbNeeded)
3627 DWORD size, left = cbBuf;
3628 BOOL space = (cbBuf > 0);
3633 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3636 size = sizeof(pi7->pszObjectGUID);
3638 if (space && size <= left) {
3639 pi7->pszObjectGUID = (LPWSTR)ptr;
3646 /* We do not have a Directory Service */
3647 pi7->dwAction = DSPRINT_UNPUBLISH;
3650 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3651 memset(pi7, 0, sizeof(*pi7));
3656 /*********************************************************************
3657 * WINSPOOL_GetPrinter_9
3659 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3661 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3662 DWORD cbBuf, LPDWORD pcbNeeded)
3665 BOOL space = (cbBuf > 0);
3669 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3670 if(space && size <= cbBuf) {
3671 pi9->pDevMode = (LPDEVMODEW)buf;
3678 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3679 if(space && size <= cbBuf) {
3680 pi9->pDevMode = (LPDEVMODEW)buf;
3686 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3687 memset(pi9, 0, sizeof(*pi9));
3692 /*****************************************************************************
3693 * GetPrinterW [WINSPOOL.@]
3695 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3696 DWORD cbBuf, LPDWORD pcbNeeded)
3699 DWORD size, needed = 0;
3701 HKEY hkeyPrinter, hkeyPrinters;
3704 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3706 if (!(name = get_opened_printer_name(hPrinter))) {
3707 SetLastError(ERROR_INVALID_HANDLE);
3711 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3713 ERR("Can't create Printers key\n");
3716 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3718 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3719 RegCloseKey(hkeyPrinters);
3720 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3727 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3729 size = sizeof(PRINTER_INFO_2W);
3731 ptr = pPrinter + size;
3733 memset(pPrinter, 0, size);
3738 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3745 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3747 size = sizeof(PRINTER_INFO_4W);
3749 ptr = pPrinter + size;
3751 memset(pPrinter, 0, size);
3756 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3764 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3766 size = sizeof(PRINTER_INFO_5W);
3768 ptr = pPrinter + size;
3770 memset(pPrinter, 0, size);
3776 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3784 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3786 size = sizeof(PRINTER_INFO_6);
3787 if (size <= cbBuf) {
3788 /* FIXME: We do not update the status yet */
3789 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3801 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3803 size = sizeof(PRINTER_INFO_7W);
3804 if (size <= cbBuf) {
3805 ptr = pPrinter + size;
3807 memset(pPrinter, 0, size);
3813 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3821 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3823 size = sizeof(PRINTER_INFO_9W);
3825 ptr = pPrinter + size;
3827 memset(pPrinter, 0, size);
3833 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
3840 FIXME("Unimplemented level %d\n", Level);
3841 SetLastError(ERROR_INVALID_LEVEL);
3842 RegCloseKey(hkeyPrinters);
3843 RegCloseKey(hkeyPrinter);
3847 RegCloseKey(hkeyPrinter);
3848 RegCloseKey(hkeyPrinters);
3850 TRACE("returning %d needed = %d\n", ret, needed);
3851 if(pcbNeeded) *pcbNeeded = needed;
3853 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3857 /*****************************************************************************
3858 * GetPrinterA [WINSPOOL.@]
3860 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3861 DWORD cbBuf, LPDWORD pcbNeeded)
3867 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
3869 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
3871 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
3872 HeapFree(GetProcessHeap(), 0, buf);
3877 /*****************************************************************************
3878 * WINSPOOL_EnumPrintersW
3880 * Implementation of EnumPrintersW
3882 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
3883 DWORD dwLevel, LPBYTE lpbPrinters,
3884 DWORD cbBuf, LPDWORD lpdwNeeded,
3885 LPDWORD lpdwReturned)
3888 HKEY hkeyPrinters, hkeyPrinter;
3889 WCHAR PrinterName[255];
3890 DWORD needed = 0, number = 0;
3891 DWORD used, i, left;
3895 memset(lpbPrinters, 0, cbBuf);
3901 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3902 if(dwType == PRINTER_ENUM_DEFAULT)
3905 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3906 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3907 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3909 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3915 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3916 FIXME("dwType = %08x\n", dwType);
3917 SetLastError(ERROR_INVALID_FLAGS);
3921 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3923 ERR("Can't create Printers key\n");
3927 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3928 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3929 RegCloseKey(hkeyPrinters);
3930 ERR("Can't query Printers key\n");
3933 TRACE("Found %d printers\n", number);
3937 used = number * sizeof(PRINTER_INFO_1W);
3940 used = number * sizeof(PRINTER_INFO_2W);
3943 used = number * sizeof(PRINTER_INFO_4W);
3946 used = number * sizeof(PRINTER_INFO_5W);
3950 SetLastError(ERROR_INVALID_LEVEL);
3951 RegCloseKey(hkeyPrinters);
3954 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3956 for(i = 0; i < number; i++) {
3957 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3959 ERR("Can't enum key number %d\n", i);
3960 RegCloseKey(hkeyPrinters);
3963 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3964 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3966 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3967 RegCloseKey(hkeyPrinters);
3972 buf = lpbPrinters + used;
3973 left = cbBuf - used;
3981 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3984 if(pi) pi += sizeof(PRINTER_INFO_1W);
3987 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3990 if(pi) pi += sizeof(PRINTER_INFO_2W);
3993 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3996 if(pi) pi += sizeof(PRINTER_INFO_4W);
3999 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4002 if(pi) pi += sizeof(PRINTER_INFO_5W);
4005 ERR("Shouldn't be here!\n");
4006 RegCloseKey(hkeyPrinter);
4007 RegCloseKey(hkeyPrinters);
4010 RegCloseKey(hkeyPrinter);
4012 RegCloseKey(hkeyPrinters);
4019 memset(lpbPrinters, 0, cbBuf);
4020 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4024 *lpdwReturned = number;
4025 SetLastError(ERROR_SUCCESS);
4030 /******************************************************************
4031 * EnumPrintersW [WINSPOOL.@]
4033 * Enumerates the available printers, print servers and print
4034 * providers, depending on the specified flags, name and level.
4038 * If level is set to 1:
4039 * Returns an array of PRINTER_INFO_1 data structures in the
4040 * lpbPrinters buffer.
4042 * If level is set to 2:
4043 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4044 * Returns an array of PRINTER_INFO_2 data structures in the
4045 * lpbPrinters buffer. Note that according to MSDN also an
4046 * OpenPrinter should be performed on every remote printer.
4048 * If level is set to 4 (officially WinNT only):
4049 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4050 * Fast: Only the registry is queried to retrieve printer names,
4051 * no connection to the driver is made.
4052 * Returns an array of PRINTER_INFO_4 data structures in the
4053 * lpbPrinters buffer.
4055 * If level is set to 5 (officially WinNT4/Win9x only):
4056 * Fast: Only the registry is queried to retrieve printer names,
4057 * no connection to the driver is made.
4058 * Returns an array of PRINTER_INFO_5 data structures in the
4059 * lpbPrinters buffer.
4061 * If level set to 3 or 6+:
4062 * returns zero (failure!)
4064 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4068 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4069 * - Only levels 2, 4 and 5 are implemented at the moment.
4070 * - 16-bit printer drivers are not enumerated.
4071 * - Returned amount of bytes used/needed does not match the real Windoze
4072 * implementation (as in this implementation, all strings are part
4073 * of the buffer, whereas Win32 keeps them somewhere else)
4074 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4077 * - In a regular Wine installation, no registry settings for printers
4078 * exist, which makes this function return an empty list.
4080 BOOL WINAPI EnumPrintersW(
4081 DWORD dwType, /* [in] Types of print objects to enumerate */
4082 LPWSTR lpszName, /* [in] name of objects to enumerate */
4083 DWORD dwLevel, /* [in] type of printer info structure */
4084 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4085 DWORD cbBuf, /* [in] max size of buffer in bytes */
4086 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4087 LPDWORD lpdwReturned /* [out] number of entries returned */
4090 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4091 lpdwNeeded, lpdwReturned);
4094 /******************************************************************
4095 * EnumPrintersA [WINSPOOL.@]
4100 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4101 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4104 UNICODE_STRING pNameU;
4108 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4109 pPrinters, cbBuf, pcbNeeded, pcReturned);
4111 pNameW = asciitounicode(&pNameU, pName);
4113 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4114 MS Office need this */
4115 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4117 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4119 RtlFreeUnicodeString(&pNameU);
4121 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4123 HeapFree(GetProcessHeap(), 0, pPrintersW);
4127 /*****************************************************************************
4128 * WINSPOOL_GetDriverInfoFromReg [internal]
4130 * Enters the information from the registry into the DRIVER_INFO struct
4133 * zero if the printer driver does not exist in the registry
4134 * (only if Level > 1) otherwise nonzero
4136 static BOOL WINSPOOL_GetDriverInfoFromReg(
4139 const printenv_t * env,
4141 LPBYTE ptr, /* DRIVER_INFO */
4142 LPBYTE pDriverStrings, /* strings buffer */
4143 DWORD cbBuf, /* size of string buffer */
4144 LPDWORD pcbNeeded) /* space needed for str. */
4148 WCHAR driverdir[MAX_PATH];
4150 LPBYTE strPtr = pDriverStrings;
4151 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4153 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4154 debugstr_w(DriverName), env,
4155 Level, di, pDriverStrings, cbBuf);
4157 if (di) ZeroMemory(di, di_sizeof[Level]);
4159 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4160 if (*pcbNeeded <= cbBuf)
4161 strcpyW((LPWSTR)strPtr, DriverName);
4163 /* pName for level 1 has a different offset! */
4165 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4169 /* .cVersion and .pName for level > 1 */
4171 di->cVersion = env->driverversion;
4172 di->pName = (LPWSTR) strPtr;
4173 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4176 /* Reserve Space for the largest subdir and a Backslash*/
4177 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4178 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4179 /* Should never Fail */
4182 lstrcatW(driverdir, env->versionsubdir);
4183 lstrcatW(driverdir, backslashW);
4185 /* dirlen must not include the terminating zero */
4186 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4188 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4189 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4190 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4195 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4198 if (*pcbNeeded <= cbBuf) {
4199 lstrcpyW((LPWSTR)strPtr, env->envname);
4200 if (di) di->pEnvironment = (LPWSTR)strPtr;
4201 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4204 /* .pDriverPath is the Graphics rendering engine.
4205 The full Path is required to avoid a crash in some apps */
4206 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4208 if (*pcbNeeded <= cbBuf)
4209 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4211 if (di) di->pDriverPath = (LPWSTR)strPtr;
4212 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4215 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4216 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4218 if (*pcbNeeded <= cbBuf)
4219 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4221 if (di) di->pDataFile = (LPWSTR)strPtr;
4222 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4225 /* .pConfigFile is the Driver user Interface */
4226 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4228 if (*pcbNeeded <= cbBuf)
4229 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4231 if (di) di->pConfigFile = (LPWSTR)strPtr;
4232 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4236 RegCloseKey(hkeyDriver);
4237 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4242 RegCloseKey(hkeyDriver);
4243 FIXME("level 5: incomplete\n");
4248 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4250 if (*pcbNeeded <= cbBuf)
4251 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4253 if (di) di->pHelpFile = (LPWSTR)strPtr;
4254 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4257 /* .pDependentFiles */
4258 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4260 if (*pcbNeeded <= cbBuf)
4261 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4263 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4264 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4266 else if (GetVersion() & 0x80000000) {
4267 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4268 size = 2 * sizeof(WCHAR);
4270 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4272 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4273 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4276 /* .pMonitorName is the optional Language Monitor */
4277 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4279 if (*pcbNeeded <= cbBuf)
4280 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4282 if (di) di->pMonitorName = (LPWSTR)strPtr;
4283 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4286 /* .pDefaultDataType */
4287 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4289 if(*pcbNeeded <= cbBuf)
4290 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4292 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4293 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4297 RegCloseKey(hkeyDriver);
4298 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4302 /* .pszzPreviousNames */
4303 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4305 if(*pcbNeeded <= cbBuf)
4306 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4308 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4309 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4313 RegCloseKey(hkeyDriver);
4314 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4318 /* support is missing, but not important enough for a FIXME */
4319 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4322 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4324 if(*pcbNeeded <= cbBuf)
4325 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4327 if (di) di->pszMfgName = (LPWSTR)strPtr;
4328 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4332 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4334 if(*pcbNeeded <= cbBuf)
4335 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4337 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4338 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4341 /* .pszHardwareID */
4342 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4344 if(*pcbNeeded <= cbBuf)
4345 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4347 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4348 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4352 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4354 if(*pcbNeeded <= cbBuf)
4355 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4357 if (di) di->pszProvider = (LPWSTR)strPtr;
4358 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4362 RegCloseKey(hkeyDriver);
4366 /* support is missing, but not important enough for a FIXME */
4367 TRACE("level 8: incomplete\n");
4369 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4370 RegCloseKey(hkeyDriver);
4374 /*****************************************************************************
4375 * GetPrinterDriverW [WINSPOOL.@]
4377 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4378 DWORD Level, LPBYTE pDriverInfo,
4379 DWORD cbBuf, LPDWORD pcbNeeded)
4382 WCHAR DriverName[100];
4383 DWORD ret, type, size, needed = 0;
4385 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4386 const printenv_t * env;
4388 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4389 Level,pDriverInfo,cbBuf, pcbNeeded);
4392 if (!(name = get_opened_printer_name(hPrinter))) {
4393 SetLastError(ERROR_INVALID_HANDLE);
4397 if (Level < 1 || Level == 7 || Level > 8) {
4398 SetLastError(ERROR_INVALID_LEVEL);
4402 env = validate_envW(pEnvironment);
4403 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4405 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4407 ERR("Can't create Printers key\n");
4410 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4412 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4413 RegCloseKey(hkeyPrinters);
4414 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4417 size = sizeof(DriverName);
4419 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4420 (LPBYTE)DriverName, &size);
4421 RegCloseKey(hkeyPrinter);
4422 RegCloseKey(hkeyPrinters);
4423 if(ret != ERROR_SUCCESS) {
4424 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4428 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4430 ERR("Can't create Drivers key\n");
4434 size = di_sizeof[Level];
4435 if ((size <= cbBuf) && pDriverInfo)
4436 ptr = pDriverInfo + size;
4438 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4439 env, Level, pDriverInfo, ptr,
4440 (cbBuf < size) ? 0 : cbBuf - size,
4442 RegCloseKey(hkeyDrivers);
4446 RegCloseKey(hkeyDrivers);
4448 if(pcbNeeded) *pcbNeeded = size + needed;
4449 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4450 if(cbBuf >= needed) return TRUE;
4451 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4455 /*****************************************************************************
4456 * GetPrinterDriverA [WINSPOOL.@]
4458 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4459 DWORD Level, LPBYTE pDriverInfo,
4460 DWORD cbBuf, LPDWORD pcbNeeded)
4463 UNICODE_STRING pEnvW;
4468 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4470 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4471 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4474 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4476 HeapFree(GetProcessHeap(), 0, buf);
4478 RtlFreeUnicodeString(&pEnvW);
4482 /*****************************************************************************
4483 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4485 * Return the PATH for the Printer-Drivers (UNICODE)
4488 * pName [I] Servername (NT only) or NULL (local Computer)
4489 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4490 * Level [I] Structure-Level (must be 1)
4491 * pDriverDirectory [O] PTR to Buffer that receives the Result
4492 * cbBuf [I] Size of Buffer at pDriverDirectory
4493 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4494 * required for pDriverDirectory
4497 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4498 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4499 * if cbBuf is too small
4501 * Native Values returned in pDriverDirectory on Success:
4502 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4503 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4504 *| win9x(Windows 4.0): "%winsysdir%"
4506 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4509 *- Only NULL or "" is supported for pName
4512 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4513 DWORD Level, LPBYTE pDriverDirectory,
4514 DWORD cbBuf, LPDWORD pcbNeeded)
4516 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4517 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4519 if ((backend == NULL) && !load_backend()) return FALSE;
4522 /* (Level != 1) is ignored in win9x */
4523 SetLastError(ERROR_INVALID_LEVEL);
4526 if (pcbNeeded == NULL) {
4527 /* (pcbNeeded == NULL) is ignored in win9x */
4528 SetLastError(RPC_X_NULL_REF_POINTER);
4532 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4533 pDriverDirectory, cbBuf, pcbNeeded);
4538 /*****************************************************************************
4539 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4541 * Return the PATH for the Printer-Drivers (ANSI)
4543 * See GetPrinterDriverDirectoryW.
4546 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4549 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4550 DWORD Level, LPBYTE pDriverDirectory,
4551 DWORD cbBuf, LPDWORD pcbNeeded)
4553 UNICODE_STRING nameW, environmentW;
4556 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4557 WCHAR *driverDirectoryW = NULL;
4559 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4560 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4562 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4564 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4565 else nameW.Buffer = NULL;
4566 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4567 else environmentW.Buffer = NULL;
4569 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4570 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4573 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4574 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4576 *pcbNeeded = needed;
4577 ret = (needed <= cbBuf) ? TRUE : FALSE;
4579 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4581 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4583 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4584 RtlFreeUnicodeString(&environmentW);
4585 RtlFreeUnicodeString(&nameW);
4590 /*****************************************************************************
4591 * AddPrinterDriverA [WINSPOOL.@]
4593 * See AddPrinterDriverW.
4596 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4598 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4599 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4602 /******************************************************************************
4603 * AddPrinterDriverW (WINSPOOL.@)
4605 * Install a Printer Driver
4608 * pName [I] Servername or NULL (local Computer)
4609 * level [I] Level for the supplied DRIVER_INFO_*W struct
4610 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4617 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4619 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4620 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4623 /*****************************************************************************
4624 * AddPrintProcessorA [WINSPOOL.@]
4626 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4627 LPSTR pPrintProcessorName)
4629 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4630 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4634 /*****************************************************************************
4635 * AddPrintProcessorW [WINSPOOL.@]
4637 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4638 LPWSTR pPrintProcessorName)
4640 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4641 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4645 /*****************************************************************************
4646 * AddPrintProvidorA [WINSPOOL.@]
4648 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4650 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4654 /*****************************************************************************
4655 * AddPrintProvidorW [WINSPOOL.@]
4657 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4659 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4663 /*****************************************************************************
4664 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4666 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4667 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4669 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4670 pDevModeOutput, pDevModeInput);
4674 /*****************************************************************************
4675 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4677 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4678 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4680 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4681 pDevModeOutput, pDevModeInput);
4685 /*****************************************************************************
4686 * PrinterProperties [WINSPOOL.@]
4688 * Displays a dialog to set the properties of the printer.
4691 * nonzero on success or zero on failure
4694 * implemented as stub only
4696 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4697 HANDLE hPrinter /* [in] handle to printer object */
4699 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4700 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4704 /*****************************************************************************
4705 * EnumJobsA [WINSPOOL.@]
4708 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4709 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4712 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4713 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4715 if(pcbNeeded) *pcbNeeded = 0;
4716 if(pcReturned) *pcReturned = 0;
4721 /*****************************************************************************
4722 * EnumJobsW [WINSPOOL.@]
4725 BOOL WINAPI EnumJobsW(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;
4737 /*****************************************************************************
4738 * WINSPOOL_EnumPrinterDrivers [internal]
4740 * Delivers information about all printer drivers installed on the
4741 * localhost or a given server
4744 * nonzero on success or zero on failure. If the buffer for the returned
4745 * information is too small the function will return an error
4748 * - only implemented for localhost, foreign hosts will return an error
4750 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4751 DWORD Level, LPBYTE pDriverInfo,
4753 DWORD cbBuf, LPDWORD pcbNeeded,
4754 LPDWORD pcFound, DWORD data_offset)
4758 const printenv_t * env;
4760 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4761 debugstr_w(pName), debugstr_w(pEnvironment),
4762 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4764 env = validate_envW(pEnvironment);
4765 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4769 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4771 ERR("Can't open Drivers key\n");
4775 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4776 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4777 RegCloseKey(hkeyDrivers);
4778 ERR("Can't query Drivers key\n");
4781 TRACE("Found %d Drivers\n", *pcFound);
4783 /* get size of single struct
4784 * unicode and ascii structure have the same size
4786 size = di_sizeof[Level];
4788 if (data_offset == 0)
4789 data_offset = size * (*pcFound);
4790 *pcbNeeded = data_offset;
4792 for( i = 0; i < *pcFound; i++) {
4793 WCHAR DriverNameW[255];
4794 PBYTE table_ptr = NULL;
4795 PBYTE data_ptr = NULL;
4798 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4800 ERR("Can't enum key number %d\n", i);
4801 RegCloseKey(hkeyDrivers);
4805 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4806 table_ptr = pDriverInfo + (driver_index + i) * size;
4807 if (pDriverInfo && *pcbNeeded <= cbBuf)
4808 data_ptr = pDriverInfo + *pcbNeeded;
4810 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4811 env, Level, table_ptr, data_ptr,
4812 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4814 RegCloseKey(hkeyDrivers);
4818 *pcbNeeded += needed;
4821 RegCloseKey(hkeyDrivers);
4823 if(cbBuf < *pcbNeeded){
4824 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4831 /*****************************************************************************
4832 * EnumPrinterDriversW [WINSPOOL.@]
4834 * see function EnumPrinterDrivers for RETURNS, BUGS
4836 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4837 LPBYTE pDriverInfo, DWORD cbBuf,
4838 LPDWORD pcbNeeded, LPDWORD pcReturned)
4840 static const WCHAR allW[] = {'a','l','l',0};
4844 if ((pcbNeeded == NULL) || (pcReturned == NULL))
4846 SetLastError(RPC_X_NULL_REF_POINTER);
4850 /* check for local drivers */
4851 if((pName) && (pName[0])) {
4852 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4853 SetLastError(ERROR_ACCESS_DENIED);
4857 /* check input parameter */
4858 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4859 SetLastError(ERROR_INVALID_LEVEL);
4863 if(pDriverInfo && cbBuf > 0)
4864 memset( pDriverInfo, 0, cbBuf);
4866 /* Exception: pull all printers */
4867 if (pEnvironment && !strcmpW(pEnvironment, allW))
4869 DWORD i, needed, bufsize = cbBuf;
4870 DWORD total_needed = 0;
4871 DWORD total_found = 0;
4874 /* Precompute the overall total; we need this to know
4875 where pointers end and data begins (i.e. data_offset) */
4876 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4879 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4880 NULL, 0, 0, &needed, &found, 0);
4881 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4882 total_needed += needed;
4883 total_found += found;
4886 data_offset = di_sizeof[Level] * total_found;
4891 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4894 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4895 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
4896 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4898 *pcReturned += found;
4899 *pcbNeeded = needed;
4900 data_offset = needed;
4901 total_found += found;
4906 /* Normal behavior */
4907 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4908 0, cbBuf, pcbNeeded, &found, 0);
4910 *pcReturned = found;
4915 /*****************************************************************************
4916 * EnumPrinterDriversA [WINSPOOL.@]
4918 * see function EnumPrinterDrivers for RETURNS, BUGS
4920 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4921 LPBYTE pDriverInfo, DWORD cbBuf,
4922 LPDWORD pcbNeeded, LPDWORD pcReturned)
4925 UNICODE_STRING pNameW, pEnvironmentW;
4926 PWSTR pwstrNameW, pwstrEnvironmentW;
4930 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4932 pwstrNameW = asciitounicode(&pNameW, pName);
4933 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4935 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
4936 buf, cbBuf, pcbNeeded, pcReturned);
4938 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
4940 HeapFree(GetProcessHeap(), 0, buf);
4942 RtlFreeUnicodeString(&pNameW);
4943 RtlFreeUnicodeString(&pEnvironmentW);
4948 /******************************************************************************
4949 * EnumPortsA (WINSPOOL.@)
4954 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4955 LPDWORD pcbNeeded, LPDWORD pcReturned)
4958 LPBYTE bufferW = NULL;
4959 LPWSTR nameW = NULL;
4961 DWORD numentries = 0;
4964 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4965 cbBuf, pcbNeeded, pcReturned);
4967 /* convert servername to unicode */
4969 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4970 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4971 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4973 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4974 needed = cbBuf * sizeof(WCHAR);
4975 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4976 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4978 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4979 if (pcbNeeded) needed = *pcbNeeded;
4980 /* HeapReAlloc return NULL, when bufferW was NULL */
4981 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4982 HeapAlloc(GetProcessHeap(), 0, needed);
4984 /* Try again with the large Buffer */
4985 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4987 needed = pcbNeeded ? *pcbNeeded : 0;
4988 numentries = pcReturned ? *pcReturned : 0;
4991 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4992 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4995 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
4996 DWORD entrysize = 0;
4999 LPPORT_INFO_2W pi2w;
5000 LPPORT_INFO_2A pi2a;
5003 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5005 /* First pass: calculate the size for all Entries */
5006 pi2w = (LPPORT_INFO_2W) bufferW;
5007 pi2a = (LPPORT_INFO_2A) pPorts;
5009 while (index < numentries) {
5011 needed += entrysize; /* PORT_INFO_?A */
5012 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5014 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5015 NULL, 0, NULL, NULL);
5017 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5018 NULL, 0, NULL, NULL);
5019 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5020 NULL, 0, NULL, NULL);
5022 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5023 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5024 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5027 /* check for errors and quit on failure */
5028 if (cbBuf < needed) {
5029 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5033 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5034 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5035 cbBuf -= len ; /* free Bytes in the user-Buffer */
5036 pi2w = (LPPORT_INFO_2W) bufferW;
5037 pi2a = (LPPORT_INFO_2A) pPorts;
5039 /* Second Pass: Fill the User Buffer (if we have one) */
5040 while ((index < numentries) && pPorts) {
5042 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5043 pi2a->pPortName = ptr;
5044 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5045 ptr, cbBuf , NULL, NULL);
5049 pi2a->pMonitorName = ptr;
5050 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5051 ptr, cbBuf, NULL, NULL);
5055 pi2a->pDescription = ptr;
5056 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5057 ptr, cbBuf, NULL, NULL);
5061 pi2a->fPortType = pi2w->fPortType;
5062 pi2a->Reserved = 0; /* documented: "must be zero" */
5065 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5066 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5067 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5072 if (pcbNeeded) *pcbNeeded = needed;
5073 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5075 HeapFree(GetProcessHeap(), 0, nameW);
5076 HeapFree(GetProcessHeap(), 0, bufferW);
5078 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5079 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5085 /******************************************************************************
5086 * EnumPortsW (WINSPOOL.@)
5088 * Enumerate available Ports
5091 * pName [I] Servername or NULL (local Computer)
5092 * Level [I] Structure-Level (1 or 2)
5093 * pPorts [O] PTR to Buffer that receives the Result
5094 * cbBuf [I] Size of Buffer at pPorts
5095 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5096 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5100 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5103 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5106 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5107 cbBuf, pcbNeeded, pcReturned);
5109 if ((backend == NULL) && !load_backend()) return FALSE;
5111 /* Level is not checked in win9x */
5112 if (!Level || (Level > 2)) {
5113 WARN("level (%d) is ignored in win9x\n", Level);
5114 SetLastError(ERROR_INVALID_LEVEL);
5117 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5118 SetLastError(RPC_X_NULL_REF_POINTER);
5122 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5125 /******************************************************************************
5126 * GetDefaultPrinterW (WINSPOOL.@)
5129 * This function must read the value from data 'device' of key
5130 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5132 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5136 WCHAR *buffer, *ptr;
5140 SetLastError(ERROR_INVALID_PARAMETER);
5144 /* make the buffer big enough for the stuff from the profile/registry,
5145 * the content must fit into the local buffer to compute the correct
5146 * size even if the extern buffer is too small or not given.
5147 * (20 for ,driver,port) */
5149 len = max(100, (insize + 20));
5150 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5152 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5154 SetLastError (ERROR_FILE_NOT_FOUND);
5158 TRACE("%s\n", debugstr_w(buffer));
5160 if ((ptr = strchrW(buffer, ',')) == NULL)
5162 SetLastError(ERROR_INVALID_NAME);
5168 *namesize = strlenW(buffer) + 1;
5169 if(!name || (*namesize > insize))
5171 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5175 strcpyW(name, buffer);
5178 HeapFree( GetProcessHeap(), 0, buffer);
5183 /******************************************************************************
5184 * GetDefaultPrinterA (WINSPOOL.@)
5186 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5190 WCHAR *bufferW = NULL;
5194 SetLastError(ERROR_INVALID_PARAMETER);
5198 if(name && *namesize) {
5200 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5203 if(!GetDefaultPrinterW( bufferW, namesize)) {
5208 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5212 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5215 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5218 HeapFree( GetProcessHeap(), 0, bufferW);
5223 /******************************************************************************
5224 * SetDefaultPrinterW (WINSPOOL.204)
5226 * Set the Name of the Default Printer
5229 * pszPrinter [I] Name of the Printer or NULL
5236 * When the Parameter is NULL or points to an Empty String and
5237 * a Default Printer was already present, then this Function changes nothing.
5238 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5239 * the First enumerated local Printer is used.
5242 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5245 TRACE("(%s)\n", debugstr_w(pszPrinter));
5247 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5251 /******************************************************************************
5252 * SetDefaultPrinterA (WINSPOOL.202)
5254 * See SetDefaultPrinterW.
5257 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5260 TRACE("(%s)\n", debugstr_a(pszPrinter));
5262 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5267 /******************************************************************************
5268 * SetPrinterDataExA (WINSPOOL.@)
5270 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5271 LPCSTR pValueName, DWORD Type,
5272 LPBYTE pData, DWORD cbData)
5274 HKEY hkeyPrinter, hkeySubkey;
5277 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5278 debugstr_a(pValueName), Type, pData, cbData);
5280 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5284 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5286 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5287 RegCloseKey(hkeyPrinter);
5290 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5291 RegCloseKey(hkeySubkey);
5292 RegCloseKey(hkeyPrinter);
5296 /******************************************************************************
5297 * SetPrinterDataExW (WINSPOOL.@)
5299 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5300 LPCWSTR pValueName, DWORD Type,
5301 LPBYTE pData, DWORD cbData)
5303 HKEY hkeyPrinter, hkeySubkey;
5306 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5307 debugstr_w(pValueName), Type, pData, cbData);
5309 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5313 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5315 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5316 RegCloseKey(hkeyPrinter);
5319 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5320 RegCloseKey(hkeySubkey);
5321 RegCloseKey(hkeyPrinter);
5325 /******************************************************************************
5326 * SetPrinterDataA (WINSPOOL.@)
5328 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5329 LPBYTE pData, DWORD cbData)
5331 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5335 /******************************************************************************
5336 * SetPrinterDataW (WINSPOOL.@)
5338 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5339 LPBYTE pData, DWORD cbData)
5341 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5345 /******************************************************************************
5346 * GetPrinterDataExA (WINSPOOL.@)
5348 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5349 LPCSTR pValueName, LPDWORD pType,
5350 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5352 HKEY hkeyPrinter, hkeySubkey;
5355 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5356 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5359 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5363 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5365 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5366 RegCloseKey(hkeyPrinter);
5370 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5371 RegCloseKey(hkeySubkey);
5372 RegCloseKey(hkeyPrinter);
5376 /******************************************************************************
5377 * GetPrinterDataExW (WINSPOOL.@)
5379 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5380 LPCWSTR pValueName, LPDWORD pType,
5381 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5383 HKEY hkeyPrinter, hkeySubkey;
5386 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5387 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5390 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5394 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5396 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5397 RegCloseKey(hkeyPrinter);
5401 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5402 RegCloseKey(hkeySubkey);
5403 RegCloseKey(hkeyPrinter);
5407 /******************************************************************************
5408 * GetPrinterDataA (WINSPOOL.@)
5410 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5411 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5413 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5414 pData, nSize, pcbNeeded);
5417 /******************************************************************************
5418 * GetPrinterDataW (WINSPOOL.@)
5420 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5421 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5423 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5424 pData, nSize, pcbNeeded);
5427 /*******************************************************************************
5428 * EnumPrinterDataExW [WINSPOOL.@]
5430 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5431 LPBYTE pEnumValues, DWORD cbEnumValues,
5432 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5434 HKEY hkPrinter, hkSubKey;
5435 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5436 cbValueNameLen, cbMaxValueLen, cbValueLen,
5441 PPRINTER_ENUM_VALUESW ppev;
5443 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5445 if (pKeyName == NULL || *pKeyName == 0)
5446 return ERROR_INVALID_PARAMETER;
5448 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5449 if (ret != ERROR_SUCCESS)
5451 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5456 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5457 if (ret != ERROR_SUCCESS)
5459 r = RegCloseKey (hkPrinter);
5460 if (r != ERROR_SUCCESS)
5461 WARN ("RegCloseKey returned %i\n", r);
5462 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5463 debugstr_w (pKeyName), ret);
5467 ret = RegCloseKey (hkPrinter);
5468 if (ret != ERROR_SUCCESS)
5470 ERR ("RegCloseKey returned %i\n", ret);
5471 r = RegCloseKey (hkSubKey);
5472 if (r != ERROR_SUCCESS)
5473 WARN ("RegCloseKey returned %i\n", r);
5477 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5478 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5479 if (ret != ERROR_SUCCESS)
5481 r = RegCloseKey (hkSubKey);
5482 if (r != ERROR_SUCCESS)
5483 WARN ("RegCloseKey returned %i\n", r);
5484 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5488 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5489 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5491 if (cValues == 0) /* empty key */
5493 r = RegCloseKey (hkSubKey);
5494 if (r != ERROR_SUCCESS)
5495 WARN ("RegCloseKey returned %i\n", r);
5496 *pcbEnumValues = *pnEnumValues = 0;
5497 return ERROR_SUCCESS;
5500 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5502 hHeap = GetProcessHeap ();
5505 ERR ("GetProcessHeap failed\n");
5506 r = RegCloseKey (hkSubKey);
5507 if (r != ERROR_SUCCESS)
5508 WARN ("RegCloseKey returned %i\n", r);
5509 return ERROR_OUTOFMEMORY;
5512 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5513 if (lpValueName == NULL)
5515 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5516 r = RegCloseKey (hkSubKey);
5517 if (r != ERROR_SUCCESS)
5518 WARN ("RegCloseKey returned %i\n", r);
5519 return ERROR_OUTOFMEMORY;
5522 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5523 if (lpValue == NULL)
5525 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5526 if (HeapFree (hHeap, 0, lpValueName) == 0)
5527 WARN ("HeapFree failed with code %i\n", GetLastError ());
5528 r = RegCloseKey (hkSubKey);
5529 if (r != ERROR_SUCCESS)
5530 WARN ("RegCloseKey returned %i\n", r);
5531 return ERROR_OUTOFMEMORY;
5534 TRACE ("pass 1: calculating buffer required for all names and values\n");
5536 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5538 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5540 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5542 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5543 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5544 NULL, NULL, lpValue, &cbValueLen);
5545 if (ret != ERROR_SUCCESS)
5547 if (HeapFree (hHeap, 0, lpValue) == 0)
5548 WARN ("HeapFree failed with code %i\n", GetLastError ());
5549 if (HeapFree (hHeap, 0, lpValueName) == 0)
5550 WARN ("HeapFree failed with code %i\n", GetLastError ());
5551 r = RegCloseKey (hkSubKey);
5552 if (r != ERROR_SUCCESS)
5553 WARN ("RegCloseKey returned %i\n", r);
5554 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5558 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5559 debugstr_w (lpValueName), dwIndex,
5560 cbValueNameLen + 1, cbValueLen);
5562 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5563 cbBufSize += cbValueLen;
5566 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5568 *pcbEnumValues = cbBufSize;
5569 *pnEnumValues = cValues;
5571 if (cbEnumValues < cbBufSize) /* buffer too small */
5573 if (HeapFree (hHeap, 0, lpValue) == 0)
5574 WARN ("HeapFree failed with code %i\n", GetLastError ());
5575 if (HeapFree (hHeap, 0, lpValueName) == 0)
5576 WARN ("HeapFree failed with code %i\n", GetLastError ());
5577 r = RegCloseKey (hkSubKey);
5578 if (r != ERROR_SUCCESS)
5579 WARN ("RegCloseKey returned %i\n", r);
5580 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5581 return ERROR_MORE_DATA;
5584 TRACE ("pass 2: copying all names and values to buffer\n");
5586 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5587 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5589 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5591 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5592 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5593 NULL, &dwType, lpValue, &cbValueLen);
5594 if (ret != ERROR_SUCCESS)
5596 if (HeapFree (hHeap, 0, lpValue) == 0)
5597 WARN ("HeapFree failed with code %i\n", GetLastError ());
5598 if (HeapFree (hHeap, 0, lpValueName) == 0)
5599 WARN ("HeapFree failed with code %i\n", GetLastError ());
5600 r = RegCloseKey (hkSubKey);
5601 if (r != ERROR_SUCCESS)
5602 WARN ("RegCloseKey returned %i\n", r);
5603 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5607 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5608 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5609 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5610 pEnumValues += cbValueNameLen;
5612 /* return # of *bytes* (including trailing \0), not # of chars */
5613 ppev[dwIndex].cbValueName = cbValueNameLen;
5615 ppev[dwIndex].dwType = dwType;
5617 memcpy (pEnumValues, lpValue, cbValueLen);
5618 ppev[dwIndex].pData = pEnumValues;
5619 pEnumValues += cbValueLen;
5621 ppev[dwIndex].cbData = cbValueLen;
5623 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5624 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5627 if (HeapFree (hHeap, 0, lpValue) == 0)
5629 ret = GetLastError ();
5630 ERR ("HeapFree failed with code %i\n", ret);
5631 if (HeapFree (hHeap, 0, lpValueName) == 0)
5632 WARN ("HeapFree failed with code %i\n", GetLastError ());
5633 r = RegCloseKey (hkSubKey);
5634 if (r != ERROR_SUCCESS)
5635 WARN ("RegCloseKey returned %i\n", r);
5639 if (HeapFree (hHeap, 0, lpValueName) == 0)
5641 ret = GetLastError ();
5642 ERR ("HeapFree failed with code %i\n", ret);
5643 r = RegCloseKey (hkSubKey);
5644 if (r != ERROR_SUCCESS)
5645 WARN ("RegCloseKey returned %i\n", r);
5649 ret = RegCloseKey (hkSubKey);
5650 if (ret != ERROR_SUCCESS)
5652 ERR ("RegCloseKey returned %i\n", ret);
5656 return ERROR_SUCCESS;
5659 /*******************************************************************************
5660 * EnumPrinterDataExA [WINSPOOL.@]
5662 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5663 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5664 * what Windows 2000 SP1 does.
5667 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5668 LPBYTE pEnumValues, DWORD cbEnumValues,
5669 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5673 DWORD ret, dwIndex, dwBufSize;
5677 TRACE ("%p %s\n", hPrinter, pKeyName);
5679 if (pKeyName == NULL || *pKeyName == 0)
5680 return ERROR_INVALID_PARAMETER;
5682 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5685 ret = GetLastError ();
5686 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5690 hHeap = GetProcessHeap ();
5693 ERR ("GetProcessHeap failed\n");
5694 return ERROR_OUTOFMEMORY;
5697 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5698 if (pKeyNameW == NULL)
5700 ERR ("Failed to allocate %i bytes from process heap\n",
5701 (LONG)(len * sizeof (WCHAR)));
5702 return ERROR_OUTOFMEMORY;
5705 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5707 ret = GetLastError ();
5708 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5709 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5710 WARN ("HeapFree failed with code %i\n", GetLastError ());
5714 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5715 pcbEnumValues, pnEnumValues);
5716 if (ret != ERROR_SUCCESS)
5718 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5719 WARN ("HeapFree failed with code %i\n", GetLastError ());
5720 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5724 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5726 ret = GetLastError ();
5727 ERR ("HeapFree failed with code %i\n", ret);
5731 if (*pnEnumValues == 0) /* empty key */
5732 return ERROR_SUCCESS;
5735 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5737 PPRINTER_ENUM_VALUESW ppev =
5738 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5740 if (dwBufSize < ppev->cbValueName)
5741 dwBufSize = ppev->cbValueName;
5743 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5744 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5745 dwBufSize = ppev->cbData;
5748 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5750 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5751 if (pBuffer == NULL)
5753 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5754 return ERROR_OUTOFMEMORY;
5757 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5759 PPRINTER_ENUM_VALUESW ppev =
5760 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5762 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5763 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5767 ret = GetLastError ();
5768 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5769 if (HeapFree (hHeap, 0, pBuffer) == 0)
5770 WARN ("HeapFree failed with code %i\n", GetLastError ());
5774 memcpy (ppev->pValueName, pBuffer, len);
5776 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5778 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5779 ppev->dwType != REG_MULTI_SZ)
5782 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5783 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5786 ret = GetLastError ();
5787 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5788 if (HeapFree (hHeap, 0, pBuffer) == 0)
5789 WARN ("HeapFree failed with code %i\n", GetLastError ());
5793 memcpy (ppev->pData, pBuffer, len);
5795 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5796 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5799 if (HeapFree (hHeap, 0, pBuffer) == 0)
5801 ret = GetLastError ();
5802 ERR ("HeapFree failed with code %i\n", ret);
5806 return ERROR_SUCCESS;
5809 /******************************************************************************
5810 * AbortPrinter (WINSPOOL.@)
5812 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5814 FIXME("(%p), stub!\n", hPrinter);
5818 /******************************************************************************
5819 * AddPortA (WINSPOOL.@)
5824 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5826 LPWSTR nameW = NULL;
5827 LPWSTR monitorW = NULL;
5831 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5834 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5835 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5836 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5840 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5841 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5842 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5844 res = AddPortW(nameW, hWnd, monitorW);
5845 HeapFree(GetProcessHeap(), 0, nameW);
5846 HeapFree(GetProcessHeap(), 0, monitorW);
5850 /******************************************************************************
5851 * AddPortW (WINSPOOL.@)
5853 * Add a Port for a specific Monitor
5856 * pName [I] Servername or NULL (local Computer)
5857 * hWnd [I] Handle to parent Window for the Dialog-Box
5858 * pMonitorName [I] Name of the Monitor that manage the Port
5865 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5867 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5869 if ((backend == NULL) && !load_backend()) return FALSE;
5871 if (!pMonitorName) {
5872 SetLastError(RPC_X_NULL_REF_POINTER);
5876 return backend->fpAddPort(pName, hWnd, pMonitorName);
5879 /******************************************************************************
5880 * AddPortExA (WINSPOOL.@)
5885 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5888 PORT_INFO_2A * pi2A;
5889 LPWSTR nameW = NULL;
5890 LPWSTR monitorW = NULL;
5894 pi2A = (PORT_INFO_2A *) pBuffer;
5896 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5897 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5899 if ((level < 1) || (level > 2)) {
5900 SetLastError(ERROR_INVALID_LEVEL);
5905 SetLastError(ERROR_INVALID_PARAMETER);
5910 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5911 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5912 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5916 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5917 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5918 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5921 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5923 if (pi2A->pPortName) {
5924 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5925 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5926 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5930 if (pi2A->pMonitorName) {
5931 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5932 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5933 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5936 if (pi2A->pDescription) {
5937 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5938 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5939 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5941 pi2W.fPortType = pi2A->fPortType;
5942 pi2W.Reserved = pi2A->Reserved;
5945 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
5947 HeapFree(GetProcessHeap(), 0, nameW);
5948 HeapFree(GetProcessHeap(), 0, monitorW);
5949 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
5950 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
5951 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
5956 /******************************************************************************
5957 * AddPortExW (WINSPOOL.@)
5959 * Add a Port for a specific Monitor, without presenting a user interface
5962 * pName [I] Servername or NULL (local Computer)
5963 * level [I] Structure-Level (1 or 2) for pBuffer
5964 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5965 * pMonitorName [I] Name of the Monitor that manage the Port
5972 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
5976 pi2 = (PORT_INFO_2W *) pBuffer;
5978 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
5979 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
5980 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
5981 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
5983 if ((backend == NULL) && !load_backend()) return FALSE;
5985 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
5986 SetLastError(ERROR_INVALID_PARAMETER);
5990 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
5993 /******************************************************************************
5994 * AddPrinterConnectionA (WINSPOOL.@)
5996 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5998 FIXME("%s\n", debugstr_a(pName));
6002 /******************************************************************************
6003 * AddPrinterConnectionW (WINSPOOL.@)
6005 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6007 FIXME("%s\n", debugstr_w(pName));
6011 /******************************************************************************
6012 * AddPrinterDriverExW (WINSPOOL.@)
6014 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6017 * pName [I] Servername or NULL (local Computer)
6018 * level [I] Level for the supplied DRIVER_INFO_*W struct
6019 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6020 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6027 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6029 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6031 if ((backend == NULL) && !load_backend()) return FALSE;
6033 if (level < 2 || level == 5 || level == 7 || level > 8) {
6034 SetLastError(ERROR_INVALID_LEVEL);
6039 SetLastError(ERROR_INVALID_PARAMETER);
6043 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6046 /******************************************************************************
6047 * AddPrinterDriverExA (WINSPOOL.@)
6049 * See AddPrinterDriverExW.
6052 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6054 DRIVER_INFO_8A *diA;
6056 LPWSTR nameW = NULL;
6061 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6063 diA = (DRIVER_INFO_8A *) pDriverInfo;
6064 ZeroMemory(&diW, sizeof(diW));
6066 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6067 SetLastError(ERROR_INVALID_LEVEL);
6072 SetLastError(ERROR_INVALID_PARAMETER);
6076 /* convert servername to unicode */
6078 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6079 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6080 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6084 diW.cVersion = diA->cVersion;
6087 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6088 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6089 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6092 if (diA->pEnvironment) {
6093 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6094 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6095 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6098 if (diA->pDriverPath) {
6099 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6100 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6101 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6104 if (diA->pDataFile) {
6105 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6106 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6107 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6110 if (diA->pConfigFile) {
6111 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6112 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6113 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6116 if ((Level > 2) && diA->pDependentFiles) {
6117 lenA = multi_sz_lenA(diA->pDependentFiles);
6118 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6119 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6120 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6123 if ((Level > 2) && diA->pMonitorName) {
6124 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6125 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6126 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6129 if ((Level > 3) && diA->pDefaultDataType) {
6130 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6131 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6132 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6135 if ((Level > 3) && diA->pszzPreviousNames) {
6136 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6137 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6138 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6139 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6142 if ((Level > 5) && diA->pszMfgName) {
6143 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6144 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6145 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6148 if ((Level > 5) && diA->pszOEMUrl) {
6149 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6150 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6151 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6154 if ((Level > 5) && diA->pszHardwareID) {
6155 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6156 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6157 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6160 if ((Level > 5) && diA->pszProvider) {
6161 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6162 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6163 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6167 FIXME("level %u is incomplete\n", Level);
6170 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6171 TRACE("got %u with %u\n", res, GetLastError());
6172 HeapFree(GetProcessHeap(), 0, nameW);
6173 HeapFree(GetProcessHeap(), 0, diW.pName);
6174 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6175 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6176 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6177 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6178 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6179 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6180 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6181 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6182 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6183 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6184 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6185 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6187 TRACE("=> %u with %u\n", res, GetLastError());
6191 /******************************************************************************
6192 * ConfigurePortA (WINSPOOL.@)
6194 * See ConfigurePortW.
6197 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6199 LPWSTR nameW = NULL;
6200 LPWSTR portW = NULL;
6204 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6206 /* convert servername to unicode */
6208 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6209 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6210 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6213 /* convert portname to unicode */
6215 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6216 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6217 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6220 res = ConfigurePortW(nameW, hWnd, portW);
6221 HeapFree(GetProcessHeap(), 0, nameW);
6222 HeapFree(GetProcessHeap(), 0, portW);
6226 /******************************************************************************
6227 * ConfigurePortW (WINSPOOL.@)
6229 * Display the Configuration-Dialog for a specific Port
6232 * pName [I] Servername or NULL (local Computer)
6233 * hWnd [I] Handle to parent Window for the Dialog-Box
6234 * pPortName [I] Name of the Port, that should be configured
6241 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6244 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6246 if ((backend == NULL) && !load_backend()) return FALSE;
6249 SetLastError(RPC_X_NULL_REF_POINTER);
6253 return backend->fpConfigurePort(pName, hWnd, pPortName);
6256 /******************************************************************************
6257 * ConnectToPrinterDlg (WINSPOOL.@)
6259 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6261 FIXME("%p %x\n", hWnd, Flags);
6265 /******************************************************************************
6266 * DeletePrinterConnectionA (WINSPOOL.@)
6268 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6270 FIXME("%s\n", debugstr_a(pName));
6274 /******************************************************************************
6275 * DeletePrinterConnectionW (WINSPOOL.@)
6277 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6279 FIXME("%s\n", debugstr_w(pName));
6283 /******************************************************************************
6284 * DeletePrinterDriverExW (WINSPOOL.@)
6286 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6287 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6292 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6293 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6295 if(pName && pName[0])
6297 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6298 SetLastError(ERROR_INVALID_PARAMETER);
6304 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6305 SetLastError(ERROR_INVALID_PARAMETER);
6309 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6313 ERR("Can't open drivers key\n");
6317 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6320 RegCloseKey(hkey_drivers);
6325 /******************************************************************************
6326 * DeletePrinterDriverExA (WINSPOOL.@)
6328 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6329 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6331 UNICODE_STRING NameW, EnvW, DriverW;
6334 asciitounicode(&NameW, pName);
6335 asciitounicode(&EnvW, pEnvironment);
6336 asciitounicode(&DriverW, pDriverName);
6338 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6340 RtlFreeUnicodeString(&DriverW);
6341 RtlFreeUnicodeString(&EnvW);
6342 RtlFreeUnicodeString(&NameW);
6347 /******************************************************************************
6348 * DeletePrinterDataExW (WINSPOOL.@)
6350 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6353 FIXME("%p %s %s\n", hPrinter,
6354 debugstr_w(pKeyName), debugstr_w(pValueName));
6355 return ERROR_INVALID_PARAMETER;
6358 /******************************************************************************
6359 * DeletePrinterDataExA (WINSPOOL.@)
6361 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6364 FIXME("%p %s %s\n", hPrinter,
6365 debugstr_a(pKeyName), debugstr_a(pValueName));
6366 return ERROR_INVALID_PARAMETER;
6369 /******************************************************************************
6370 * DeletePrintProcessorA (WINSPOOL.@)
6372 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6374 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6375 debugstr_a(pPrintProcessorName));
6379 /******************************************************************************
6380 * DeletePrintProcessorW (WINSPOOL.@)
6382 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6384 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6385 debugstr_w(pPrintProcessorName));
6389 /******************************************************************************
6390 * DeletePrintProvidorA (WINSPOOL.@)
6392 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6394 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6395 debugstr_a(pPrintProviderName));
6399 /******************************************************************************
6400 * DeletePrintProvidorW (WINSPOOL.@)
6402 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6404 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6405 debugstr_w(pPrintProviderName));
6409 /******************************************************************************
6410 * EnumFormsA (WINSPOOL.@)
6412 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6413 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6415 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6416 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6420 /******************************************************************************
6421 * EnumFormsW (WINSPOOL.@)
6423 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6424 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6426 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6427 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6431 /*****************************************************************************
6432 * EnumMonitorsA [WINSPOOL.@]
6434 * See EnumMonitorsW.
6437 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6438 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6441 LPBYTE bufferW = NULL;
6442 LPWSTR nameW = NULL;
6444 DWORD numentries = 0;
6447 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6448 cbBuf, pcbNeeded, pcReturned);
6450 /* convert servername to unicode */
6452 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6453 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6454 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6456 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6457 needed = cbBuf * sizeof(WCHAR);
6458 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6459 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6461 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6462 if (pcbNeeded) needed = *pcbNeeded;
6463 /* HeapReAlloc return NULL, when bufferW was NULL */
6464 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6465 HeapAlloc(GetProcessHeap(), 0, needed);
6467 /* Try again with the large Buffer */
6468 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6470 numentries = pcReturned ? *pcReturned : 0;
6473 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6474 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6477 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6478 DWORD entrysize = 0;
6481 LPMONITOR_INFO_2W mi2w;
6482 LPMONITOR_INFO_2A mi2a;
6484 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6485 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6487 /* First pass: calculate the size for all Entries */
6488 mi2w = (LPMONITOR_INFO_2W) bufferW;
6489 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6491 while (index < numentries) {
6493 needed += entrysize; /* MONITOR_INFO_?A */
6494 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6496 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6497 NULL, 0, NULL, NULL);
6499 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6500 NULL, 0, NULL, NULL);
6501 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6502 NULL, 0, NULL, NULL);
6504 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6505 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6506 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6509 /* check for errors and quit on failure */
6510 if (cbBuf < needed) {
6511 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6515 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6516 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6517 cbBuf -= len ; /* free Bytes in the user-Buffer */
6518 mi2w = (LPMONITOR_INFO_2W) bufferW;
6519 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6521 /* Second Pass: Fill the User Buffer (if we have one) */
6522 while ((index < numentries) && pMonitors) {
6524 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6526 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6527 ptr, cbBuf , NULL, NULL);
6531 mi2a->pEnvironment = ptr;
6532 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6533 ptr, cbBuf, NULL, NULL);
6537 mi2a->pDLLName = ptr;
6538 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6539 ptr, cbBuf, NULL, NULL);
6543 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6544 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6545 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6549 if (pcbNeeded) *pcbNeeded = needed;
6550 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6552 HeapFree(GetProcessHeap(), 0, nameW);
6553 HeapFree(GetProcessHeap(), 0, bufferW);
6555 TRACE("returning %d with %d (%d byte for %d entries)\n",
6556 (res), GetLastError(), needed, numentries);
6562 /*****************************************************************************
6563 * EnumMonitorsW [WINSPOOL.@]
6565 * Enumerate available Port-Monitors
6568 * pName [I] Servername or NULL (local Computer)
6569 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6570 * pMonitors [O] PTR to Buffer that receives the Result
6571 * cbBuf [I] Size of Buffer at pMonitors
6572 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6573 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6577 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6580 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6581 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6584 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6585 cbBuf, pcbNeeded, pcReturned);
6587 if ((backend == NULL) && !load_backend()) return FALSE;
6589 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6590 SetLastError(RPC_X_NULL_REF_POINTER);
6594 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6597 /******************************************************************************
6598 * SpoolerInit (WINSPOOL.@)
6600 * Initialize the Spooler
6607 * The function fails on windows, when the spooler service is not running
6610 BOOL WINAPI SpoolerInit(void)
6613 if ((backend == NULL) && !load_backend()) return FALSE;
6617 /******************************************************************************
6618 * XcvDataW (WINSPOOL.@)
6620 * Execute commands in the Printmonitor DLL
6623 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6624 * pszDataName [i] Name of the command to execute
6625 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6626 * cbInputData [i] Size in Bytes of Buffer at pInputData
6627 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6628 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6629 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6630 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6637 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6638 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6640 * Minimal List of commands, that a Printmonitor DLL should support:
6642 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6643 *| "AddPort" : Add a Port
6644 *| "DeletePort": Delete a Port
6646 * Many Printmonitors support additional commands. Examples for localspl.dll:
6647 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6648 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6651 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6652 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6653 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6655 opened_printer_t *printer;
6657 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6658 pInputData, cbInputData, pOutputData,
6659 cbOutputData, pcbOutputNeeded, pdwStatus);
6661 if ((backend == NULL) && !load_backend()) return FALSE;
6663 printer = get_opened_printer(hXcv);
6664 if (!printer || (!printer->backend_printer)) {
6665 SetLastError(ERROR_INVALID_HANDLE);
6669 if (!pcbOutputNeeded) {
6670 SetLastError(ERROR_INVALID_PARAMETER);
6674 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6675 SetLastError(RPC_X_NULL_REF_POINTER);
6679 *pcbOutputNeeded = 0;
6681 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6682 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6686 /*****************************************************************************
6687 * EnumPrinterDataA [WINSPOOL.@]
6690 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6691 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6692 DWORD cbData, LPDWORD pcbData )
6694 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6695 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6696 return ERROR_NO_MORE_ITEMS;
6699 /*****************************************************************************
6700 * EnumPrinterDataW [WINSPOOL.@]
6703 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6704 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6705 DWORD cbData, LPDWORD pcbData )
6707 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6708 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6709 return ERROR_NO_MORE_ITEMS;
6712 /*****************************************************************************
6713 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6716 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6717 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6718 LPDWORD pcbNeeded, LPDWORD pcReturned)
6720 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6721 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6722 pcbNeeded, pcReturned);
6726 /*****************************************************************************
6727 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6730 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6731 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6732 LPDWORD pcbNeeded, LPDWORD pcReturned)
6734 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6735 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6736 pcbNeeded, pcReturned);
6740 /*****************************************************************************
6741 * EnumPrintProcessorsA [WINSPOOL.@]
6743 * See EnumPrintProcessorsW.
6746 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6747 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6750 LPBYTE bufferW = NULL;
6751 LPWSTR nameW = NULL;
6754 DWORD numentries = 0;
6757 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6758 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6760 /* convert names to unicode */
6762 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6763 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6764 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6767 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6768 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6769 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6772 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6773 needed = cbBuf * sizeof(WCHAR);
6774 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6775 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6777 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6778 if (pcbNeeded) needed = *pcbNeeded;
6779 /* HeapReAlloc return NULL, when bufferW was NULL */
6780 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6781 HeapAlloc(GetProcessHeap(), 0, needed);
6783 /* Try again with the large Buffer */
6784 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6786 numentries = pcReturned ? *pcReturned : 0;
6790 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6793 PPRINTPROCESSOR_INFO_1W ppiw;
6794 PPRINTPROCESSOR_INFO_1A ppia;
6796 /* First pass: calculate the size for all Entries */
6797 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6798 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6800 while (index < numentries) {
6802 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6803 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6805 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6806 NULL, 0, NULL, NULL);
6808 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6809 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6812 /* check for errors and quit on failure */
6813 if (cbBuf < needed) {
6814 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6819 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6820 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6821 cbBuf -= len ; /* free Bytes in the user-Buffer */
6822 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6823 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6825 /* Second Pass: Fill the User Buffer (if we have one) */
6826 while ((index < numentries) && pPPInfo) {
6828 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6830 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6831 ptr, cbBuf , NULL, NULL);
6835 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6836 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6841 if (pcbNeeded) *pcbNeeded = needed;
6842 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6844 HeapFree(GetProcessHeap(), 0, nameW);
6845 HeapFree(GetProcessHeap(), 0, envW);
6846 HeapFree(GetProcessHeap(), 0, bufferW);
6848 TRACE("returning %d with %d (%d byte for %d entries)\n",
6849 (res), GetLastError(), needed, numentries);
6854 /*****************************************************************************
6855 * EnumPrintProcessorsW [WINSPOOL.@]
6857 * Enumerate available Print Processors
6860 * pName [I] Servername or NULL (local Computer)
6861 * pEnvironment [I] Printing-Environment or NULL (Default)
6862 * Level [I] Structure-Level (Only 1 is allowed)
6863 * pPPInfo [O] PTR to Buffer that receives the Result
6864 * cbBuf [I] Size of Buffer at pPPInfo
6865 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6866 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6870 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6873 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6874 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6877 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6878 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6880 if ((backend == NULL) && !load_backend()) return FALSE;
6882 if (!pcbNeeded || !pcReturned) {
6883 SetLastError(RPC_X_NULL_REF_POINTER);
6887 if (!pPPInfo && (cbBuf > 0)) {
6888 SetLastError(ERROR_INVALID_USER_BUFFER);
6892 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6893 cbBuf, pcbNeeded, pcReturned);
6896 /*****************************************************************************
6897 * ExtDeviceMode [WINSPOOL.@]
6900 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6901 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6904 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6905 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6906 debugstr_a(pProfile), fMode);
6910 /*****************************************************************************
6911 * FindClosePrinterChangeNotification [WINSPOOL.@]
6914 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6916 FIXME("Stub: %p\n", hChange);
6920 /*****************************************************************************
6921 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6924 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6925 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6927 FIXME("Stub: %p %x %x %p\n",
6928 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6929 return INVALID_HANDLE_VALUE;
6932 /*****************************************************************************
6933 * FindNextPrinterChangeNotification [WINSPOOL.@]
6936 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6937 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6939 FIXME("Stub: %p %p %p %p\n",
6940 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6944 /*****************************************************************************
6945 * FreePrinterNotifyInfo [WINSPOOL.@]
6948 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6950 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6954 /*****************************************************************************
6957 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6958 * ansi depending on the unicode parameter.
6960 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6970 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6973 memcpy(ptr, str, *size);
6980 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6983 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6990 /*****************************************************************************
6993 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6994 LPDWORD pcbNeeded, BOOL unicode)
6996 DWORD size, left = cbBuf;
6997 BOOL space = (cbBuf > 0);
7004 ji1->JobId = job->job_id;
7007 string_to_buf(job->document_title, ptr, left, &size, unicode);
7008 if(space && size <= left)
7010 ji1->pDocument = (LPWSTR)ptr;
7021 /*****************************************************************************
7024 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7025 LPDWORD pcbNeeded, BOOL unicode)
7027 DWORD size, left = cbBuf;
7028 BOOL space = (cbBuf > 0);
7035 ji2->JobId = job->job_id;
7038 string_to_buf(job->document_title, ptr, left, &size, unicode);
7039 if(space && size <= left)
7041 ji2->pDocument = (LPWSTR)ptr;
7052 /*****************************************************************************
7055 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7056 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7059 DWORD needed = 0, size;
7063 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7065 EnterCriticalSection(&printer_handles_cs);
7066 job = get_job(hPrinter, JobId);
7073 size = sizeof(JOB_INFO_1W);
7078 memset(pJob, 0, size);
7082 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7087 size = sizeof(JOB_INFO_2W);
7092 memset(pJob, 0, size);
7096 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7101 size = sizeof(JOB_INFO_3);
7105 memset(pJob, 0, size);
7114 SetLastError(ERROR_INVALID_LEVEL);
7118 *pcbNeeded = needed;
7120 LeaveCriticalSection(&printer_handles_cs);
7124 /*****************************************************************************
7125 * GetJobA [WINSPOOL.@]
7128 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7129 DWORD cbBuf, LPDWORD pcbNeeded)
7131 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7134 /*****************************************************************************
7135 * GetJobW [WINSPOOL.@]
7138 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7139 DWORD cbBuf, LPDWORD pcbNeeded)
7141 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7144 /*****************************************************************************
7147 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7149 char *unixname, *queue, *cmd;
7150 char fmt[] = "lpr -P%s %s";
7154 if(!(unixname = wine_get_unix_file_name(filename)))
7157 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7158 queue = HeapAlloc(GetProcessHeap(), 0, len);
7159 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7161 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7162 sprintf(cmd, fmt, queue, unixname);
7164 TRACE("printing with: %s\n", cmd);
7167 HeapFree(GetProcessHeap(), 0, cmd);
7168 HeapFree(GetProcessHeap(), 0, queue);
7169 HeapFree(GetProcessHeap(), 0, unixname);
7173 /*****************************************************************************
7176 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7178 #ifdef SONAME_LIBCUPS
7181 char *unixname, *queue, *unix_doc_title;
7185 if(!(unixname = wine_get_unix_file_name(filename)))
7188 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7189 queue = HeapAlloc(GetProcessHeap(), 0, len);
7190 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7192 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7193 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7194 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7196 TRACE("printing via cups\n");
7197 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7198 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7199 HeapFree(GetProcessHeap(), 0, queue);
7200 HeapFree(GetProcessHeap(), 0, unixname);
7206 return schedule_lpr(printer_name, filename);
7210 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7217 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7221 if(HIWORD(wparam) == BN_CLICKED)
7223 if(LOWORD(wparam) == IDOK)
7226 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7229 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7230 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7232 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7234 WCHAR caption[200], message[200];
7237 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7238 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7239 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7240 if(mb_ret == IDCANCEL)
7242 HeapFree(GetProcessHeap(), 0, filename);
7246 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7247 if(hf == INVALID_HANDLE_VALUE)
7249 WCHAR caption[200], message[200];
7251 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7252 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7253 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7254 HeapFree(GetProcessHeap(), 0, filename);
7258 DeleteFileW(filename);
7259 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7261 EndDialog(hwnd, IDOK);
7264 if(LOWORD(wparam) == IDCANCEL)
7266 EndDialog(hwnd, IDCANCEL);
7275 /*****************************************************************************
7278 static BOOL get_filename(LPWSTR *filename)
7280 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7281 file_dlg_proc, (LPARAM)filename) == IDOK;
7284 /*****************************************************************************
7287 static BOOL schedule_file(LPCWSTR filename)
7289 LPWSTR output = NULL;
7291 if(get_filename(&output))
7294 TRACE("copy to %s\n", debugstr_w(output));
7295 r = CopyFileW(filename, output, FALSE);
7296 HeapFree(GetProcessHeap(), 0, output);
7302 /*****************************************************************************
7305 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7308 char *unixname, *cmdA;
7310 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7314 if(!(unixname = wine_get_unix_file_name(filename)))
7317 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7318 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7319 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7321 TRACE("printing with: %s\n", cmdA);
7323 if((file_fd = open(unixname, O_RDONLY)) == -1)
7328 ERR("pipe() failed!\n");
7338 /* reset signals that we previously set to SIG_IGN */
7339 signal(SIGPIPE, SIG_DFL);
7340 signal(SIGCHLD, SIG_DFL);
7342 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7346 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7347 write(fds[1], buf, no_read);
7352 if(file_fd != -1) close(file_fd);
7353 if(fds[0] != -1) close(fds[0]);
7354 if(fds[1] != -1) close(fds[1]);
7356 HeapFree(GetProcessHeap(), 0, cmdA);
7357 HeapFree(GetProcessHeap(), 0, unixname);
7364 /*****************************************************************************
7367 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7369 int in_fd, out_fd, no_read;
7372 char *unixname, *outputA;
7375 if(!(unixname = wine_get_unix_file_name(filename)))
7378 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7379 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7380 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7382 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7383 in_fd = open(unixname, O_RDONLY);
7384 if(out_fd == -1 || in_fd == -1)
7387 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7388 write(out_fd, buf, no_read);
7392 if(in_fd != -1) close(in_fd);
7393 if(out_fd != -1) close(out_fd);
7394 HeapFree(GetProcessHeap(), 0, outputA);
7395 HeapFree(GetProcessHeap(), 0, unixname);
7399 /*****************************************************************************
7400 * ScheduleJob [WINSPOOL.@]
7403 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7405 opened_printer_t *printer;
7407 struct list *cursor, *cursor2;
7409 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7410 EnterCriticalSection(&printer_handles_cs);
7411 printer = get_opened_printer(hPrinter);
7415 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7417 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7420 if(job->job_id != dwJobID) continue;
7422 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7423 if(hf != INVALID_HANDLE_VALUE)
7425 PRINTER_INFO_5W *pi5;
7429 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7430 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7432 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7433 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7434 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7435 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7436 debugstr_w(pi5->pPortName));
7440 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7441 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7443 DWORD type, count = sizeof(output);
7444 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7447 if(output[0] == '|')
7449 ret = schedule_pipe(output + 1, job->filename);
7453 ret = schedule_unixfile(output, job->filename);
7455 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7457 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7459 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7461 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7463 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7465 ret = schedule_file(job->filename);
7469 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7471 HeapFree(GetProcessHeap(), 0, pi5);
7473 DeleteFileW(job->filename);
7475 list_remove(cursor);
7476 HeapFree(GetProcessHeap(), 0, job->document_title);
7477 HeapFree(GetProcessHeap(), 0, job->filename);
7478 HeapFree(GetProcessHeap(), 0, job);
7482 LeaveCriticalSection(&printer_handles_cs);
7486 /*****************************************************************************
7487 * StartDocDlgA [WINSPOOL.@]
7489 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7491 UNICODE_STRING usBuffer;
7494 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7497 docW.cbSize = sizeof(docW);
7498 if (doc->lpszDocName)
7500 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7501 if (!(docW.lpszDocName = docnameW)) return NULL;
7503 if (doc->lpszOutput)
7505 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7506 if (!(docW.lpszOutput = outputW)) return NULL;
7508 if (doc->lpszDatatype)
7510 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7511 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7513 docW.fwType = doc->fwType;
7515 retW = StartDocDlgW(hPrinter, &docW);
7519 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7520 ret = HeapAlloc(GetProcessHeap(), 0, len);
7521 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7522 HeapFree(GetProcessHeap(), 0, retW);
7525 HeapFree(GetProcessHeap(), 0, datatypeW);
7526 HeapFree(GetProcessHeap(), 0, outputW);
7527 HeapFree(GetProcessHeap(), 0, docnameW);
7532 /*****************************************************************************
7533 * StartDocDlgW [WINSPOOL.@]
7535 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7536 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7537 * port is "FILE:". Also returns the full path if passed a relative path.
7539 * The caller should free the returned string from the process heap.
7541 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7546 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7548 PRINTER_INFO_5W *pi5;
7549 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7550 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7552 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7553 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7554 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7556 HeapFree(GetProcessHeap(), 0, pi5);
7559 HeapFree(GetProcessHeap(), 0, pi5);
7562 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7566 if (get_filename(&name))
7568 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7570 HeapFree(GetProcessHeap(), 0, name);
7573 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7574 GetFullPathNameW(name, len, ret, NULL);
7575 HeapFree(GetProcessHeap(), 0, name);
7580 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7583 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7584 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7586 attr = GetFileAttributesW(ret);
7587 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7589 HeapFree(GetProcessHeap(), 0, ret);