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);
1360 FIXME("for level %u\n", level);
1362 pPrintersW += pi_sizeof[level];
1363 out += pi_sizeof[level];
1368 /***********************************************************
1369 * PRINTER_INFO_2AtoW
1370 * Creates a unicode copy of PRINTER_INFO_2A on heap
1372 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1374 LPPRINTER_INFO_2W piW;
1375 UNICODE_STRING usBuffer;
1377 if(!piA) return NULL;
1378 piW = HeapAlloc(heap, 0, sizeof(*piW));
1379 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1381 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1382 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1383 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1384 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1385 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1386 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1387 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1388 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1389 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1390 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1391 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1392 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1396 /***********************************************************
1397 * FREE_PRINTER_INFO_2W
1398 * Free PRINTER_INFO_2W and all strings
1400 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1404 HeapFree(heap,0,piW->pServerName);
1405 HeapFree(heap,0,piW->pPrinterName);
1406 HeapFree(heap,0,piW->pShareName);
1407 HeapFree(heap,0,piW->pPortName);
1408 HeapFree(heap,0,piW->pDriverName);
1409 HeapFree(heap,0,piW->pComment);
1410 HeapFree(heap,0,piW->pLocation);
1411 HeapFree(heap,0,piW->pDevMode);
1412 HeapFree(heap,0,piW->pSepFile);
1413 HeapFree(heap,0,piW->pPrintProcessor);
1414 HeapFree(heap,0,piW->pDatatype);
1415 HeapFree(heap,0,piW->pParameters);
1416 HeapFree(heap,0,piW);
1420 /******************************************************************
1421 * DeviceCapabilities [WINSPOOL.@]
1422 * DeviceCapabilitiesA [WINSPOOL.@]
1425 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1426 LPSTR pOutput, LPDEVMODEA lpdm)
1430 if (!GDI_CallDeviceCapabilities16)
1432 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1434 if (!GDI_CallDeviceCapabilities16) return -1;
1436 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1438 /* If DC_PAPERSIZE map POINT16s to POINTs */
1439 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1440 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1441 POINT *pt = (POINT *)pOutput;
1443 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1444 for(i = 0; i < ret; i++, pt++)
1449 HeapFree( GetProcessHeap(), 0, tmp );
1455 /*****************************************************************************
1456 * DeviceCapabilitiesW [WINSPOOL.@]
1458 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1461 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1462 WORD fwCapability, LPWSTR pOutput,
1463 const DEVMODEW *pDevMode)
1465 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1466 LPSTR pDeviceA = strdupWtoA(pDevice);
1467 LPSTR pPortA = strdupWtoA(pPort);
1470 if(pOutput && (fwCapability == DC_BINNAMES ||
1471 fwCapability == DC_FILEDEPENDENCIES ||
1472 fwCapability == DC_PAPERNAMES)) {
1473 /* These need A -> W translation */
1476 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1480 switch(fwCapability) {
1485 case DC_FILEDEPENDENCIES:
1489 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1490 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1492 for(i = 0; i < ret; i++)
1493 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1494 pOutput + (i * size), size);
1495 HeapFree(GetProcessHeap(), 0, pOutputA);
1497 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1498 (LPSTR)pOutput, dmA);
1500 HeapFree(GetProcessHeap(),0,pPortA);
1501 HeapFree(GetProcessHeap(),0,pDeviceA);
1502 HeapFree(GetProcessHeap(),0,dmA);
1506 /******************************************************************
1507 * DocumentPropertiesA [WINSPOOL.@]
1509 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1511 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1512 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1513 LPDEVMODEA pDevModeInput,DWORD fMode )
1515 LPSTR lpName = pDeviceName;
1516 static CHAR port[] = "LPT1:";
1519 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1520 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1524 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1526 ERR("no name from hPrinter?\n");
1527 SetLastError(ERROR_INVALID_HANDLE);
1530 lpName = strdupWtoA(lpNameW);
1533 if (!GDI_CallExtDeviceMode16)
1535 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1537 if (!GDI_CallExtDeviceMode16) {
1538 ERR("No CallExtDeviceMode16?\n");
1542 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1543 pDevModeInput, NULL, fMode);
1546 HeapFree(GetProcessHeap(),0,lpName);
1551 /*****************************************************************************
1552 * DocumentPropertiesW (WINSPOOL.@)
1554 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1556 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1558 LPDEVMODEW pDevModeOutput,
1559 LPDEVMODEW pDevModeInput, DWORD fMode)
1562 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1563 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1564 LPDEVMODEA pDevModeOutputA = NULL;
1567 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1568 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1570 if(pDevModeOutput) {
1571 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1572 if(ret < 0) return ret;
1573 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1575 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1576 pDevModeInputA, fMode);
1577 if(pDevModeOutput) {
1578 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1579 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1581 if(fMode == 0 && ret > 0)
1582 ret += (CCHDEVICENAME + CCHFORMNAME);
1583 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1584 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1588 /******************************************************************
1589 * OpenPrinterA [WINSPOOL.@]
1594 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1595 LPPRINTER_DEFAULTSA pDefault)
1597 UNICODE_STRING lpPrinterNameW;
1598 UNICODE_STRING usBuffer;
1599 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1600 PWSTR pwstrPrinterNameW;
1603 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1606 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1607 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1608 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1609 pDefaultW = &DefaultW;
1611 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1613 RtlFreeUnicodeString(&usBuffer);
1614 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1616 RtlFreeUnicodeString(&lpPrinterNameW);
1620 /******************************************************************
1621 * OpenPrinterW [WINSPOOL.@]
1623 * Open a Printer / Printserver or a Printer-Object
1626 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1627 * phPrinter [O] The resulting Handle is stored here
1628 * pDefault [I] PTR to Default Printer Settings or NULL
1635 * lpPrinterName is one of:
1636 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1637 *| Printer: "PrinterName"
1638 *| Printer-Object: "PrinterName,Job xxx"
1639 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1640 *| XcvPort: "Servername,XcvPort PortName"
1643 *| Printer-Object not supported
1644 *| pDefaults is ignored
1647 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1650 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1652 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1653 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1657 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1658 SetLastError(ERROR_INVALID_PARAMETER);
1662 /* Get the unique handle of the printer or Printserver */
1663 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1664 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1665 return (*phPrinter != 0);
1668 /******************************************************************
1669 * AddMonitorA [WINSPOOL.@]
1674 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1676 LPWSTR nameW = NULL;
1679 LPMONITOR_INFO_2A mi2a;
1680 MONITOR_INFO_2W mi2w;
1682 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1683 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1684 debugstr_a(mi2a ? mi2a->pName : NULL),
1685 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
1686 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
1689 SetLastError(ERROR_INVALID_LEVEL);
1693 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1699 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1700 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1701 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1704 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1706 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1707 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1708 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1710 if (mi2a->pEnvironment) {
1711 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1712 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1713 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1715 if (mi2a->pDLLName) {
1716 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1717 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1718 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1721 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1723 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1724 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1725 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1727 HeapFree(GetProcessHeap(), 0, nameW);
1731 /******************************************************************************
1732 * AddMonitorW [WINSPOOL.@]
1734 * Install a Printmonitor
1737 * pName [I] Servername or NULL (local Computer)
1738 * Level [I] Structure-Level (Must be 2)
1739 * pMonitors [I] PTR to MONITOR_INFO_2
1746 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1749 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1751 LPMONITOR_INFO_2W mi2w;
1753 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1754 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1755 debugstr_w(mi2w ? mi2w->pName : NULL),
1756 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1757 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1759 if ((backend == NULL) && !load_backend()) return FALSE;
1762 SetLastError(ERROR_INVALID_LEVEL);
1766 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1771 return backend->fpAddMonitor(pName, Level, pMonitors);
1774 /******************************************************************
1775 * DeletePrinterDriverA [WINSPOOL.@]
1778 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1780 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
1783 /******************************************************************
1784 * DeletePrinterDriverW [WINSPOOL.@]
1787 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1789 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
1792 /******************************************************************
1793 * DeleteMonitorA [WINSPOOL.@]
1795 * See DeleteMonitorW.
1798 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1800 LPWSTR nameW = NULL;
1801 LPWSTR EnvironmentW = NULL;
1802 LPWSTR MonitorNameW = NULL;
1807 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1808 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1809 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1813 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1814 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1815 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1818 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1819 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1820 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1823 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1825 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1826 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1827 HeapFree(GetProcessHeap(), 0, nameW);
1831 /******************************************************************
1832 * DeleteMonitorW [WINSPOOL.@]
1834 * Delete a specific Printmonitor from a Printing-Environment
1837 * pName [I] Servername or NULL (local Computer)
1838 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1839 * pMonitorName [I] Name of the Monitor, that should be deleted
1846 * pEnvironment is ignored in Windows for the local Computer.
1849 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1852 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1853 debugstr_w(pMonitorName));
1855 if ((backend == NULL) && !load_backend()) return FALSE;
1857 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
1861 /******************************************************************
1862 * DeletePortA [WINSPOOL.@]
1867 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1869 LPWSTR nameW = NULL;
1870 LPWSTR portW = NULL;
1874 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
1876 /* convert servername to unicode */
1878 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1879 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1880 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1883 /* convert portname to unicode */
1885 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
1886 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1887 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
1890 res = DeletePortW(nameW, hWnd, portW);
1891 HeapFree(GetProcessHeap(), 0, nameW);
1892 HeapFree(GetProcessHeap(), 0, portW);
1896 /******************************************************************
1897 * DeletePortW [WINSPOOL.@]
1899 * Delete a specific Port
1902 * pName [I] Servername or NULL (local Computer)
1903 * hWnd [I] Handle to parent Window for the Dialog-Box
1904 * pPortName [I] Name of the Port, that should be deleted
1911 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1913 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1915 if ((backend == NULL) && !load_backend()) return FALSE;
1918 SetLastError(RPC_X_NULL_REF_POINTER);
1922 return backend->fpDeletePort(pName, hWnd, pPortName);
1925 /******************************************************************************
1926 * SetPrinterW [WINSPOOL.@]
1928 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1930 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
1931 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1935 /******************************************************************************
1936 * WritePrinter [WINSPOOL.@]
1938 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1940 opened_printer_t *printer;
1943 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1945 EnterCriticalSection(&printer_handles_cs);
1946 printer = get_opened_printer(hPrinter);
1949 SetLastError(ERROR_INVALID_HANDLE);
1955 SetLastError(ERROR_SPL_NO_STARTDOC);
1959 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1961 LeaveCriticalSection(&printer_handles_cs);
1965 /*****************************************************************************
1966 * AddFormA [WINSPOOL.@]
1968 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1970 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1974 /*****************************************************************************
1975 * AddFormW [WINSPOOL.@]
1977 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1979 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
1983 /*****************************************************************************
1984 * AddJobA [WINSPOOL.@]
1986 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1989 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1993 SetLastError(ERROR_INVALID_LEVEL);
1997 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2000 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2001 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2002 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2003 if(*pcbNeeded > cbBuf) {
2004 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2007 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2008 addjobA->JobId = addjobW->JobId;
2009 addjobA->Path = (char *)(addjobA + 1);
2010 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2016 /*****************************************************************************
2017 * AddJobW [WINSPOOL.@]
2019 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2021 opened_printer_t *printer;
2024 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2025 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2026 WCHAR path[MAX_PATH], filename[MAX_PATH];
2028 ADDJOB_INFO_1W *addjob;
2030 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2032 EnterCriticalSection(&printer_handles_cs);
2034 printer = get_opened_printer(hPrinter);
2037 SetLastError(ERROR_INVALID_HANDLE);
2042 SetLastError(ERROR_INVALID_LEVEL);
2046 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2050 job->job_id = InterlockedIncrement(&next_job_id);
2052 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2053 if(path[len - 1] != '\\')
2055 memcpy(path + len, spool_path, sizeof(spool_path));
2056 sprintfW(filename, fmtW, path, job->job_id);
2058 len = strlenW(filename);
2059 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2060 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2061 job->document_title = strdupW(default_doc_title);
2062 list_add_tail(&printer->queue->jobs, &job->entry);
2064 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2065 if(*pcbNeeded <= cbBuf) {
2066 addjob = (ADDJOB_INFO_1W*)pData;
2067 addjob->JobId = job->job_id;
2068 addjob->Path = (WCHAR *)(addjob + 1);
2069 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2072 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2075 LeaveCriticalSection(&printer_handles_cs);
2079 /*****************************************************************************
2080 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2082 * Return the PATH for the Print-Processors
2084 * See GetPrintProcessorDirectoryW.
2088 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2089 DWORD level, LPBYTE Info,
2090 DWORD cbBuf, LPDWORD pcbNeeded)
2092 LPWSTR serverW = NULL;
2097 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2098 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2102 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2103 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2104 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2108 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2109 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2110 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2113 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2114 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2116 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2119 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2120 cbBuf, NULL, NULL) > 0;
2123 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2124 HeapFree(GetProcessHeap(), 0, envW);
2125 HeapFree(GetProcessHeap(), 0, serverW);
2129 /*****************************************************************************
2130 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2132 * Return the PATH for the Print-Processors
2135 * server [I] Servername (NT only) or NULL (local Computer)
2136 * env [I] Printing-Environment (see below) or NULL (Default)
2137 * level [I] Structure-Level (must be 1)
2138 * Info [O] PTR to Buffer that receives the Result
2139 * cbBuf [I] Size of Buffer at "Info"
2140 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2141 * required for the Buffer at "Info"
2144 * Success: TRUE and in pcbNeeded the Bytes used in Info
2145 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2146 * if cbBuf is too small
2148 * Native Values returned in Info on Success:
2149 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2150 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2151 *| win9x(Windows 4.0): "%winsysdir%"
2153 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2156 * Only NULL or "" is supported for server
2159 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2160 DWORD level, LPBYTE Info,
2161 DWORD cbBuf, LPDWORD pcbNeeded)
2164 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2165 Info, cbBuf, pcbNeeded);
2167 if ((backend == NULL) && !load_backend()) return FALSE;
2170 /* (Level != 1) is ignored in win9x */
2171 SetLastError(ERROR_INVALID_LEVEL);
2175 if (pcbNeeded == NULL) {
2176 /* (pcbNeeded == NULL) is ignored in win9x */
2177 SetLastError(RPC_X_NULL_REF_POINTER);
2181 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2184 /*****************************************************************************
2185 * WINSPOOL_OpenDriverReg [internal]
2187 * opens the registry for the printer drivers depending on the given input
2188 * variable pEnvironment
2191 * the opened hkey on success
2194 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2198 const printenv_t * env;
2201 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2203 if (!pEnvironment || unicode) {
2204 /* pEnvironment was NULL or a Unicode-String: use it direct */
2205 env = validate_envW(pEnvironment);
2209 /* pEnvironment was an ANSI-String: convert to unicode first */
2211 INT len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2212 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2213 if (buffer) MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, buffer, len);
2214 env = validate_envW(buffer);
2215 HeapFree(GetProcessHeap(), 0, buffer);
2217 if (!env) return NULL;
2219 buffer = HeapAlloc( GetProcessHeap(), 0,
2220 (strlenW(DriversW) + strlenW(env->envname) +
2221 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2223 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2224 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2225 HeapFree(GetProcessHeap(), 0, buffer);
2230 /*****************************************************************************
2231 * AddPrinterW [WINSPOOL.@]
2233 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2235 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2239 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2241 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2242 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2243 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2244 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2245 statusW[] = {'S','t','a','t','u','s',0},
2246 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2248 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2251 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2252 SetLastError(ERROR_INVALID_PARAMETER);
2256 ERR("Level = %d, unsupported!\n", Level);
2257 SetLastError(ERROR_INVALID_LEVEL);
2261 SetLastError(ERROR_INVALID_PARAMETER);
2264 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2266 ERR("Can't create Printers key\n");
2269 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2270 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2271 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2272 RegCloseKey(hkeyPrinter);
2273 RegCloseKey(hkeyPrinters);
2276 RegCloseKey(hkeyPrinter);
2278 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2280 ERR("Can't create Drivers key\n");
2281 RegCloseKey(hkeyPrinters);
2284 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2286 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2287 RegCloseKey(hkeyPrinters);
2288 RegCloseKey(hkeyDrivers);
2289 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2292 RegCloseKey(hkeyDriver);
2293 RegCloseKey(hkeyDrivers);
2295 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2296 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2297 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2298 RegCloseKey(hkeyPrinters);
2302 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2304 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2305 SetLastError(ERROR_INVALID_PRINTER_NAME);
2306 RegCloseKey(hkeyPrinters);
2309 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2310 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2311 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2313 /* See if we can load the driver. We may need the devmode structure anyway
2316 * Note that DocumentPropertiesW will briefly try to open the printer we
2317 * just create to find a DEVMODEA struct (it will use the WINEPS default
2318 * one in case it is not there, so we are ok).
2320 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2323 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2324 size = sizeof(DEVMODEW);
2330 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2332 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2334 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2335 HeapFree(GetProcessHeap(),0,dmW);
2340 /* set devmode to printer name */
2341 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2345 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2346 and we support these drivers. NT writes DEVMODEW so somehow
2347 we'll need to distinguish between these when we support NT
2351 dmA = DEVMODEdupWtoA(dmW);
2352 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2353 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2354 HeapFree(GetProcessHeap(), 0, dmA);
2356 HeapFree(GetProcessHeap(), 0, dmW);
2358 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2359 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2360 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2361 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2363 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2364 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2365 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2366 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2367 (LPBYTE)&pi->Priority, sizeof(DWORD));
2368 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2369 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2370 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2371 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2372 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2373 (LPBYTE)&pi->Status, sizeof(DWORD));
2374 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2375 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2377 RegCloseKey(hkeyPrinter);
2378 RegCloseKey(hkeyPrinters);
2379 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2380 ERR("OpenPrinter failing\n");
2386 /*****************************************************************************
2387 * AddPrinterA [WINSPOOL.@]
2389 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2391 UNICODE_STRING pNameW;
2393 PRINTER_INFO_2W *piW;
2394 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2397 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2399 ERR("Level = %d, unsupported!\n", Level);
2400 SetLastError(ERROR_INVALID_LEVEL);
2403 pwstrNameW = asciitounicode(&pNameW,pName);
2404 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2406 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2408 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2409 RtlFreeUnicodeString(&pNameW);
2414 /*****************************************************************************
2415 * ClosePrinter [WINSPOOL.@]
2417 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2419 UINT_PTR i = (UINT_PTR)hPrinter;
2420 opened_printer_t *printer = NULL;
2423 TRACE("(%p)\n", hPrinter);
2425 EnterCriticalSection(&printer_handles_cs);
2427 if ((i > 0) && (i <= nb_printer_handles))
2428 printer = printer_handles[i - 1];
2433 struct list *cursor, *cursor2;
2435 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2437 if (printer->backend_printer) {
2438 backend->fpClosePrinter(printer->backend_printer);
2442 EndDocPrinter(hPrinter);
2444 if(InterlockedDecrement(&printer->queue->ref) == 0)
2446 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2448 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2449 ScheduleJob(hPrinter, job->job_id);
2451 HeapFree(GetProcessHeap(), 0, printer->queue);
2454 HeapFree(GetProcessHeap(), 0, printer->printername);
2455 HeapFree(GetProcessHeap(), 0, printer->name);
2456 HeapFree(GetProcessHeap(), 0, printer);
2457 printer_handles[i - 1] = NULL;
2460 LeaveCriticalSection(&printer_handles_cs);
2464 /*****************************************************************************
2465 * DeleteFormA [WINSPOOL.@]
2467 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2469 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2473 /*****************************************************************************
2474 * DeleteFormW [WINSPOOL.@]
2476 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2478 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2482 /*****************************************************************************
2483 * DeletePrinter [WINSPOOL.@]
2485 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2487 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2488 HKEY hkeyPrinters, hkey;
2491 SetLastError(ERROR_INVALID_HANDLE);
2494 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2495 RegDeleteTreeW(hkeyPrinters, lpNameW);
2496 RegCloseKey(hkeyPrinters);
2498 WriteProfileStringW(devicesW, lpNameW, NULL);
2499 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2501 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2502 RegDeleteValueW(hkey, lpNameW);
2506 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2507 RegDeleteValueW(hkey, lpNameW);
2513 /*****************************************************************************
2514 * SetPrinterA [WINSPOOL.@]
2516 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2519 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
2523 /*****************************************************************************
2524 * SetJobA [WINSPOOL.@]
2526 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2527 LPBYTE pJob, DWORD Command)
2531 UNICODE_STRING usBuffer;
2533 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2535 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2536 are all ignored by SetJob, so we don't bother copying them */
2544 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2545 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2547 JobW = (LPBYTE)info1W;
2548 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2549 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2550 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2551 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2552 info1W->Status = info1A->Status;
2553 info1W->Priority = info1A->Priority;
2554 info1W->Position = info1A->Position;
2555 info1W->PagesPrinted = info1A->PagesPrinted;
2560 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2561 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2563 JobW = (LPBYTE)info2W;
2564 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2565 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2566 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2567 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2568 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2569 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2570 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2571 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2572 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2573 info2W->Status = info2A->Status;
2574 info2W->Priority = info2A->Priority;
2575 info2W->Position = info2A->Position;
2576 info2W->StartTime = info2A->StartTime;
2577 info2W->UntilTime = info2A->UntilTime;
2578 info2W->PagesPrinted = info2A->PagesPrinted;
2582 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2583 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2586 SetLastError(ERROR_INVALID_LEVEL);
2590 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2596 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2597 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2598 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2599 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2600 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2605 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2606 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2607 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2608 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2609 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2610 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2611 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2612 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2613 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2617 HeapFree(GetProcessHeap(), 0, JobW);
2622 /*****************************************************************************
2623 * SetJobW [WINSPOOL.@]
2625 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2626 LPBYTE pJob, DWORD Command)
2631 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
2632 FIXME("Ignoring everything other than document title\n");
2634 EnterCriticalSection(&printer_handles_cs);
2635 job = get_job(hPrinter, JobId);
2645 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2646 HeapFree(GetProcessHeap(), 0, job->document_title);
2647 job->document_title = strdupW(info1->pDocument);
2652 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2653 HeapFree(GetProcessHeap(), 0, job->document_title);
2654 job->document_title = strdupW(info2->pDocument);
2660 SetLastError(ERROR_INVALID_LEVEL);
2665 LeaveCriticalSection(&printer_handles_cs);
2669 /*****************************************************************************
2670 * EndDocPrinter [WINSPOOL.@]
2672 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2674 opened_printer_t *printer;
2676 TRACE("(%p)\n", hPrinter);
2678 EnterCriticalSection(&printer_handles_cs);
2680 printer = get_opened_printer(hPrinter);
2683 SetLastError(ERROR_INVALID_HANDLE);
2689 SetLastError(ERROR_SPL_NO_STARTDOC);
2693 CloseHandle(printer->doc->hf);
2694 ScheduleJob(hPrinter, printer->doc->job_id);
2695 HeapFree(GetProcessHeap(), 0, printer->doc);
2696 printer->doc = NULL;
2699 LeaveCriticalSection(&printer_handles_cs);
2703 /*****************************************************************************
2704 * EndPagePrinter [WINSPOOL.@]
2706 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2708 FIXME("(%p): stub\n", hPrinter);
2712 /*****************************************************************************
2713 * StartDocPrinterA [WINSPOOL.@]
2715 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2717 UNICODE_STRING usBuffer;
2719 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2722 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2723 or one (DOC_INFO_3) extra DWORDs */
2727 doc2W.JobId = doc2->JobId;
2730 doc2W.dwMode = doc2->dwMode;
2733 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2734 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2735 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2739 SetLastError(ERROR_INVALID_LEVEL);
2743 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2745 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2746 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2747 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2752 /*****************************************************************************
2753 * StartDocPrinterW [WINSPOOL.@]
2755 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2757 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2758 opened_printer_t *printer;
2759 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2760 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2761 JOB_INFO_1W job_info;
2762 DWORD needed, ret = 0;
2766 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2767 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2768 debugstr_w(doc->pDatatype));
2770 if(Level < 1 || Level > 3)
2772 SetLastError(ERROR_INVALID_LEVEL);
2776 EnterCriticalSection(&printer_handles_cs);
2777 printer = get_opened_printer(hPrinter);
2780 SetLastError(ERROR_INVALID_HANDLE);
2786 SetLastError(ERROR_INVALID_PRINTER_STATE);
2790 /* Even if we're printing to a file we still add a print job, we'll
2791 just ignore the spool file name */
2793 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2795 ERR("AddJob failed gle %u\n", GetLastError());
2799 if(doc->pOutputFile)
2800 filename = doc->pOutputFile;
2802 filename = addjob->Path;
2804 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2805 if(hf == INVALID_HANDLE_VALUE)
2808 memset(&job_info, 0, sizeof(job_info));
2809 job_info.pDocument = doc->pDocName;
2810 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2812 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2813 printer->doc->hf = hf;
2814 ret = printer->doc->job_id = addjob->JobId;
2816 LeaveCriticalSection(&printer_handles_cs);
2821 /*****************************************************************************
2822 * StartPagePrinter [WINSPOOL.@]
2824 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2826 FIXME("(%p): stub\n", hPrinter);
2830 /*****************************************************************************
2831 * GetFormA [WINSPOOL.@]
2833 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2834 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2836 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
2837 Level,pForm,cbBuf,pcbNeeded);
2841 /*****************************************************************************
2842 * GetFormW [WINSPOOL.@]
2844 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2845 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2847 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
2848 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2852 /*****************************************************************************
2853 * SetFormA [WINSPOOL.@]
2855 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2858 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2862 /*****************************************************************************
2863 * SetFormW [WINSPOOL.@]
2865 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2868 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
2872 /*****************************************************************************
2873 * ReadPrinter [WINSPOOL.@]
2875 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2876 LPDWORD pNoBytesRead)
2878 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2882 /*****************************************************************************
2883 * ResetPrinterA [WINSPOOL.@]
2885 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2887 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2891 /*****************************************************************************
2892 * ResetPrinterW [WINSPOOL.@]
2894 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2896 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2900 /*****************************************************************************
2901 * WINSPOOL_GetDWORDFromReg
2903 * Return DWORD associated with ValueName from hkey.
2905 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2907 DWORD sz = sizeof(DWORD), type, value = 0;
2910 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2912 if(ret != ERROR_SUCCESS) {
2913 WARN("Got ret = %d on name %s\n", ret, ValueName);
2916 if(type != REG_DWORD) {
2917 ERR("Got type %d\n", type);
2924 /*****************************************************************************
2925 * get_filename_from_reg [internal]
2927 * Get ValueName from hkey storing result in out
2928 * when the Value in the registry has only a filename, use driverdir as prefix
2929 * outlen is space left in out
2930 * String is stored either as unicode or ascii
2934 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
2935 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
2937 WCHAR filename[MAX_PATH];
2941 LPWSTR buffer = filename;
2945 size = sizeof(filename);
2947 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
2948 if (ret == ERROR_MORE_DATA) {
2949 TRACE("need dynamic buffer: %u\n", size);
2950 buffer = HeapAlloc(GetProcessHeap(), 0, size);
2952 /* No Memory is bad */
2956 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
2959 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
2960 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
2966 /* do we have a full path ? */
2967 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
2968 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
2971 /* we must build the full Path */
2973 if ((out) && (outlen > dirlen)) {
2975 lstrcpyW((LPWSTR)out, driverdir);
2979 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
2988 /* write the filename */
2990 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
2991 if ((out) && (outlen >= size)) {
2992 lstrcpyW((LPWSTR)out, ptr);
3001 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3002 if ((out) && (outlen >= size)) {
3003 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3011 ptr += lstrlenW(ptr)+1;
3012 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3015 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3017 /* write the multisz-termination */
3018 if (type == REG_MULTI_SZ) {
3019 size = (unicode) ? sizeof(WCHAR) : 1;
3022 if (out && (outlen >= size)) {
3023 memset (out, 0, size);
3029 /*****************************************************************************
3030 * WINSPOOL_GetStringFromReg
3032 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3033 * String is stored either as unicode or ascii.
3034 * Bit of a hack here to get the ValueName if we want ascii.
3036 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3037 DWORD buflen, DWORD *needed,
3040 DWORD sz = buflen, type;
3044 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3046 LPSTR ValueNameA = strdupWtoA(ValueName);
3047 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3048 HeapFree(GetProcessHeap(),0,ValueNameA);
3050 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3051 WARN("Got ret = %d\n", ret);
3055 /* add space for terminating '\0' */
3056 sz += unicode ? sizeof(WCHAR) : 1;
3060 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3065 /*****************************************************************************
3066 * WINSPOOL_GetDefaultDevMode
3068 * Get a default DevMode values for wineps.
3072 static void WINSPOOL_GetDefaultDevMode(
3074 DWORD buflen, DWORD *needed,
3078 static const char szwps[] = "wineps.drv";
3080 /* fill default DEVMODE - should be read from ppd... */
3081 ZeroMemory( &dm, sizeof(dm) );
3082 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3083 dm.dmSpecVersion = DM_SPECVERSION;
3084 dm.dmDriverVersion = 1;
3085 dm.dmSize = sizeof(DEVMODEA);
3086 dm.dmDriverExtra = 0;
3088 DM_ORIENTATION | DM_PAPERSIZE |
3089 DM_PAPERLENGTH | DM_PAPERWIDTH |
3092 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3093 DM_YRESOLUTION | DM_TTOPTION;
3095 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3096 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3097 dm.u1.s1.dmPaperLength = 2970;
3098 dm.u1.s1.dmPaperWidth = 2100;
3100 dm.u1.s1.dmScale = 100;
3101 dm.u1.s1.dmCopies = 1;
3102 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3103 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3106 dm.dmYResolution = 300; /* 300dpi */
3107 dm.dmTTOption = DMTT_BITMAP;
3110 /* dm.dmLogPixels */
3111 /* dm.dmBitsPerPel */
3112 /* dm.dmPelsWidth */
3113 /* dm.dmPelsHeight */
3114 /* dm.u2.dmDisplayFlags */
3115 /* dm.dmDisplayFrequency */
3116 /* dm.dmICMMethod */
3117 /* dm.dmICMIntent */
3118 /* dm.dmMediaType */
3119 /* dm.dmDitherType */
3120 /* dm.dmReserved1 */
3121 /* dm.dmReserved2 */
3122 /* dm.dmPanningWidth */
3123 /* dm.dmPanningHeight */
3126 if(buflen >= sizeof(DEVMODEW)) {
3127 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3128 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3129 HeapFree(GetProcessHeap(),0,pdmW);
3131 *needed = sizeof(DEVMODEW);
3135 if(buflen >= sizeof(DEVMODEA)) {
3136 memcpy(ptr, &dm, sizeof(DEVMODEA));
3138 *needed = sizeof(DEVMODEA);
3142 /*****************************************************************************
3143 * WINSPOOL_GetDevModeFromReg
3145 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3146 * DevMode is stored either as unicode or ascii.
3148 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3150 DWORD buflen, DWORD *needed,
3153 DWORD sz = buflen, type;
3156 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3157 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3158 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3159 if (sz < sizeof(DEVMODEA))
3161 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3164 /* ensures that dmSize is not erratically bogus if registry is invalid */
3165 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3166 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3168 sz += (CCHDEVICENAME + CCHFORMNAME);
3170 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3171 memcpy(ptr, dmW, sz);
3172 HeapFree(GetProcessHeap(),0,dmW);
3179 /*********************************************************************
3180 * WINSPOOL_GetPrinter_1
3182 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3183 * The strings are either stored as unicode or ascii.
3185 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3186 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3189 DWORD size, left = cbBuf;
3190 BOOL space = (cbBuf > 0);
3195 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3197 if(space && size <= left) {
3198 pi1->pName = (LPWSTR)ptr;
3206 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3207 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3209 if(space && size <= left) {
3210 pi1->pDescription = (LPWSTR)ptr;
3218 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3220 if(space && size <= left) {
3221 pi1->pComment = (LPWSTR)ptr;
3229 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3231 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3232 memset(pi1, 0, sizeof(*pi1));
3236 /*********************************************************************
3237 * WINSPOOL_GetPrinter_2
3239 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3240 * The strings are either stored as unicode or ascii.
3242 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3243 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3246 DWORD size, left = cbBuf;
3247 BOOL space = (cbBuf > 0);
3252 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3254 if(space && size <= left) {
3255 pi2->pPrinterName = (LPWSTR)ptr;
3262 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3264 if(space && size <= left) {
3265 pi2->pShareName = (LPWSTR)ptr;
3272 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3274 if(space && size <= left) {
3275 pi2->pPortName = (LPWSTR)ptr;
3282 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3284 if(space && size <= left) {
3285 pi2->pDriverName = (LPWSTR)ptr;
3292 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3294 if(space && size <= left) {
3295 pi2->pComment = (LPWSTR)ptr;
3302 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3304 if(space && size <= left) {
3305 pi2->pLocation = (LPWSTR)ptr;
3312 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3314 if(space && size <= left) {
3315 pi2->pDevMode = (LPDEVMODEW)ptr;
3324 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3325 if(space && size <= left) {
3326 pi2->pDevMode = (LPDEVMODEW)ptr;
3333 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3335 if(space && size <= left) {
3336 pi2->pSepFile = (LPWSTR)ptr;
3343 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3345 if(space && size <= left) {
3346 pi2->pPrintProcessor = (LPWSTR)ptr;
3353 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3355 if(space && size <= left) {
3356 pi2->pDatatype = (LPWSTR)ptr;
3363 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3365 if(space && size <= left) {
3366 pi2->pParameters = (LPWSTR)ptr;
3374 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3375 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3376 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3377 "Default Priority");
3378 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3379 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3382 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3383 memset(pi2, 0, sizeof(*pi2));
3388 /*********************************************************************
3389 * WINSPOOL_GetPrinter_4
3391 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3393 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3394 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3397 DWORD size, left = cbBuf;
3398 BOOL space = (cbBuf > 0);
3403 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3405 if(space && size <= left) {
3406 pi4->pPrinterName = (LPWSTR)ptr;
3414 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3417 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3418 memset(pi4, 0, sizeof(*pi4));
3423 /*********************************************************************
3424 * WINSPOOL_GetPrinter_5
3426 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3428 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3429 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3432 DWORD size, left = cbBuf;
3433 BOOL space = (cbBuf > 0);
3438 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3440 if(space && size <= left) {
3441 pi5->pPrinterName = (LPWSTR)ptr;
3448 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3450 if(space && size <= left) {
3451 pi5->pPortName = (LPWSTR)ptr;
3459 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3460 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3462 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3466 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3467 memset(pi5, 0, sizeof(*pi5));
3472 /*********************************************************************
3473 * WINSPOOL_GetPrinter_7
3475 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3477 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3478 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3480 DWORD size, left = cbBuf;
3481 BOOL space = (cbBuf > 0);
3486 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
3488 if (space && size <= left) {
3489 pi7->pszObjectGUID = (LPWSTR)ptr;
3497 /* We do not have a Directory Service */
3498 pi7->dwAction = DSPRINT_UNPUBLISH;
3501 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3502 memset(pi7, 0, sizeof(*pi7));
3507 /*********************************************************************
3508 * WINSPOOL_GetPrinter_9
3510 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
3511 * The strings are either stored as unicode or ascii.
3513 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3514 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3517 BOOL space = (cbBuf > 0);
3521 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
3522 if(space && size <= cbBuf) {
3523 pi9->pDevMode = (LPDEVMODEW)buf;
3530 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
3531 if(space && size <= cbBuf) {
3532 pi9->pDevMode = (LPDEVMODEW)buf;
3538 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3539 memset(pi9, 0, sizeof(*pi9));
3544 /*****************************************************************************
3545 * WINSPOOL_GetPrinter
3547 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3548 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3549 * just a collection of pointers to strings.
3551 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3552 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3555 DWORD size, needed = 0;
3557 HKEY hkeyPrinter, hkeyPrinters;
3560 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3562 if (!(name = get_opened_printer_name(hPrinter))) {
3563 SetLastError(ERROR_INVALID_HANDLE);
3567 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3569 ERR("Can't create Printers key\n");
3572 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3574 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3575 RegCloseKey(hkeyPrinters);
3576 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3583 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3585 size = sizeof(PRINTER_INFO_2W);
3587 ptr = pPrinter + size;
3589 memset(pPrinter, 0, size);
3594 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3602 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3604 size = sizeof(PRINTER_INFO_4W);
3606 ptr = pPrinter + size;
3608 memset(pPrinter, 0, size);
3613 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3622 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3624 size = sizeof(PRINTER_INFO_5W);
3626 ptr = pPrinter + size;
3628 memset(pPrinter, 0, size);
3634 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3643 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3645 size = sizeof(PRINTER_INFO_6);
3646 if (size <= cbBuf) {
3647 /* FIXME: We do not update the status yet */
3648 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3660 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3662 size = sizeof(PRINTER_INFO_7W);
3663 if (size <= cbBuf) {
3664 ptr = pPrinter + size;
3666 memset(pPrinter, 0, size);
3672 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
3680 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3682 size = sizeof(PRINTER_INFO_9W);
3684 ptr = pPrinter + size;
3686 memset(pPrinter, 0, size);
3692 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
3699 FIXME("Unimplemented level %d\n", Level);
3700 SetLastError(ERROR_INVALID_LEVEL);
3701 RegCloseKey(hkeyPrinters);
3702 RegCloseKey(hkeyPrinter);
3706 RegCloseKey(hkeyPrinter);
3707 RegCloseKey(hkeyPrinters);
3709 TRACE("returning %d needed = %d\n", ret, needed);
3710 if(pcbNeeded) *pcbNeeded = needed;
3712 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3716 /*****************************************************************************
3717 * GetPrinterW [WINSPOOL.@]
3719 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3720 DWORD cbBuf, LPDWORD pcbNeeded)
3722 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3726 /*****************************************************************************
3727 * GetPrinterA [WINSPOOL.@]
3729 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3730 DWORD cbBuf, LPDWORD pcbNeeded)
3732 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3736 /*****************************************************************************
3737 * WINSPOOL_EnumPrinters
3739 * Implementation of EnumPrintersA|W
3741 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3742 DWORD dwLevel, LPBYTE lpbPrinters,
3743 DWORD cbBuf, LPDWORD lpdwNeeded,
3744 LPDWORD lpdwReturned, BOOL unicode)
3747 HKEY hkeyPrinters, hkeyPrinter;
3748 WCHAR PrinterName[255];
3749 DWORD needed = 0, number = 0;
3750 DWORD used, i, left;
3754 memset(lpbPrinters, 0, cbBuf);
3760 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3761 if(dwType == PRINTER_ENUM_DEFAULT)
3764 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3765 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
3766 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3768 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3774 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3775 FIXME("dwType = %08x\n", dwType);
3776 SetLastError(ERROR_INVALID_FLAGS);
3780 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3782 ERR("Can't create Printers key\n");
3786 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3787 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3788 RegCloseKey(hkeyPrinters);
3789 ERR("Can't query Printers key\n");
3792 TRACE("Found %d printers\n", number);
3796 used = number * sizeof(PRINTER_INFO_1W);
3799 used = number * sizeof(PRINTER_INFO_2W);
3802 used = number * sizeof(PRINTER_INFO_4W);
3805 used = number * sizeof(PRINTER_INFO_5W);
3809 SetLastError(ERROR_INVALID_LEVEL);
3810 RegCloseKey(hkeyPrinters);
3813 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3815 for(i = 0; i < number; i++) {
3816 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
3818 ERR("Can't enum key number %d\n", i);
3819 RegCloseKey(hkeyPrinters);
3822 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
3823 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3825 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3826 RegCloseKey(hkeyPrinters);
3831 buf = lpbPrinters + used;
3832 left = cbBuf - used;
3840 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
3841 left, &needed, unicode);
3843 if(pi) pi += sizeof(PRINTER_INFO_1W);
3846 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3847 left, &needed, unicode);
3849 if(pi) pi += sizeof(PRINTER_INFO_2W);
3852 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3853 left, &needed, unicode);
3855 if(pi) pi += sizeof(PRINTER_INFO_4W);
3858 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3859 left, &needed, unicode);
3861 if(pi) pi += sizeof(PRINTER_INFO_5W);
3864 ERR("Shouldn't be here!\n");
3865 RegCloseKey(hkeyPrinter);
3866 RegCloseKey(hkeyPrinters);
3869 RegCloseKey(hkeyPrinter);
3871 RegCloseKey(hkeyPrinters);
3878 memset(lpbPrinters, 0, cbBuf);
3879 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3883 *lpdwReturned = number;
3884 SetLastError(ERROR_SUCCESS);
3889 /******************************************************************
3890 * EnumPrintersW [WINSPOOL.@]
3892 * Enumerates the available printers, print servers and print
3893 * providers, depending on the specified flags, name and level.
3897 * If level is set to 1:
3898 * Returns an array of PRINTER_INFO_1 data structures in the
3899 * lpbPrinters buffer.
3901 * If level is set to 2:
3902 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3903 * Returns an array of PRINTER_INFO_2 data structures in the
3904 * lpbPrinters buffer. Note that according to MSDN also an
3905 * OpenPrinter should be performed on every remote printer.
3907 * If level is set to 4 (officially WinNT only):
3908 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3909 * Fast: Only the registry is queried to retrieve printer names,
3910 * no connection to the driver is made.
3911 * Returns an array of PRINTER_INFO_4 data structures in the
3912 * lpbPrinters buffer.
3914 * If level is set to 5 (officially WinNT4/Win9x only):
3915 * Fast: Only the registry is queried to retrieve printer names,
3916 * no connection to the driver is made.
3917 * Returns an array of PRINTER_INFO_5 data structures in the
3918 * lpbPrinters buffer.
3920 * If level set to 3 or 6+:
3921 * returns zero (failure!)
3923 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3927 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3928 * - Only levels 2, 4 and 5 are implemented at the moment.
3929 * - 16-bit printer drivers are not enumerated.
3930 * - Returned amount of bytes used/needed does not match the real Windoze
3931 * implementation (as in this implementation, all strings are part
3932 * of the buffer, whereas Win32 keeps them somewhere else)
3933 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3936 * - In a regular Wine installation, no registry settings for printers
3937 * exist, which makes this function return an empty list.
3939 BOOL WINAPI EnumPrintersW(
3940 DWORD dwType, /* [in] Types of print objects to enumerate */
3941 LPWSTR lpszName, /* [in] name of objects to enumerate */
3942 DWORD dwLevel, /* [in] type of printer info structure */
3943 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3944 DWORD cbBuf, /* [in] max size of buffer in bytes */
3945 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3946 LPDWORD lpdwReturned /* [out] number of entries returned */
3949 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3950 lpdwNeeded, lpdwReturned, TRUE);
3953 /******************************************************************
3954 * EnumPrintersA [WINSPOOL.@]
3959 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
3960 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
3963 UNICODE_STRING pNameU;
3967 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
3968 pPrinters, cbBuf, pcbNeeded, pcReturned);
3970 pNameW = asciitounicode(&pNameU, pName);
3972 /* Request a buffer with a size, that is big enough for EnumPrintersW.
3973 MS Office need this */
3974 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
3976 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
3978 RtlFreeUnicodeString(&pNameU);
3980 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
3982 HeapFree(GetProcessHeap(), 0, pPrintersW);
3986 /*****************************************************************************
3987 * WINSPOOL_GetDriverInfoFromReg [internal]
3989 * Enters the information from the registry into the DRIVER_INFO struct
3992 * zero if the printer driver does not exist in the registry
3993 * (only if Level > 1) otherwise nonzero
3995 static BOOL WINSPOOL_GetDriverInfoFromReg(
3998 const printenv_t * env,
4000 LPBYTE ptr, /* DRIVER_INFO */
4001 LPBYTE pDriverStrings, /* strings buffer */
4002 DWORD cbBuf, /* size of string buffer */
4003 LPDWORD pcbNeeded, /* space needed for str. */
4004 BOOL unicode) /* type of strings */
4008 WCHAR driverdir[MAX_PATH];
4010 LPBYTE strPtr = pDriverStrings;
4011 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4013 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4014 debugstr_w(DriverName), env,
4015 Level, di, pDriverStrings, cbBuf, unicode);
4017 if (di) ZeroMemory(di, di_sizeof[Level]);
4020 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4021 if (*pcbNeeded <= cbBuf)
4022 strcpyW((LPWSTR)strPtr, DriverName);
4026 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4027 if (*pcbNeeded <= cbBuf)
4028 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4031 /* pName for level 1 has a different offset! */
4033 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4037 /* .cVersion and .pName for level > 1 */
4039 di->cVersion = env->driverversion;
4040 di->pName = (LPWSTR) strPtr;
4041 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4044 /* Reserve Space for the largest subdir and a Backslash*/
4045 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4046 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4047 /* Should never Fail */
4050 lstrcatW(driverdir, env->versionsubdir);
4051 lstrcatW(driverdir, backslashW);
4053 /* dirlen must not include the terminating zero */
4054 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4055 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4057 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4058 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4059 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4065 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4067 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4070 if (*pcbNeeded <= cbBuf) {
4072 lstrcpyW((LPWSTR)strPtr, env->envname);
4076 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4078 if (di) di->pEnvironment = (LPWSTR)strPtr;
4079 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4082 /* .pDriverPath is the Graphics rendering engine.
4083 The full Path is required to avoid a crash in some apps */
4084 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4086 if (*pcbNeeded <= cbBuf)
4087 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4089 if (di) di->pDriverPath = (LPWSTR)strPtr;
4090 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4093 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4094 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4096 if (*pcbNeeded <= cbBuf)
4097 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4099 if (di) di->pDataFile = (LPWSTR)strPtr;
4100 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4103 /* .pConfigFile is the Driver user Interface */
4104 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4106 if (*pcbNeeded <= cbBuf)
4107 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4109 if (di) di->pConfigFile = (LPWSTR)strPtr;
4110 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4114 RegCloseKey(hkeyDriver);
4115 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4120 RegCloseKey(hkeyDriver);
4121 FIXME("level 5: incomplete\n");
4126 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4128 if (*pcbNeeded <= cbBuf)
4129 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4131 if (di) di->pHelpFile = (LPWSTR)strPtr;
4132 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4135 /* .pDependentFiles */
4136 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4138 if (*pcbNeeded <= cbBuf)
4139 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4141 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4142 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4144 else if (GetVersion() & 0x80000000) {
4145 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4146 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4148 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4150 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4151 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4154 /* .pMonitorName is the optional Language Monitor */
4155 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4157 if (*pcbNeeded <= cbBuf)
4158 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4160 if (di) di->pMonitorName = (LPWSTR)strPtr;
4161 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4164 /* .pDefaultDataType */
4165 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4167 if(*pcbNeeded <= cbBuf)
4168 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4170 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4171 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4175 RegCloseKey(hkeyDriver);
4176 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4180 /* .pszzPreviousNames */
4181 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4183 if(*pcbNeeded <= cbBuf)
4184 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4186 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4187 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4191 RegCloseKey(hkeyDriver);
4192 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4196 /* support is missing, but not important enough for a FIXME */
4197 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4200 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4202 if(*pcbNeeded <= cbBuf)
4203 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4205 if (di) di->pszMfgName = (LPWSTR)strPtr;
4206 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4210 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4212 if(*pcbNeeded <= cbBuf)
4213 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4215 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4216 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4219 /* .pszHardwareID */
4220 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4222 if(*pcbNeeded <= cbBuf)
4223 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4225 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4226 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4230 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4232 if(*pcbNeeded <= cbBuf)
4233 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4235 if (di) di->pszProvider = (LPWSTR)strPtr;
4236 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4240 RegCloseKey(hkeyDriver);
4244 /* support is missing, but not important enough for a FIXME */
4245 TRACE("level 8: incomplete\n");
4247 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4248 RegCloseKey(hkeyDriver);
4252 /*****************************************************************************
4253 * WINSPOOL_GetPrinterDriver
4255 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4256 DWORD Level, LPBYTE pDriverInfo,
4257 DWORD cbBuf, LPDWORD pcbNeeded,
4261 WCHAR DriverName[100];
4262 DWORD ret, type, size, needed = 0;
4264 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4265 const printenv_t * env;
4267 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4268 Level,pDriverInfo,cbBuf, pcbNeeded);
4271 if (!(name = get_opened_printer_name(hPrinter))) {
4272 SetLastError(ERROR_INVALID_HANDLE);
4276 if (Level < 1 || Level == 7 || Level > 8) {
4277 SetLastError(ERROR_INVALID_LEVEL);
4281 env = validate_envW(pEnvironment);
4282 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4284 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4286 ERR("Can't create Printers key\n");
4289 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4291 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4292 RegCloseKey(hkeyPrinters);
4293 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4296 size = sizeof(DriverName);
4298 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4299 (LPBYTE)DriverName, &size);
4300 RegCloseKey(hkeyPrinter);
4301 RegCloseKey(hkeyPrinters);
4302 if(ret != ERROR_SUCCESS) {
4303 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4307 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4309 ERR("Can't create Drivers key\n");
4313 size = di_sizeof[Level];
4314 if ((size <= cbBuf) && pDriverInfo)
4315 ptr = pDriverInfo + size;
4317 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4318 env, Level, pDriverInfo, ptr,
4319 (cbBuf < size) ? 0 : cbBuf - size,
4320 &needed, unicode)) {
4321 RegCloseKey(hkeyDrivers);
4325 RegCloseKey(hkeyDrivers);
4327 if(pcbNeeded) *pcbNeeded = size + needed;
4328 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4329 if(cbBuf >= needed) return TRUE;
4330 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4334 /*****************************************************************************
4335 * GetPrinterDriverA [WINSPOOL.@]
4337 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4338 DWORD Level, LPBYTE pDriverInfo,
4339 DWORD cbBuf, LPDWORD pcbNeeded)
4342 UNICODE_STRING pEnvW;
4345 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4346 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4347 cbBuf, pcbNeeded, FALSE);
4348 RtlFreeUnicodeString(&pEnvW);
4351 /*****************************************************************************
4352 * GetPrinterDriverW [WINSPOOL.@]
4354 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4355 DWORD Level, LPBYTE pDriverInfo,
4356 DWORD cbBuf, LPDWORD pcbNeeded)
4358 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4359 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4362 /*****************************************************************************
4363 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4365 * Return the PATH for the Printer-Drivers (UNICODE)
4368 * pName [I] Servername (NT only) or NULL (local Computer)
4369 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4370 * Level [I] Structure-Level (must be 1)
4371 * pDriverDirectory [O] PTR to Buffer that receives the Result
4372 * cbBuf [I] Size of Buffer at pDriverDirectory
4373 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4374 * required for pDriverDirectory
4377 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4378 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4379 * if cbBuf is too small
4381 * Native Values returned in pDriverDirectory on Success:
4382 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4383 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4384 *| win9x(Windows 4.0): "%winsysdir%"
4386 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4389 *- Only NULL or "" is supported for pName
4392 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4393 DWORD Level, LPBYTE pDriverDirectory,
4394 DWORD cbBuf, LPDWORD pcbNeeded)
4396 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4397 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4399 if ((backend == NULL) && !load_backend()) return FALSE;
4402 /* (Level != 1) is ignored in win9x */
4403 SetLastError(ERROR_INVALID_LEVEL);
4406 if (pcbNeeded == NULL) {
4407 /* (pcbNeeded == NULL) is ignored in win9x */
4408 SetLastError(RPC_X_NULL_REF_POINTER);
4412 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4413 pDriverDirectory, cbBuf, pcbNeeded);
4418 /*****************************************************************************
4419 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4421 * Return the PATH for the Printer-Drivers (ANSI)
4423 * See GetPrinterDriverDirectoryW.
4426 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4429 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4430 DWORD Level, LPBYTE pDriverDirectory,
4431 DWORD cbBuf, LPDWORD pcbNeeded)
4433 UNICODE_STRING nameW, environmentW;
4436 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4437 WCHAR *driverDirectoryW = NULL;
4439 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4440 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4442 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4444 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4445 else nameW.Buffer = NULL;
4446 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4447 else environmentW.Buffer = NULL;
4449 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4450 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4453 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4454 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4456 *pcbNeeded = needed;
4457 ret = (needed <= cbBuf) ? TRUE : FALSE;
4459 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4461 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4463 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4464 RtlFreeUnicodeString(&environmentW);
4465 RtlFreeUnicodeString(&nameW);
4470 /*****************************************************************************
4471 * AddPrinterDriverA [WINSPOOL.@]
4473 * See AddPrinterDriverW.
4476 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4478 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4479 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4482 /******************************************************************************
4483 * AddPrinterDriverW (WINSPOOL.@)
4485 * Install a Printer Driver
4488 * pName [I] Servername or NULL (local Computer)
4489 * level [I] Level for the supplied DRIVER_INFO_*W struct
4490 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4497 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4499 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4500 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4503 /*****************************************************************************
4504 * AddPrintProcessorA [WINSPOOL.@]
4506 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4507 LPSTR pPrintProcessorName)
4509 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4510 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4514 /*****************************************************************************
4515 * AddPrintProcessorW [WINSPOOL.@]
4517 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4518 LPWSTR pPrintProcessorName)
4520 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4521 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4525 /*****************************************************************************
4526 * AddPrintProvidorA [WINSPOOL.@]
4528 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4530 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4534 /*****************************************************************************
4535 * AddPrintProvidorW [WINSPOOL.@]
4537 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4539 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4543 /*****************************************************************************
4544 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4546 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4547 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4549 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4550 pDevModeOutput, pDevModeInput);
4554 /*****************************************************************************
4555 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4557 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4558 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4560 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4561 pDevModeOutput, pDevModeInput);
4565 /*****************************************************************************
4566 * PrinterProperties [WINSPOOL.@]
4568 * Displays a dialog to set the properties of the printer.
4571 * nonzero on success or zero on failure
4574 * implemented as stub only
4576 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4577 HANDLE hPrinter /* [in] handle to printer object */
4579 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4580 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4584 /*****************************************************************************
4585 * EnumJobsA [WINSPOOL.@]
4588 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4589 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4592 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4593 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4595 if(pcbNeeded) *pcbNeeded = 0;
4596 if(pcReturned) *pcReturned = 0;
4601 /*****************************************************************************
4602 * EnumJobsW [WINSPOOL.@]
4605 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4606 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4609 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4610 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4612 if(pcbNeeded) *pcbNeeded = 0;
4613 if(pcReturned) *pcReturned = 0;
4617 /*****************************************************************************
4618 * WINSPOOL_EnumPrinterDrivers [internal]
4620 * Delivers information about all printer drivers installed on the
4621 * localhost or a given server
4624 * nonzero on success or zero on failure. If the buffer for the returned
4625 * information is too small the function will return an error
4628 * - only implemented for localhost, foreign hosts will return an error
4630 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4631 DWORD Level, LPBYTE pDriverInfo,
4632 DWORD cbBuf, LPDWORD pcbNeeded,
4633 LPDWORD pcReturned, BOOL unicode)
4636 DWORD i, needed, number = 0, size = 0;
4637 WCHAR DriverNameW[255];
4639 const printenv_t * env;
4641 TRACE("%s,%s,%d,%p,%d,%d\n",
4642 debugstr_w(pName), debugstr_w(pEnvironment),
4643 Level, pDriverInfo, cbBuf, unicode);
4645 /* check for local drivers */
4646 if((pName) && (pName[0])) {
4647 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4648 SetLastError(ERROR_ACCESS_DENIED);
4652 env = validate_envW(pEnvironment);
4653 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4655 /* check input parameter */
4656 if ((Level < 1) || (Level == 7) || (Level > 8)) {
4657 SetLastError(ERROR_INVALID_LEVEL);
4661 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
4662 SetLastError(RPC_X_NULL_REF_POINTER);
4666 /* initialize return values */
4668 memset( pDriverInfo, 0, cbBuf);
4672 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4674 ERR("Can't open Drivers key\n");
4678 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4679 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4680 RegCloseKey(hkeyDrivers);
4681 ERR("Can't query Drivers key\n");
4684 TRACE("Found %d Drivers\n", number);
4686 /* get size of single struct
4687 * unicode and ascii structure have the same size
4689 size = di_sizeof[Level];
4691 /* calculate required buffer size */
4692 *pcbNeeded = size * number;
4694 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4696 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4697 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4699 ERR("Can't enum key number %d\n", i);
4700 RegCloseKey(hkeyDrivers);
4703 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4705 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4706 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4707 &needed, unicode)) {
4708 RegCloseKey(hkeyDrivers);
4711 *pcbNeeded += needed;
4714 RegCloseKey(hkeyDrivers);
4716 if(cbBuf < *pcbNeeded){
4717 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4721 *pcReturned = number;
4725 /*****************************************************************************
4726 * EnumPrinterDriversW [WINSPOOL.@]
4728 * see function EnumPrinterDrivers for RETURNS, BUGS
4730 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4731 LPBYTE pDriverInfo, DWORD cbBuf,
4732 LPDWORD pcbNeeded, LPDWORD pcReturned)
4734 static const WCHAR allW[] = {'a','l','l',0};
4736 if (pEnvironment && !strcmpW(pEnvironment, allW))
4739 DWORD i, needed, returned, bufsize = cbBuf;
4741 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4743 needed = returned = 0;
4744 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
4745 pDriverInfo, bufsize, &needed, &returned, TRUE);
4746 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
4750 if (pDriverInfo) pDriverInfo += needed;
4751 if (pcReturned) *pcReturned += returned;
4753 if (pcbNeeded) *pcbNeeded += needed;
4757 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4758 cbBuf, pcbNeeded, pcReturned, TRUE);
4761 /*****************************************************************************
4762 * EnumPrinterDriversA [WINSPOOL.@]
4764 * see function EnumPrinterDrivers for RETURNS, BUGS
4766 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4767 LPBYTE pDriverInfo, DWORD cbBuf,
4768 LPDWORD pcbNeeded, LPDWORD pcReturned)
4771 UNICODE_STRING pNameW, pEnvironmentW;
4772 PWSTR pwstrNameW, pwstrEnvironmentW;
4774 pwstrNameW = asciitounicode(&pNameW, pName);
4775 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4777 if (pEnvironment && !strcmp(pEnvironment, "all"))
4779 DWORD i, needed, returned, bufsize = cbBuf;
4781 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
4783 needed = returned = 0;
4784 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, all_printenv[i]->envname, Level,
4785 pDriverInfo, bufsize, &needed, &returned, FALSE);
4786 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) break;
4790 if (pDriverInfo) pDriverInfo += needed;
4791 if (pcReturned) *pcReturned += returned;
4793 if (pcbNeeded) *pcbNeeded += needed;
4796 else ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4797 Level, pDriverInfo, cbBuf, pcbNeeded,
4799 RtlFreeUnicodeString(&pNameW);
4800 RtlFreeUnicodeString(&pEnvironmentW);
4805 /******************************************************************************
4806 * EnumPortsA (WINSPOOL.@)
4811 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
4812 LPDWORD pcbNeeded, LPDWORD pcReturned)
4815 LPBYTE bufferW = NULL;
4816 LPWSTR nameW = NULL;
4818 DWORD numentries = 0;
4821 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
4822 cbBuf, pcbNeeded, pcReturned);
4824 /* convert servername to unicode */
4826 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
4827 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
4828 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
4830 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
4831 needed = cbBuf * sizeof(WCHAR);
4832 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
4833 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4835 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
4836 if (pcbNeeded) needed = *pcbNeeded;
4837 /* HeapReAlloc return NULL, when bufferW was NULL */
4838 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
4839 HeapAlloc(GetProcessHeap(), 0, needed);
4841 /* Try again with the large Buffer */
4842 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
4844 needed = pcbNeeded ? *pcbNeeded : 0;
4845 numentries = pcReturned ? *pcReturned : 0;
4848 W2k require the buffersize from EnumPortsW also for EnumPortsA.
4849 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
4852 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
4853 DWORD entrysize = 0;
4856 LPPORT_INFO_2W pi2w;
4857 LPPORT_INFO_2A pi2a;
4860 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
4862 /* First pass: calculate the size for all Entries */
4863 pi2w = (LPPORT_INFO_2W) bufferW;
4864 pi2a = (LPPORT_INFO_2A) pPorts;
4866 while (index < numentries) {
4868 needed += entrysize; /* PORT_INFO_?A */
4869 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
4871 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4872 NULL, 0, NULL, NULL);
4874 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4875 NULL, 0, NULL, NULL);
4876 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4877 NULL, 0, NULL, NULL);
4879 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4880 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4881 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4884 /* check for errors and quit on failure */
4885 if (cbBuf < needed) {
4886 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4890 len = entrysize * numentries; /* room for all PORT_INFO_?A */
4891 ptr = (LPSTR) &pPorts[len]; /* room for strings */
4892 cbBuf -= len ; /* free Bytes in the user-Buffer */
4893 pi2w = (LPPORT_INFO_2W) bufferW;
4894 pi2a = (LPPORT_INFO_2A) pPorts;
4896 /* Second Pass: Fill the User Buffer (if we have one) */
4897 while ((index < numentries) && pPorts) {
4899 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
4900 pi2a->pPortName = ptr;
4901 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
4902 ptr, cbBuf , NULL, NULL);
4906 pi2a->pMonitorName = ptr;
4907 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
4908 ptr, cbBuf, NULL, NULL);
4912 pi2a->pDescription = ptr;
4913 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
4914 ptr, cbBuf, NULL, NULL);
4918 pi2a->fPortType = pi2w->fPortType;
4919 pi2a->Reserved = 0; /* documented: "must be zero" */
4922 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
4923 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
4924 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
4929 if (pcbNeeded) *pcbNeeded = needed;
4930 if (pcReturned) *pcReturned = (res) ? numentries : 0;
4932 HeapFree(GetProcessHeap(), 0, nameW);
4933 HeapFree(GetProcessHeap(), 0, bufferW);
4935 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
4936 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
4942 /******************************************************************************
4943 * EnumPortsW (WINSPOOL.@)
4945 * Enumerate available Ports
4948 * pName [I] Servername or NULL (local Computer)
4949 * Level [I] Structure-Level (1 or 2)
4950 * pPorts [O] PTR to Buffer that receives the Result
4951 * cbBuf [I] Size of Buffer at pPorts
4952 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
4953 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
4957 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
4960 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4963 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
4964 cbBuf, pcbNeeded, pcReturned);
4966 if ((backend == NULL) && !load_backend()) return FALSE;
4968 /* Level is not checked in win9x */
4969 if (!Level || (Level > 2)) {
4970 WARN("level (%d) is ignored in win9x\n", Level);
4971 SetLastError(ERROR_INVALID_LEVEL);
4974 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
4975 SetLastError(RPC_X_NULL_REF_POINTER);
4979 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
4982 /******************************************************************************
4983 * GetDefaultPrinterW (WINSPOOL.@)
4986 * This function must read the value from data 'device' of key
4987 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4989 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4993 WCHAR *buffer, *ptr;
4997 SetLastError(ERROR_INVALID_PARAMETER);
5001 /* make the buffer big enough for the stuff from the profile/registry,
5002 * the content must fit into the local buffer to compute the correct
5003 * size even if the extern buffer is too small or not given.
5004 * (20 for ,driver,port) */
5006 len = max(100, (insize + 20));
5007 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5009 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5011 SetLastError (ERROR_FILE_NOT_FOUND);
5015 TRACE("%s\n", debugstr_w(buffer));
5017 if ((ptr = strchrW(buffer, ',')) == NULL)
5019 SetLastError(ERROR_INVALID_NAME);
5025 *namesize = strlenW(buffer) + 1;
5026 if(!name || (*namesize > insize))
5028 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5032 strcpyW(name, buffer);
5035 HeapFree( GetProcessHeap(), 0, buffer);
5040 /******************************************************************************
5041 * GetDefaultPrinterA (WINSPOOL.@)
5043 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5047 WCHAR *bufferW = NULL;
5051 SetLastError(ERROR_INVALID_PARAMETER);
5055 if(name && *namesize) {
5057 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5060 if(!GetDefaultPrinterW( bufferW, namesize)) {
5065 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5069 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5072 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5075 HeapFree( GetProcessHeap(), 0, bufferW);
5080 /******************************************************************************
5081 * SetDefaultPrinterW (WINSPOOL.204)
5083 * Set the Name of the Default Printer
5086 * pszPrinter [I] Name of the Printer or NULL
5093 * When the Parameter is NULL or points to an Empty String and
5094 * a Default Printer was already present, then this Function changes nothing.
5095 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5096 * the First enumerated local Printer is used.
5099 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5102 TRACE("(%s)\n", debugstr_w(pszPrinter));
5104 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5108 /******************************************************************************
5109 * SetDefaultPrinterA (WINSPOOL.202)
5111 * See SetDefaultPrinterW.
5114 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5117 TRACE("(%s)\n", debugstr_a(pszPrinter));
5119 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5124 /******************************************************************************
5125 * SetPrinterDataExA (WINSPOOL.@)
5127 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5128 LPCSTR pValueName, DWORD Type,
5129 LPBYTE pData, DWORD cbData)
5131 HKEY hkeyPrinter, hkeySubkey;
5134 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5135 debugstr_a(pValueName), Type, pData, cbData);
5137 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5141 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5143 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5144 RegCloseKey(hkeyPrinter);
5147 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5148 RegCloseKey(hkeySubkey);
5149 RegCloseKey(hkeyPrinter);
5153 /******************************************************************************
5154 * SetPrinterDataExW (WINSPOOL.@)
5156 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5157 LPCWSTR pValueName, DWORD Type,
5158 LPBYTE pData, DWORD cbData)
5160 HKEY hkeyPrinter, hkeySubkey;
5163 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5164 debugstr_w(pValueName), Type, pData, cbData);
5166 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5170 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5172 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5173 RegCloseKey(hkeyPrinter);
5176 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5177 RegCloseKey(hkeySubkey);
5178 RegCloseKey(hkeyPrinter);
5182 /******************************************************************************
5183 * SetPrinterDataA (WINSPOOL.@)
5185 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5186 LPBYTE pData, DWORD cbData)
5188 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5192 /******************************************************************************
5193 * SetPrinterDataW (WINSPOOL.@)
5195 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5196 LPBYTE pData, DWORD cbData)
5198 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5202 /******************************************************************************
5203 * GetPrinterDataExA (WINSPOOL.@)
5205 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5206 LPCSTR pValueName, LPDWORD pType,
5207 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5209 HKEY hkeyPrinter, hkeySubkey;
5212 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5213 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5216 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5220 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5222 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5223 RegCloseKey(hkeyPrinter);
5227 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5228 RegCloseKey(hkeySubkey);
5229 RegCloseKey(hkeyPrinter);
5233 /******************************************************************************
5234 * GetPrinterDataExW (WINSPOOL.@)
5236 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5237 LPCWSTR pValueName, LPDWORD pType,
5238 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5240 HKEY hkeyPrinter, hkeySubkey;
5243 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5244 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5247 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5251 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5253 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5254 RegCloseKey(hkeyPrinter);
5258 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5259 RegCloseKey(hkeySubkey);
5260 RegCloseKey(hkeyPrinter);
5264 /******************************************************************************
5265 * GetPrinterDataA (WINSPOOL.@)
5267 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5268 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5270 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5271 pData, nSize, pcbNeeded);
5274 /******************************************************************************
5275 * GetPrinterDataW (WINSPOOL.@)
5277 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5278 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5280 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5281 pData, nSize, pcbNeeded);
5284 /*******************************************************************************
5285 * EnumPrinterDataExW [WINSPOOL.@]
5287 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5288 LPBYTE pEnumValues, DWORD cbEnumValues,
5289 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5291 HKEY hkPrinter, hkSubKey;
5292 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5293 cbValueNameLen, cbMaxValueLen, cbValueLen,
5298 PPRINTER_ENUM_VALUESW ppev;
5300 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5302 if (pKeyName == NULL || *pKeyName == 0)
5303 return ERROR_INVALID_PARAMETER;
5305 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5306 if (ret != ERROR_SUCCESS)
5308 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5313 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5314 if (ret != ERROR_SUCCESS)
5316 r = RegCloseKey (hkPrinter);
5317 if (r != ERROR_SUCCESS)
5318 WARN ("RegCloseKey returned %i\n", r);
5319 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5320 debugstr_w (pKeyName), ret);
5324 ret = RegCloseKey (hkPrinter);
5325 if (ret != ERROR_SUCCESS)
5327 ERR ("RegCloseKey returned %i\n", ret);
5328 r = RegCloseKey (hkSubKey);
5329 if (r != ERROR_SUCCESS)
5330 WARN ("RegCloseKey returned %i\n", r);
5334 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5335 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5336 if (ret != ERROR_SUCCESS)
5338 r = RegCloseKey (hkSubKey);
5339 if (r != ERROR_SUCCESS)
5340 WARN ("RegCloseKey returned %i\n", r);
5341 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5345 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5346 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5348 if (cValues == 0) /* empty key */
5350 r = RegCloseKey (hkSubKey);
5351 if (r != ERROR_SUCCESS)
5352 WARN ("RegCloseKey returned %i\n", r);
5353 *pcbEnumValues = *pnEnumValues = 0;
5354 return ERROR_SUCCESS;
5357 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5359 hHeap = GetProcessHeap ();
5362 ERR ("GetProcessHeap failed\n");
5363 r = RegCloseKey (hkSubKey);
5364 if (r != ERROR_SUCCESS)
5365 WARN ("RegCloseKey returned %i\n", r);
5366 return ERROR_OUTOFMEMORY;
5369 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5370 if (lpValueName == NULL)
5372 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5373 r = RegCloseKey (hkSubKey);
5374 if (r != ERROR_SUCCESS)
5375 WARN ("RegCloseKey returned %i\n", r);
5376 return ERROR_OUTOFMEMORY;
5379 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5380 if (lpValue == NULL)
5382 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5383 if (HeapFree (hHeap, 0, lpValueName) == 0)
5384 WARN ("HeapFree failed with code %i\n", GetLastError ());
5385 r = RegCloseKey (hkSubKey);
5386 if (r != ERROR_SUCCESS)
5387 WARN ("RegCloseKey returned %i\n", r);
5388 return ERROR_OUTOFMEMORY;
5391 TRACE ("pass 1: calculating buffer required for all names and values\n");
5393 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5395 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5397 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5399 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5400 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5401 NULL, NULL, lpValue, &cbValueLen);
5402 if (ret != ERROR_SUCCESS)
5404 if (HeapFree (hHeap, 0, lpValue) == 0)
5405 WARN ("HeapFree failed with code %i\n", GetLastError ());
5406 if (HeapFree (hHeap, 0, lpValueName) == 0)
5407 WARN ("HeapFree failed with code %i\n", GetLastError ());
5408 r = RegCloseKey (hkSubKey);
5409 if (r != ERROR_SUCCESS)
5410 WARN ("RegCloseKey returned %i\n", r);
5411 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5415 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5416 debugstr_w (lpValueName), dwIndex,
5417 cbValueNameLen + 1, cbValueLen);
5419 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5420 cbBufSize += cbValueLen;
5423 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5425 *pcbEnumValues = cbBufSize;
5426 *pnEnumValues = cValues;
5428 if (cbEnumValues < cbBufSize) /* buffer too small */
5430 if (HeapFree (hHeap, 0, lpValue) == 0)
5431 WARN ("HeapFree failed with code %i\n", GetLastError ());
5432 if (HeapFree (hHeap, 0, lpValueName) == 0)
5433 WARN ("HeapFree failed with code %i\n", GetLastError ());
5434 r = RegCloseKey (hkSubKey);
5435 if (r != ERROR_SUCCESS)
5436 WARN ("RegCloseKey returned %i\n", r);
5437 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5438 return ERROR_MORE_DATA;
5441 TRACE ("pass 2: copying all names and values to buffer\n");
5443 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5444 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5446 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5448 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5449 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5450 NULL, &dwType, lpValue, &cbValueLen);
5451 if (ret != ERROR_SUCCESS)
5453 if (HeapFree (hHeap, 0, lpValue) == 0)
5454 WARN ("HeapFree failed with code %i\n", GetLastError ());
5455 if (HeapFree (hHeap, 0, lpValueName) == 0)
5456 WARN ("HeapFree failed with code %i\n", GetLastError ());
5457 r = RegCloseKey (hkSubKey);
5458 if (r != ERROR_SUCCESS)
5459 WARN ("RegCloseKey returned %i\n", r);
5460 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5464 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5465 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5466 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5467 pEnumValues += cbValueNameLen;
5469 /* return # of *bytes* (including trailing \0), not # of chars */
5470 ppev[dwIndex].cbValueName = cbValueNameLen;
5472 ppev[dwIndex].dwType = dwType;
5474 memcpy (pEnumValues, lpValue, cbValueLen);
5475 ppev[dwIndex].pData = pEnumValues;
5476 pEnumValues += cbValueLen;
5478 ppev[dwIndex].cbData = cbValueLen;
5480 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5481 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5484 if (HeapFree (hHeap, 0, lpValue) == 0)
5486 ret = GetLastError ();
5487 ERR ("HeapFree failed with code %i\n", ret);
5488 if (HeapFree (hHeap, 0, lpValueName) == 0)
5489 WARN ("HeapFree failed with code %i\n", GetLastError ());
5490 r = RegCloseKey (hkSubKey);
5491 if (r != ERROR_SUCCESS)
5492 WARN ("RegCloseKey returned %i\n", r);
5496 if (HeapFree (hHeap, 0, lpValueName) == 0)
5498 ret = GetLastError ();
5499 ERR ("HeapFree failed with code %i\n", ret);
5500 r = RegCloseKey (hkSubKey);
5501 if (r != ERROR_SUCCESS)
5502 WARN ("RegCloseKey returned %i\n", r);
5506 ret = RegCloseKey (hkSubKey);
5507 if (ret != ERROR_SUCCESS)
5509 ERR ("RegCloseKey returned %i\n", ret);
5513 return ERROR_SUCCESS;
5516 /*******************************************************************************
5517 * EnumPrinterDataExA [WINSPOOL.@]
5519 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5520 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5521 * what Windows 2000 SP1 does.
5524 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5525 LPBYTE pEnumValues, DWORD cbEnumValues,
5526 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5530 DWORD ret, dwIndex, dwBufSize;
5534 TRACE ("%p %s\n", hPrinter, pKeyName);
5536 if (pKeyName == NULL || *pKeyName == 0)
5537 return ERROR_INVALID_PARAMETER;
5539 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5542 ret = GetLastError ();
5543 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5547 hHeap = GetProcessHeap ();
5550 ERR ("GetProcessHeap failed\n");
5551 return ERROR_OUTOFMEMORY;
5554 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5555 if (pKeyNameW == NULL)
5557 ERR ("Failed to allocate %i bytes from process heap\n",
5558 (LONG)(len * sizeof (WCHAR)));
5559 return ERROR_OUTOFMEMORY;
5562 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5564 ret = GetLastError ();
5565 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5566 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5567 WARN ("HeapFree failed with code %i\n", GetLastError ());
5571 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5572 pcbEnumValues, pnEnumValues);
5573 if (ret != ERROR_SUCCESS)
5575 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5576 WARN ("HeapFree failed with code %i\n", GetLastError ());
5577 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5581 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5583 ret = GetLastError ();
5584 ERR ("HeapFree failed with code %i\n", ret);
5588 if (*pnEnumValues == 0) /* empty key */
5589 return ERROR_SUCCESS;
5592 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5594 PPRINTER_ENUM_VALUESW ppev =
5595 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5597 if (dwBufSize < ppev->cbValueName)
5598 dwBufSize = ppev->cbValueName;
5600 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5601 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5602 dwBufSize = ppev->cbData;
5605 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5607 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5608 if (pBuffer == NULL)
5610 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5611 return ERROR_OUTOFMEMORY;
5614 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5616 PPRINTER_ENUM_VALUESW ppev =
5617 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5619 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5620 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5624 ret = GetLastError ();
5625 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5626 if (HeapFree (hHeap, 0, pBuffer) == 0)
5627 WARN ("HeapFree failed with code %i\n", GetLastError ());
5631 memcpy (ppev->pValueName, pBuffer, len);
5633 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5635 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5636 ppev->dwType != REG_MULTI_SZ)
5639 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5640 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5643 ret = GetLastError ();
5644 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5645 if (HeapFree (hHeap, 0, pBuffer) == 0)
5646 WARN ("HeapFree failed with code %i\n", GetLastError ());
5650 memcpy (ppev->pData, pBuffer, len);
5652 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5653 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5656 if (HeapFree (hHeap, 0, pBuffer) == 0)
5658 ret = GetLastError ();
5659 ERR ("HeapFree failed with code %i\n", ret);
5663 return ERROR_SUCCESS;
5666 /******************************************************************************
5667 * AbortPrinter (WINSPOOL.@)
5669 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5671 FIXME("(%p), stub!\n", hPrinter);
5675 /******************************************************************************
5676 * AddPortA (WINSPOOL.@)
5681 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5683 LPWSTR nameW = NULL;
5684 LPWSTR monitorW = NULL;
5688 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5691 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5692 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5693 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5697 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5698 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5699 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5701 res = AddPortW(nameW, hWnd, monitorW);
5702 HeapFree(GetProcessHeap(), 0, nameW);
5703 HeapFree(GetProcessHeap(), 0, monitorW);
5707 /******************************************************************************
5708 * AddPortW (WINSPOOL.@)
5710 * Add a Port for a specific Monitor
5713 * pName [I] Servername or NULL (local Computer)
5714 * hWnd [I] Handle to parent Window for the Dialog-Box
5715 * pMonitorName [I] Name of the Monitor that manage the Port
5722 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5724 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5726 if ((backend == NULL) && !load_backend()) return FALSE;
5728 if (!pMonitorName) {
5729 SetLastError(RPC_X_NULL_REF_POINTER);
5733 return backend->fpAddPort(pName, hWnd, pMonitorName);
5736 /******************************************************************************
5737 * AddPortExA (WINSPOOL.@)
5742 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
5745 PORT_INFO_2A * pi2A;
5746 LPWSTR nameW = NULL;
5747 LPWSTR monitorW = NULL;
5751 pi2A = (PORT_INFO_2A *) pBuffer;
5753 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
5754 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
5756 if ((level < 1) || (level > 2)) {
5757 SetLastError(ERROR_INVALID_LEVEL);
5762 SetLastError(ERROR_INVALID_PARAMETER);
5767 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5768 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5769 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5773 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5774 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5775 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5778 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
5780 if (pi2A->pPortName) {
5781 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
5782 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5783 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
5787 if (pi2A->pMonitorName) {
5788 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
5789 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5790 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
5793 if (pi2A->pDescription) {
5794 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
5795 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5796 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
5798 pi2W.fPortType = pi2A->fPortType;
5799 pi2W.Reserved = pi2A->Reserved;
5802 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
5804 HeapFree(GetProcessHeap(), 0, nameW);
5805 HeapFree(GetProcessHeap(), 0, monitorW);
5806 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
5807 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
5808 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
5813 /******************************************************************************
5814 * AddPortExW (WINSPOOL.@)
5816 * Add a Port for a specific Monitor, without presenting a user interface
5819 * pName [I] Servername or NULL (local Computer)
5820 * level [I] Structure-Level (1 or 2) for pBuffer
5821 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5822 * pMonitorName [I] Name of the Monitor that manage the Port
5829 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
5833 pi2 = (PORT_INFO_2W *) pBuffer;
5835 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
5836 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
5837 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
5838 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
5840 if ((backend == NULL) && !load_backend()) return FALSE;
5842 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
5843 SetLastError(ERROR_INVALID_PARAMETER);
5847 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
5850 /******************************************************************************
5851 * AddPrinterConnectionA (WINSPOOL.@)
5853 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5855 FIXME("%s\n", debugstr_a(pName));
5859 /******************************************************************************
5860 * AddPrinterConnectionW (WINSPOOL.@)
5862 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5864 FIXME("%s\n", debugstr_w(pName));
5868 /******************************************************************************
5869 * AddPrinterDriverExW (WINSPOOL.@)
5871 * Install a Printer Driver with the Option to upgrade / downgrade the Files
5874 * pName [I] Servername or NULL (local Computer)
5875 * level [I] Level for the supplied DRIVER_INFO_*W struct
5876 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5877 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
5884 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5886 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
5888 if ((backend == NULL) && !load_backend()) return FALSE;
5890 if (level < 2 || level == 5 || level == 7 || level > 8) {
5891 SetLastError(ERROR_INVALID_LEVEL);
5896 SetLastError(ERROR_INVALID_PARAMETER);
5900 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
5903 /******************************************************************************
5904 * AddPrinterDriverExA (WINSPOOL.@)
5906 * See AddPrinterDriverExW.
5909 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5911 DRIVER_INFO_8A *diA;
5913 LPWSTR nameW = NULL;
5918 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
5920 diA = (DRIVER_INFO_8A *) pDriverInfo;
5921 ZeroMemory(&diW, sizeof(diW));
5923 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
5924 SetLastError(ERROR_INVALID_LEVEL);
5929 SetLastError(ERROR_INVALID_PARAMETER);
5933 /* convert servername to unicode */
5935 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5936 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5937 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5941 diW.cVersion = diA->cVersion;
5944 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
5945 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5946 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
5949 if (diA->pEnvironment) {
5950 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
5951 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5952 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
5955 if (diA->pDriverPath) {
5956 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
5957 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5958 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
5961 if (diA->pDataFile) {
5962 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
5963 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5964 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
5967 if (diA->pConfigFile) {
5968 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
5969 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5970 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
5973 if ((Level > 2) && diA->pDependentFiles) {
5974 lenA = multi_sz_lenA(diA->pDependentFiles);
5975 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
5976 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5977 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
5980 if ((Level > 2) && diA->pMonitorName) {
5981 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
5982 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5983 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
5986 if ((Level > 3) && diA->pDefaultDataType) {
5987 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
5988 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5989 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
5992 if ((Level > 3) && diA->pszzPreviousNames) {
5993 lenA = multi_sz_lenA(diA->pszzPreviousNames);
5994 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
5995 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5996 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
5999 if ((Level > 5) && diA->pszMfgName) {
6000 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6001 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6002 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6005 if ((Level > 5) && diA->pszOEMUrl) {
6006 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6007 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6008 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6011 if ((Level > 5) && diA->pszHardwareID) {
6012 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6013 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6014 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6017 if ((Level > 5) && diA->pszProvider) {
6018 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6019 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6020 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6024 FIXME("level %u is incomplete\n", Level);
6027 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6028 TRACE("got %u with %u\n", res, GetLastError());
6029 HeapFree(GetProcessHeap(), 0, nameW);
6030 HeapFree(GetProcessHeap(), 0, diW.pName);
6031 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6032 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6033 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6034 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6035 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6036 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6037 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6038 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6039 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6040 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6041 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6042 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6044 TRACE("=> %u with %u\n", res, GetLastError());
6048 /******************************************************************************
6049 * ConfigurePortA (WINSPOOL.@)
6051 * See ConfigurePortW.
6054 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6056 LPWSTR nameW = NULL;
6057 LPWSTR portW = NULL;
6061 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6063 /* convert servername to unicode */
6065 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6066 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6067 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6070 /* convert portname to unicode */
6072 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6073 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6074 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6077 res = ConfigurePortW(nameW, hWnd, portW);
6078 HeapFree(GetProcessHeap(), 0, nameW);
6079 HeapFree(GetProcessHeap(), 0, portW);
6083 /******************************************************************************
6084 * ConfigurePortW (WINSPOOL.@)
6086 * Display the Configuration-Dialog for a specific Port
6089 * pName [I] Servername or NULL (local Computer)
6090 * hWnd [I] Handle to parent Window for the Dialog-Box
6091 * pPortName [I] Name of the Port, that should be configured
6098 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6101 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6103 if ((backend == NULL) && !load_backend()) return FALSE;
6106 SetLastError(RPC_X_NULL_REF_POINTER);
6110 return backend->fpConfigurePort(pName, hWnd, pPortName);
6113 /******************************************************************************
6114 * ConnectToPrinterDlg (WINSPOOL.@)
6116 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6118 FIXME("%p %x\n", hWnd, Flags);
6122 /******************************************************************************
6123 * DeletePrinterConnectionA (WINSPOOL.@)
6125 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6127 FIXME("%s\n", debugstr_a(pName));
6131 /******************************************************************************
6132 * DeletePrinterConnectionW (WINSPOOL.@)
6134 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6136 FIXME("%s\n", debugstr_w(pName));
6140 /******************************************************************************
6141 * DeletePrinterDriverExW (WINSPOOL.@)
6143 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6144 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6149 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6150 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6152 if(pName && pName[0])
6154 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6155 SetLastError(ERROR_INVALID_PARAMETER);
6161 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6162 SetLastError(ERROR_INVALID_PARAMETER);
6166 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6170 ERR("Can't open drivers key\n");
6174 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6177 RegCloseKey(hkey_drivers);
6182 /******************************************************************************
6183 * DeletePrinterDriverExA (WINSPOOL.@)
6185 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6186 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6188 UNICODE_STRING NameW, EnvW, DriverW;
6191 asciitounicode(&NameW, pName);
6192 asciitounicode(&EnvW, pEnvironment);
6193 asciitounicode(&DriverW, pDriverName);
6195 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6197 RtlFreeUnicodeString(&DriverW);
6198 RtlFreeUnicodeString(&EnvW);
6199 RtlFreeUnicodeString(&NameW);
6204 /******************************************************************************
6205 * DeletePrinterDataExW (WINSPOOL.@)
6207 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6210 FIXME("%p %s %s\n", hPrinter,
6211 debugstr_w(pKeyName), debugstr_w(pValueName));
6212 return ERROR_INVALID_PARAMETER;
6215 /******************************************************************************
6216 * DeletePrinterDataExA (WINSPOOL.@)
6218 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6221 FIXME("%p %s %s\n", hPrinter,
6222 debugstr_a(pKeyName), debugstr_a(pValueName));
6223 return ERROR_INVALID_PARAMETER;
6226 /******************************************************************************
6227 * DeletePrintProcessorA (WINSPOOL.@)
6229 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6231 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6232 debugstr_a(pPrintProcessorName));
6236 /******************************************************************************
6237 * DeletePrintProcessorW (WINSPOOL.@)
6239 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6241 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6242 debugstr_w(pPrintProcessorName));
6246 /******************************************************************************
6247 * DeletePrintProvidorA (WINSPOOL.@)
6249 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6251 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6252 debugstr_a(pPrintProviderName));
6256 /******************************************************************************
6257 * DeletePrintProvidorW (WINSPOOL.@)
6259 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6261 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6262 debugstr_w(pPrintProviderName));
6266 /******************************************************************************
6267 * EnumFormsA (WINSPOOL.@)
6269 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6270 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6272 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6273 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6277 /******************************************************************************
6278 * EnumFormsW (WINSPOOL.@)
6280 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6281 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6283 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6284 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6288 /*****************************************************************************
6289 * EnumMonitorsA [WINSPOOL.@]
6291 * See EnumMonitorsW.
6294 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6295 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6298 LPBYTE bufferW = NULL;
6299 LPWSTR nameW = NULL;
6301 DWORD numentries = 0;
6304 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6305 cbBuf, pcbNeeded, pcReturned);
6307 /* convert servername to unicode */
6309 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6310 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6311 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6313 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6314 needed = cbBuf * sizeof(WCHAR);
6315 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6316 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6318 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6319 if (pcbNeeded) needed = *pcbNeeded;
6320 /* HeapReAlloc return NULL, when bufferW was NULL */
6321 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6322 HeapAlloc(GetProcessHeap(), 0, needed);
6324 /* Try again with the large Buffer */
6325 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6327 numentries = pcReturned ? *pcReturned : 0;
6330 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6331 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6334 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6335 DWORD entrysize = 0;
6338 LPMONITOR_INFO_2W mi2w;
6339 LPMONITOR_INFO_2A mi2a;
6341 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6342 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6344 /* First pass: calculate the size for all Entries */
6345 mi2w = (LPMONITOR_INFO_2W) bufferW;
6346 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6348 while (index < numentries) {
6350 needed += entrysize; /* MONITOR_INFO_?A */
6351 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6353 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6354 NULL, 0, NULL, NULL);
6356 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6357 NULL, 0, NULL, NULL);
6358 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6359 NULL, 0, NULL, NULL);
6361 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6362 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6363 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6366 /* check for errors and quit on failure */
6367 if (cbBuf < needed) {
6368 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6372 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6373 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6374 cbBuf -= len ; /* free Bytes in the user-Buffer */
6375 mi2w = (LPMONITOR_INFO_2W) bufferW;
6376 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6378 /* Second Pass: Fill the User Buffer (if we have one) */
6379 while ((index < numentries) && pMonitors) {
6381 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6383 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6384 ptr, cbBuf , NULL, NULL);
6388 mi2a->pEnvironment = ptr;
6389 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6390 ptr, cbBuf, NULL, NULL);
6394 mi2a->pDLLName = ptr;
6395 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6396 ptr, cbBuf, NULL, NULL);
6400 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6401 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6402 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6406 if (pcbNeeded) *pcbNeeded = needed;
6407 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6409 HeapFree(GetProcessHeap(), 0, nameW);
6410 HeapFree(GetProcessHeap(), 0, bufferW);
6412 TRACE("returning %d with %d (%d byte for %d entries)\n",
6413 (res), GetLastError(), needed, numentries);
6419 /*****************************************************************************
6420 * EnumMonitorsW [WINSPOOL.@]
6422 * Enumerate available Port-Monitors
6425 * pName [I] Servername or NULL (local Computer)
6426 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6427 * pMonitors [O] PTR to Buffer that receives the Result
6428 * cbBuf [I] Size of Buffer at pMonitors
6429 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6430 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6434 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6437 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6438 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6441 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6442 cbBuf, pcbNeeded, pcReturned);
6444 if ((backend == NULL) && !load_backend()) return FALSE;
6446 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6447 SetLastError(RPC_X_NULL_REF_POINTER);
6451 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6454 /******************************************************************************
6455 * SpoolerInit (WINSPOOL.@)
6457 * Initialize the Spooler
6464 * The function fails on windows, when the spooler service is not running
6467 BOOL WINAPI SpoolerInit(void)
6470 if ((backend == NULL) && !load_backend()) return FALSE;
6474 /******************************************************************************
6475 * XcvDataW (WINSPOOL.@)
6477 * Execute commands in the Printmonitor DLL
6480 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6481 * pszDataName [i] Name of the command to execute
6482 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6483 * cbInputData [i] Size in Bytes of Buffer at pInputData
6484 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6485 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6486 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6487 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6494 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6495 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6497 * Minimal List of commands, that a Printmonitor DLL should support:
6499 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6500 *| "AddPort" : Add a Port
6501 *| "DeletePort": Delete a Port
6503 * Many Printmonitors support additional commands. Examples for localspl.dll:
6504 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6505 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6508 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6509 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6510 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6512 opened_printer_t *printer;
6514 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6515 pInputData, cbInputData, pOutputData,
6516 cbOutputData, pcbOutputNeeded, pdwStatus);
6518 if ((backend == NULL) && !load_backend()) return FALSE;
6520 printer = get_opened_printer(hXcv);
6521 if (!printer || (!printer->backend_printer)) {
6522 SetLastError(ERROR_INVALID_HANDLE);
6526 if (!pcbOutputNeeded) {
6527 SetLastError(ERROR_INVALID_PARAMETER);
6531 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6532 SetLastError(RPC_X_NULL_REF_POINTER);
6536 *pcbOutputNeeded = 0;
6538 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6539 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6543 /*****************************************************************************
6544 * EnumPrinterDataA [WINSPOOL.@]
6547 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6548 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6549 DWORD cbData, LPDWORD pcbData )
6551 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6552 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6553 return ERROR_NO_MORE_ITEMS;
6556 /*****************************************************************************
6557 * EnumPrinterDataW [WINSPOOL.@]
6560 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6561 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6562 DWORD cbData, LPDWORD pcbData )
6564 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6565 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6566 return ERROR_NO_MORE_ITEMS;
6569 /*****************************************************************************
6570 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6573 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6574 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6575 LPDWORD pcbNeeded, LPDWORD pcReturned)
6577 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6578 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6579 pcbNeeded, pcReturned);
6583 /*****************************************************************************
6584 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6587 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6588 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6589 LPDWORD pcbNeeded, LPDWORD pcReturned)
6591 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6592 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6593 pcbNeeded, pcReturned);
6597 /*****************************************************************************
6598 * EnumPrintProcessorsA [WINSPOOL.@]
6600 * See EnumPrintProcessorsW.
6603 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6604 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6607 LPBYTE bufferW = NULL;
6608 LPWSTR nameW = NULL;
6611 DWORD numentries = 0;
6614 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
6615 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6617 /* convert names to unicode */
6619 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6620 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6621 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6624 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
6625 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6626 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
6629 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6630 needed = cbBuf * sizeof(WCHAR);
6631 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6632 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6634 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6635 if (pcbNeeded) needed = *pcbNeeded;
6636 /* HeapReAlloc return NULL, when bufferW was NULL */
6637 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6638 HeapAlloc(GetProcessHeap(), 0, needed);
6640 /* Try again with the large Buffer */
6641 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
6643 numentries = pcReturned ? *pcReturned : 0;
6647 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
6650 PPRINTPROCESSOR_INFO_1W ppiw;
6651 PPRINTPROCESSOR_INFO_1A ppia;
6653 /* First pass: calculate the size for all Entries */
6654 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6655 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6657 while (index < numentries) {
6659 needed += sizeof(PRINTPROCESSOR_INFO_1A);
6660 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
6662 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6663 NULL, 0, NULL, NULL);
6665 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6666 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6669 /* check for errors and quit on failure */
6670 if (cbBuf < needed) {
6671 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6676 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
6677 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
6678 cbBuf -= len ; /* free Bytes in the user-Buffer */
6679 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
6680 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
6682 /* Second Pass: Fill the User Buffer (if we have one) */
6683 while ((index < numentries) && pPPInfo) {
6685 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
6687 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
6688 ptr, cbBuf , NULL, NULL);
6692 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
6693 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
6698 if (pcbNeeded) *pcbNeeded = needed;
6699 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6701 HeapFree(GetProcessHeap(), 0, nameW);
6702 HeapFree(GetProcessHeap(), 0, envW);
6703 HeapFree(GetProcessHeap(), 0, bufferW);
6705 TRACE("returning %d with %d (%d byte for %d entries)\n",
6706 (res), GetLastError(), needed, numentries);
6711 /*****************************************************************************
6712 * EnumPrintProcessorsW [WINSPOOL.@]
6714 * Enumerate available Print Processors
6717 * pName [I] Servername or NULL (local Computer)
6718 * pEnvironment [I] Printing-Environment or NULL (Default)
6719 * Level [I] Structure-Level (Only 1 is allowed)
6720 * pPPInfo [O] PTR to Buffer that receives the Result
6721 * cbBuf [I] Size of Buffer at pPPInfo
6722 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
6723 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
6727 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
6730 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6731 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6734 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
6735 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
6737 if ((backend == NULL) && !load_backend()) return FALSE;
6739 if (!pcbNeeded || !pcReturned) {
6740 SetLastError(RPC_X_NULL_REF_POINTER);
6744 if (!pPPInfo && (cbBuf > 0)) {
6745 SetLastError(ERROR_INVALID_USER_BUFFER);
6749 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
6750 cbBuf, pcbNeeded, pcReturned);
6753 /*****************************************************************************
6754 * ExtDeviceMode [WINSPOOL.@]
6757 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6758 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6761 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6762 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6763 debugstr_a(pProfile), fMode);
6767 /*****************************************************************************
6768 * FindClosePrinterChangeNotification [WINSPOOL.@]
6771 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6773 FIXME("Stub: %p\n", hChange);
6777 /*****************************************************************************
6778 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6781 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6782 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6784 FIXME("Stub: %p %x %x %p\n",
6785 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6786 return INVALID_HANDLE_VALUE;
6789 /*****************************************************************************
6790 * FindNextPrinterChangeNotification [WINSPOOL.@]
6793 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6794 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6796 FIXME("Stub: %p %p %p %p\n",
6797 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6801 /*****************************************************************************
6802 * FreePrinterNotifyInfo [WINSPOOL.@]
6805 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6807 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6811 /*****************************************************************************
6814 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6815 * ansi depending on the unicode parameter.
6817 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6827 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6830 memcpy(ptr, str, *size);
6837 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6840 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6847 /*****************************************************************************
6850 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6851 LPDWORD pcbNeeded, BOOL unicode)
6853 DWORD size, left = cbBuf;
6854 BOOL space = (cbBuf > 0);
6861 ji1->JobId = job->job_id;
6864 string_to_buf(job->document_title, ptr, left, &size, unicode);
6865 if(space && size <= left)
6867 ji1->pDocument = (LPWSTR)ptr;
6878 /*****************************************************************************
6881 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6882 LPDWORD pcbNeeded, BOOL unicode)
6884 DWORD size, left = cbBuf;
6885 BOOL space = (cbBuf > 0);
6892 ji2->JobId = job->job_id;
6895 string_to_buf(job->document_title, ptr, left, &size, unicode);
6896 if(space && size <= left)
6898 ji2->pDocument = (LPWSTR)ptr;
6909 /*****************************************************************************
6912 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6913 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6916 DWORD needed = 0, size;
6920 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6922 EnterCriticalSection(&printer_handles_cs);
6923 job = get_job(hPrinter, JobId);
6930 size = sizeof(JOB_INFO_1W);
6935 memset(pJob, 0, size);
6939 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6944 size = sizeof(JOB_INFO_2W);
6949 memset(pJob, 0, size);
6953 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6958 size = sizeof(JOB_INFO_3);
6962 memset(pJob, 0, size);
6971 SetLastError(ERROR_INVALID_LEVEL);
6975 *pcbNeeded = needed;
6977 LeaveCriticalSection(&printer_handles_cs);
6981 /*****************************************************************************
6982 * GetJobA [WINSPOOL.@]
6985 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6986 DWORD cbBuf, LPDWORD pcbNeeded)
6988 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6991 /*****************************************************************************
6992 * GetJobW [WINSPOOL.@]
6995 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6996 DWORD cbBuf, LPDWORD pcbNeeded)
6998 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7001 /*****************************************************************************
7004 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7006 char *unixname, *queue, *cmd;
7007 char fmt[] = "lpr -P%s %s";
7011 if(!(unixname = wine_get_unix_file_name(filename)))
7014 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7015 queue = HeapAlloc(GetProcessHeap(), 0, len);
7016 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7018 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7019 sprintf(cmd, fmt, queue, unixname);
7021 TRACE("printing with: %s\n", cmd);
7024 HeapFree(GetProcessHeap(), 0, cmd);
7025 HeapFree(GetProcessHeap(), 0, queue);
7026 HeapFree(GetProcessHeap(), 0, unixname);
7030 /*****************************************************************************
7033 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7035 #ifdef SONAME_LIBCUPS
7038 char *unixname, *queue, *unix_doc_title;
7042 if(!(unixname = wine_get_unix_file_name(filename)))
7045 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7046 queue = HeapAlloc(GetProcessHeap(), 0, len);
7047 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7049 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7050 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7051 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7053 TRACE("printing via cups\n");
7054 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7055 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7056 HeapFree(GetProcessHeap(), 0, queue);
7057 HeapFree(GetProcessHeap(), 0, unixname);
7063 return schedule_lpr(printer_name, filename);
7067 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7074 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7078 if(HIWORD(wparam) == BN_CLICKED)
7080 if(LOWORD(wparam) == IDOK)
7083 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7086 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7087 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7089 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7091 WCHAR caption[200], message[200];
7094 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7095 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7096 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7097 if(mb_ret == IDCANCEL)
7099 HeapFree(GetProcessHeap(), 0, filename);
7103 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7104 if(hf == INVALID_HANDLE_VALUE)
7106 WCHAR caption[200], message[200];
7108 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7109 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7110 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7111 HeapFree(GetProcessHeap(), 0, filename);
7115 DeleteFileW(filename);
7116 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7118 EndDialog(hwnd, IDOK);
7121 if(LOWORD(wparam) == IDCANCEL)
7123 EndDialog(hwnd, IDCANCEL);
7132 /*****************************************************************************
7135 static BOOL get_filename(LPWSTR *filename)
7137 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7138 file_dlg_proc, (LPARAM)filename) == IDOK;
7141 /*****************************************************************************
7144 static BOOL schedule_file(LPCWSTR filename)
7146 LPWSTR output = NULL;
7148 if(get_filename(&output))
7151 TRACE("copy to %s\n", debugstr_w(output));
7152 r = CopyFileW(filename, output, FALSE);
7153 HeapFree(GetProcessHeap(), 0, output);
7159 /*****************************************************************************
7162 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7165 char *unixname, *cmdA;
7167 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7171 if(!(unixname = wine_get_unix_file_name(filename)))
7174 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7175 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7176 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7178 TRACE("printing with: %s\n", cmdA);
7180 if((file_fd = open(unixname, O_RDONLY)) == -1)
7185 ERR("pipe() failed!\n");
7195 /* reset signals that we previously set to SIG_IGN */
7196 signal(SIGPIPE, SIG_DFL);
7197 signal(SIGCHLD, SIG_DFL);
7199 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7203 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7204 write(fds[1], buf, no_read);
7209 if(file_fd != -1) close(file_fd);
7210 if(fds[0] != -1) close(fds[0]);
7211 if(fds[1] != -1) close(fds[1]);
7213 HeapFree(GetProcessHeap(), 0, cmdA);
7214 HeapFree(GetProcessHeap(), 0, unixname);
7221 /*****************************************************************************
7224 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7226 int in_fd, out_fd, no_read;
7229 char *unixname, *outputA;
7232 if(!(unixname = wine_get_unix_file_name(filename)))
7235 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7236 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7237 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7239 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7240 in_fd = open(unixname, O_RDONLY);
7241 if(out_fd == -1 || in_fd == -1)
7244 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7245 write(out_fd, buf, no_read);
7249 if(in_fd != -1) close(in_fd);
7250 if(out_fd != -1) close(out_fd);
7251 HeapFree(GetProcessHeap(), 0, outputA);
7252 HeapFree(GetProcessHeap(), 0, unixname);
7256 /*****************************************************************************
7257 * ScheduleJob [WINSPOOL.@]
7260 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7262 opened_printer_t *printer;
7264 struct list *cursor, *cursor2;
7266 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7267 EnterCriticalSection(&printer_handles_cs);
7268 printer = get_opened_printer(hPrinter);
7272 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7274 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7277 if(job->job_id != dwJobID) continue;
7279 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7280 if(hf != INVALID_HANDLE_VALUE)
7282 PRINTER_INFO_5W *pi5;
7286 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7287 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7289 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7290 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7291 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7292 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7293 debugstr_w(pi5->pPortName));
7297 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7298 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7300 DWORD type, count = sizeof(output);
7301 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7304 if(output[0] == '|')
7306 ret = schedule_pipe(output + 1, job->filename);
7310 ret = schedule_unixfile(output, job->filename);
7312 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7314 ret = schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7316 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7318 ret = schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7320 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7322 ret = schedule_file(job->filename);
7326 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7328 HeapFree(GetProcessHeap(), 0, pi5);
7330 DeleteFileW(job->filename);
7332 list_remove(cursor);
7333 HeapFree(GetProcessHeap(), 0, job->document_title);
7334 HeapFree(GetProcessHeap(), 0, job->filename);
7335 HeapFree(GetProcessHeap(), 0, job);
7339 LeaveCriticalSection(&printer_handles_cs);
7343 /*****************************************************************************
7344 * StartDocDlgA [WINSPOOL.@]
7346 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7348 UNICODE_STRING usBuffer;
7351 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7354 docW.cbSize = sizeof(docW);
7355 if (doc->lpszDocName)
7357 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7358 if (!(docW.lpszDocName = docnameW)) return NULL;
7360 if (doc->lpszOutput)
7362 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7363 if (!(docW.lpszOutput = outputW)) return NULL;
7365 if (doc->lpszDatatype)
7367 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7368 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7370 docW.fwType = doc->fwType;
7372 retW = StartDocDlgW(hPrinter, &docW);
7376 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7377 ret = HeapAlloc(GetProcessHeap(), 0, len);
7378 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7379 HeapFree(GetProcessHeap(), 0, retW);
7382 HeapFree(GetProcessHeap(), 0, datatypeW);
7383 HeapFree(GetProcessHeap(), 0, outputW);
7384 HeapFree(GetProcessHeap(), 0, docnameW);
7389 /*****************************************************************************
7390 * StartDocDlgW [WINSPOOL.@]
7392 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7393 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7394 * port is "FILE:". Also returns the full path if passed a relative path.
7396 * The caller should free the returned string from the process heap.
7398 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7403 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7405 PRINTER_INFO_5W *pi5;
7406 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7407 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7409 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7410 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7411 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7413 HeapFree(GetProcessHeap(), 0, pi5);
7416 HeapFree(GetProcessHeap(), 0, pi5);
7419 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7423 if (get_filename(&name))
7425 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7427 HeapFree(GetProcessHeap(), 0, name);
7430 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7431 GetFullPathNameW(name, len, ret, NULL);
7432 HeapFree(GetProcessHeap(), 0, name);
7437 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7440 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7441 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7443 attr = GetFileAttributesW(ret);
7444 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7446 HeapFree(GetProcessHeap(), 0, ret);