4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005-2010 Detlef Riekenberg
10 * Copyright 2010 Vitaly Perov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
37 #ifdef HAVE_SYS_WAIT_H
44 #ifdef HAVE_CUPS_CUPS_H
45 # include <cups/cups.h>
48 #define NONAMELESSUNION
49 #define NONAMELESSSTRUCT
50 #include "wine/library.h"
59 #include "wine/windef16.h"
60 #include "wine/unicode.h"
61 #include "wine/debug.h"
62 #include "wine/list.h"
65 #include "ddk/winsplp.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
70 /* ############################### */
72 static CRITICAL_SECTION printer_handles_cs;
73 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
75 0, 0, &printer_handles_cs,
76 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
77 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
79 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
81 /* ############################### */
96 HANDLE backend_printer;
107 WCHAR *document_title;
117 LPCWSTR versionregpath;
118 LPCWSTR versionsubdir;
121 /* ############################### */
123 static opened_printer_t **printer_handles;
124 static UINT nb_printer_handles;
125 static LONG next_job_id = 1;
127 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
128 WORD fwCapability, LPSTR lpszOutput,
130 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
131 LPSTR lpszDevice, LPSTR lpszPort,
132 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
135 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
136 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
137 'c','o','n','t','r','o','l','\\',
138 'P','r','i','n','t','\\',
139 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
140 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
142 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
143 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
144 'C','o','n','t','r','o','l','\\',
145 'P','r','i','n','t','\\',
146 'P','r','i','n','t','e','r','s',0};
148 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
150 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'W','i','n','d','o','w','s',0};
156 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
157 'M','i','c','r','o','s','o','f','t','\\',
158 'W','i','n','d','o','w','s',' ','N','T','\\',
159 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
160 'D','e','v','i','c','e','s',0};
162 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
163 'M','i','c','r','o','s','o','f','t','\\',
164 'W','i','n','d','o','w','s',' ','N','T','\\',
165 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
166 'P','o','r','t','s',0};
168 static const WCHAR WinNT_CV_PrinterPortsW[] = { 'S','o','f','t','w','a','r','e','\\',
169 'M','i','c','r','o','s','o','f','t','\\',
170 'W','i','n','d','o','w','s',' ','N','T','\\',
171 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
172 'P','r','i','n','t','e','r','P','o','r','t','s',0};
174 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
175 static WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
176 static const WCHAR envname_x64W[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
177 static WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
178 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
179 static const WCHAR subdir_x64W[] = {'x','6','4',0};
180 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
181 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
182 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
183 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
184 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
186 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
187 static const WCHAR backslashW[] = {'\\',0};
188 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
189 'i','o','n',' ','F','i','l','e',0};
190 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
191 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
192 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
193 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
194 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
195 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
196 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
197 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
198 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
199 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
200 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
201 static const WCHAR NameW[] = {'N','a','m','e',0};
202 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
203 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
204 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
205 static const WCHAR PortW[] = {'P','o','r','t',0};
206 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
207 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
208 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
209 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
210 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
211 static const WCHAR PrinterPortsW[] = {'P','r','i','n','t','e','r','P','o','r','t','s',0};
212 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
213 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
214 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
215 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
216 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
217 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
218 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
219 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
220 static WCHAR generic_ppdW[] = {'g','e','n','e','r','i','c','.','p','p','d',0};
221 static WCHAR rawW[] = {'R','A','W',0};
222 static WCHAR driver_9x[] = {'w','i','n','e','p','s','1','6','.','d','r','v',0};
223 static WCHAR driver_nt[] = {'w','i','n','e','p','s','.','d','r','v',0};
224 static const WCHAR timeout_15_45[] = {',','1','5',',','4','5',0};
225 static const WCHAR commaW[] = {',',0};
226 static WCHAR emptyStringW[] = {0};
228 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
230 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
231 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
232 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
234 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
235 'D','o','c','u','m','e','n','t',0};
237 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
238 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
239 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
240 0, sizeof(DRIVER_INFO_8W)};
243 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
244 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
245 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
246 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
247 sizeof(PRINTER_INFO_9W)};
249 static const printenv_t env_x64 = {envname_x64W, subdir_x64W, 3, Version3_RegPathW, Version3_SubdirW};
250 static const printenv_t env_x86 = {envname_x86W, subdir_x86W, 3, Version3_RegPathW, Version3_SubdirW};
251 static const printenv_t env_win40 = {envname_win40W, subdir_win40W, 0, Version0_RegPathW, Version0_SubdirW};
253 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
255 /******************************************************************
256 * validate the user-supplied printing-environment [internal]
259 * env [I] PTR to Environment-String or NULL
263 * Success: PTR to printenv_t
266 * An empty string is handled the same way as NULL.
267 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
271 static const printenv_t * validate_envW(LPCWSTR env)
273 const printenv_t *result = NULL;
276 TRACE("testing %s\n", debugstr_w(env));
279 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
281 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
283 result = all_printenv[i];
288 if (result == NULL) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env));
290 SetLastError(ERROR_INVALID_ENVIRONMENT);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
296 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
298 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
312 return usBufferPtr->Buffer;
314 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
318 static LPWSTR strdupW(LPCWSTR p)
324 len = (strlenW(p) + 1) * sizeof(WCHAR);
325 ret = HeapAlloc(GetProcessHeap(), 0, len);
330 static LPSTR strdupWtoA( LPCWSTR str )
335 if (!str) return NULL;
336 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
337 ret = HeapAlloc( GetProcessHeap(), 0, len );
338 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
342 static DEVMODEW *dup_devmode( const DEVMODEW *dm )
346 if (!dm) return NULL;
347 ret = HeapAlloc( GetProcessHeap(), 0, dm->dmSize + dm->dmDriverExtra );
348 if (ret) memcpy( ret, dm, dm->dmSize + dm->dmDriverExtra );
352 /***********************************************************
354 * Creates an ansi copy of supplied devmode
356 static DEVMODEA *DEVMODEdupWtoA( const DEVMODEW *dmW )
361 if (!dmW) return NULL;
362 size = dmW->dmSize - CCHDEVICENAME -
363 ((dmW->dmSize > FIELD_OFFSET( DEVMODEW, dmFormName )) ? CCHFORMNAME : 0);
365 dmA = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra );
366 if (!dmA) return NULL;
368 WideCharToMultiByte( CP_ACP, 0, dmW->dmDeviceName, -1,
369 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL );
371 if (FIELD_OFFSET( DEVMODEW, dmFormName ) >= dmW->dmSize)
373 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
374 dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
378 memcpy( &dmA->dmSpecVersion, &dmW->dmSpecVersion,
379 FIELD_OFFSET( DEVMODEW, dmFormName ) - FIELD_OFFSET( DEVMODEW, dmSpecVersion ) );
380 WideCharToMultiByte( CP_ACP, 0, dmW->dmFormName, -1,
381 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL );
383 memcpy( &dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET( DEVMODEW, dmLogPixels ) );
387 memcpy( (char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra );
392 /******************************************************************
393 * verify, that the filename is a local file
396 static inline BOOL is_local_file(LPWSTR name)
398 return (name[0] && (name[1] == ':') && (name[2] == '\\'));
401 /* ################################ */
403 static int multi_sz_lenA(const char *str)
405 const char *ptr = str;
409 ptr += lstrlenA(ptr) + 1;
412 return ptr - str + 1;
416 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
419 /* If forcing, or no profile string entry for device yet, set the entry
421 * The always change entry if not WINEPS yet is discussable.
424 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
426 !strstr(qbuf,"WINEPS.DRV")
428 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
431 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
432 WriteProfileStringA("windows","device",buf);
433 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
434 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
437 HeapFree(GetProcessHeap(),0,buf);
441 static BOOL add_printer_driver(WCHAR *name)
445 ZeroMemory(&di3, sizeof(DRIVER_INFO_3W));
448 di3.pEnvironment = envname_x86W;
449 di3.pDriverPath = driver_nt;
450 di3.pDataFile = generic_ppdW;
451 di3.pConfigFile = driver_nt;
452 di3.pDefaultDataType = rawW;
454 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
455 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
458 di3.pEnvironment = envname_win40W;
459 di3.pDriverPath = driver_9x;
460 di3.pConfigFile = driver_9x;
461 if (AddPrinterDriverW(NULL, 3, (LPBYTE)&di3) ||
462 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
467 ERR("failed with %u for %s (%s)\n", GetLastError(), debugstr_w(di3.pDriverPath), debugstr_w(di3.pEnvironment));
471 #ifdef SONAME_LIBCUPS
472 static typeof(cupsFreeDests) *pcupsFreeDests;
473 static typeof(cupsGetDests) *pcupsGetDests;
474 static typeof(cupsGetPPD) *pcupsGetPPD;
475 static typeof(cupsPrintFile) *pcupsPrintFile;
476 static void *cupshandle;
478 static BOOL CUPS_LoadPrinters(void)
481 BOOL hadprinter = FALSE, haddefault = FALSE;
485 HKEY hkeyPrinter, hkeyPrinters;
487 WCHAR nameW[MAX_PATH];
489 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
491 TRACE("%s\n", loaderror);
494 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
497 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
498 if (!p##x) return FALSE;
500 DYNCUPS(cupsFreeDests);
502 DYNCUPS(cupsGetDests);
503 DYNCUPS(cupsPrintFile);
506 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
508 ERR("Can't create Printers key\n");
512 nrofdests = pcupsGetDests(&dests);
513 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
514 for (i=0;i<nrofdests;i++) {
515 MultiByteToWideChar(CP_UNIXCP, 0, dests[i].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
517 port = HeapAlloc(GetProcessHeap(), 0, sizeof(CUPS_Port) + lstrlenW(nameW) * sizeof(WCHAR));
518 lstrcpyW(port, CUPS_Port);
519 lstrcatW(port, nameW);
521 TRACE("Printer %d: %s\n", i, debugstr_w(nameW));
522 if(RegOpenKeyW(hkeyPrinters, nameW, &hkeyPrinter) == ERROR_SUCCESS) {
523 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
525 TRACE("Printer already exists\n");
526 /* overwrite old LPR:* port */
527 RegSetValueExW(hkeyPrinter, PortW, 0, REG_SZ, (LPBYTE)port, (lstrlenW(port) + 1) * sizeof(WCHAR));
528 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
529 RegCloseKey(hkeyPrinter);
531 static WCHAR comment_cups[] = {'W','I','N','E','P','S',' ','P','r','i','n','t','e','r',
532 ' ','u','s','i','n','g',' ','C','U','P','S',0};
534 add_printer_driver(nameW);
536 memset(&pi2, 0, sizeof(PRINTER_INFO_2W));
537 pi2.pPrinterName = nameW;
538 pi2.pDatatype = rawW;
539 pi2.pPrintProcessor = WinPrintW;
540 pi2.pDriverName = nameW;
541 pi2.pComment = comment_cups;
542 pi2.pLocation = emptyStringW;
543 pi2.pPortName = port;
544 pi2.pParameters = emptyStringW;
545 pi2.pShareName = emptyStringW;
546 pi2.pSepFile = emptyStringW;
548 if (!AddPrinterW(NULL, 2, (LPBYTE)&pi2)) {
549 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
550 ERR("printer '%s' not added by AddPrinter (error %d)\n", debugstr_w(nameW), GetLastError());
553 HeapFree(GetProcessHeap(),0,port);
556 if (dests[i].is_default) {
557 SetDefaultPrinterW(nameW);
561 if (hadprinter && !haddefault) {
562 MultiByteToWideChar(CP_UNIXCP, 0, dests[0].name, -1, nameW, sizeof(nameW) / sizeof(WCHAR));
563 SetDefaultPrinterW(nameW);
565 pcupsFreeDests(nrofdests, dests);
566 RegCloseKey(hkeyPrinters);
572 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
573 PRINTER_INFO_2A pinfo2a;
576 char *e,*s,*name,*prettyname,*devname;
577 BOOL ret = FALSE, set_default = FALSE;
578 char *port = NULL, *env_default;
579 HKEY hkeyPrinter, hkeyPrinters;
580 WCHAR devnameW[MAX_PATH];
582 while (isspace(*pent)) pent++;
583 r = strchr(pent,':');
587 name_len = strlen(pent);
588 name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
589 memcpy(name, pent, name_len);
590 name[name_len] = '\0';
596 TRACE("name=%s entry=%s\n",name, pent);
598 if(ispunct(*name)) { /* a tc entry, not a real printer */
599 TRACE("skipping tc entry\n");
603 if(strstr(pent,":server")) { /* server only version so skip */
604 TRACE("skipping server entry\n");
608 /* Determine whether this is a postscript printer. */
611 env_default = getenv("PRINTER");
613 /* Get longest name, usually the one at the right for later display. */
614 while((s=strchr(prettyname,'|'))) {
617 while(isspace(*--e)) *e = '\0';
618 TRACE("\t%s\n", debugstr_a(prettyname));
619 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
620 for(prettyname = s+1; isspace(*prettyname); prettyname++)
623 e = prettyname + strlen(prettyname);
624 while(isspace(*--e)) *e = '\0';
625 TRACE("\t%s\n", debugstr_a(prettyname));
626 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
628 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
629 * if it is too long, we use it as comment below. */
630 devname = prettyname;
631 if (strlen(devname)>=CCHDEVICENAME-1)
633 if (strlen(devname)>=CCHDEVICENAME-1) {
638 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
639 sprintf(port,"LPR:%s",name);
641 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
643 ERR("Can't create Printers key\n");
648 MultiByteToWideChar(CP_ACP, 0, devname, -1, devnameW, sizeof(devnameW) / sizeof(WCHAR));
650 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
651 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
653 TRACE("Printer already exists\n");
654 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
655 RegCloseKey(hkeyPrinter);
657 static CHAR data_type[] = "RAW",
658 print_proc[] = "WinPrint",
659 comment[] = "WINEPS Printer using LPR",
660 params[] = "<parameters?>",
661 share_name[] = "<share name?>",
662 sep_file[] = "<sep file?>";
664 add_printer_driver(devnameW);
666 memset(&pinfo2a,0,sizeof(pinfo2a));
667 pinfo2a.pPrinterName = devname;
668 pinfo2a.pDatatype = data_type;
669 pinfo2a.pPrintProcessor = print_proc;
670 pinfo2a.pDriverName = devname;
671 pinfo2a.pComment = comment;
672 pinfo2a.pLocation = prettyname;
673 pinfo2a.pPortName = port;
674 pinfo2a.pParameters = params;
675 pinfo2a.pShareName = share_name;
676 pinfo2a.pSepFile = sep_file;
678 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
679 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
680 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
683 RegCloseKey(hkeyPrinters);
685 if (isfirst || set_default)
686 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
689 HeapFree(GetProcessHeap(), 0, port);
690 HeapFree(GetProcessHeap(), 0, name);
695 PRINTCAP_LoadPrinters(void) {
696 BOOL hadprinter = FALSE;
700 BOOL had_bash = FALSE;
702 f = fopen("/etc/printcap","r");
706 while(fgets(buf,sizeof(buf),f)) {
709 end=strchr(buf,'\n');
713 while(isspace(*start)) start++;
714 if(*start == '#' || *start == '\0')
717 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
718 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
719 HeapFree(GetProcessHeap(),0,pent);
723 if (end && *--end == '\\') {
730 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
733 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
739 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
740 HeapFree(GetProcessHeap(),0,pent);
746 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
749 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
750 (lstrlenW(value) + 1) * sizeof(WCHAR));
752 return ERROR_FILE_NOT_FOUND;
755 static inline DWORD set_reg_devmode( HKEY key, const WCHAR *name, const DEVMODEW *dm )
757 DEVMODEA *dmA = DEVMODEdupWtoA( dm );
758 DWORD ret = ERROR_FILE_NOT_FOUND;
760 /* FIXME: Write DEVMODEA not DEVMODEW into reg. This is what win9x does
761 and we support these drivers. NT writes DEVMODEW so somehow
762 we'll need to distinguish between these when we support NT
767 ret = RegSetValueExW( key, name, 0, REG_BINARY,
768 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra );
769 HeapFree( GetProcessHeap(), 0, dmA );
775 /******************************************************************
776 * get_servername_from_name (internal)
778 * for an external server, a copy of the serverpart from the full name is returned
781 static LPWSTR get_servername_from_name(LPCWSTR name)
785 WCHAR buffer[MAX_PATH];
788 if (name == NULL) return NULL;
789 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
791 server = strdupW(&name[2]); /* skip over both backslash */
792 if (server == NULL) return NULL;
794 /* strip '\' and the printername */
795 ptr = strchrW(server, '\\');
796 if (ptr) ptr[0] = '\0';
798 TRACE("found %s\n", debugstr_w(server));
800 len = sizeof(buffer)/sizeof(buffer[0]);
801 if (GetComputerNameW(buffer, &len)) {
802 if (lstrcmpW(buffer, server) == 0) {
803 /* The requested Servername is our computername */
804 HeapFree(GetProcessHeap(), 0, server);
811 /******************************************************************
812 * get_basename_from_name (internal)
814 * skip over the serverpart from the full name
817 static LPCWSTR get_basename_from_name(LPCWSTR name)
819 if (name == NULL) return NULL;
820 if ((name[0] == '\\') && (name[1] == '\\')) {
821 /* skip over the servername and search for the following '\' */
822 name = strchrW(&name[2], '\\');
823 if ((name) && (name[1])) {
824 /* found a separator ('\') followed by a name:
825 skip over the separator and return the rest */
830 /* no basename present (we found only a servername) */
837 static void free_printer_entry( opened_printer_t *printer )
839 /* the queue is shared, so don't free that here */
840 HeapFree( GetProcessHeap(), 0, printer->printername );
841 HeapFree( GetProcessHeap(), 0, printer->name );
842 HeapFree( GetProcessHeap(), 0, printer->devmode );
843 HeapFree( GetProcessHeap(), 0, printer );
846 /******************************************************************
847 * get_opened_printer_entry
848 * Get the first place empty in the opened printer table
851 * - pDefault is ignored
853 static HANDLE get_opened_printer_entry(LPWSTR name, LPPRINTER_DEFAULTSW pDefault)
855 UINT_PTR handle = nb_printer_handles, i;
856 jobqueue_t *queue = NULL;
857 opened_printer_t *printer = NULL;
861 if ((backend == NULL) && !load_backend()) return NULL;
863 servername = get_servername_from_name(name);
865 FIXME("server %s not supported\n", debugstr_w(servername));
866 HeapFree(GetProcessHeap(), 0, servername);
867 SetLastError(ERROR_INVALID_PRINTER_NAME);
871 printername = get_basename_from_name(name);
872 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
874 /* an empty printername is invalid */
875 if (printername && (!printername[0])) {
876 SetLastError(ERROR_INVALID_PARAMETER);
880 EnterCriticalSection(&printer_handles_cs);
882 for (i = 0; i < nb_printer_handles; i++)
884 if (!printer_handles[i])
886 if(handle == nb_printer_handles)
891 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
892 queue = printer_handles[i]->queue;
896 if (handle >= nb_printer_handles)
898 opened_printer_t **new_array;
900 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
901 (nb_printer_handles + 16) * sizeof(*new_array) );
903 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
904 (nb_printer_handles + 16) * sizeof(*new_array) );
911 printer_handles = new_array;
912 nb_printer_handles += 16;
915 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
921 /* get a printer handle from the backend */
922 if (! backend->fpOpenPrinter(name, &printer->backend_printer, pDefault)) {
927 /* clone the base name. This is NULL for the printserver */
928 printer->printername = strdupW(printername);
930 /* clone the full name */
931 printer->name = strdupW(name);
932 if (name && (!printer->name)) {
937 if (pDefault && pDefault->pDevMode)
938 printer->devmode = dup_devmode( pDefault->pDevMode );
941 printer->queue = queue;
944 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
945 if (!printer->queue) {
949 list_init(&printer->queue->jobs);
950 printer->queue->ref = 0;
952 InterlockedIncrement(&printer->queue->ref);
954 printer_handles[handle] = printer;
957 LeaveCriticalSection(&printer_handles_cs);
958 if (!handle && printer) {
959 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
960 free_printer_entry( printer );
963 return (HANDLE)handle;
966 /******************************************************************
968 * Get the pointer to the opened printer referred by the handle
970 static opened_printer_t *get_opened_printer(HANDLE hprn)
972 UINT_PTR idx = (UINT_PTR)hprn;
973 opened_printer_t *ret = NULL;
975 EnterCriticalSection(&printer_handles_cs);
977 if ((idx > 0) && (idx <= nb_printer_handles)) {
978 ret = printer_handles[idx - 1];
980 LeaveCriticalSection(&printer_handles_cs);
984 /******************************************************************
985 * get_opened_printer_name
986 * Get the pointer to the opened printer name referred by the handle
988 static LPCWSTR get_opened_printer_name(HANDLE hprn)
990 opened_printer_t *printer = get_opened_printer(hprn);
991 if(!printer) return NULL;
992 return printer->name;
995 /******************************************************************
996 * WINSPOOL_GetOpenedPrinterRegKey
999 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1001 LPCWSTR name = get_opened_printer_name(hPrinter);
1005 if(!name) return ERROR_INVALID_HANDLE;
1007 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1011 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1013 ERR("Can't find opened printer %s in registry\n",
1015 RegCloseKey(hkeyPrinters);
1016 return ERROR_INVALID_PRINTER_NAME; /* ? */
1018 RegCloseKey(hkeyPrinters);
1019 return ERROR_SUCCESS;
1022 void WINSPOOL_LoadSystemPrinters(void)
1024 HKEY hkey, hkeyPrinters;
1026 DWORD needed, num, i;
1027 WCHAR PrinterName[256];
1030 /* This ensures that all printer entries have a valid Name value. If causes
1031 problems later if they don't. If one is found to be missed we create one
1032 and set it equal to the name of the key */
1033 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1034 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1035 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1036 for(i = 0; i < num; i++) {
1037 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1038 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1039 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1040 set_reg_szW(hkey, NameW, PrinterName);
1047 RegCloseKey(hkeyPrinters);
1050 /* We want to avoid calling AddPrinter on printers as much as
1051 possible, because on cups printers this will (eventually) lead
1052 to a call to cupsGetPPD which takes forever, even with non-cups
1053 printers AddPrinter takes a while. So we'll tag all printers that
1054 were automatically added last time around, if they still exist
1055 we'll leave them be otherwise we'll delete them. */
1056 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num) && needed) {
1057 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1058 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1059 for(i = 0; i < num; i++) {
1060 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1061 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1062 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1064 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1072 HeapFree(GetProcessHeap(), 0, pi);
1076 #ifdef SONAME_LIBCUPS
1077 done = CUPS_LoadPrinters();
1080 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1081 PRINTCAP_LoadPrinters();
1083 /* Now enumerate the list again and delete any printers that are still tagged */
1084 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1086 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1087 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1088 for(i = 0; i < num; i++) {
1089 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1090 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1091 BOOL delete_driver = FALSE;
1092 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1093 DWORD dw, type, size = sizeof(dw);
1094 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1095 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1096 DeletePrinter(hprn);
1097 delete_driver = TRUE;
1103 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1108 HeapFree(GetProcessHeap(), 0, pi);
1115 /******************************************************************
1118 * Get the pointer to the specified job.
1119 * Should hold the printer_handles_cs before calling.
1121 static job_t *get_job(HANDLE hprn, DWORD JobId)
1123 opened_printer_t *printer = get_opened_printer(hprn);
1126 if(!printer) return NULL;
1127 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1129 if(job->job_id == JobId)
1135 /***********************************************************
1138 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1141 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1144 Formname = (dmA->dmSize > off_formname);
1145 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1146 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1147 dmW->dmDeviceName, CCHDEVICENAME);
1149 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1150 dmA->dmSize - CCHDEVICENAME);
1152 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1153 off_formname - CCHDEVICENAME);
1154 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1155 dmW->dmFormName, CCHFORMNAME);
1156 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1157 (off_formname + CCHFORMNAME));
1160 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1161 dmA->dmDriverExtra);
1165 /******************************************************************
1166 * convert_printerinfo_W_to_A [internal]
1169 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1170 DWORD level, DWORD outlen, DWORD numentries)
1176 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1178 len = pi_sizeof[level] * numentries;
1179 ptr = (LPSTR) out + len;
1182 /* copy the numbers of all PRINTER_INFO_* first */
1183 memcpy(out, pPrintersW, len);
1185 while (id < numentries) {
1189 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1190 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1192 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1193 if (piW->pDescription) {
1194 piA->pDescription = ptr;
1195 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1196 ptr, outlen, NULL, NULL);
1202 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1203 ptr, outlen, NULL, NULL);
1207 if (piW->pComment) {
1208 piA->pComment = ptr;
1209 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1210 ptr, outlen, NULL, NULL);
1219 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1220 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1223 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1224 if (piW->pServerName) {
1225 piA->pServerName = ptr;
1226 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1227 ptr, outlen, NULL, NULL);
1231 if (piW->pPrinterName) {
1232 piA->pPrinterName = ptr;
1233 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1234 ptr, outlen, NULL, NULL);
1238 if (piW->pShareName) {
1239 piA->pShareName = ptr;
1240 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1241 ptr, outlen, NULL, NULL);
1245 if (piW->pPortName) {
1246 piA->pPortName = ptr;
1247 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1248 ptr, outlen, NULL, NULL);
1252 if (piW->pDriverName) {
1253 piA->pDriverName = ptr;
1254 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1255 ptr, outlen, NULL, NULL);
1259 if (piW->pComment) {
1260 piA->pComment = ptr;
1261 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1262 ptr, outlen, NULL, NULL);
1266 if (piW->pLocation) {
1267 piA->pLocation = ptr;
1268 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1269 ptr, outlen, NULL, NULL);
1274 dmA = DEVMODEdupWtoA(piW->pDevMode);
1276 /* align DEVMODEA to a DWORD boundary */
1277 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1281 piA->pDevMode = (LPDEVMODEA) ptr;
1282 len = dmA->dmSize + dmA->dmDriverExtra;
1283 memcpy(ptr, dmA, len);
1284 HeapFree(GetProcessHeap(), 0, dmA);
1290 if (piW->pSepFile) {
1291 piA->pSepFile = ptr;
1292 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1293 ptr, outlen, NULL, NULL);
1297 if (piW->pPrintProcessor) {
1298 piA->pPrintProcessor = ptr;
1299 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1300 ptr, outlen, NULL, NULL);
1304 if (piW->pDatatype) {
1305 piA->pDatatype = ptr;
1306 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1307 ptr, outlen, NULL, NULL);
1311 if (piW->pParameters) {
1312 piA->pParameters = ptr;
1313 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1314 ptr, outlen, NULL, NULL);
1318 if (piW->pSecurityDescriptor) {
1319 piA->pSecurityDescriptor = NULL;
1320 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1327 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1328 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1330 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1332 if (piW->pPrinterName) {
1333 piA->pPrinterName = ptr;
1334 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1335 ptr, outlen, NULL, NULL);
1339 if (piW->pServerName) {
1340 piA->pServerName = ptr;
1341 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1342 ptr, outlen, NULL, NULL);
1351 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1352 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1354 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1356 if (piW->pPrinterName) {
1357 piA->pPrinterName = ptr;
1358 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1359 ptr, outlen, NULL, NULL);
1363 if (piW->pPortName) {
1364 piA->pPortName = ptr;
1365 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1366 ptr, outlen, NULL, NULL);
1373 case 6: /* 6A and 6W are the same structure */
1378 PRINTER_INFO_7W * piW = (PRINTER_INFO_7W *) pPrintersW;
1379 PRINTER_INFO_7A * piA = (PRINTER_INFO_7A *) out;
1381 TRACE("(%u) #%u\n", level, id);
1382 if (piW->pszObjectGUID) {
1383 piA->pszObjectGUID = ptr;
1384 len = WideCharToMultiByte(CP_ACP, 0, piW->pszObjectGUID, -1,
1385 ptr, outlen, NULL, NULL);
1394 PRINTER_INFO_9W * piW = (PRINTER_INFO_9W *) pPrintersW;
1395 PRINTER_INFO_9A * piA = (PRINTER_INFO_9A *) out;
1398 TRACE("(%u) #%u\n", level, id);
1399 dmA = DEVMODEdupWtoA(piW->pDevMode);
1401 /* align DEVMODEA to a DWORD boundary */
1402 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1406 piA->pDevMode = (LPDEVMODEA) ptr;
1407 len = dmA->dmSize + dmA->dmDriverExtra;
1408 memcpy(ptr, dmA, len);
1409 HeapFree(GetProcessHeap(), 0, dmA);
1419 FIXME("for level %u\n", level);
1421 pPrintersW += pi_sizeof[level];
1422 out += pi_sizeof[level];
1427 /******************************************************************
1428 * convert_driverinfo_W_to_A [internal]
1431 static void convert_driverinfo_W_to_A(LPBYTE out, LPBYTE pDriversW,
1432 DWORD level, DWORD outlen, DWORD numentries)
1438 TRACE("(%p, %p, %d, %u, %u)\n", out, pDriversW, level, outlen, numentries);
1440 len = di_sizeof[level] * numentries;
1441 ptr = (LPSTR) out + len;
1444 /* copy the numbers of all PRINTER_INFO_* first */
1445 memcpy(out, pDriversW, len);
1447 #define COPY_STRING(fld) \
1450 len = WideCharToMultiByte(CP_ACP, 0, diW->fld, -1, ptr, outlen, NULL, NULL);\
1451 ptr += len; outlen -= len;\
1453 #define COPY_MULTIZ_STRING(fld) \
1454 { LPWSTR p = diW->fld; if (p){ \
1457 len = WideCharToMultiByte(CP_ACP, 0, p, -1, ptr, outlen, NULL, NULL);\
1458 ptr += len; outlen -= len; p += len;\
1460 while(len > 1 && outlen > 0); \
1463 while (id < numentries)
1469 DRIVER_INFO_1W * diW = (DRIVER_INFO_1W *) pDriversW;
1470 DRIVER_INFO_1A * diA = (DRIVER_INFO_1A *) out;
1472 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1479 DRIVER_INFO_2W * diW = (DRIVER_INFO_2W *) pDriversW;
1480 DRIVER_INFO_2A * diA = (DRIVER_INFO_2A *) out;
1482 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1485 COPY_STRING(pEnvironment);
1486 COPY_STRING(pDriverPath);
1487 COPY_STRING(pDataFile);
1488 COPY_STRING(pConfigFile);
1493 DRIVER_INFO_3W * diW = (DRIVER_INFO_3W *) pDriversW;
1494 DRIVER_INFO_3A * diA = (DRIVER_INFO_3A *) out;
1496 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1499 COPY_STRING(pEnvironment);
1500 COPY_STRING(pDriverPath);
1501 COPY_STRING(pDataFile);
1502 COPY_STRING(pConfigFile);
1503 COPY_STRING(pHelpFile);
1504 COPY_MULTIZ_STRING(pDependentFiles);
1505 COPY_STRING(pMonitorName);
1506 COPY_STRING(pDefaultDataType);
1511 DRIVER_INFO_4W * diW = (DRIVER_INFO_4W *) pDriversW;
1512 DRIVER_INFO_4A * diA = (DRIVER_INFO_4A *) out;
1514 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1517 COPY_STRING(pEnvironment);
1518 COPY_STRING(pDriverPath);
1519 COPY_STRING(pDataFile);
1520 COPY_STRING(pConfigFile);
1521 COPY_STRING(pHelpFile);
1522 COPY_MULTIZ_STRING(pDependentFiles);
1523 COPY_STRING(pMonitorName);
1524 COPY_STRING(pDefaultDataType);
1525 COPY_MULTIZ_STRING(pszzPreviousNames);
1530 DRIVER_INFO_5W * diW = (DRIVER_INFO_5W *) pDriversW;
1531 DRIVER_INFO_5A * diA = (DRIVER_INFO_5A *) out;
1533 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1536 COPY_STRING(pEnvironment);
1537 COPY_STRING(pDriverPath);
1538 COPY_STRING(pDataFile);
1539 COPY_STRING(pConfigFile);
1544 DRIVER_INFO_6W * diW = (DRIVER_INFO_6W *) pDriversW;
1545 DRIVER_INFO_6A * diA = (DRIVER_INFO_6A *) out;
1547 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1550 COPY_STRING(pEnvironment);
1551 COPY_STRING(pDriverPath);
1552 COPY_STRING(pDataFile);
1553 COPY_STRING(pConfigFile);
1554 COPY_STRING(pHelpFile);
1555 COPY_MULTIZ_STRING(pDependentFiles);
1556 COPY_STRING(pMonitorName);
1557 COPY_STRING(pDefaultDataType);
1558 COPY_MULTIZ_STRING(pszzPreviousNames);
1559 COPY_STRING(pszMfgName);
1560 COPY_STRING(pszOEMUrl);
1561 COPY_STRING(pszHardwareID);
1562 COPY_STRING(pszProvider);
1567 DRIVER_INFO_8W * diW = (DRIVER_INFO_8W *) pDriversW;
1568 DRIVER_INFO_8A * diA = (DRIVER_INFO_8A *) out;
1570 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(diW->pName));
1573 COPY_STRING(pEnvironment);
1574 COPY_STRING(pDriverPath);
1575 COPY_STRING(pDataFile);
1576 COPY_STRING(pConfigFile);
1577 COPY_STRING(pHelpFile);
1578 COPY_MULTIZ_STRING(pDependentFiles);
1579 COPY_STRING(pMonitorName);
1580 COPY_STRING(pDefaultDataType);
1581 COPY_MULTIZ_STRING(pszzPreviousNames);
1582 COPY_STRING(pszMfgName);
1583 COPY_STRING(pszOEMUrl);
1584 COPY_STRING(pszHardwareID);
1585 COPY_STRING(pszProvider);
1586 COPY_STRING(pszPrintProcessor);
1587 COPY_STRING(pszVendorSetup);
1588 COPY_MULTIZ_STRING(pszzColorProfiles);
1589 COPY_STRING(pszInfPath);
1590 COPY_MULTIZ_STRING(pszzCoreDriverDependencies);
1596 FIXME("for level %u\n", level);
1599 pDriversW += di_sizeof[level];
1600 out += di_sizeof[level];
1605 #undef COPY_MULTIZ_STRING
1609 /***********************************************************
1612 static void *printer_info_AtoW( const void *data, DWORD level )
1615 UNICODE_STRING usBuffer;
1617 if (!data) return NULL;
1619 if (level < 1 || level > 9) return NULL;
1621 ret = HeapAlloc( GetProcessHeap(), 0, pi_sizeof[level] );
1622 if (!ret) return NULL;
1624 memcpy( ret, data, pi_sizeof[level] ); /* copy everything first */
1630 const PRINTER_INFO_2A *piA = (const PRINTER_INFO_2A *)data;
1631 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)ret;
1633 piW->pServerName = asciitounicode( &usBuffer, piA->pServerName );
1634 piW->pPrinterName = asciitounicode( &usBuffer, piA->pPrinterName );
1635 piW->pShareName = asciitounicode( &usBuffer, piA->pShareName );
1636 piW->pPortName = asciitounicode( &usBuffer, piA->pPortName );
1637 piW->pDriverName = asciitounicode( &usBuffer, piA->pDriverName );
1638 piW->pComment = asciitounicode( &usBuffer, piA->pComment );
1639 piW->pLocation = asciitounicode( &usBuffer, piA->pLocation );
1640 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1641 piW->pSepFile = asciitounicode( &usBuffer, piA->pSepFile );
1642 piW->pPrintProcessor = asciitounicode( &usBuffer, piA->pPrintProcessor );
1643 piW->pDatatype = asciitounicode( &usBuffer, piA->pDatatype );
1644 piW->pParameters = asciitounicode( &usBuffer, piA->pParameters );
1651 const PRINTER_INFO_9A *piA = (const PRINTER_INFO_9A *)data;
1652 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)ret;
1654 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW( piA->pDevMode ) : NULL;
1659 FIXME( "Unhandled level %d\n", level );
1660 HeapFree( GetProcessHeap(), 0, ret );
1667 /***********************************************************
1670 static void free_printer_info( void *data, DWORD level )
1678 PRINTER_INFO_2W *piW = (PRINTER_INFO_2W *)data;
1680 HeapFree( GetProcessHeap(), 0, piW->pServerName );
1681 HeapFree( GetProcessHeap(), 0, piW->pPrinterName );
1682 HeapFree( GetProcessHeap(), 0, piW->pShareName );
1683 HeapFree( GetProcessHeap(), 0, piW->pPortName );
1684 HeapFree( GetProcessHeap(), 0, piW->pDriverName );
1685 HeapFree( GetProcessHeap(), 0, piW->pComment );
1686 HeapFree( GetProcessHeap(), 0, piW->pLocation );
1687 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1688 HeapFree( GetProcessHeap(), 0, piW->pSepFile );
1689 HeapFree( GetProcessHeap(), 0, piW->pPrintProcessor );
1690 HeapFree( GetProcessHeap(), 0, piW->pDatatype );
1691 HeapFree( GetProcessHeap(), 0, piW->pParameters );
1698 PRINTER_INFO_9W *piW = (PRINTER_INFO_9W *)data;
1700 HeapFree( GetProcessHeap(), 0, piW->pDevMode );
1705 FIXME( "Unhandled level %d\n", level );
1708 HeapFree( GetProcessHeap(), 0, data );
1712 /******************************************************************
1713 * DeviceCapabilities [WINSPOOL.@]
1714 * DeviceCapabilitiesA [WINSPOOL.@]
1717 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1718 LPSTR pOutput, LPDEVMODEA lpdm)
1722 if (!GDI_CallDeviceCapabilities16)
1724 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1726 if (!GDI_CallDeviceCapabilities16) return -1;
1728 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1730 /* If DC_PAPERSIZE map POINT16s to POINTs */
1731 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1732 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1733 POINT *pt = (POINT *)pOutput;
1735 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1736 for(i = 0; i < ret; i++, pt++)
1741 HeapFree( GetProcessHeap(), 0, tmp );
1747 /*****************************************************************************
1748 * DeviceCapabilitiesW [WINSPOOL.@]
1750 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1753 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1754 WORD fwCapability, LPWSTR pOutput,
1755 const DEVMODEW *pDevMode)
1757 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
1758 LPSTR pDeviceA = strdupWtoA(pDevice);
1759 LPSTR pPortA = strdupWtoA(pPort);
1762 if(pOutput && (fwCapability == DC_BINNAMES ||
1763 fwCapability == DC_FILEDEPENDENCIES ||
1764 fwCapability == DC_PAPERNAMES)) {
1765 /* These need A -> W translation */
1768 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1772 switch(fwCapability) {
1777 case DC_FILEDEPENDENCIES:
1781 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1782 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1784 for(i = 0; i < ret; i++)
1785 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1786 pOutput + (i * size), size);
1787 HeapFree(GetProcessHeap(), 0, pOutputA);
1789 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1790 (LPSTR)pOutput, dmA);
1792 HeapFree(GetProcessHeap(),0,pPortA);
1793 HeapFree(GetProcessHeap(),0,pDeviceA);
1794 HeapFree(GetProcessHeap(),0,dmA);
1798 /******************************************************************
1799 * DocumentPropertiesA [WINSPOOL.@]
1801 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1803 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1804 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1805 LPDEVMODEA pDevModeInput,DWORD fMode )
1807 LPSTR lpName = pDeviceName;
1808 static CHAR port[] = "LPT1:";
1811 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1812 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1816 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1818 ERR("no name from hPrinter?\n");
1819 SetLastError(ERROR_INVALID_HANDLE);
1822 lpName = strdupWtoA(lpNameW);
1825 if (!GDI_CallExtDeviceMode16)
1827 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1829 if (!GDI_CallExtDeviceMode16) {
1830 ERR("No CallExtDeviceMode16?\n");
1834 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1835 pDevModeInput, NULL, fMode);
1838 HeapFree(GetProcessHeap(),0,lpName);
1843 /*****************************************************************************
1844 * DocumentPropertiesW (WINSPOOL.@)
1846 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1848 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1850 LPDEVMODEW pDevModeOutput,
1851 LPDEVMODEW pDevModeInput, DWORD fMode)
1854 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1855 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
1856 LPDEVMODEA pDevModeOutputA = NULL;
1859 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1860 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1862 if(pDevModeOutput) {
1863 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1864 if(ret < 0) return ret;
1865 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1867 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1868 pDevModeInputA, fMode);
1869 if(pDevModeOutput) {
1870 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1871 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1873 if(fMode == 0 && ret > 0)
1874 ret += (CCHDEVICENAME + CCHFORMNAME);
1875 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1876 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1880 /*****************************************************************************
1881 * IsValidDevmodeA [WINSPOOL.@]
1883 * Validate a DEVMODE structure and fix errors if possible.
1886 BOOL WINAPI IsValidDevmodeA(PDEVMODEA *pDevMode, SIZE_T size)
1888 FIXME("(%p,%ld): stub\n", pDevMode, size);
1896 /*****************************************************************************
1897 * IsValidDevmodeW [WINSPOOL.@]
1899 * Validate a DEVMODE structure and fix errors if possible.
1902 BOOL WINAPI IsValidDevmodeW(PDEVMODEW *pDevMode, SIZE_T size)
1904 FIXME("(%p,%ld): stub\n", pDevMode, size);
1912 /******************************************************************
1913 * OpenPrinterA [WINSPOOL.@]
1918 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1919 LPPRINTER_DEFAULTSA pDefault)
1921 UNICODE_STRING lpPrinterNameW;
1922 UNICODE_STRING usBuffer;
1923 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1924 PWSTR pwstrPrinterNameW;
1927 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1930 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1931 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1932 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1933 pDefaultW = &DefaultW;
1935 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1937 RtlFreeUnicodeString(&usBuffer);
1938 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1940 RtlFreeUnicodeString(&lpPrinterNameW);
1944 /******************************************************************
1945 * OpenPrinterW [WINSPOOL.@]
1947 * Open a Printer / Printserver or a Printer-Object
1950 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1951 * phPrinter [O] The resulting Handle is stored here
1952 * pDefault [I] PTR to Default Printer Settings or NULL
1959 * lpPrinterName is one of:
1960 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1961 *| Printer: "PrinterName"
1962 *| Printer-Object: "PrinterName,Job xxx"
1963 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1964 *| XcvPort: "Servername,XcvPort PortName"
1967 *| Printer-Object not supported
1968 *| pDefaults is ignored
1971 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1974 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1977 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1978 SetLastError(ERROR_INVALID_PARAMETER);
1982 /* Get the unique handle of the printer or Printserver */
1983 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1984 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1985 return (*phPrinter != 0);
1988 /******************************************************************
1989 * AddMonitorA [WINSPOOL.@]
1994 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1996 LPWSTR nameW = NULL;
1999 LPMONITOR_INFO_2A mi2a;
2000 MONITOR_INFO_2W mi2w;
2002 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2003 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2004 debugstr_a(mi2a ? mi2a->pName : NULL),
2005 debugstr_a(mi2a ? mi2a->pEnvironment : NULL),
2006 debugstr_a(mi2a ? mi2a->pDLLName : NULL));
2009 SetLastError(ERROR_INVALID_LEVEL);
2013 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2019 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2020 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2021 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2024 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2026 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2027 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2028 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2030 if (mi2a->pEnvironment) {
2031 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2032 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2033 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2035 if (mi2a->pDLLName) {
2036 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2037 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2038 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2041 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2043 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2044 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2045 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2047 HeapFree(GetProcessHeap(), 0, nameW);
2051 /******************************************************************************
2052 * AddMonitorW [WINSPOOL.@]
2054 * Install a Printmonitor
2057 * pName [I] Servername or NULL (local Computer)
2058 * Level [I] Structure-Level (Must be 2)
2059 * pMonitors [I] PTR to MONITOR_INFO_2
2066 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2069 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2071 LPMONITOR_INFO_2W mi2w;
2073 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2074 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2075 debugstr_w(mi2w ? mi2w->pName : NULL),
2076 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
2077 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
2079 if ((backend == NULL) && !load_backend()) return FALSE;
2082 SetLastError(ERROR_INVALID_LEVEL);
2086 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2091 return backend->fpAddMonitor(pName, Level, pMonitors);
2094 /******************************************************************
2095 * DeletePrinterDriverA [WINSPOOL.@]
2098 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2100 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2103 /******************************************************************
2104 * DeletePrinterDriverW [WINSPOOL.@]
2107 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2109 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2112 /******************************************************************
2113 * DeleteMonitorA [WINSPOOL.@]
2115 * See DeleteMonitorW.
2118 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2120 LPWSTR nameW = NULL;
2121 LPWSTR EnvironmentW = NULL;
2122 LPWSTR MonitorNameW = NULL;
2127 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2128 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2129 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2133 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2134 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2135 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2138 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2139 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2140 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2143 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2145 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2146 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2147 HeapFree(GetProcessHeap(), 0, nameW);
2151 /******************************************************************
2152 * DeleteMonitorW [WINSPOOL.@]
2154 * Delete a specific Printmonitor from a Printing-Environment
2157 * pName [I] Servername or NULL (local Computer)
2158 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2159 * pMonitorName [I] Name of the Monitor, that should be deleted
2166 * pEnvironment is ignored in Windows for the local Computer.
2169 BOOL WINAPI DeleteMonitorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2172 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2173 debugstr_w(pMonitorName));
2175 if ((backend == NULL) && !load_backend()) return FALSE;
2177 return backend->fpDeleteMonitor(pName, pEnvironment, pMonitorName);
2181 /******************************************************************
2182 * DeletePortA [WINSPOOL.@]
2187 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2189 LPWSTR nameW = NULL;
2190 LPWSTR portW = NULL;
2194 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2196 /* convert servername to unicode */
2198 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2199 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2200 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2203 /* convert portname to unicode */
2205 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2206 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2207 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2210 res = DeletePortW(nameW, hWnd, portW);
2211 HeapFree(GetProcessHeap(), 0, nameW);
2212 HeapFree(GetProcessHeap(), 0, portW);
2216 /******************************************************************
2217 * DeletePortW [WINSPOOL.@]
2219 * Delete a specific Port
2222 * pName [I] Servername or NULL (local Computer)
2223 * hWnd [I] Handle to parent Window for the Dialog-Box
2224 * pPortName [I] Name of the Port, that should be deleted
2231 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2233 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2235 if ((backend == NULL) && !load_backend()) return FALSE;
2238 SetLastError(RPC_X_NULL_REF_POINTER);
2242 return backend->fpDeletePort(pName, hWnd, pPortName);
2245 /******************************************************************************
2246 * WritePrinter [WINSPOOL.@]
2248 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2250 opened_printer_t *printer;
2253 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2255 EnterCriticalSection(&printer_handles_cs);
2256 printer = get_opened_printer(hPrinter);
2259 SetLastError(ERROR_INVALID_HANDLE);
2265 SetLastError(ERROR_SPL_NO_STARTDOC);
2269 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2271 LeaveCriticalSection(&printer_handles_cs);
2275 /*****************************************************************************
2276 * AddFormA [WINSPOOL.@]
2278 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2280 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2284 /*****************************************************************************
2285 * AddFormW [WINSPOOL.@]
2287 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2289 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2293 /*****************************************************************************
2294 * AddJobA [WINSPOOL.@]
2296 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2299 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2303 SetLastError(ERROR_INVALID_LEVEL);
2307 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2310 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2311 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2312 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2313 if(*pcbNeeded > cbBuf) {
2314 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2317 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2318 addjobA->JobId = addjobW->JobId;
2319 addjobA->Path = (char *)(addjobA + 1);
2320 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2326 /*****************************************************************************
2327 * AddJobW [WINSPOOL.@]
2329 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2331 opened_printer_t *printer;
2334 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2335 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2336 WCHAR path[MAX_PATH], filename[MAX_PATH];
2338 ADDJOB_INFO_1W *addjob;
2340 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2342 EnterCriticalSection(&printer_handles_cs);
2344 printer = get_opened_printer(hPrinter);
2347 SetLastError(ERROR_INVALID_HANDLE);
2352 SetLastError(ERROR_INVALID_LEVEL);
2356 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2360 job->job_id = InterlockedIncrement(&next_job_id);
2362 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2363 if(path[len - 1] != '\\')
2365 memcpy(path + len, spool_path, sizeof(spool_path));
2366 sprintfW(filename, fmtW, path, job->job_id);
2368 len = strlenW(filename);
2369 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2370 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2371 job->portname = NULL;
2372 job->document_title = strdupW(default_doc_title);
2373 job->printer_name = strdupW(printer->name);
2374 job->devmode = dup_devmode( printer->devmode );
2375 list_add_tail(&printer->queue->jobs, &job->entry);
2377 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2378 if(*pcbNeeded <= cbBuf) {
2379 addjob = (ADDJOB_INFO_1W*)pData;
2380 addjob->JobId = job->job_id;
2381 addjob->Path = (WCHAR *)(addjob + 1);
2382 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2385 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2388 LeaveCriticalSection(&printer_handles_cs);
2392 /*****************************************************************************
2393 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2395 * Return the PATH for the Print-Processors
2397 * See GetPrintProcessorDirectoryW.
2401 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2402 DWORD level, LPBYTE Info,
2403 DWORD cbBuf, LPDWORD pcbNeeded)
2405 LPWSTR serverW = NULL;
2410 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2411 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2415 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2416 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2417 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2421 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2422 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2423 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2426 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2427 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2429 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2432 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2433 cbBuf, NULL, NULL) > 0;
2436 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2437 HeapFree(GetProcessHeap(), 0, envW);
2438 HeapFree(GetProcessHeap(), 0, serverW);
2442 /*****************************************************************************
2443 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2445 * Return the PATH for the Print-Processors
2448 * server [I] Servername (NT only) or NULL (local Computer)
2449 * env [I] Printing-Environment (see below) or NULL (Default)
2450 * level [I] Structure-Level (must be 1)
2451 * Info [O] PTR to Buffer that receives the Result
2452 * cbBuf [I] Size of Buffer at "Info"
2453 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2454 * required for the Buffer at "Info"
2457 * Success: TRUE and in pcbNeeded the Bytes used in Info
2458 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2459 * if cbBuf is too small
2461 * Native Values returned in Info on Success:
2462 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2463 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2464 *| win9x(Windows 4.0): "%winsysdir%"
2466 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2469 * Only NULL or "" is supported for server
2472 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2473 DWORD level, LPBYTE Info,
2474 DWORD cbBuf, LPDWORD pcbNeeded)
2477 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server), debugstr_w(env), level,
2478 Info, cbBuf, pcbNeeded);
2480 if ((backend == NULL) && !load_backend()) return FALSE;
2483 /* (Level != 1) is ignored in win9x */
2484 SetLastError(ERROR_INVALID_LEVEL);
2488 if (pcbNeeded == NULL) {
2489 /* (pcbNeeded == NULL) is ignored in win9x */
2490 SetLastError(RPC_X_NULL_REF_POINTER);
2494 return backend->fpGetPrintProcessorDirectory(server, env, level, Info, cbBuf, pcbNeeded);
2497 /*****************************************************************************
2498 * WINSPOOL_OpenDriverReg [internal]
2500 * opens the registry for the printer drivers depending on the given input
2501 * variable pEnvironment
2504 * the opened hkey on success
2507 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment)
2511 const printenv_t * env;
2513 TRACE("(%s)\n", debugstr_w(pEnvironment));
2515 env = validate_envW(pEnvironment);
2516 if (!env) return NULL;
2518 buffer = HeapAlloc( GetProcessHeap(), 0,
2519 (strlenW(DriversW) + strlenW(env->envname) +
2520 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2522 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2523 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2524 HeapFree(GetProcessHeap(), 0, buffer);
2529 /*****************************************************************************
2530 * set_devices_and_printerports [internal]
2532 * set the [Devices] and [PrinterPorts] entries for a printer.
2535 static void set_devices_and_printerports(PRINTER_INFO_2W *pi)
2537 DWORD portlen = lstrlenW(pi->pPortName) * sizeof(WCHAR);
2541 TRACE("(%p) %s\n", pi, debugstr_w(pi->pPrinterName));
2543 /* FIXME: the driver must change to "winspool" */
2544 devline = HeapAlloc(GetProcessHeap(), 0, sizeof(driver_nt) + portlen + sizeof(timeout_15_45));
2546 lstrcpyW(devline, driver_nt);
2547 lstrcatW(devline, commaW);
2548 lstrcatW(devline, pi->pPortName);
2550 TRACE("using %s\n", debugstr_w(devline));
2551 WriteProfileStringW(devicesW, pi->pPrinterName, devline);
2552 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey)) {
2553 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2554 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2558 lstrcatW(devline, timeout_15_45);
2559 WriteProfileStringW(PrinterPortsW, pi->pPrinterName, devline);
2560 if (!RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey)) {
2561 RegSetValueExW(hkey, pi->pPrinterName, 0, REG_SZ, (LPBYTE)devline,
2562 (lstrlenW(devline) + 1) * sizeof(WCHAR));
2565 HeapFree(GetProcessHeap(), 0, devline);
2569 /*****************************************************************************
2570 * AddPrinterW [WINSPOOL.@]
2572 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2574 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2577 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2579 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2580 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2581 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2582 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2583 statusW[] = {'S','t','a','t','u','s',0},
2584 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2586 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2589 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2590 SetLastError(ERROR_INVALID_PARAMETER);
2594 ERR("Level = %d, unsupported!\n", Level);
2595 SetLastError(ERROR_INVALID_LEVEL);
2599 SetLastError(ERROR_INVALID_PARAMETER);
2602 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2604 ERR("Can't create Printers key\n");
2607 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2608 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2609 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2610 RegCloseKey(hkeyPrinter);
2611 RegCloseKey(hkeyPrinters);
2614 RegCloseKey(hkeyPrinter);
2616 hkeyDrivers = WINSPOOL_OpenDriverReg(NULL);
2618 ERR("Can't create Drivers key\n");
2619 RegCloseKey(hkeyPrinters);
2622 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2624 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2625 RegCloseKey(hkeyPrinters);
2626 RegCloseKey(hkeyDrivers);
2627 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2630 RegCloseKey(hkeyDriver);
2631 RegCloseKey(hkeyDrivers);
2633 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2634 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2635 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2636 RegCloseKey(hkeyPrinters);
2640 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2642 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2643 SetLastError(ERROR_INVALID_PRINTER_NAME);
2644 RegCloseKey(hkeyPrinters);
2648 set_devices_and_printerports(pi);
2649 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2650 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2651 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2653 /* See if we can load the driver. We may need the devmode structure anyway
2656 * Note that DocumentPropertiesW will briefly try to open the printer we
2657 * just create to find a DEVMODE struct (it will use the WINEPS default
2658 * one in case it is not there, so we are ok).
2660 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2663 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2664 size = sizeof(DEVMODEW);
2670 dm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
2672 if (DocumentPropertiesW(0, 0, pi->pPrinterName, dm, NULL, DM_OUT_BUFFER) < 0)
2674 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2675 HeapFree( GetProcessHeap(), 0, dm );
2680 /* set devmode to printer name */
2681 lstrcpynW( dm->dmDeviceName, pi->pPrinterName, CCHDEVICENAME );
2685 set_reg_devmode( hkeyPrinter, default_devmodeW, dm );
2686 if (!pi->pDevMode) HeapFree( GetProcessHeap(), 0, dm );
2688 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2689 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2690 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2691 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2693 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2694 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2695 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2696 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2697 (LPBYTE)&pi->Priority, sizeof(DWORD));
2698 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2699 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2700 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2701 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2702 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2703 (LPBYTE)&pi->Status, sizeof(DWORD));
2704 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2705 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2707 RegCloseKey(hkeyPrinter);
2708 RegCloseKey(hkeyPrinters);
2709 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2710 ERR("OpenPrinter failing\n");
2716 /*****************************************************************************
2717 * AddPrinterA [WINSPOOL.@]
2719 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2721 UNICODE_STRING pNameW;
2723 PRINTER_INFO_2W *piW;
2724 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2727 TRACE("(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2729 ERR("Level = %d, unsupported!\n", Level);
2730 SetLastError(ERROR_INVALID_LEVEL);
2733 pwstrNameW = asciitounicode(&pNameW,pName);
2734 piW = printer_info_AtoW( piA, Level );
2736 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2738 free_printer_info( piW, Level );
2739 RtlFreeUnicodeString(&pNameW);
2744 /*****************************************************************************
2745 * ClosePrinter [WINSPOOL.@]
2747 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2749 UINT_PTR i = (UINT_PTR)hPrinter;
2750 opened_printer_t *printer = NULL;
2753 TRACE("(%p)\n", hPrinter);
2755 EnterCriticalSection(&printer_handles_cs);
2757 if ((i > 0) && (i <= nb_printer_handles))
2758 printer = printer_handles[i - 1];
2763 struct list *cursor, *cursor2;
2765 TRACE("closing %s (doc: %p)\n", debugstr_w(printer->name), printer->doc);
2767 if (printer->backend_printer) {
2768 backend->fpClosePrinter(printer->backend_printer);
2772 EndDocPrinter(hPrinter);
2774 if(InterlockedDecrement(&printer->queue->ref) == 0)
2776 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2778 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2779 ScheduleJob(hPrinter, job->job_id);
2781 HeapFree(GetProcessHeap(), 0, printer->queue);
2784 free_printer_entry( printer );
2785 printer_handles[i - 1] = NULL;
2788 LeaveCriticalSection(&printer_handles_cs);
2792 /*****************************************************************************
2793 * DeleteFormA [WINSPOOL.@]
2795 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2797 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2801 /*****************************************************************************
2802 * DeleteFormW [WINSPOOL.@]
2804 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2806 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2810 /*****************************************************************************
2811 * DeletePrinter [WINSPOOL.@]
2813 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2815 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2816 HKEY hkeyPrinters, hkey;
2819 SetLastError(ERROR_INVALID_HANDLE);
2822 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2823 RegDeleteTreeW(hkeyPrinters, lpNameW);
2824 RegCloseKey(hkeyPrinters);
2826 WriteProfileStringW(devicesW, lpNameW, NULL);
2827 WriteProfileStringW(PrinterPortsW, lpNameW, NULL);
2829 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2830 RegDeleteValueW(hkey, lpNameW);
2834 if(RegCreateKeyW(HKEY_CURRENT_USER, WinNT_CV_PrinterPortsW, &hkey) == ERROR_SUCCESS) {
2835 RegDeleteValueW(hkey, lpNameW);
2841 /*****************************************************************************
2842 * SetPrinterA [WINSPOOL.@]
2844 BOOL WINAPI SetPrinterA( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2851 dataW = printer_info_AtoW( data, level );
2852 if (!dataW) return FALSE;
2855 ret = SetPrinterW( printer, level, dataW, command );
2857 if (dataW != data) free_printer_info( dataW, level );
2862 static BOOL set_printer_9( HKEY key, const PRINTER_INFO_9W *pi )
2864 if (!pi->pDevMode) return FALSE;
2866 set_reg_devmode( key, Default_DevModeW, pi->pDevMode );
2870 /******************************************************************************
2871 * SetPrinterW [WINSPOOL.@]
2873 BOOL WINAPI SetPrinterW( HANDLE printer, DWORD level, LPBYTE data, DWORD command )
2878 TRACE( "(%p, %d, %p, %d)\n", printer, level, data, command );
2880 if (command != 0) FIXME( "Ignoring command %d\n", command );
2882 if (WINSPOOL_GetOpenedPrinterRegKey( printer, &key ))
2889 PRINTER_INFO_9W *pi = (PRINTER_INFO_9W *)data;
2890 ret = set_printer_9( key, pi );
2895 FIXME( "Unimplemented level %d\n", level );
2896 SetLastError( ERROR_INVALID_LEVEL );
2903 /*****************************************************************************
2904 * SetJobA [WINSPOOL.@]
2906 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2907 LPBYTE pJob, DWORD Command)
2911 UNICODE_STRING usBuffer;
2913 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
2915 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2916 are all ignored by SetJob, so we don't bother copying them */
2924 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2925 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2927 JobW = (LPBYTE)info1W;
2928 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2929 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2930 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2931 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2932 info1W->Status = info1A->Status;
2933 info1W->Priority = info1A->Priority;
2934 info1W->Position = info1A->Position;
2935 info1W->PagesPrinted = info1A->PagesPrinted;
2940 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2941 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2943 JobW = (LPBYTE)info2W;
2944 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2945 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2946 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2947 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2948 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2949 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2950 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2951 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2952 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2953 info2W->Status = info2A->Status;
2954 info2W->Priority = info2A->Priority;
2955 info2W->Position = info2A->Position;
2956 info2W->StartTime = info2A->StartTime;
2957 info2W->UntilTime = info2A->UntilTime;
2958 info2W->PagesPrinted = info2A->PagesPrinted;
2962 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2963 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2966 SetLastError(ERROR_INVALID_LEVEL);
2970 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2976 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2977 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2978 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2979 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2980 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2985 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2986 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2987 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2988 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2989 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2990 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2991 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2992 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2993 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2997 HeapFree(GetProcessHeap(), 0, JobW);
3002 /*****************************************************************************
3003 * SetJobW [WINSPOOL.@]
3005 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3006 LPBYTE pJob, DWORD Command)
3011 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3012 FIXME("Ignoring everything other than document title\n");
3014 EnterCriticalSection(&printer_handles_cs);
3015 job = get_job(hPrinter, JobId);
3025 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3026 HeapFree(GetProcessHeap(), 0, job->document_title);
3027 job->document_title = strdupW(info1->pDocument);
3032 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3033 HeapFree(GetProcessHeap(), 0, job->document_title);
3034 job->document_title = strdupW(info2->pDocument);
3035 HeapFree(GetProcessHeap(), 0, job->devmode);
3036 job->devmode = dup_devmode( info2->pDevMode );
3042 SetLastError(ERROR_INVALID_LEVEL);
3047 LeaveCriticalSection(&printer_handles_cs);
3051 /*****************************************************************************
3052 * EndDocPrinter [WINSPOOL.@]
3054 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3056 opened_printer_t *printer;
3058 TRACE("(%p)\n", hPrinter);
3060 EnterCriticalSection(&printer_handles_cs);
3062 printer = get_opened_printer(hPrinter);
3065 SetLastError(ERROR_INVALID_HANDLE);
3071 SetLastError(ERROR_SPL_NO_STARTDOC);
3075 CloseHandle(printer->doc->hf);
3076 ScheduleJob(hPrinter, printer->doc->job_id);
3077 HeapFree(GetProcessHeap(), 0, printer->doc);
3078 printer->doc = NULL;
3081 LeaveCriticalSection(&printer_handles_cs);
3085 /*****************************************************************************
3086 * EndPagePrinter [WINSPOOL.@]
3088 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3090 FIXME("(%p): stub\n", hPrinter);
3094 /*****************************************************************************
3095 * StartDocPrinterA [WINSPOOL.@]
3097 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3099 UNICODE_STRING usBuffer;
3101 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3104 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3105 or one (DOC_INFO_3) extra DWORDs */
3109 doc2W.JobId = doc2->JobId;
3112 doc2W.dwMode = doc2->dwMode;
3115 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3116 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3117 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3121 SetLastError(ERROR_INVALID_LEVEL);
3125 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3127 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3128 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3129 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3134 /*****************************************************************************
3135 * StartDocPrinterW [WINSPOOL.@]
3137 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3139 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3140 opened_printer_t *printer;
3141 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3142 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3143 JOB_INFO_1W job_info;
3144 DWORD needed, ret = 0;
3149 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3150 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3151 debugstr_w(doc->pDatatype));
3153 if(Level < 1 || Level > 3)
3155 SetLastError(ERROR_INVALID_LEVEL);
3159 EnterCriticalSection(&printer_handles_cs);
3160 printer = get_opened_printer(hPrinter);
3163 SetLastError(ERROR_INVALID_HANDLE);
3169 SetLastError(ERROR_INVALID_PRINTER_STATE);
3173 /* Even if we're printing to a file we still add a print job, we'll
3174 just ignore the spool file name */
3176 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3178 ERR("AddJob failed gle %u\n", GetLastError());
3182 /* use pOutputFile only, when it is a real filename */
3183 if ((doc->pOutputFile) && is_local_file(doc->pOutputFile))
3184 filename = doc->pOutputFile;
3186 filename = addjob->Path;
3188 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3189 if(hf == INVALID_HANDLE_VALUE)
3192 memset(&job_info, 0, sizeof(job_info));
3193 job_info.pDocument = doc->pDocName;
3194 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3196 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3197 printer->doc->hf = hf;
3198 ret = printer->doc->job_id = addjob->JobId;
3199 job = get_job(hPrinter, ret);
3200 job->portname = strdupW(doc->pOutputFile);
3203 LeaveCriticalSection(&printer_handles_cs);
3208 /*****************************************************************************
3209 * StartPagePrinter [WINSPOOL.@]
3211 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3213 FIXME("(%p): stub\n", hPrinter);
3217 /*****************************************************************************
3218 * GetFormA [WINSPOOL.@]
3220 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3221 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3223 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3224 Level,pForm,cbBuf,pcbNeeded);
3228 /*****************************************************************************
3229 * GetFormW [WINSPOOL.@]
3231 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3232 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3234 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3235 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3239 /*****************************************************************************
3240 * SetFormA [WINSPOOL.@]
3242 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3245 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3249 /*****************************************************************************
3250 * SetFormW [WINSPOOL.@]
3252 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3255 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3259 /*****************************************************************************
3260 * ReadPrinter [WINSPOOL.@]
3262 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3263 LPDWORD pNoBytesRead)
3265 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3269 /*****************************************************************************
3270 * ResetPrinterA [WINSPOOL.@]
3272 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3274 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3278 /*****************************************************************************
3279 * ResetPrinterW [WINSPOOL.@]
3281 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3283 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3287 /*****************************************************************************
3288 * WINSPOOL_GetDWORDFromReg
3290 * Return DWORD associated with ValueName from hkey.
3292 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3294 DWORD sz = sizeof(DWORD), type, value = 0;
3297 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3299 if(ret != ERROR_SUCCESS) {
3300 WARN("Got ret = %d on name %s\n", ret, ValueName);
3303 if(type != REG_DWORD) {
3304 ERR("Got type %d\n", type);
3311 /*****************************************************************************
3312 * get_filename_from_reg [internal]
3314 * Get ValueName from hkey storing result in out
3315 * when the Value in the registry has only a filename, use driverdir as prefix
3316 * outlen is space left in out
3317 * String is stored either as unicode or ascii
3321 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3322 LPBYTE out, DWORD outlen, LPDWORD needed)
3324 WCHAR filename[MAX_PATH];
3328 LPWSTR buffer = filename;
3332 size = sizeof(filename);
3334 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3335 if (ret == ERROR_MORE_DATA) {
3336 TRACE("need dynamic buffer: %u\n", size);
3337 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3339 /* No Memory is bad */
3343 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3346 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3347 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3353 /* do we have a full path ? */
3354 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3355 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3358 /* we must build the full Path */
3360 if ((out) && (outlen > dirlen)) {
3361 lstrcpyW((LPWSTR)out, driverdir);
3369 /* write the filename */
3370 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3371 if ((out) && (outlen >= size)) {
3372 lstrcpyW((LPWSTR)out, ptr);
3379 ptr += lstrlenW(ptr)+1;
3380 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3383 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3385 /* write the multisz-termination */
3386 if (type == REG_MULTI_SZ) {
3387 size = sizeof(WCHAR);
3390 if (out && (outlen >= size)) {
3391 memset (out, 0, size);
3397 /*****************************************************************************
3398 * WINSPOOL_GetStringFromReg
3400 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3401 * String is stored as unicode.
3403 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3404 DWORD buflen, DWORD *needed)
3406 DWORD sz = buflen, type;
3409 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3410 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3411 WARN("Got ret = %d\n", ret);
3415 /* add space for terminating '\0' */
3416 sz += sizeof(WCHAR);
3420 TRACE("%s: %s\n", debugstr_w(ValueName), debugstr_w((LPCWSTR)ptr));
3425 /*****************************************************************************
3426 * WINSPOOL_GetDefaultDevMode
3428 * Get a default DevMode values for wineps.
3432 static void WINSPOOL_GetDefaultDevMode(
3434 DWORD buflen, DWORD *needed)
3437 static const WCHAR szWwps[] = {'w', 'i', 'n', 'e', 'p', 's', '.', 'd', 'r', 'v', 0 };
3439 /* fill default DEVMODE - should be read from ppd... */
3440 ZeroMemory( &dm, sizeof(dm) );
3441 memcpy(dm.dmDeviceName,szWwps,sizeof szWwps);
3442 dm.dmSpecVersion = DM_SPECVERSION;
3443 dm.dmDriverVersion = 1;
3444 dm.dmSize = sizeof(DEVMODEW);
3445 dm.dmDriverExtra = 0;
3447 DM_ORIENTATION | DM_PAPERSIZE |
3448 DM_PAPERLENGTH | DM_PAPERWIDTH |
3451 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3452 DM_YRESOLUTION | DM_TTOPTION;
3454 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3455 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3456 dm.u1.s1.dmPaperLength = 2970;
3457 dm.u1.s1.dmPaperWidth = 2100;
3459 dm.u1.s1.dmScale = 100;
3460 dm.u1.s1.dmCopies = 1;
3461 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3462 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3465 dm.dmYResolution = 300; /* 300dpi */
3466 dm.dmTTOption = DMTT_BITMAP;
3469 /* dm.dmLogPixels */
3470 /* dm.dmBitsPerPel */
3471 /* dm.dmPelsWidth */
3472 /* dm.dmPelsHeight */
3473 /* dm.u2.dmDisplayFlags */
3474 /* dm.dmDisplayFrequency */
3475 /* dm.dmICMMethod */
3476 /* dm.dmICMIntent */
3477 /* dm.dmMediaType */
3478 /* dm.dmDitherType */
3479 /* dm.dmReserved1 */
3480 /* dm.dmReserved2 */
3481 /* dm.dmPanningWidth */
3482 /* dm.dmPanningHeight */
3484 if(buflen >= sizeof(DEVMODEW))
3485 memcpy(ptr, &dm, sizeof(DEVMODEW));
3486 *needed = sizeof(DEVMODEW);
3489 /*****************************************************************************
3490 * WINSPOOL_GetDevModeFromReg
3492 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3493 * DevMode is stored either as unicode or ascii.
3495 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3497 DWORD buflen, DWORD *needed)
3499 DWORD sz = buflen, type;
3502 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3503 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3504 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3505 if (sz < sizeof(DEVMODEA))
3507 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3510 /* ensures that dmSize is not erratically bogus if registry is invalid */
3511 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3512 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3513 sz += (CCHDEVICENAME + CCHFORMNAME);
3514 if (ptr && (buflen >= sz)) {
3515 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3516 memcpy(ptr, dmW, sz);
3517 HeapFree(GetProcessHeap(),0,dmW);
3523 /*********************************************************************
3524 * WINSPOOL_GetPrinter_1
3526 * Fills out a PRINTER_INFO_1W struct storing the strings in buf.
3528 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3529 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3531 DWORD size, left = cbBuf;
3532 BOOL space = (cbBuf > 0);
3537 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3538 if(space && size <= left) {
3539 pi1->pName = (LPWSTR)ptr;
3547 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3548 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3549 if(space && size <= left) {
3550 pi1->pDescription = (LPWSTR)ptr;
3558 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3559 if(space && size <= left) {
3560 pi1->pComment = (LPWSTR)ptr;
3568 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3570 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3571 memset(pi1, 0, sizeof(*pi1));
3575 /*********************************************************************
3576 * WINSPOOL_GetPrinter_2
3578 * Fills out a PRINTER_INFO_2W struct storing the strings in buf.
3580 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3581 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3583 DWORD size, left = cbBuf;
3584 BOOL space = (cbBuf > 0);
3589 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3590 if(space && size <= left) {
3591 pi2->pPrinterName = (LPWSTR)ptr;
3598 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size)) {
3599 if(space && size <= left) {
3600 pi2->pShareName = (LPWSTR)ptr;
3607 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3608 if(space && size <= left) {
3609 pi2->pPortName = (LPWSTR)ptr;
3616 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left, &size)) {
3617 if(space && size <= left) {
3618 pi2->pDriverName = (LPWSTR)ptr;
3625 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size)) {
3626 if(space && size <= left) {
3627 pi2->pComment = (LPWSTR)ptr;
3634 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size)) {
3635 if(space && size <= left) {
3636 pi2->pLocation = (LPWSTR)ptr;
3643 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left, &size)) {
3644 if(space && size <= left) {
3645 pi2->pDevMode = (LPDEVMODEW)ptr;
3654 WINSPOOL_GetDefaultDevMode(ptr, left, &size);
3655 if(space && size <= left) {
3656 pi2->pDevMode = (LPDEVMODEW)ptr;
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left, &size)) {
3664 if(space && size <= left) {
3665 pi2->pSepFile = (LPWSTR)ptr;
3672 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left, &size)) {
3673 if(space && size <= left) {
3674 pi2->pPrintProcessor = (LPWSTR)ptr;
3681 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left, &size)) {
3682 if(space && size <= left) {
3683 pi2->pDatatype = (LPWSTR)ptr;
3690 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left, &size)) {
3691 if(space && size <= left) {
3692 pi2->pParameters = (LPWSTR)ptr;
3700 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3701 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3702 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3703 "Default Priority");
3704 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3705 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3708 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3709 memset(pi2, 0, sizeof(*pi2));
3714 /*********************************************************************
3715 * WINSPOOL_GetPrinter_4
3717 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3719 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3720 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3722 DWORD size, left = cbBuf;
3723 BOOL space = (cbBuf > 0);
3728 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3729 if(space && size <= left) {
3730 pi4->pPrinterName = (LPWSTR)ptr;
3738 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3741 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3742 memset(pi4, 0, sizeof(*pi4));
3747 /*********************************************************************
3748 * WINSPOOL_GetPrinter_5
3750 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3752 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3753 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded)
3755 DWORD size, left = cbBuf;
3756 BOOL space = (cbBuf > 0);
3761 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size)) {
3762 if(space && size <= left) {
3763 pi5->pPrinterName = (LPWSTR)ptr;
3770 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size)) {
3771 if(space && size <= left) {
3772 pi5->pPortName = (LPWSTR)ptr;
3780 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3781 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3783 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3787 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3788 memset(pi5, 0, sizeof(*pi5));
3793 /*********************************************************************
3794 * WINSPOOL_GetPrinter_7
3796 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
3798 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
3799 DWORD cbBuf, LPDWORD pcbNeeded)
3801 DWORD size, left = cbBuf;
3802 BOOL space = (cbBuf > 0);
3807 if (! WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size))
3810 size = sizeof(pi7->pszObjectGUID);
3812 if (space && size <= left) {
3813 pi7->pszObjectGUID = (LPWSTR)ptr;
3820 /* We do not have a Directory Service */
3821 pi7->dwAction = DSPRINT_UNPUBLISH;
3824 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
3825 memset(pi7, 0, sizeof(*pi7));
3830 /*********************************************************************
3831 * WINSPOOL_GetPrinter_9
3833 * Fills out a PRINTER_INFO_9AW struct storing the strings in buf.
3835 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
3836 DWORD cbBuf, LPDWORD pcbNeeded)
3839 BOOL space = (cbBuf > 0);
3843 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size)) {
3844 if(space && size <= cbBuf) {
3845 pi9->pDevMode = (LPDEVMODEW)buf;
3852 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size);
3853 if(space && size <= cbBuf) {
3854 pi9->pDevMode = (LPDEVMODEW)buf;
3860 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
3861 memset(pi9, 0, sizeof(*pi9));
3866 /*****************************************************************************
3867 * GetPrinterW [WINSPOOL.@]
3869 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3870 DWORD cbBuf, LPDWORD pcbNeeded)
3873 DWORD size, needed = 0;
3875 HKEY hkeyPrinter, hkeyPrinters;
3878 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3880 if (!(name = get_opened_printer_name(hPrinter))) {
3881 SetLastError(ERROR_INVALID_HANDLE);
3885 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3887 ERR("Can't create Printers key\n");
3890 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3892 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3893 RegCloseKey(hkeyPrinters);
3894 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3901 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3903 size = sizeof(PRINTER_INFO_2W);
3905 ptr = pPrinter + size;
3907 memset(pPrinter, 0, size);
3912 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed);
3919 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3921 size = sizeof(PRINTER_INFO_4W);
3923 ptr = pPrinter + size;
3925 memset(pPrinter, 0, size);
3930 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed);
3938 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3940 size = sizeof(PRINTER_INFO_5W);
3942 ptr = pPrinter + size;
3944 memset(pPrinter, 0, size);
3950 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed);
3958 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
3960 size = sizeof(PRINTER_INFO_6);
3961 if (size <= cbBuf) {
3962 /* FIXME: We do not update the status yet */
3963 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
3975 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
3977 size = sizeof(PRINTER_INFO_7W);
3978 if (size <= cbBuf) {
3979 ptr = pPrinter + size;
3981 memset(pPrinter, 0, size);
3987 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed);
3995 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
3997 size = sizeof(PRINTER_INFO_9W);
3999 ptr = pPrinter + size;
4001 memset(pPrinter, 0, size);
4007 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed);
4014 FIXME("Unimplemented level %d\n", Level);
4015 SetLastError(ERROR_INVALID_LEVEL);
4016 RegCloseKey(hkeyPrinters);
4017 RegCloseKey(hkeyPrinter);
4021 RegCloseKey(hkeyPrinter);
4022 RegCloseKey(hkeyPrinters);
4024 TRACE("returning %d needed = %d\n", ret, needed);
4025 if(pcbNeeded) *pcbNeeded = needed;
4027 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4031 /*****************************************************************************
4032 * GetPrinterA [WINSPOOL.@]
4034 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4035 DWORD cbBuf, LPDWORD pcbNeeded)
4041 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4043 ret = GetPrinterW(hPrinter, Level, buf, cbBuf, pcbNeeded);
4045 convert_printerinfo_W_to_A(pPrinter, buf, Level, cbBuf, 1);
4046 HeapFree(GetProcessHeap(), 0, buf);
4051 /*****************************************************************************
4052 * WINSPOOL_EnumPrintersW
4054 * Implementation of EnumPrintersW
4056 static BOOL WINSPOOL_EnumPrintersW(DWORD dwType, LPWSTR lpszName,
4057 DWORD dwLevel, LPBYTE lpbPrinters,
4058 DWORD cbBuf, LPDWORD lpdwNeeded,
4059 LPDWORD lpdwReturned)
4062 HKEY hkeyPrinters, hkeyPrinter;
4063 WCHAR PrinterName[255];
4064 DWORD needed = 0, number = 0;
4065 DWORD used, i, left;
4069 memset(lpbPrinters, 0, cbBuf);
4075 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4076 if(dwType == PRINTER_ENUM_DEFAULT)
4079 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4080 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4081 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4083 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4089 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4090 FIXME("dwType = %08x\n", dwType);
4091 SetLastError(ERROR_INVALID_FLAGS);
4095 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4097 ERR("Can't create Printers key\n");
4101 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4102 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4103 RegCloseKey(hkeyPrinters);
4104 ERR("Can't query Printers key\n");
4107 TRACE("Found %d printers\n", number);
4111 used = number * sizeof(PRINTER_INFO_1W);
4114 used = number * sizeof(PRINTER_INFO_2W);
4117 used = number * sizeof(PRINTER_INFO_4W);
4120 used = number * sizeof(PRINTER_INFO_5W);
4124 SetLastError(ERROR_INVALID_LEVEL);
4125 RegCloseKey(hkeyPrinters);
4128 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4130 for(i = 0; i < number; i++) {
4131 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4133 ERR("Can't enum key number %d\n", i);
4134 RegCloseKey(hkeyPrinters);
4137 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4138 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4140 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4141 RegCloseKey(hkeyPrinters);
4146 buf = lpbPrinters + used;
4147 left = cbBuf - used;
4155 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4158 if(pi) pi += sizeof(PRINTER_INFO_1W);
4161 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4164 if(pi) pi += sizeof(PRINTER_INFO_2W);
4167 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4170 if(pi) pi += sizeof(PRINTER_INFO_4W);
4173 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4176 if(pi) pi += sizeof(PRINTER_INFO_5W);
4179 ERR("Shouldn't be here!\n");
4180 RegCloseKey(hkeyPrinter);
4181 RegCloseKey(hkeyPrinters);
4184 RegCloseKey(hkeyPrinter);
4186 RegCloseKey(hkeyPrinters);
4193 memset(lpbPrinters, 0, cbBuf);
4194 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4198 *lpdwReturned = number;
4199 SetLastError(ERROR_SUCCESS);
4204 /******************************************************************
4205 * EnumPrintersW [WINSPOOL.@]
4207 * Enumerates the available printers, print servers and print
4208 * providers, depending on the specified flags, name and level.
4212 * If level is set to 1:
4213 * Returns an array of PRINTER_INFO_1 data structures in the
4214 * lpbPrinters buffer.
4216 * If level is set to 2:
4217 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4218 * Returns an array of PRINTER_INFO_2 data structures in the
4219 * lpbPrinters buffer. Note that according to MSDN also an
4220 * OpenPrinter should be performed on every remote printer.
4222 * If level is set to 4 (officially WinNT only):
4223 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4224 * Fast: Only the registry is queried to retrieve printer names,
4225 * no connection to the driver is made.
4226 * Returns an array of PRINTER_INFO_4 data structures in the
4227 * lpbPrinters buffer.
4229 * If level is set to 5 (officially WinNT4/Win9x only):
4230 * Fast: Only the registry is queried to retrieve printer names,
4231 * no connection to the driver is made.
4232 * Returns an array of PRINTER_INFO_5 data structures in the
4233 * lpbPrinters buffer.
4235 * If level set to 3 or 6+:
4236 * returns zero (failure!)
4238 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4242 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4243 * - Only levels 2, 4 and 5 are implemented at the moment.
4244 * - 16-bit printer drivers are not enumerated.
4245 * - Returned amount of bytes used/needed does not match the real Windoze
4246 * implementation (as in this implementation, all strings are part
4247 * of the buffer, whereas Win32 keeps them somewhere else)
4248 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4251 * - In a regular Wine installation, no registry settings for printers
4252 * exist, which makes this function return an empty list.
4254 BOOL WINAPI EnumPrintersW(
4255 DWORD dwType, /* [in] Types of print objects to enumerate */
4256 LPWSTR lpszName, /* [in] name of objects to enumerate */
4257 DWORD dwLevel, /* [in] type of printer info structure */
4258 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4259 DWORD cbBuf, /* [in] max size of buffer in bytes */
4260 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4261 LPDWORD lpdwReturned /* [out] number of entries returned */
4264 return WINSPOOL_EnumPrintersW(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4265 lpdwNeeded, lpdwReturned);
4268 /******************************************************************
4269 * EnumPrintersA [WINSPOOL.@]
4274 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4275 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4278 UNICODE_STRING pNameU;
4282 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4283 pPrinters, cbBuf, pcbNeeded, pcReturned);
4285 pNameW = asciitounicode(&pNameU, pName);
4287 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4288 MS Office need this */
4289 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4291 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4293 RtlFreeUnicodeString(&pNameU);
4295 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4297 HeapFree(GetProcessHeap(), 0, pPrintersW);
4301 /*****************************************************************************
4302 * WINSPOOL_GetDriverInfoFromReg [internal]
4304 * Enters the information from the registry into the DRIVER_INFO struct
4307 * zero if the printer driver does not exist in the registry
4308 * (only if Level > 1) otherwise nonzero
4310 static BOOL WINSPOOL_GetDriverInfoFromReg(
4313 const printenv_t * env,
4315 LPBYTE ptr, /* DRIVER_INFO */
4316 LPBYTE pDriverStrings, /* strings buffer */
4317 DWORD cbBuf, /* size of string buffer */
4318 LPDWORD pcbNeeded) /* space needed for str. */
4322 WCHAR driverdir[MAX_PATH];
4324 LPBYTE strPtr = pDriverStrings;
4325 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4327 TRACE("(%p, %s, %p, %d, %p, %p, %d)\n", hkeyDrivers,
4328 debugstr_w(DriverName), env,
4329 Level, di, pDriverStrings, cbBuf);
4331 if (di) ZeroMemory(di, di_sizeof[Level]);
4333 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4334 if (*pcbNeeded <= cbBuf)
4335 strcpyW((LPWSTR)strPtr, DriverName);
4337 /* pName for level 1 has a different offset! */
4339 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4343 /* .cVersion and .pName for level > 1 */
4345 di->cVersion = env->driverversion;
4346 di->pName = (LPWSTR) strPtr;
4347 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4350 /* Reserve Space for the largest subdir and a Backslash*/
4351 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4352 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4353 /* Should never Fail */
4356 lstrcatW(driverdir, env->versionsubdir);
4357 lstrcatW(driverdir, backslashW);
4359 /* dirlen must not include the terminating zero */
4360 dirlen = lstrlenW(driverdir) * sizeof(WCHAR);
4362 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4363 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4364 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4369 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4372 if (*pcbNeeded <= cbBuf) {
4373 lstrcpyW((LPWSTR)strPtr, env->envname);
4374 if (di) di->pEnvironment = (LPWSTR)strPtr;
4375 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4378 /* .pDriverPath is the Graphics rendering engine.
4379 The full Path is required to avoid a crash in some apps */
4380 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size)) {
4382 if (*pcbNeeded <= cbBuf)
4383 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp);
4385 if (di) di->pDriverPath = (LPWSTR)strPtr;
4386 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4389 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4390 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size)) {
4392 if (*pcbNeeded <= cbBuf)
4393 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size);
4395 if (di) di->pDataFile = (LPWSTR)strPtr;
4396 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4399 /* .pConfigFile is the Driver user Interface */
4400 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size)) {
4402 if (*pcbNeeded <= cbBuf)
4403 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size);
4405 if (di) di->pConfigFile = (LPWSTR)strPtr;
4406 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4410 RegCloseKey(hkeyDriver);
4411 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4416 RegCloseKey(hkeyDriver);
4417 FIXME("level 5: incomplete\n");
4422 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size)) {
4424 if (*pcbNeeded <= cbBuf)
4425 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size);
4427 if (di) di->pHelpFile = (LPWSTR)strPtr;
4428 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4431 /* .pDependentFiles */
4432 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size)) {
4434 if (*pcbNeeded <= cbBuf)
4435 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size);
4437 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4438 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4440 else if (GetVersion() & 0x80000000) {
4441 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4442 size = 2 * sizeof(WCHAR);
4444 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4446 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4447 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4450 /* .pMonitorName is the optional Language Monitor */
4451 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size)) {
4453 if (*pcbNeeded <= cbBuf)
4454 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size);
4456 if (di) di->pMonitorName = (LPWSTR)strPtr;
4457 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4460 /* .pDefaultDataType */
4461 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size)) {
4463 if(*pcbNeeded <= cbBuf)
4464 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size);
4466 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4467 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4471 RegCloseKey(hkeyDriver);
4472 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4476 /* .pszzPreviousNames */
4477 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size)) {
4479 if(*pcbNeeded <= cbBuf)
4480 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size);
4482 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4483 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4487 RegCloseKey(hkeyDriver);
4488 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4492 /* support is missing, but not important enough for a FIXME */
4493 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4496 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size)) {
4498 if(*pcbNeeded <= cbBuf)
4499 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size);
4501 if (di) di->pszMfgName = (LPWSTR)strPtr;
4502 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4506 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size)) {
4508 if(*pcbNeeded <= cbBuf)
4509 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size);
4511 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4512 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4515 /* .pszHardwareID */
4516 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size)) {
4518 if(*pcbNeeded <= cbBuf)
4519 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size);
4521 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4522 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4526 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size)) {
4528 if(*pcbNeeded <= cbBuf)
4529 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size);
4531 if (di) di->pszProvider = (LPWSTR)strPtr;
4532 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4536 RegCloseKey(hkeyDriver);
4540 /* support is missing, but not important enough for a FIXME */
4541 TRACE("level 8: incomplete\n");
4543 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4544 RegCloseKey(hkeyDriver);
4548 /*****************************************************************************
4549 * GetPrinterDriverW [WINSPOOL.@]
4551 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4552 DWORD Level, LPBYTE pDriverInfo,
4553 DWORD cbBuf, LPDWORD pcbNeeded)
4556 WCHAR DriverName[100];
4557 DWORD ret, type, size, needed = 0;
4559 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4560 const printenv_t * env;
4562 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4563 Level,pDriverInfo,cbBuf, pcbNeeded);
4566 ZeroMemory(pDriverInfo, cbBuf);
4568 if (!(name = get_opened_printer_name(hPrinter))) {
4569 SetLastError(ERROR_INVALID_HANDLE);
4573 if (Level < 1 || Level == 7 || Level > 8) {
4574 SetLastError(ERROR_INVALID_LEVEL);
4578 env = validate_envW(pEnvironment);
4579 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4581 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4583 ERR("Can't create Printers key\n");
4586 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4588 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4589 RegCloseKey(hkeyPrinters);
4590 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4593 size = sizeof(DriverName);
4595 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4596 (LPBYTE)DriverName, &size);
4597 RegCloseKey(hkeyPrinter);
4598 RegCloseKey(hkeyPrinters);
4599 if(ret != ERROR_SUCCESS) {
4600 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4604 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4606 ERR("Can't create Drivers key\n");
4610 size = di_sizeof[Level];
4611 if ((size <= cbBuf) && pDriverInfo)
4612 ptr = pDriverInfo + size;
4614 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4615 env, Level, pDriverInfo, ptr,
4616 (cbBuf < size) ? 0 : cbBuf - size,
4618 RegCloseKey(hkeyDrivers);
4622 RegCloseKey(hkeyDrivers);
4624 if(pcbNeeded) *pcbNeeded = size + needed;
4625 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4626 if(cbBuf >= size + needed) return TRUE;
4627 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4631 /*****************************************************************************
4632 * GetPrinterDriverA [WINSPOOL.@]
4634 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4635 DWORD Level, LPBYTE pDriverInfo,
4636 DWORD cbBuf, LPDWORD pcbNeeded)
4639 UNICODE_STRING pEnvW;
4645 ZeroMemory(pDriverInfo, cbBuf);
4646 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
4649 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4650 ret = GetPrinterDriverW(hPrinter, pwstrEnvW, Level, buf,
4653 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, 1);
4655 HeapFree(GetProcessHeap(), 0, buf);
4657 RtlFreeUnicodeString(&pEnvW);
4661 /*****************************************************************************
4662 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4664 * Return the PATH for the Printer-Drivers (UNICODE)
4667 * pName [I] Servername (NT only) or NULL (local Computer)
4668 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4669 * Level [I] Structure-Level (must be 1)
4670 * pDriverDirectory [O] PTR to Buffer that receives the Result
4671 * cbBuf [I] Size of Buffer at pDriverDirectory
4672 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4673 * required for pDriverDirectory
4676 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4677 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4678 * if cbBuf is too small
4680 * Native Values returned in pDriverDirectory on Success:
4681 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4682 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4683 *| win9x(Windows 4.0): "%winsysdir%"
4685 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4688 *- Only NULL or "" is supported for pName
4691 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4692 DWORD Level, LPBYTE pDriverDirectory,
4693 DWORD cbBuf, LPDWORD pcbNeeded)
4695 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4696 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4698 if ((backend == NULL) && !load_backend()) return FALSE;
4701 /* (Level != 1) is ignored in win9x */
4702 SetLastError(ERROR_INVALID_LEVEL);
4705 if (pcbNeeded == NULL) {
4706 /* (pcbNeeded == NULL) is ignored in win9x */
4707 SetLastError(RPC_X_NULL_REF_POINTER);
4711 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
4712 pDriverDirectory, cbBuf, pcbNeeded);
4717 /*****************************************************************************
4718 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4720 * Return the PATH for the Printer-Drivers (ANSI)
4722 * See GetPrinterDriverDirectoryW.
4725 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4728 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4729 DWORD Level, LPBYTE pDriverDirectory,
4730 DWORD cbBuf, LPDWORD pcbNeeded)
4732 UNICODE_STRING nameW, environmentW;
4735 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4736 WCHAR *driverDirectoryW = NULL;
4738 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4739 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4741 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4743 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4744 else nameW.Buffer = NULL;
4745 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4746 else environmentW.Buffer = NULL;
4748 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4749 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4752 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4753 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4755 *pcbNeeded = needed;
4756 ret = (needed <= cbBuf) ? TRUE : FALSE;
4758 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4760 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4762 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4763 RtlFreeUnicodeString(&environmentW);
4764 RtlFreeUnicodeString(&nameW);
4769 /*****************************************************************************
4770 * AddPrinterDriverA [WINSPOOL.@]
4772 * See AddPrinterDriverW.
4775 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4777 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4778 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4781 /******************************************************************************
4782 * AddPrinterDriverW (WINSPOOL.@)
4784 * Install a Printer Driver
4787 * pName [I] Servername or NULL (local Computer)
4788 * level [I] Level for the supplied DRIVER_INFO_*W struct
4789 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4796 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4798 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4799 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4802 /*****************************************************************************
4803 * AddPrintProcessorA [WINSPOOL.@]
4805 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4806 LPSTR pPrintProcessorName)
4808 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4809 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4813 /*****************************************************************************
4814 * AddPrintProcessorW [WINSPOOL.@]
4816 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4817 LPWSTR pPrintProcessorName)
4819 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4820 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4824 /*****************************************************************************
4825 * AddPrintProvidorA [WINSPOOL.@]
4827 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4829 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4833 /*****************************************************************************
4834 * AddPrintProvidorW [WINSPOOL.@]
4836 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4838 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4842 /*****************************************************************************
4843 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4845 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4846 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4848 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4849 pDevModeOutput, pDevModeInput);
4853 /*****************************************************************************
4854 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4856 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4857 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4859 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4860 pDevModeOutput, pDevModeInput);
4864 /*****************************************************************************
4865 * PrinterProperties [WINSPOOL.@]
4867 * Displays a dialog to set the properties of the printer.
4870 * nonzero on success or zero on failure
4873 * implemented as stub only
4875 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4876 HANDLE hPrinter /* [in] handle to printer object */
4878 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4879 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4883 /*****************************************************************************
4884 * EnumJobsA [WINSPOOL.@]
4887 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4888 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4891 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4892 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4894 if(pcbNeeded) *pcbNeeded = 0;
4895 if(pcReturned) *pcReturned = 0;
4900 /*****************************************************************************
4901 * EnumJobsW [WINSPOOL.@]
4904 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4905 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4908 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4909 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4911 if(pcbNeeded) *pcbNeeded = 0;
4912 if(pcReturned) *pcReturned = 0;
4916 /*****************************************************************************
4917 * WINSPOOL_EnumPrinterDrivers [internal]
4919 * Delivers information about all printer drivers installed on the
4920 * localhost or a given server
4923 * nonzero on success or zero on failure. If the buffer for the returned
4924 * information is too small the function will return an error
4927 * - only implemented for localhost, foreign hosts will return an error
4929 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4930 DWORD Level, LPBYTE pDriverInfo,
4932 DWORD cbBuf, LPDWORD pcbNeeded,
4933 LPDWORD pcFound, DWORD data_offset)
4937 const printenv_t * env;
4939 TRACE("%s,%s,%d,%p,%d,%d,%d\n",
4940 debugstr_w(pName), debugstr_w(pEnvironment),
4941 Level, pDriverInfo, driver_index, cbBuf, data_offset);
4943 env = validate_envW(pEnvironment);
4944 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4948 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment);
4950 ERR("Can't open Drivers key\n");
4954 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, pcFound, NULL, NULL,
4955 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4956 RegCloseKey(hkeyDrivers);
4957 ERR("Can't query Drivers key\n");
4960 TRACE("Found %d Drivers\n", *pcFound);
4962 /* get size of single struct
4963 * unicode and ascii structure have the same size
4965 size = di_sizeof[Level];
4967 if (data_offset == 0)
4968 data_offset = size * (*pcFound);
4969 *pcbNeeded = data_offset;
4971 for( i = 0; i < *pcFound; i++) {
4972 WCHAR DriverNameW[255];
4973 PBYTE table_ptr = NULL;
4974 PBYTE data_ptr = NULL;
4977 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
4979 ERR("Can't enum key number %d\n", i);
4980 RegCloseKey(hkeyDrivers);
4984 if (pDriverInfo && ((driver_index + i + 1) * size) <= cbBuf)
4985 table_ptr = pDriverInfo + (driver_index + i) * size;
4986 if (pDriverInfo && *pcbNeeded <= cbBuf)
4987 data_ptr = pDriverInfo + *pcbNeeded;
4989 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4990 env, Level, table_ptr, data_ptr,
4991 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4993 RegCloseKey(hkeyDrivers);
4997 *pcbNeeded += needed;
5000 RegCloseKey(hkeyDrivers);
5002 if(cbBuf < *pcbNeeded){
5003 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5010 /*****************************************************************************
5011 * EnumPrinterDriversW [WINSPOOL.@]
5013 * see function EnumPrinterDrivers for RETURNS, BUGS
5015 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5016 LPBYTE pDriverInfo, DWORD cbBuf,
5017 LPDWORD pcbNeeded, LPDWORD pcReturned)
5019 static const WCHAR allW[] = {'a','l','l',0};
5023 if ((pcbNeeded == NULL) || (pcReturned == NULL))
5025 SetLastError(RPC_X_NULL_REF_POINTER);
5029 /* check for local drivers */
5030 if((pName) && (pName[0])) {
5031 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5032 SetLastError(ERROR_ACCESS_DENIED);
5036 /* check input parameter */
5037 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5038 SetLastError(ERROR_INVALID_LEVEL);
5042 if(pDriverInfo && cbBuf > 0)
5043 memset( pDriverInfo, 0, cbBuf);
5045 /* Exception: pull all printers */
5046 if (pEnvironment && !strcmpW(pEnvironment, allW))
5048 DWORD i, needed, bufsize = cbBuf;
5049 DWORD total_needed = 0;
5050 DWORD total_found = 0;
5053 /* Precompute the overall total; we need this to know
5054 where pointers end and data begins (i.e. data_offset) */
5055 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5058 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5059 NULL, 0, 0, &needed, &found, 0);
5060 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5061 total_needed += needed;
5062 total_found += found;
5065 data_offset = di_sizeof[Level] * total_found;
5070 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
5073 ret = WINSPOOL_EnumPrinterDrivers(pName, all_printenv[i]->envname, Level,
5074 pDriverInfo, total_found, bufsize, &needed, &found, data_offset);
5075 if (!ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
5077 *pcReturned += found;
5078 *pcbNeeded = needed;
5079 data_offset = needed;
5080 total_found += found;
5085 /* Normal behavior */
5086 ret = WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5087 0, cbBuf, pcbNeeded, &found, 0);
5089 *pcReturned = found;
5094 /*****************************************************************************
5095 * EnumPrinterDriversA [WINSPOOL.@]
5097 * see function EnumPrinterDrivers for RETURNS, BUGS
5099 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5100 LPBYTE pDriverInfo, DWORD cbBuf,
5101 LPDWORD pcbNeeded, LPDWORD pcReturned)
5104 UNICODE_STRING pNameW, pEnvironmentW;
5105 PWSTR pwstrNameW, pwstrEnvironmentW;
5109 buf = HeapAlloc(GetProcessHeap(), 0, cbBuf);
5111 pwstrNameW = asciitounicode(&pNameW, pName);
5112 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5114 ret = EnumPrinterDriversW(pwstrNameW, pwstrEnvironmentW, Level,
5115 buf, cbBuf, pcbNeeded, pcReturned);
5117 convert_driverinfo_W_to_A(pDriverInfo, buf, Level, cbBuf, *pcReturned);
5119 HeapFree(GetProcessHeap(), 0, buf);
5121 RtlFreeUnicodeString(&pNameW);
5122 RtlFreeUnicodeString(&pEnvironmentW);
5127 /******************************************************************************
5128 * EnumPortsA (WINSPOOL.@)
5133 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5134 LPDWORD pcbNeeded, LPDWORD pcReturned)
5137 LPBYTE bufferW = NULL;
5138 LPWSTR nameW = NULL;
5140 DWORD numentries = 0;
5143 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5144 cbBuf, pcbNeeded, pcReturned);
5146 /* convert servername to unicode */
5148 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5149 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5150 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5152 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5153 needed = cbBuf * sizeof(WCHAR);
5154 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5155 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5157 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5158 if (pcbNeeded) needed = *pcbNeeded;
5159 /* HeapReAlloc return NULL, when bufferW was NULL */
5160 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5161 HeapAlloc(GetProcessHeap(), 0, needed);
5163 /* Try again with the large Buffer */
5164 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5166 needed = pcbNeeded ? *pcbNeeded : 0;
5167 numentries = pcReturned ? *pcReturned : 0;
5170 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5171 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5174 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5175 DWORD entrysize = 0;
5178 LPPORT_INFO_2W pi2w;
5179 LPPORT_INFO_2A pi2a;
5182 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5184 /* First pass: calculate the size for all Entries */
5185 pi2w = (LPPORT_INFO_2W) bufferW;
5186 pi2a = (LPPORT_INFO_2A) pPorts;
5188 while (index < numentries) {
5190 needed += entrysize; /* PORT_INFO_?A */
5191 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5193 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5194 NULL, 0, NULL, NULL);
5196 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5197 NULL, 0, NULL, NULL);
5198 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5199 NULL, 0, NULL, NULL);
5201 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5202 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5203 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5206 /* check for errors and quit on failure */
5207 if (cbBuf < needed) {
5208 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5212 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5213 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5214 cbBuf -= len ; /* free Bytes in the user-Buffer */
5215 pi2w = (LPPORT_INFO_2W) bufferW;
5216 pi2a = (LPPORT_INFO_2A) pPorts;
5218 /* Second Pass: Fill the User Buffer (if we have one) */
5219 while ((index < numentries) && pPorts) {
5221 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5222 pi2a->pPortName = ptr;
5223 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5224 ptr, cbBuf , NULL, NULL);
5228 pi2a->pMonitorName = ptr;
5229 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5230 ptr, cbBuf, NULL, NULL);
5234 pi2a->pDescription = ptr;
5235 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5236 ptr, cbBuf, NULL, NULL);
5240 pi2a->fPortType = pi2w->fPortType;
5241 pi2a->Reserved = 0; /* documented: "must be zero" */
5244 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5245 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5246 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5251 if (pcbNeeded) *pcbNeeded = needed;
5252 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5254 HeapFree(GetProcessHeap(), 0, nameW);
5255 HeapFree(GetProcessHeap(), 0, bufferW);
5257 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5258 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5264 /******************************************************************************
5265 * EnumPortsW (WINSPOOL.@)
5267 * Enumerate available Ports
5270 * pName [I] Servername or NULL (local Computer)
5271 * Level [I] Structure-Level (1 or 2)
5272 * pPorts [O] PTR to Buffer that receives the Result
5273 * cbBuf [I] Size of Buffer at pPorts
5274 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
5275 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
5279 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
5282 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5285 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5286 cbBuf, pcbNeeded, pcReturned);
5288 if ((backend == NULL) && !load_backend()) return FALSE;
5290 /* Level is not checked in win9x */
5291 if (!Level || (Level > 2)) {
5292 WARN("level (%d) is ignored in win9x\n", Level);
5293 SetLastError(ERROR_INVALID_LEVEL);
5296 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
5297 SetLastError(RPC_X_NULL_REF_POINTER);
5301 return backend->fpEnumPorts(pName, Level, pPorts, cbBuf, pcbNeeded, pcReturned);
5304 /******************************************************************************
5305 * GetDefaultPrinterW (WINSPOOL.@)
5308 * This function must read the value from data 'device' of key
5309 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5311 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5315 WCHAR *buffer, *ptr;
5319 SetLastError(ERROR_INVALID_PARAMETER);
5323 /* make the buffer big enough for the stuff from the profile/registry,
5324 * the content must fit into the local buffer to compute the correct
5325 * size even if the extern buffer is too small or not given.
5326 * (20 for ,driver,port) */
5328 len = max(100, (insize + 20));
5329 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5331 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5333 SetLastError (ERROR_FILE_NOT_FOUND);
5337 TRACE("%s\n", debugstr_w(buffer));
5339 if ((ptr = strchrW(buffer, ',')) == NULL)
5341 SetLastError(ERROR_INVALID_NAME);
5347 *namesize = strlenW(buffer) + 1;
5348 if(!name || (*namesize > insize))
5350 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5354 strcpyW(name, buffer);
5357 HeapFree( GetProcessHeap(), 0, buffer);
5362 /******************************************************************************
5363 * GetDefaultPrinterA (WINSPOOL.@)
5365 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5369 WCHAR *bufferW = NULL;
5373 SetLastError(ERROR_INVALID_PARAMETER);
5377 if(name && *namesize) {
5379 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5382 if(!GetDefaultPrinterW( bufferW, namesize)) {
5387 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5391 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5394 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5397 HeapFree( GetProcessHeap(), 0, bufferW);
5402 /******************************************************************************
5403 * SetDefaultPrinterW (WINSPOOL.204)
5405 * Set the Name of the Default Printer
5408 * pszPrinter [I] Name of the Printer or NULL
5415 * When the Parameter is NULL or points to an Empty String and
5416 * a Default Printer was already present, then this Function changes nothing.
5417 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5418 * the First enumerated local Printer is used.
5421 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5423 WCHAR default_printer[MAX_PATH];
5424 LPWSTR buffer = NULL;
5430 TRACE("(%s)\n", debugstr_w(pszPrinter));
5431 if ((pszPrinter == NULL) || (pszPrinter[0] == '\0')) {
5433 default_printer[0] = '\0';
5434 size = sizeof(default_printer)/sizeof(WCHAR);
5436 /* if we have a default Printer, do nothing. */
5437 if (GetDefaultPrinterW(default_printer, &size))
5441 /* we have no default Printer: search local Printers and use the first */
5442 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, PrintersW, 0, KEY_READ, &hreg)) {
5444 default_printer[0] = '\0';
5445 size = sizeof(default_printer)/sizeof(WCHAR);
5446 if (!RegEnumKeyExW(hreg, 0, default_printer, &size, NULL, NULL, NULL, NULL)) {
5448 pszPrinter = default_printer;
5449 TRACE("using %s\n", debugstr_w(pszPrinter));
5454 if (pszPrinter == NULL) {
5455 TRACE("no local printer found\n");
5456 SetLastError(ERROR_FILE_NOT_FOUND);
5461 /* "pszPrinter" is never empty or NULL here. */
5462 namelen = lstrlenW(pszPrinter);
5463 size = namelen + (MAX_PATH * 2) + 3; /* printer,driver,port and a 0 */
5464 buffer = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
5466 (RegOpenKeyExW(HKEY_CURRENT_USER, user_printers_reg_key, 0, KEY_READ, &hreg) != ERROR_SUCCESS)) {
5467 HeapFree(GetProcessHeap(), 0, buffer);
5468 SetLastError(ERROR_FILE_NOT_FOUND);
5472 /* read the devices entry for the printer (driver,port) to build the string for the
5473 default device entry (printer,driver,port) */
5474 memcpy(buffer, pszPrinter, namelen * sizeof(WCHAR));
5475 buffer[namelen] = ',';
5476 namelen++; /* move index to the start of the driver */
5478 size = ((MAX_PATH * 2) + 2) * sizeof(WCHAR); /* driver,port and a 0 */
5479 lres = RegQueryValueExW(hreg, pszPrinter, NULL, NULL, (LPBYTE) (&buffer[namelen]), &size);
5481 TRACE("set device to %s\n", debugstr_w(buffer));
5483 if (!WriteProfileStringW(windowsW, deviceW, buffer)) {
5484 TRACE("failed to set the device entry: %d\n", GetLastError());
5485 lres = ERROR_INVALID_PRINTER_NAME;
5488 /* remove the next section, when INIFileMapping is implemented */
5491 if (!RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hdev)) {
5492 RegSetValueExW(hdev, deviceW, 0, REG_SZ, (LPBYTE)buffer, (lstrlenW(buffer) + 1) * sizeof(WCHAR));
5499 if (lres != ERROR_FILE_NOT_FOUND)
5500 FIXME("RegQueryValueExW failed with %d for %s\n", lres, debugstr_w(pszPrinter));
5502 SetLastError(ERROR_INVALID_PRINTER_NAME);
5506 HeapFree(GetProcessHeap(), 0, buffer);
5507 return (lres == ERROR_SUCCESS);
5510 /******************************************************************************
5511 * SetDefaultPrinterA (WINSPOOL.202)
5513 * See SetDefaultPrinterW.
5516 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5518 LPWSTR bufferW = NULL;
5521 TRACE("(%s)\n", debugstr_a(pszPrinter));
5523 INT len = MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, NULL, 0);
5524 bufferW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5525 if (bufferW) MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, bufferW, len);
5527 res = SetDefaultPrinterW(bufferW);
5528 HeapFree(GetProcessHeap(), 0, bufferW);
5532 /******************************************************************************
5533 * SetPrinterDataExA (WINSPOOL.@)
5535 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5536 LPCSTR pValueName, DWORD Type,
5537 LPBYTE pData, DWORD cbData)
5539 HKEY hkeyPrinter, hkeySubkey;
5542 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5543 debugstr_a(pValueName), Type, pData, cbData);
5545 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5549 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5551 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5552 RegCloseKey(hkeyPrinter);
5555 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5556 RegCloseKey(hkeySubkey);
5557 RegCloseKey(hkeyPrinter);
5561 /******************************************************************************
5562 * SetPrinterDataExW (WINSPOOL.@)
5564 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5565 LPCWSTR pValueName, DWORD Type,
5566 LPBYTE pData, DWORD cbData)
5568 HKEY hkeyPrinter, hkeySubkey;
5571 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5572 debugstr_w(pValueName), Type, pData, cbData);
5574 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5578 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5580 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5581 RegCloseKey(hkeyPrinter);
5584 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5585 RegCloseKey(hkeySubkey);
5586 RegCloseKey(hkeyPrinter);
5590 /******************************************************************************
5591 * SetPrinterDataA (WINSPOOL.@)
5593 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5594 LPBYTE pData, DWORD cbData)
5596 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5600 /******************************************************************************
5601 * SetPrinterDataW (WINSPOOL.@)
5603 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5604 LPBYTE pData, DWORD cbData)
5606 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5610 /******************************************************************************
5611 * GetPrinterDataExA (WINSPOOL.@)
5613 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5614 LPCSTR pValueName, LPDWORD pType,
5615 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5617 opened_printer_t *printer;
5618 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5621 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_a(pKeyName),
5622 debugstr_a(pValueName), pType, pData, nSize, pcbNeeded);
5624 printer = get_opened_printer(hPrinter);
5625 if(!printer) return ERROR_INVALID_HANDLE;
5627 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5628 if (ret) return ret;
5630 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5632 if (printer->name) {
5634 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5636 RegCloseKey(hkeyPrinters);
5639 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5640 WARN("Can't open subkey %s: %d\n", debugstr_a(pKeyName), ret);
5641 RegCloseKey(hkeyPrinter);
5642 RegCloseKey(hkeyPrinters);
5647 ret = RegQueryValueExA(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5648 0, pType, pData, pcbNeeded);
5650 if (!ret && !pData) ret = ERROR_MORE_DATA;
5652 RegCloseKey(hkeySubkey);
5653 RegCloseKey(hkeyPrinter);
5654 RegCloseKey(hkeyPrinters);
5656 TRACE("--> %d\n", ret);
5660 /******************************************************************************
5661 * GetPrinterDataExW (WINSPOOL.@)
5663 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5664 LPCWSTR pValueName, LPDWORD pType,
5665 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5667 opened_printer_t *printer;
5668 HKEY hkeyPrinters, hkeyPrinter = 0, hkeySubkey = 0;
5671 TRACE("(%p, %s, %s, %p, %p, %u, %p)\n", hPrinter, debugstr_w(pKeyName),
5672 debugstr_w(pValueName), pType, pData, nSize, pcbNeeded);
5674 printer = get_opened_printer(hPrinter);
5675 if(!printer) return ERROR_INVALID_HANDLE;
5677 ret = RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters);
5678 if (ret) return ret;
5680 TRACE("printer->name: %s\n", debugstr_w(printer->name));
5682 if (printer->name) {
5684 ret = RegOpenKeyW(hkeyPrinters, printer->name, &hkeyPrinter);
5686 RegCloseKey(hkeyPrinters);
5689 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey)) != ERROR_SUCCESS) {
5690 WARN("Can't open subkey %s: %d\n", debugstr_w(pKeyName), ret);
5691 RegCloseKey(hkeyPrinter);
5692 RegCloseKey(hkeyPrinters);
5697 ret = RegQueryValueExW(printer->name ? hkeySubkey : hkeyPrinters, pValueName,
5698 0, pType, pData, pcbNeeded);
5700 if (!ret && !pData) ret = ERROR_MORE_DATA;
5702 RegCloseKey(hkeySubkey);
5703 RegCloseKey(hkeyPrinter);
5704 RegCloseKey(hkeyPrinters);
5706 TRACE("--> %d\n", ret);
5710 /******************************************************************************
5711 * GetPrinterDataA (WINSPOOL.@)
5713 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5714 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5716 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5717 pData, nSize, pcbNeeded);
5720 /******************************************************************************
5721 * GetPrinterDataW (WINSPOOL.@)
5723 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5724 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5726 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5727 pData, nSize, pcbNeeded);
5730 /*******************************************************************************
5731 * EnumPrinterDataExW [WINSPOOL.@]
5733 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5734 LPBYTE pEnumValues, DWORD cbEnumValues,
5735 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5737 HKEY hkPrinter, hkSubKey;
5738 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5739 cbValueNameLen, cbMaxValueLen, cbValueLen,
5744 PPRINTER_ENUM_VALUESW ppev;
5746 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5748 if (pKeyName == NULL || *pKeyName == 0)
5749 return ERROR_INVALID_PARAMETER;
5751 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5752 if (ret != ERROR_SUCCESS)
5754 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5759 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5760 if (ret != ERROR_SUCCESS)
5762 r = RegCloseKey (hkPrinter);
5763 if (r != ERROR_SUCCESS)
5764 WARN ("RegCloseKey returned %i\n", r);
5765 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5766 debugstr_w (pKeyName), ret);
5770 ret = RegCloseKey (hkPrinter);
5771 if (ret != ERROR_SUCCESS)
5773 ERR ("RegCloseKey returned %i\n", ret);
5774 r = RegCloseKey (hkSubKey);
5775 if (r != ERROR_SUCCESS)
5776 WARN ("RegCloseKey returned %i\n", r);
5780 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5781 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5782 if (ret != ERROR_SUCCESS)
5784 r = RegCloseKey (hkSubKey);
5785 if (r != ERROR_SUCCESS)
5786 WARN ("RegCloseKey returned %i\n", r);
5787 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5791 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5792 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5794 if (cValues == 0) /* empty key */
5796 r = RegCloseKey (hkSubKey);
5797 if (r != ERROR_SUCCESS)
5798 WARN ("RegCloseKey returned %i\n", r);
5799 *pcbEnumValues = *pnEnumValues = 0;
5800 return ERROR_SUCCESS;
5803 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5805 hHeap = GetProcessHeap ();
5808 ERR ("GetProcessHeap failed\n");
5809 r = RegCloseKey (hkSubKey);
5810 if (r != ERROR_SUCCESS)
5811 WARN ("RegCloseKey returned %i\n", r);
5812 return ERROR_OUTOFMEMORY;
5815 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5816 if (lpValueName == NULL)
5818 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5819 r = RegCloseKey (hkSubKey);
5820 if (r != ERROR_SUCCESS)
5821 WARN ("RegCloseKey returned %i\n", r);
5822 return ERROR_OUTOFMEMORY;
5825 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5826 if (lpValue == NULL)
5828 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5829 if (HeapFree (hHeap, 0, lpValueName) == 0)
5830 WARN ("HeapFree failed with code %i\n", GetLastError ());
5831 r = RegCloseKey (hkSubKey);
5832 if (r != ERROR_SUCCESS)
5833 WARN ("RegCloseKey returned %i\n", r);
5834 return ERROR_OUTOFMEMORY;
5837 TRACE ("pass 1: calculating buffer required for all names and values\n");
5839 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5841 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5843 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5845 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5846 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5847 NULL, NULL, lpValue, &cbValueLen);
5848 if (ret != ERROR_SUCCESS)
5850 if (HeapFree (hHeap, 0, lpValue) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5852 if (HeapFree (hHeap, 0, lpValueName) == 0)
5853 WARN ("HeapFree failed with code %i\n", GetLastError ());
5854 r = RegCloseKey (hkSubKey);
5855 if (r != ERROR_SUCCESS)
5856 WARN ("RegCloseKey returned %i\n", r);
5857 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5861 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5862 debugstr_w (lpValueName), dwIndex,
5863 cbValueNameLen + 1, cbValueLen);
5865 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5866 cbBufSize += cbValueLen;
5869 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5871 *pcbEnumValues = cbBufSize;
5872 *pnEnumValues = cValues;
5874 if (cbEnumValues < cbBufSize) /* buffer too small */
5876 if (HeapFree (hHeap, 0, lpValue) == 0)
5877 WARN ("HeapFree failed with code %i\n", GetLastError ());
5878 if (HeapFree (hHeap, 0, lpValueName) == 0)
5879 WARN ("HeapFree failed with code %i\n", GetLastError ());
5880 r = RegCloseKey (hkSubKey);
5881 if (r != ERROR_SUCCESS)
5882 WARN ("RegCloseKey returned %i\n", r);
5883 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5884 return ERROR_MORE_DATA;
5887 TRACE ("pass 2: copying all names and values to buffer\n");
5889 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5890 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5892 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5894 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5895 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5896 NULL, &dwType, lpValue, &cbValueLen);
5897 if (ret != ERROR_SUCCESS)
5899 if (HeapFree (hHeap, 0, lpValue) == 0)
5900 WARN ("HeapFree failed with code %i\n", GetLastError ());
5901 if (HeapFree (hHeap, 0, lpValueName) == 0)
5902 WARN ("HeapFree failed with code %i\n", GetLastError ());
5903 r = RegCloseKey (hkSubKey);
5904 if (r != ERROR_SUCCESS)
5905 WARN ("RegCloseKey returned %i\n", r);
5906 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5910 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5911 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5912 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5913 pEnumValues += cbValueNameLen;
5915 /* return # of *bytes* (including trailing \0), not # of chars */
5916 ppev[dwIndex].cbValueName = cbValueNameLen;
5918 ppev[dwIndex].dwType = dwType;
5920 memcpy (pEnumValues, lpValue, cbValueLen);
5921 ppev[dwIndex].pData = pEnumValues;
5922 pEnumValues += cbValueLen;
5924 ppev[dwIndex].cbData = cbValueLen;
5926 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5927 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5930 if (HeapFree (hHeap, 0, lpValue) == 0)
5932 ret = GetLastError ();
5933 ERR ("HeapFree failed with code %i\n", ret);
5934 if (HeapFree (hHeap, 0, lpValueName) == 0)
5935 WARN ("HeapFree failed with code %i\n", GetLastError ());
5936 r = RegCloseKey (hkSubKey);
5937 if (r != ERROR_SUCCESS)
5938 WARN ("RegCloseKey returned %i\n", r);
5942 if (HeapFree (hHeap, 0, lpValueName) == 0)
5944 ret = GetLastError ();
5945 ERR ("HeapFree failed with code %i\n", ret);
5946 r = RegCloseKey (hkSubKey);
5947 if (r != ERROR_SUCCESS)
5948 WARN ("RegCloseKey returned %i\n", r);
5952 ret = RegCloseKey (hkSubKey);
5953 if (ret != ERROR_SUCCESS)
5955 ERR ("RegCloseKey returned %i\n", ret);
5959 return ERROR_SUCCESS;
5962 /*******************************************************************************
5963 * EnumPrinterDataExA [WINSPOOL.@]
5965 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5966 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5967 * what Windows 2000 SP1 does.
5970 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5971 LPBYTE pEnumValues, DWORD cbEnumValues,
5972 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5976 DWORD ret, dwIndex, dwBufSize;
5980 TRACE ("%p %s\n", hPrinter, pKeyName);
5982 if (pKeyName == NULL || *pKeyName == 0)
5983 return ERROR_INVALID_PARAMETER;
5985 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5988 ret = GetLastError ();
5989 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5993 hHeap = GetProcessHeap ();
5996 ERR ("GetProcessHeap failed\n");
5997 return ERROR_OUTOFMEMORY;
6000 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6001 if (pKeyNameW == NULL)
6003 ERR ("Failed to allocate %i bytes from process heap\n",
6004 (LONG)(len * sizeof (WCHAR)));
6005 return ERROR_OUTOFMEMORY;
6008 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6010 ret = GetLastError ();
6011 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6012 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6013 WARN ("HeapFree failed with code %i\n", GetLastError ());
6017 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6018 pcbEnumValues, pnEnumValues);
6019 if (ret != ERROR_SUCCESS)
6021 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6022 WARN ("HeapFree failed with code %i\n", GetLastError ());
6023 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6027 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6029 ret = GetLastError ();
6030 ERR ("HeapFree failed with code %i\n", ret);
6034 if (*pnEnumValues == 0) /* empty key */
6035 return ERROR_SUCCESS;
6038 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6040 PPRINTER_ENUM_VALUESW ppev =
6041 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6043 if (dwBufSize < ppev->cbValueName)
6044 dwBufSize = ppev->cbValueName;
6046 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6047 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6048 dwBufSize = ppev->cbData;
6051 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6053 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6054 if (pBuffer == NULL)
6056 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6057 return ERROR_OUTOFMEMORY;
6060 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6062 PPRINTER_ENUM_VALUESW ppev =
6063 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6065 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6066 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6070 ret = GetLastError ();
6071 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6072 if (HeapFree (hHeap, 0, pBuffer) == 0)
6073 WARN ("HeapFree failed with code %i\n", GetLastError ());
6077 memcpy (ppev->pValueName, pBuffer, len);
6079 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6081 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6082 ppev->dwType != REG_MULTI_SZ)
6085 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6086 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6089 ret = GetLastError ();
6090 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6091 if (HeapFree (hHeap, 0, pBuffer) == 0)
6092 WARN ("HeapFree failed with code %i\n", GetLastError ());
6096 memcpy (ppev->pData, pBuffer, len);
6098 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6099 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6102 if (HeapFree (hHeap, 0, pBuffer) == 0)
6104 ret = GetLastError ();
6105 ERR ("HeapFree failed with code %i\n", ret);
6109 return ERROR_SUCCESS;
6112 /******************************************************************************
6113 * AbortPrinter (WINSPOOL.@)
6115 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6117 FIXME("(%p), stub!\n", hPrinter);
6121 /******************************************************************************
6122 * AddPortA (WINSPOOL.@)
6127 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6129 LPWSTR nameW = NULL;
6130 LPWSTR monitorW = NULL;
6134 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6137 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6138 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6139 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6143 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6144 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6145 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6147 res = AddPortW(nameW, hWnd, monitorW);
6148 HeapFree(GetProcessHeap(), 0, nameW);
6149 HeapFree(GetProcessHeap(), 0, monitorW);
6153 /******************************************************************************
6154 * AddPortW (WINSPOOL.@)
6156 * Add a Port for a specific Monitor
6159 * pName [I] Servername or NULL (local Computer)
6160 * hWnd [I] Handle to parent Window for the Dialog-Box
6161 * pMonitorName [I] Name of the Monitor that manage the Port
6168 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6170 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6172 if ((backend == NULL) && !load_backend()) return FALSE;
6174 if (!pMonitorName) {
6175 SetLastError(RPC_X_NULL_REF_POINTER);
6179 return backend->fpAddPort(pName, hWnd, pMonitorName);
6182 /******************************************************************************
6183 * AddPortExA (WINSPOOL.@)
6188 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6191 PORT_INFO_2A * pi2A;
6192 LPWSTR nameW = NULL;
6193 LPWSTR monitorW = NULL;
6197 pi2A = (PORT_INFO_2A *) pBuffer;
6199 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6200 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6202 if ((level < 1) || (level > 2)) {
6203 SetLastError(ERROR_INVALID_LEVEL);
6208 SetLastError(ERROR_INVALID_PARAMETER);
6213 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6214 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6215 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6219 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6220 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6221 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6224 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6226 if (pi2A->pPortName) {
6227 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6228 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6229 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6233 if (pi2A->pMonitorName) {
6234 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6235 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6236 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6239 if (pi2A->pDescription) {
6240 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6241 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6242 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6244 pi2W.fPortType = pi2A->fPortType;
6245 pi2W.Reserved = pi2A->Reserved;
6248 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6250 HeapFree(GetProcessHeap(), 0, nameW);
6251 HeapFree(GetProcessHeap(), 0, monitorW);
6252 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6253 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6254 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6259 /******************************************************************************
6260 * AddPortExW (WINSPOOL.@)
6262 * Add a Port for a specific Monitor, without presenting a user interface
6265 * pName [I] Servername or NULL (local Computer)
6266 * level [I] Structure-Level (1 or 2) for pBuffer
6267 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6268 * pMonitorName [I] Name of the Monitor that manage the Port
6275 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6279 pi2 = (PORT_INFO_2W *) pBuffer;
6281 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6282 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6283 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6284 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6286 if ((backend == NULL) && !load_backend()) return FALSE;
6288 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6289 SetLastError(ERROR_INVALID_PARAMETER);
6293 return backend->fpAddPortEx(pName, level, pBuffer, pMonitorName);
6296 /******************************************************************************
6297 * AddPrinterConnectionA (WINSPOOL.@)
6299 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6301 FIXME("%s\n", debugstr_a(pName));
6305 /******************************************************************************
6306 * AddPrinterConnectionW (WINSPOOL.@)
6308 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6310 FIXME("%s\n", debugstr_w(pName));
6314 /******************************************************************************
6315 * AddPrinterDriverExW (WINSPOOL.@)
6317 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6320 * pName [I] Servername or NULL (local Computer)
6321 * level [I] Level for the supplied DRIVER_INFO_*W struct
6322 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6323 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6330 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6332 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6334 if ((backend == NULL) && !load_backend()) return FALSE;
6336 if (level < 2 || level == 5 || level == 7 || level > 8) {
6337 SetLastError(ERROR_INVALID_LEVEL);
6342 SetLastError(ERROR_INVALID_PARAMETER);
6346 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6349 /******************************************************************************
6350 * AddPrinterDriverExA (WINSPOOL.@)
6352 * See AddPrinterDriverExW.
6355 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6357 DRIVER_INFO_8A *diA;
6359 LPWSTR nameW = NULL;
6364 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6366 diA = (DRIVER_INFO_8A *) pDriverInfo;
6367 ZeroMemory(&diW, sizeof(diW));
6369 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6370 SetLastError(ERROR_INVALID_LEVEL);
6375 SetLastError(ERROR_INVALID_PARAMETER);
6379 /* convert servername to unicode */
6381 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6382 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6383 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6387 diW.cVersion = diA->cVersion;
6390 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6391 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6392 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6395 if (diA->pEnvironment) {
6396 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6397 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6398 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6401 if (diA->pDriverPath) {
6402 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6403 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6404 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6407 if (diA->pDataFile) {
6408 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6409 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6410 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6413 if (diA->pConfigFile) {
6414 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6415 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6416 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6419 if ((Level > 2) && diA->pDependentFiles) {
6420 lenA = multi_sz_lenA(diA->pDependentFiles);
6421 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6422 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6423 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6426 if ((Level > 2) && diA->pMonitorName) {
6427 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6428 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6429 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6432 if ((Level > 3) && diA->pDefaultDataType) {
6433 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6434 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6435 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6438 if ((Level > 3) && diA->pszzPreviousNames) {
6439 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6440 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6441 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6442 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6445 if ((Level > 5) && diA->pszMfgName) {
6446 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6447 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6448 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6451 if ((Level > 5) && diA->pszOEMUrl) {
6452 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6453 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6454 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6457 if ((Level > 5) && diA->pszHardwareID) {
6458 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6459 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6460 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6463 if ((Level > 5) && diA->pszProvider) {
6464 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6465 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6466 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6470 FIXME("level %u is incomplete\n", Level);
6473 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6474 TRACE("got %u with %u\n", res, GetLastError());
6475 HeapFree(GetProcessHeap(), 0, nameW);
6476 HeapFree(GetProcessHeap(), 0, diW.pName);
6477 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6478 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6479 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6480 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6481 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6482 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6483 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6484 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6485 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6486 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6487 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6488 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6490 TRACE("=> %u with %u\n", res, GetLastError());
6494 /******************************************************************************
6495 * ConfigurePortA (WINSPOOL.@)
6497 * See ConfigurePortW.
6500 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6502 LPWSTR nameW = NULL;
6503 LPWSTR portW = NULL;
6507 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6509 /* convert servername to unicode */
6511 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6512 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6513 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6516 /* convert portname to unicode */
6518 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6519 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6520 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6523 res = ConfigurePortW(nameW, hWnd, portW);
6524 HeapFree(GetProcessHeap(), 0, nameW);
6525 HeapFree(GetProcessHeap(), 0, portW);
6529 /******************************************************************************
6530 * ConfigurePortW (WINSPOOL.@)
6532 * Display the Configuration-Dialog for a specific Port
6535 * pName [I] Servername or NULL (local Computer)
6536 * hWnd [I] Handle to parent Window for the Dialog-Box
6537 * pPortName [I] Name of the Port, that should be configured
6544 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6547 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6549 if ((backend == NULL) && !load_backend()) return FALSE;
6552 SetLastError(RPC_X_NULL_REF_POINTER);
6556 return backend->fpConfigurePort(pName, hWnd, pPortName);
6559 /******************************************************************************
6560 * ConnectToPrinterDlg (WINSPOOL.@)
6562 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6564 FIXME("%p %x\n", hWnd, Flags);
6568 /******************************************************************************
6569 * DeletePrinterConnectionA (WINSPOOL.@)
6571 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6573 FIXME("%s\n", debugstr_a(pName));
6577 /******************************************************************************
6578 * DeletePrinterConnectionW (WINSPOOL.@)
6580 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6582 FIXME("%s\n", debugstr_w(pName));
6586 /******************************************************************************
6587 * DeletePrinterDriverExW (WINSPOOL.@)
6589 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6590 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6595 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6596 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6598 if(pName && pName[0])
6600 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6601 SetLastError(ERROR_INVALID_PARAMETER);
6607 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6608 SetLastError(ERROR_INVALID_PARAMETER);
6612 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment);
6616 ERR("Can't open drivers key\n");
6620 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6623 RegCloseKey(hkey_drivers);
6628 /******************************************************************************
6629 * DeletePrinterDriverExA (WINSPOOL.@)
6631 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6632 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6634 UNICODE_STRING NameW, EnvW, DriverW;
6637 asciitounicode(&NameW, pName);
6638 asciitounicode(&EnvW, pEnvironment);
6639 asciitounicode(&DriverW, pDriverName);
6641 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6643 RtlFreeUnicodeString(&DriverW);
6644 RtlFreeUnicodeString(&EnvW);
6645 RtlFreeUnicodeString(&NameW);
6650 /******************************************************************************
6651 * DeletePrinterDataExW (WINSPOOL.@)
6653 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6656 FIXME("%p %s %s\n", hPrinter,
6657 debugstr_w(pKeyName), debugstr_w(pValueName));
6658 return ERROR_INVALID_PARAMETER;
6661 /******************************************************************************
6662 * DeletePrinterDataExA (WINSPOOL.@)
6664 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6667 FIXME("%p %s %s\n", hPrinter,
6668 debugstr_a(pKeyName), debugstr_a(pValueName));
6669 return ERROR_INVALID_PARAMETER;
6672 /******************************************************************************
6673 * DeletePrintProcessorA (WINSPOOL.@)
6675 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6677 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6678 debugstr_a(pPrintProcessorName));
6682 /******************************************************************************
6683 * DeletePrintProcessorW (WINSPOOL.@)
6685 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6687 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6688 debugstr_w(pPrintProcessorName));
6692 /******************************************************************************
6693 * DeletePrintProvidorA (WINSPOOL.@)
6695 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6697 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6698 debugstr_a(pPrintProviderName));
6702 /******************************************************************************
6703 * DeletePrintProvidorW (WINSPOOL.@)
6705 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6707 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6708 debugstr_w(pPrintProviderName));
6712 /******************************************************************************
6713 * EnumFormsA (WINSPOOL.@)
6715 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6716 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6718 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6719 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6723 /******************************************************************************
6724 * EnumFormsW (WINSPOOL.@)
6726 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6727 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6729 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6730 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6734 /*****************************************************************************
6735 * EnumMonitorsA [WINSPOOL.@]
6737 * See EnumMonitorsW.
6740 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6741 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6744 LPBYTE bufferW = NULL;
6745 LPWSTR nameW = NULL;
6747 DWORD numentries = 0;
6750 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6751 cbBuf, pcbNeeded, pcReturned);
6753 /* convert servername to unicode */
6755 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6756 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6757 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6759 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6760 needed = cbBuf * sizeof(WCHAR);
6761 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6762 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6764 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6765 if (pcbNeeded) needed = *pcbNeeded;
6766 /* HeapReAlloc return NULL, when bufferW was NULL */
6767 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6768 HeapAlloc(GetProcessHeap(), 0, needed);
6770 /* Try again with the large Buffer */
6771 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6773 numentries = pcReturned ? *pcReturned : 0;
6776 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6777 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6780 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6781 DWORD entrysize = 0;
6784 LPMONITOR_INFO_2W mi2w;
6785 LPMONITOR_INFO_2A mi2a;
6787 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6788 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6790 /* First pass: calculate the size for all Entries */
6791 mi2w = (LPMONITOR_INFO_2W) bufferW;
6792 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6794 while (index < numentries) {
6796 needed += entrysize; /* MONITOR_INFO_?A */
6797 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6799 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6800 NULL, 0, NULL, NULL);
6802 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6803 NULL, 0, NULL, NULL);
6804 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6805 NULL, 0, NULL, NULL);
6807 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6808 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6809 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6812 /* check for errors and quit on failure */
6813 if (cbBuf < needed) {
6814 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6818 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6819 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6820 cbBuf -= len ; /* free Bytes in the user-Buffer */
6821 mi2w = (LPMONITOR_INFO_2W) bufferW;
6822 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6824 /* Second Pass: Fill the User Buffer (if we have one) */
6825 while ((index < numentries) && pMonitors) {
6827 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6829 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6830 ptr, cbBuf , NULL, NULL);
6834 mi2a->pEnvironment = ptr;
6835 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6836 ptr, cbBuf, NULL, NULL);
6840 mi2a->pDLLName = ptr;
6841 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6842 ptr, cbBuf, NULL, NULL);
6846 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6847 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6848 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6852 if (pcbNeeded) *pcbNeeded = needed;
6853 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6855 HeapFree(GetProcessHeap(), 0, nameW);
6856 HeapFree(GetProcessHeap(), 0, bufferW);
6858 TRACE("returning %d with %d (%d byte for %d entries)\n",
6859 (res), GetLastError(), needed, numentries);
6865 /*****************************************************************************
6866 * EnumMonitorsW [WINSPOOL.@]
6868 * Enumerate available Port-Monitors
6871 * pName [I] Servername or NULL (local Computer)
6872 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6873 * pMonitors [O] PTR to Buffer that receives the Result
6874 * cbBuf [I] Size of Buffer at pMonitors
6875 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6876 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6880 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6883 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6884 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6887 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6888 cbBuf, pcbNeeded, pcReturned);
6890 if ((backend == NULL) && !load_backend()) return FALSE;
6892 if (!pcbNeeded || !pcReturned || (!pMonitors && (cbBuf > 0))) {
6893 SetLastError(RPC_X_NULL_REF_POINTER);
6897 return backend->fpEnumMonitors(pName, Level, pMonitors, cbBuf, pcbNeeded, pcReturned);
6900 /******************************************************************************
6901 * SpoolerInit (WINSPOOL.@)
6903 * Initialize the Spooler
6910 * The function fails on windows, when the spooler service is not running
6913 BOOL WINAPI SpoolerInit(void)
6916 if ((backend == NULL) && !load_backend()) return FALSE;
6920 /******************************************************************************
6921 * XcvDataW (WINSPOOL.@)
6923 * Execute commands in the Printmonitor DLL
6926 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6927 * pszDataName [i] Name of the command to execute
6928 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6929 * cbInputData [i] Size in Bytes of Buffer at pInputData
6930 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6931 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6932 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6933 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6940 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6941 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6943 * Minimal List of commands, that a Printmonitor DLL should support:
6945 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6946 *| "AddPort" : Add a Port
6947 *| "DeletePort": Delete a Port
6949 * Many Printmonitors support additional commands. Examples for localspl.dll:
6950 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6951 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6954 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6955 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6956 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6958 opened_printer_t *printer;
6960 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6961 pInputData, cbInputData, pOutputData,
6962 cbOutputData, pcbOutputNeeded, pdwStatus);
6964 if ((backend == NULL) && !load_backend()) return FALSE;
6966 printer = get_opened_printer(hXcv);
6967 if (!printer || (!printer->backend_printer)) {
6968 SetLastError(ERROR_INVALID_HANDLE);
6972 if (!pcbOutputNeeded) {
6973 SetLastError(ERROR_INVALID_PARAMETER);
6977 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6978 SetLastError(RPC_X_NULL_REF_POINTER);
6982 *pcbOutputNeeded = 0;
6984 return backend->fpXcvData(printer->backend_printer, pszDataName, pInputData,
6985 cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
6989 /*****************************************************************************
6990 * EnumPrinterDataA [WINSPOOL.@]
6993 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6994 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6995 DWORD cbData, LPDWORD pcbData )
6997 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6998 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6999 return ERROR_NO_MORE_ITEMS;
7002 /*****************************************************************************
7003 * EnumPrinterDataW [WINSPOOL.@]
7006 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7007 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7008 DWORD cbData, LPDWORD pcbData )
7010 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7011 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7012 return ERROR_NO_MORE_ITEMS;
7015 /*****************************************************************************
7016 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7019 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7020 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7021 LPDWORD pcbNeeded, LPDWORD pcReturned)
7023 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7024 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7025 pcbNeeded, pcReturned);
7029 /*****************************************************************************
7030 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7033 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7034 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7035 LPDWORD pcbNeeded, LPDWORD pcReturned)
7037 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7038 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7039 pcbNeeded, pcReturned);
7043 /*****************************************************************************
7044 * EnumPrintProcessorsA [WINSPOOL.@]
7046 * See EnumPrintProcessorsW.
7049 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7050 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7053 LPBYTE bufferW = NULL;
7054 LPWSTR nameW = NULL;
7057 DWORD numentries = 0;
7060 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), debugstr_a(pEnvironment),
7061 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7063 /* convert names to unicode */
7065 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7066 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7067 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7070 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
7071 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7072 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, envW, len);
7075 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7076 needed = cbBuf * sizeof(WCHAR);
7077 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7078 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7080 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7081 if (pcbNeeded) needed = *pcbNeeded;
7082 /* HeapReAlloc return NULL, when bufferW was NULL */
7083 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7084 HeapAlloc(GetProcessHeap(), 0, needed);
7086 /* Try again with the large Buffer */
7087 res = EnumPrintProcessorsW(nameW, envW, Level, bufferW, needed, pcbNeeded, pcReturned);
7089 numentries = pcReturned ? *pcReturned : 0;
7093 /* EnumPrintProcessorsW collected all Data. Parse them to calculate ANSI-Size */
7096 PPRINTPROCESSOR_INFO_1W ppiw;
7097 PPRINTPROCESSOR_INFO_1A ppia;
7099 /* First pass: calculate the size for all Entries */
7100 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7101 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7103 while (index < numentries) {
7105 needed += sizeof(PRINTPROCESSOR_INFO_1A);
7106 TRACE("%p: parsing #%d (%s)\n", ppiw, index, debugstr_w(ppiw->pName));
7108 needed += WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7109 NULL, 0, NULL, NULL);
7111 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7112 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7115 /* check for errors and quit on failure */
7116 if (cbBuf < needed) {
7117 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7122 len = numentries * sizeof(PRINTPROCESSOR_INFO_1A); /* room for structs */
7123 ptr = (LPSTR) &pPPInfo[len]; /* start of strings */
7124 cbBuf -= len ; /* free Bytes in the user-Buffer */
7125 ppiw = (PPRINTPROCESSOR_INFO_1W) bufferW;
7126 ppia = (PPRINTPROCESSOR_INFO_1A) pPPInfo;
7128 /* Second Pass: Fill the User Buffer (if we have one) */
7129 while ((index < numentries) && pPPInfo) {
7131 TRACE("%p: writing PRINTPROCESSOR_INFO_1A #%d\n", ppia, index);
7133 len = WideCharToMultiByte(CP_ACP, 0, ppiw->pName, -1,
7134 ptr, cbBuf , NULL, NULL);
7138 ppiw = (PPRINTPROCESSOR_INFO_1W) (((LPBYTE)ppiw) + sizeof(PRINTPROCESSOR_INFO_1W));
7139 ppia = (PPRINTPROCESSOR_INFO_1A) (((LPBYTE)ppia) + sizeof(PRINTPROCESSOR_INFO_1A));
7144 if (pcbNeeded) *pcbNeeded = needed;
7145 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7147 HeapFree(GetProcessHeap(), 0, nameW);
7148 HeapFree(GetProcessHeap(), 0, envW);
7149 HeapFree(GetProcessHeap(), 0, bufferW);
7151 TRACE("returning %d with %d (%d byte for %d entries)\n",
7152 (res), GetLastError(), needed, numentries);
7157 /*****************************************************************************
7158 * EnumPrintProcessorsW [WINSPOOL.@]
7160 * Enumerate available Print Processors
7163 * pName [I] Servername or NULL (local Computer)
7164 * pEnvironment [I] Printing-Environment or NULL (Default)
7165 * Level [I] Structure-Level (Only 1 is allowed)
7166 * pPPInfo [O] PTR to Buffer that receives the Result
7167 * cbBuf [I] Size of Buffer at pPPInfo
7168 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
7169 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
7173 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
7176 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7177 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7180 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
7181 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
7183 if ((backend == NULL) && !load_backend()) return FALSE;
7185 if (!pcbNeeded || !pcReturned) {
7186 SetLastError(RPC_X_NULL_REF_POINTER);
7190 if (!pPPInfo && (cbBuf > 0)) {
7191 SetLastError(ERROR_INVALID_USER_BUFFER);
7195 return backend->fpEnumPrintProcessors(pName, pEnvironment, Level, pPPInfo,
7196 cbBuf, pcbNeeded, pcReturned);
7199 /*****************************************************************************
7200 * ExtDeviceMode [WINSPOOL.@]
7203 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7204 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7207 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7208 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7209 debugstr_a(pProfile), fMode);
7213 /*****************************************************************************
7214 * FindClosePrinterChangeNotification [WINSPOOL.@]
7217 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7219 FIXME("Stub: %p\n", hChange);
7223 /*****************************************************************************
7224 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7227 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7228 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7230 FIXME("Stub: %p %x %x %p\n",
7231 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7232 return INVALID_HANDLE_VALUE;
7235 /*****************************************************************************
7236 * FindNextPrinterChangeNotification [WINSPOOL.@]
7239 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7240 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7242 FIXME("Stub: %p %p %p %p\n",
7243 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7247 /*****************************************************************************
7248 * FreePrinterNotifyInfo [WINSPOOL.@]
7251 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7253 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7257 /*****************************************************************************
7260 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7261 * ansi depending on the unicode parameter.
7263 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7273 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7276 memcpy(ptr, str, *size);
7283 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7286 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7293 /*****************************************************************************
7296 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7297 LPDWORD pcbNeeded, BOOL unicode)
7299 DWORD size, left = cbBuf;
7300 BOOL space = (cbBuf > 0);
7307 ji1->JobId = job->job_id;
7310 string_to_buf(job->document_title, ptr, left, &size, unicode);
7311 if(space && size <= left)
7313 ji1->pDocument = (LPWSTR)ptr;
7321 if (job->printer_name)
7323 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7324 if(space && size <= left)
7326 ji1->pPrinterName = (LPWSTR)ptr;
7338 /*****************************************************************************
7341 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7342 LPDWORD pcbNeeded, BOOL unicode)
7344 DWORD size, left = cbBuf;
7346 BOOL space = (cbBuf > 0);
7348 LPDEVMODEA dmA = NULL;
7355 ji2->JobId = job->job_id;
7358 string_to_buf(job->document_title, ptr, left, &size, unicode);
7359 if(space && size <= left)
7361 ji2->pDocument = (LPWSTR)ptr;
7369 if (job->printer_name)
7371 string_to_buf(job->printer_name, ptr, left, &size, unicode);
7372 if(space && size <= left)
7374 ji2->pPrinterName = (LPWSTR)ptr;
7387 dmA = DEVMODEdupWtoA(job->devmode);
7388 devmode = (LPDEVMODEW) dmA;
7389 if (dmA) size = dmA->dmSize + dmA->dmDriverExtra;
7393 devmode = job->devmode;
7394 size = devmode->dmSize + devmode->dmDriverExtra;
7398 FIXME("Can't convert DEVMODE W to A\n");
7401 /* align DEVMODE to a DWORD boundary */
7402 shift = (4 - (*pcbNeeded & 3)) & 3;
7408 memcpy(ptr, devmode, size-shift);
7409 ji2->pDevMode = (LPDEVMODEW)ptr;
7410 if (!unicode) HeapFree(GetProcessHeap(), 0, dmA);
7423 /*****************************************************************************
7426 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7427 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7430 DWORD needed = 0, size;
7434 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7436 EnterCriticalSection(&printer_handles_cs);
7437 job = get_job(hPrinter, JobId);
7444 size = sizeof(JOB_INFO_1W);
7449 memset(pJob, 0, size);
7453 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7458 size = sizeof(JOB_INFO_2W);
7463 memset(pJob, 0, size);
7467 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7472 size = sizeof(JOB_INFO_3);
7476 memset(pJob, 0, size);
7485 SetLastError(ERROR_INVALID_LEVEL);
7489 *pcbNeeded = needed;
7491 LeaveCriticalSection(&printer_handles_cs);
7495 /*****************************************************************************
7496 * GetJobA [WINSPOOL.@]
7499 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7500 DWORD cbBuf, LPDWORD pcbNeeded)
7502 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7505 /*****************************************************************************
7506 * GetJobW [WINSPOOL.@]
7509 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7510 DWORD cbBuf, LPDWORD pcbNeeded)
7512 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7515 /*****************************************************************************
7518 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7521 char *unixname, *cmdA;
7523 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7529 if(!(unixname = wine_get_unix_file_name(filename)))
7532 len = WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, NULL, 0, NULL, NULL);
7533 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7534 WideCharToMultiByte(CP_UNIXCP, 0, cmd, -1, cmdA, len, NULL, NULL);
7536 TRACE("printing with: %s\n", cmdA);
7538 if((file_fd = open(unixname, O_RDONLY)) == -1)
7543 ERR("pipe() failed!\n");
7547 if ((pid = fork()) == 0)
7553 /* reset signals that we previously set to SIG_IGN */
7554 signal(SIGPIPE, SIG_DFL);
7556 execl("/bin/sh", "/bin/sh", "-c", cmdA, NULL);
7561 ERR("fork() failed!\n");
7565 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7566 write(fds[1], buf, no_read);
7573 wret = waitpid(pid, &status, 0);
7574 } while (wret < 0 && errno == EINTR);
7577 ERR("waitpid() failed!\n");
7580 if (!WIFEXITED(status) || WEXITSTATUS(status))
7582 ERR("child process failed! %d\n", status);
7589 if(file_fd != -1) close(file_fd);
7590 if(fds[0] != -1) close(fds[0]);
7591 if(fds[1] != -1) close(fds[1]);
7593 HeapFree(GetProcessHeap(), 0, cmdA);
7594 HeapFree(GetProcessHeap(), 0, unixname);
7601 /*****************************************************************************
7604 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7607 const WCHAR fmtW[] = {'l','p','r',' ','-','P','\'','%','s','\'',0};
7610 cmd = HeapAlloc(GetProcessHeap(), 0, strlenW(printer_name) * sizeof(WCHAR) + sizeof(fmtW));
7611 sprintfW(cmd, fmtW, printer_name);
7613 r = schedule_pipe(cmd, filename);
7615 HeapFree(GetProcessHeap(), 0, cmd);
7619 /*****************************************************************************
7622 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7624 #ifdef SONAME_LIBCUPS
7627 char *unixname, *queue, *unix_doc_title;
7631 if(!(unixname = wine_get_unix_file_name(filename)))
7634 len = WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7635 queue = HeapAlloc(GetProcessHeap(), 0, len);
7636 WideCharToMultiByte(CP_UNIXCP, 0, printer_name, -1, queue, len, NULL, NULL);
7638 len = WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, NULL, 0, NULL, NULL);
7639 unix_doc_title = HeapAlloc(GetProcessHeap(), 0, len);
7640 WideCharToMultiByte(CP_UNIXCP, 0, document_title, -1, unix_doc_title, len, NULL, NULL);
7642 TRACE("printing via cups\n");
7643 ret = pcupsPrintFile(queue, unixname, unix_doc_title, 0, NULL);
7644 HeapFree(GetProcessHeap(), 0, unix_doc_title);
7645 HeapFree(GetProcessHeap(), 0, queue);
7646 HeapFree(GetProcessHeap(), 0, unixname);
7652 return schedule_lpr(printer_name, filename);
7656 static INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7663 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7667 if(HIWORD(wparam) == BN_CLICKED)
7669 if(LOWORD(wparam) == IDOK)
7672 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7675 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7676 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7678 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7680 WCHAR caption[200], message[200];
7683 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7684 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7685 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7686 if(mb_ret == IDCANCEL)
7688 HeapFree(GetProcessHeap(), 0, filename);
7692 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7693 if(hf == INVALID_HANDLE_VALUE)
7695 WCHAR caption[200], message[200];
7697 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7698 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7699 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7700 HeapFree(GetProcessHeap(), 0, filename);
7704 DeleteFileW(filename);
7705 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7707 EndDialog(hwnd, IDOK);
7710 if(LOWORD(wparam) == IDCANCEL)
7712 EndDialog(hwnd, IDCANCEL);
7721 /*****************************************************************************
7724 static BOOL get_filename(LPWSTR *filename)
7726 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7727 file_dlg_proc, (LPARAM)filename) == IDOK;
7730 /*****************************************************************************
7733 static BOOL schedule_file(LPCWSTR filename)
7735 LPWSTR output = NULL;
7737 if(get_filename(&output))
7740 TRACE("copy to %s\n", debugstr_w(output));
7741 r = CopyFileW(filename, output, FALSE);
7742 HeapFree(GetProcessHeap(), 0, output);
7748 /*****************************************************************************
7751 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7753 int in_fd, out_fd, no_read;
7756 char *unixname, *outputA;
7759 if(!(unixname = wine_get_unix_file_name(filename)))
7762 len = WideCharToMultiByte(CP_UNIXCP, 0, output, -1, NULL, 0, NULL, NULL);
7763 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7764 WideCharToMultiByte(CP_UNIXCP, 0, output, -1, outputA, len, NULL, NULL);
7766 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7767 in_fd = open(unixname, O_RDONLY);
7768 if(out_fd == -1 || in_fd == -1)
7771 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7772 write(out_fd, buf, no_read);
7776 if(in_fd != -1) close(in_fd);
7777 if(out_fd != -1) close(out_fd);
7778 HeapFree(GetProcessHeap(), 0, outputA);
7779 HeapFree(GetProcessHeap(), 0, unixname);
7783 /*****************************************************************************
7784 * ScheduleJob [WINSPOOL.@]
7787 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7789 opened_printer_t *printer;
7791 struct list *cursor, *cursor2;
7793 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7794 EnterCriticalSection(&printer_handles_cs);
7795 printer = get_opened_printer(hPrinter);
7799 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7801 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7804 if(job->job_id != dwJobID) continue;
7806 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7807 if(hf != INVALID_HANDLE_VALUE)
7809 PRINTER_INFO_5W *pi5 = NULL;
7810 LPWSTR portname = job->portname;
7814 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7815 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7819 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7820 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7821 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7822 portname = pi5->pPortName;
7824 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7825 debugstr_w(portname));
7829 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7830 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7832 DWORD type, count = sizeof(output);
7833 RegQueryValueExW(hkey, portname, NULL, &type, (LPBYTE)output, &count);
7836 if(output[0] == '|')
7838 ret = schedule_pipe(output + 1, job->filename);
7842 ret = schedule_unixfile(output, job->filename);
7844 else if(!strncmpW(portname, LPR_Port, strlenW(LPR_Port)))
7846 ret = schedule_lpr(portname + strlenW(LPR_Port), job->filename);
7848 else if(!strncmpW(portname, CUPS_Port, strlenW(CUPS_Port)))
7850 ret = schedule_cups(portname + strlenW(CUPS_Port), job->filename, job->document_title);
7852 else if(!strncmpW(portname, FILE_Port, strlenW(FILE_Port)))
7854 ret = schedule_file(job->filename);
7858 FIXME("can't schedule to port %s\n", debugstr_w(portname));
7860 HeapFree(GetProcessHeap(), 0, pi5);
7862 DeleteFileW(job->filename);
7864 list_remove(cursor);
7865 HeapFree(GetProcessHeap(), 0, job->document_title);
7866 HeapFree(GetProcessHeap(), 0, job->printer_name);
7867 HeapFree(GetProcessHeap(), 0, job->portname);
7868 HeapFree(GetProcessHeap(), 0, job->filename);
7869 HeapFree(GetProcessHeap(), 0, job->devmode);
7870 HeapFree(GetProcessHeap(), 0, job);
7874 LeaveCriticalSection(&printer_handles_cs);
7878 /*****************************************************************************
7879 * StartDocDlgA [WINSPOOL.@]
7881 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7883 UNICODE_STRING usBuffer;
7886 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7889 docW.cbSize = sizeof(docW);
7890 if (doc->lpszDocName)
7892 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7893 if (!(docW.lpszDocName = docnameW)) return NULL;
7895 if (doc->lpszOutput)
7897 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7898 if (!(docW.lpszOutput = outputW)) return NULL;
7900 if (doc->lpszDatatype)
7902 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7903 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7905 docW.fwType = doc->fwType;
7907 retW = StartDocDlgW(hPrinter, &docW);
7911 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7912 ret = HeapAlloc(GetProcessHeap(), 0, len);
7913 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7914 HeapFree(GetProcessHeap(), 0, retW);
7917 HeapFree(GetProcessHeap(), 0, datatypeW);
7918 HeapFree(GetProcessHeap(), 0, outputW);
7919 HeapFree(GetProcessHeap(), 0, docnameW);
7924 /*****************************************************************************
7925 * StartDocDlgW [WINSPOOL.@]
7927 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7928 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7929 * port is "FILE:". Also returns the full path if passed a relative path.
7931 * The caller should free the returned string from the process heap.
7933 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7938 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7940 PRINTER_INFO_5W *pi5;
7941 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7942 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7944 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7945 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7946 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7948 HeapFree(GetProcessHeap(), 0, pi5);
7951 HeapFree(GetProcessHeap(), 0, pi5);
7954 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7958 if (get_filename(&name))
7960 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7962 HeapFree(GetProcessHeap(), 0, name);
7965 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7966 GetFullPathNameW(name, len, ret, NULL);
7967 HeapFree(GetProcessHeap(), 0, name);
7972 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7975 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7976 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7978 attr = GetFileAttributesW(ret);
7979 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7981 HeapFree(GetProcessHeap(), 0, ret);