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, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
97 WCHAR *document_title;
105 LPCWSTR versionregpath;
106 LPCWSTR versionsubdir;
109 /* ############################### */
111 static opened_printer_t **printer_handles;
112 static int nb_printer_handles;
113 static LONG next_job_id = 1;
115 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
116 WORD fwCapability, LPSTR lpszOutput,
118 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
119 LPSTR lpszDevice, LPSTR lpszPort,
120 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
123 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
124 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
125 'c','o','n','t','r','o','l','\\',
126 'P','r','i','n','t','\\',
127 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
128 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
130 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'C','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'M','o','n','i','t','o','r','s',0};
136 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
137 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
138 'C','o','n','t','r','o','l','\\',
139 'P','r','i','n','t','\\',
140 'P','r','i','n','t','e','r','s',0};
142 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
144 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
145 'M','i','c','r','o','s','o','f','t','\\',
146 'W','i','n','d','o','w','s',' ','N','T','\\',
147 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
148 'W','i','n','d','o','w','s',0};
150 static const WCHAR user_printers_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 'D','e','v','i','c','e','s',0};
156 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
157 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
158 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
159 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
160 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
161 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
162 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
164 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
166 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
167 'i','o','n',' ','F','i','l','e',0};
168 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
169 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
170 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
172 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
174 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
175 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
176 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
177 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
178 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
179 static const WCHAR NameW[] = {'N','a','m','e',0};
180 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
181 static const WCHAR PortW[] = {'P','o','r','t',0};
182 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
184 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
186 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
187 'v','e','r','D','a','t','a',0};
188 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
190 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
191 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
192 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
193 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
194 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
195 static const WCHAR emptyStringW[] = {0};
197 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
199 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
200 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
201 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
203 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
204 'D','o','c','u','m','e','n','t',0};
206 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
207 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
208 DWORD Level, LPBYTE pDriverInfo,
209 DWORD cbBuf, LPDWORD pcbNeeded,
211 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
212 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
214 /******************************************************************
215 * validate the user-supplied printing-environment [internal]
218 * env [I] PTR to Environment-String or NULL
222 * Success: PTR to printenv_t
225 * An empty string is handled the same way as NULL.
226 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
230 static const printenv_t * validate_envW(LPCWSTR env)
232 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
233 3, Version3_RegPathW, Version3_SubdirW};
234 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
235 0, emptyStringW, emptyStringW};
236 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
238 const printenv_t *result = NULL;
241 TRACE("testing %s\n", debugstr_w(env));
244 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
246 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
248 result = all_printenv[i];
253 if (result == NULL) {
254 FIXME("unsupported Environment: %s\n", debugstr_w(env));
255 SetLastError(ERROR_INVALID_ENVIRONMENT);
257 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
261 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
263 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
269 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
270 if passed a NULL string. This returns NULLs to the result.
272 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
276 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
277 return usBufferPtr->Buffer;
279 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
283 static LPWSTR strdupW(LPCWSTR p)
289 len = (strlenW(p) + 1) * sizeof(WCHAR);
290 ret = HeapAlloc(GetProcessHeap(), 0, len);
296 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
299 /* If forcing, or no profile string entry for device yet, set the entry
301 * The always change entry if not WINEPS yet is discussable.
304 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
306 !strstr(qbuf,"WINEPS.DRV")
308 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
311 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
312 WriteProfileStringA("windows","device",buf);
313 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
314 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
317 HeapFree(GetProcessHeap(),0,buf);
321 #ifdef HAVE_CUPS_CUPS_H
322 static typeof(cupsGetDests) *pcupsGetDests;
323 static typeof(cupsGetPPD) *pcupsGetPPD;
324 static typeof(cupsPrintFile) *pcupsPrintFile;
325 static void *cupshandle;
327 static BOOL CUPS_LoadPrinters(void)
330 BOOL hadprinter = FALSE;
332 PRINTER_INFO_2A pinfo2a;
334 HKEY hkeyPrinter, hkeyPrinters, hkey;
336 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
339 TRACE("loaded %s\n", SONAME_LIBCUPS);
342 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
343 if (!p##x) return FALSE;
346 DYNCUPS(cupsGetDests);
347 DYNCUPS(cupsPrintFile);
350 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
352 ERR("Can't create Printers key\n");
356 nrofdests = pcupsGetDests(&dests);
357 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
358 for (i=0;i<nrofdests;i++) {
359 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
360 sprintf(port,"LPR:%s",dests[i].name);
361 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
362 sprintf(devline,"WINEPS.DRV,%s",port);
363 WriteProfileStringA("devices",dests[i].name,devline);
364 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
365 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
368 HeapFree(GetProcessHeap(),0,devline);
370 TRACE("Printer %d: %s\n", i, dests[i].name);
371 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
372 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
374 TRACE("Printer already exists\n");
375 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
376 RegCloseKey(hkeyPrinter);
378 memset(&pinfo2a,0,sizeof(pinfo2a));
379 pinfo2a.pPrinterName = dests[i].name;
380 pinfo2a.pDatatype = "RAW";
381 pinfo2a.pPrintProcessor = "WinPrint";
382 pinfo2a.pDriverName = "PS Driver";
383 pinfo2a.pComment = "WINEPS Printer using CUPS";
384 pinfo2a.pLocation = "<physical location of printer>";
385 pinfo2a.pPortName = port;
386 pinfo2a.pParameters = "<parameters?>";
387 pinfo2a.pShareName = "<share name?>";
388 pinfo2a.pSepFile = "<sep file?>";
390 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
391 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
392 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
395 HeapFree(GetProcessHeap(),0,port);
398 if (dests[i].is_default)
399 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
401 RegCloseKey(hkeyPrinters);
407 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
408 PRINTER_INFO_2A pinfo2a;
409 char *e,*s,*name,*prettyname,*devname;
410 BOOL ret = FALSE, set_default = FALSE;
411 char *port,*devline,*env_default;
412 HKEY hkeyPrinter, hkeyPrinters, hkey;
414 while (isspace(*pent)) pent++;
415 s = strchr(pent,':');
417 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
425 TRACE("name=%s entry=%s\n",name, pent);
427 if(ispunct(*name)) { /* a tc entry, not a real printer */
428 TRACE("skipping tc entry\n");
432 if(strstr(pent,":server")) { /* server only version so skip */
433 TRACE("skipping server entry\n");
437 /* Determine whether this is a postscript printer. */
440 env_default = getenv("PRINTER");
442 /* Get longest name, usually the one at the right for later display. */
443 while((s=strchr(prettyname,'|'))) {
446 while(isspace(*--e)) *e = '\0';
447 TRACE("\t%s\n", debugstr_a(prettyname));
448 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
449 for(prettyname = s+1; isspace(*prettyname); prettyname++)
452 e = prettyname + strlen(prettyname);
453 while(isspace(*--e)) *e = '\0';
454 TRACE("\t%s\n", debugstr_a(prettyname));
455 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
457 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
458 * if it is too long, we use it as comment below. */
459 devname = prettyname;
460 if (strlen(devname)>=CCHDEVICENAME-1)
462 if (strlen(devname)>=CCHDEVICENAME-1) {
467 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
468 sprintf(port,"LPR:%s",name);
470 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
471 sprintf(devline,"WINEPS.DRV,%s",port);
472 WriteProfileStringA("devices",devname,devline);
473 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
474 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
477 HeapFree(GetProcessHeap(),0,devline);
479 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
481 ERR("Can't create Printers key\n");
485 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
486 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
488 TRACE("Printer already exists\n");
489 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
490 RegCloseKey(hkeyPrinter);
492 memset(&pinfo2a,0,sizeof(pinfo2a));
493 pinfo2a.pPrinterName = devname;
494 pinfo2a.pDatatype = "RAW";
495 pinfo2a.pPrintProcessor = "WinPrint";
496 pinfo2a.pDriverName = "PS Driver";
497 pinfo2a.pComment = "WINEPS Printer using LPR";
498 pinfo2a.pLocation = prettyname;
499 pinfo2a.pPortName = port;
500 pinfo2a.pParameters = "<parameters?>";
501 pinfo2a.pShareName = "<share name?>";
502 pinfo2a.pSepFile = "<sep file?>";
504 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
505 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
506 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
509 RegCloseKey(hkeyPrinters);
511 if (isfirst || set_default)
512 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
514 HeapFree(GetProcessHeap(), 0, port);
516 HeapFree(GetProcessHeap(), 0, name);
521 PRINTCAP_LoadPrinters(void) {
522 BOOL hadprinter = FALSE;
526 BOOL had_bash = FALSE;
528 f = fopen("/etc/printcap","r");
532 while(fgets(buf,sizeof(buf),f)) {
535 end=strchr(buf,'\n');
539 while(isspace(*start)) start++;
540 if(*start == '#' || *start == '\0')
543 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
544 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
545 HeapFree(GetProcessHeap(),0,pent);
549 if (end && *--end == '\\') {
556 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
559 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
565 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
566 HeapFree(GetProcessHeap(),0,pent);
572 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
575 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
576 lstrlenW(value) * sizeof(WCHAR));
578 return ERROR_FILE_NOT_FOUND;
581 void WINSPOOL_LoadSystemPrinters(void)
583 HKEY hkey, hkeyPrinters;
586 DWORD needed, num, i;
587 WCHAR PrinterName[256];
590 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
591 di3a.pName = "PS Driver";
592 di3a.pEnvironment = NULL; /* NULL means auto */
593 di3a.pDriverPath = "wineps16";
594 di3a.pDataFile = "<datafile?>";
595 di3a.pConfigFile = "wineps16";
596 di3a.pHelpFile = "<helpfile?>";
597 di3a.pDependentFiles = "<dependend files?>";
598 di3a.pMonitorName = "<monitor name?>";
599 di3a.pDefaultDataType = "RAW";
601 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
602 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
606 /* This ensures that all printer entries have a valid Name value. If causes
607 problems later if they don't. If one is found to be missed we create one
608 and set it equal to the name of the key */
609 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
610 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
611 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
612 for(i = 0; i < num; i++) {
613 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
614 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
615 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
616 set_reg_szW(hkey, NameW, PrinterName);
623 RegCloseKey(hkeyPrinters);
626 /* We want to avoid calling AddPrinter on printers as much as
627 possible, because on cups printers this will (eventually) lead
628 to a call to cupsGetPPD which takes forever, even with non-cups
629 printers AddPrinter takes a while. So we'll tag all printers that
630 were automatically added last time around, if they still exist
631 we'll leave them be otherwise we'll delete them. */
632 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
634 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
635 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
636 for(i = 0; i < num; i++) {
637 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
638 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
639 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
641 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
649 HeapFree(GetProcessHeap(), 0, pi);
653 #ifdef HAVE_CUPS_CUPS_H
654 done = CUPS_LoadPrinters();
657 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
658 /* Check for [ppd] section in config file before parsing /etc/printcap */
659 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
660 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
661 &hkey) == ERROR_SUCCESS) {
663 PRINTCAP_LoadPrinters();
667 /* Now enumerate the list again and delete any printers that a still tagged */
668 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
670 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
671 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
672 for(i = 0; i < num; i++) {
673 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
674 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
675 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
676 DWORD dw, type, size = sizeof(dw);
677 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
678 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
688 HeapFree(GetProcessHeap(), 0, pi);
695 /*****************************************************************************
696 * enumerate the local monitors (INTERNAL)
698 * returns the needed size (in bytes) for pMonitors
699 * and *lpreturned is set to number of entries returned in pMonitors
702 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
707 LPMONITOR_INFO_2W mi;
708 WCHAR buffer[MAX_PATH];
709 WCHAR dllname[MAX_PATH];
717 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
719 numentries = *lpreturned; /* this is 0, when we scan the registry */
720 len = entrysize * numentries;
721 ptr = (LPWSTR) &pMonitors[len];
724 len = sizeof(buffer);
727 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
728 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
729 /* Scan all Monitor-Registry-Keys */
730 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
731 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
732 dllsize = sizeof(dllname);
735 /* The Monitor must have a Driver-DLL */
736 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
737 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
738 /* We found a valid DLL for this Monitor. */
739 TRACE("using Driver: %s\n", debugstr_w(dllname));
744 /* Windows returns only Port-Monitors here, but to simplify our code,
745 we do no filtering for Language-Monitors */
749 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
751 /* we install and return only monitors for "Windows NT x86" */
752 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
756 /* required size is calculated. Now fill the user-buffer */
757 if (pMonitors && (cbBuf >= needed)){
758 mi = (LPMONITOR_INFO_2W) pMonitors;
759 pMonitors += entrysize;
761 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
763 lstrcpyW(ptr, buffer); /* Name of the Monitor */
764 ptr += (len+1); /* len is lstrlenW(monitorname) */
766 mi->pEnvironment = ptr;
767 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
768 ptr += (lstrlenW(envname_x86W)+1);
771 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
772 ptr += (dllsize / sizeof(WCHAR));
777 len = sizeof(buffer);
782 *lpreturned = numentries;
783 TRACE("need %ld byte for %ld entries\n", needed, numentries);
787 /******************************************************************
788 * get_opened_printer_entry
789 * Get the first place empty in the opened printer table
792 * - pDefault is ignored
794 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
796 UINT_PTR handle = nb_printer_handles, i;
797 jobqueue_t *queue = NULL;
798 opened_printer_t *printer = NULL;
800 EnterCriticalSection(&printer_handles_cs);
802 for (i = 0; i < nb_printer_handles; i++)
804 if (!printer_handles[i])
806 if(handle == nb_printer_handles)
811 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
812 queue = printer_handles[i]->queue;
816 if (handle >= nb_printer_handles)
818 opened_printer_t **new_array;
820 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
821 (nb_printer_handles + 16) * sizeof(*new_array) );
823 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
824 (nb_printer_handles + 16) * sizeof(*new_array) );
831 printer_handles = new_array;
832 nb_printer_handles += 16;
835 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
842 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
843 if (!printer->name) {
847 strcpyW(printer->name, name);
851 printer->queue = queue;
854 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
855 if (!printer->queue) {
859 list_init(&printer->queue->jobs);
860 printer->queue->ref = 0;
862 InterlockedIncrement(&printer->queue->ref);
864 printer_handles[handle] = printer;
867 LeaveCriticalSection(&printer_handles_cs);
868 if (!handle && printer) {
869 /* Something Failed: Free the Buffers */
870 HeapFree(GetProcessHeap(), 0, printer->name);
871 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
872 HeapFree(GetProcessHeap(), 0, printer);
875 return (HANDLE)handle;
878 /******************************************************************
880 * Get the pointer to the opened printer referred by the handle
882 static opened_printer_t *get_opened_printer(HANDLE hprn)
884 UINT_PTR idx = (UINT_PTR)hprn;
885 opened_printer_t *ret = NULL;
887 EnterCriticalSection(&printer_handles_cs);
889 if ((idx <= 0) || (idx > nb_printer_handles))
892 ret = printer_handles[idx - 1];
894 LeaveCriticalSection(&printer_handles_cs);
898 /******************************************************************
899 * get_opened_printer_name
900 * Get the pointer to the opened printer name referred by the handle
902 static LPCWSTR get_opened_printer_name(HANDLE hprn)
904 opened_printer_t *printer = get_opened_printer(hprn);
905 if(!printer) return NULL;
906 return printer->name;
909 /******************************************************************
910 * WINSPOOL_GetOpenedPrinterRegKey
913 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
915 LPCWSTR name = get_opened_printer_name(hPrinter);
919 if(!name) return ERROR_INVALID_HANDLE;
921 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
925 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
927 ERR("Can't find opened printer %s in registry\n",
929 RegCloseKey(hkeyPrinters);
930 return ERROR_INVALID_PRINTER_NAME; /* ? */
932 RegCloseKey(hkeyPrinters);
933 return ERROR_SUCCESS;
936 /******************************************************************
939 * Get the pointer to the specified job.
940 * Should hold the printer_handles_cs before calling.
942 static job_t *get_job(HANDLE hprn, DWORD JobId)
944 opened_printer_t *printer = get_opened_printer(hprn);
947 if(!printer) return NULL;
948 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
950 if(job->job_id == JobId)
956 /***********************************************************
959 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
962 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
965 Formname = (dmA->dmSize > off_formname);
966 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
967 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
968 dmW->dmDeviceName, CCHDEVICENAME);
970 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
971 dmA->dmSize - CCHDEVICENAME);
973 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
974 off_formname - CCHDEVICENAME);
975 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
976 dmW->dmFormName, CCHFORMNAME);
977 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
978 (off_formname + CCHFORMNAME));
981 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
986 /***********************************************************
988 * Creates an ascii copy of supplied devmode on heap
990 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
995 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
997 if(!dmW) return NULL;
998 Formname = (dmW->dmSize > off_formname);
999 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1000 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1001 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1002 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1004 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1005 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1007 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1008 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1009 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1010 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1011 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1012 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1015 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1016 dmW->dmDriverExtra);
1020 /***********************************************************
1021 * PRINTER_INFO_2AtoW
1022 * Creates a unicode copy of PRINTER_INFO_2A on heap
1024 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1026 LPPRINTER_INFO_2W piW;
1027 UNICODE_STRING usBuffer;
1029 if(!piA) return NULL;
1030 piW = HeapAlloc(heap, 0, sizeof(*piW));
1031 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1033 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1034 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1035 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1036 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1037 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1038 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1039 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1040 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1041 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1042 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1043 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1044 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1048 /***********************************************************
1049 * FREE_PRINTER_INFO_2W
1050 * Free PRINTER_INFO_2W and all strings
1052 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1056 HeapFree(heap,0,piW->pServerName);
1057 HeapFree(heap,0,piW->pPrinterName);
1058 HeapFree(heap,0,piW->pShareName);
1059 HeapFree(heap,0,piW->pPortName);
1060 HeapFree(heap,0,piW->pDriverName);
1061 HeapFree(heap,0,piW->pComment);
1062 HeapFree(heap,0,piW->pLocation);
1063 HeapFree(heap,0,piW->pDevMode);
1064 HeapFree(heap,0,piW->pSepFile);
1065 HeapFree(heap,0,piW->pPrintProcessor);
1066 HeapFree(heap,0,piW->pDatatype);
1067 HeapFree(heap,0,piW->pParameters);
1068 HeapFree(heap,0,piW);
1072 /******************************************************************
1073 * DeviceCapabilities [WINSPOOL.@]
1074 * DeviceCapabilitiesA [WINSPOOL.@]
1077 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1078 LPSTR pOutput, LPDEVMODEA lpdm)
1082 if (!GDI_CallDeviceCapabilities16)
1084 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1086 if (!GDI_CallDeviceCapabilities16) return -1;
1088 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1090 /* If DC_PAPERSIZE map POINT16s to POINTs */
1091 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1092 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1093 POINT *pt = (POINT *)pOutput;
1095 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1096 for(i = 0; i < ret; i++, pt++)
1101 HeapFree( GetProcessHeap(), 0, tmp );
1107 /*****************************************************************************
1108 * DeviceCapabilitiesW [WINSPOOL.@]
1110 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1113 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1114 WORD fwCapability, LPWSTR pOutput,
1115 const DEVMODEW *pDevMode)
1117 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1118 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1119 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1122 if(pOutput && (fwCapability == DC_BINNAMES ||
1123 fwCapability == DC_FILEDEPENDENCIES ||
1124 fwCapability == DC_PAPERNAMES)) {
1125 /* These need A -> W translation */
1128 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1132 switch(fwCapability) {
1137 case DC_FILEDEPENDENCIES:
1141 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1142 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1144 for(i = 0; i < ret; i++)
1145 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1146 pOutput + (i * size), size);
1147 HeapFree(GetProcessHeap(), 0, pOutputA);
1149 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1150 (LPSTR)pOutput, dmA);
1152 HeapFree(GetProcessHeap(),0,pPortA);
1153 HeapFree(GetProcessHeap(),0,pDeviceA);
1154 HeapFree(GetProcessHeap(),0,dmA);
1158 /******************************************************************
1159 * DocumentPropertiesA [WINSPOOL.@]
1161 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1163 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1164 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1165 LPDEVMODEA pDevModeInput,DWORD fMode )
1167 LPSTR lpName = pDeviceName;
1170 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1171 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1175 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1177 ERR("no name from hPrinter?\n");
1178 SetLastError(ERROR_INVALID_HANDLE);
1181 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1184 if (!GDI_CallExtDeviceMode16)
1186 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1188 if (!GDI_CallExtDeviceMode16) {
1189 ERR("No CallExtDeviceMode16?\n");
1193 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1194 pDevModeInput, NULL, fMode);
1197 HeapFree(GetProcessHeap(),0,lpName);
1202 /*****************************************************************************
1203 * DocumentPropertiesW (WINSPOOL.@)
1205 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1207 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1209 LPDEVMODEW pDevModeOutput,
1210 LPDEVMODEW pDevModeInput, DWORD fMode)
1213 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1214 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1215 LPDEVMODEA pDevModeOutputA = NULL;
1218 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1219 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1221 if(pDevModeOutput) {
1222 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1223 if(ret < 0) return ret;
1224 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1226 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1227 pDevModeInputA, fMode);
1228 if(pDevModeOutput) {
1229 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1230 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1232 if(fMode == 0 && ret > 0)
1233 ret += (CCHDEVICENAME + CCHFORMNAME);
1234 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1235 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1239 /******************************************************************
1240 * OpenPrinterA [WINSPOOL.@]
1245 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1246 LPPRINTER_DEFAULTSA pDefault)
1248 UNICODE_STRING lpPrinterNameW;
1249 UNICODE_STRING usBuffer;
1250 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1251 PWSTR pwstrPrinterNameW;
1254 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1257 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1258 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1259 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1260 pDefaultW = &DefaultW;
1262 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1264 RtlFreeUnicodeString(&usBuffer);
1265 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1267 RtlFreeUnicodeString(&lpPrinterNameW);
1271 /******************************************************************
1272 * OpenPrinterW [WINSPOOL.@]
1274 * Open a Printer / Printserver or a Printer-Object
1277 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1278 * phPrinter [O] The resulting Handle is stored here
1279 * pDefault [I] PTR to Default Printer Settings or NULL
1286 * lpPrinterName is one of:
1287 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1288 *| Printer: "PrinterName"
1289 *| Printer-Object: "PrinterName,Job xxx"
1290 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1291 *| XcvPort: "Servername,XcvPort PortName"
1294 *| Printer-Object not supported
1295 *| XcvMonitor not supported
1296 *| XcvPort not supported
1297 *| pDefaults is ignored
1300 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1302 HKEY hkeyPrinters = NULL;
1303 HKEY hkeyPrinter = NULL;
1305 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1307 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1308 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1311 if(lpPrinterName != NULL)
1313 /* Check any Printer exists */
1314 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1315 ERR("Can't create Printers key\n");
1316 SetLastError(ERROR_FILE_NOT_FOUND);
1319 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1320 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1322 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1323 RegCloseKey(hkeyPrinters);
1324 SetLastError(ERROR_INVALID_PRINTER_NAME);
1327 RegCloseKey(hkeyPrinter);
1328 RegCloseKey(hkeyPrinters);
1331 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1332 SetLastError(ERROR_INVALID_PARAMETER);
1336 /* Get the unique handle of the printer or Printserver */
1337 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1338 return (*phPrinter != 0);
1341 /******************************************************************
1342 * AddMonitorA [WINSPOOL.@]
1347 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1349 LPWSTR nameW = NULL;
1352 LPMONITOR_INFO_2A mi2a;
1353 MONITOR_INFO_2W mi2w;
1355 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1356 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1357 mi2a ? debugstr_a(mi2a->pName) : NULL,
1358 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1359 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1362 SetLastError(ERROR_INVALID_LEVEL);
1366 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1372 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1373 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1374 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1377 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1379 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1380 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1381 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1383 if (mi2a->pEnvironment) {
1384 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1385 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1386 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1388 if (mi2a->pDLLName) {
1389 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1390 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1391 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1394 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1396 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1397 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1398 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1400 HeapFree(GetProcessHeap(), 0, nameW);
1404 /******************************************************************************
1405 * AddMonitorW [WINSPOOL.@]
1407 * Install a Printmonitor
1410 * pName [I] Servername or NULL (local Computer)
1411 * Level [I] Structure-Level (Must be 2)
1412 * pMonitors [I] PTR to MONITOR_INFO_2
1419 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1422 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1424 LPMONITOR_INFO_2W mi2w;
1427 HMODULE hdll = NULL;
1431 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1432 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1433 mi2w ? debugstr_w(mi2w->pName) : NULL,
1434 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1435 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1438 SetLastError(ERROR_INVALID_LEVEL);
1442 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1447 if (pName && (pName[0])) {
1448 FIXME("for server %s not implemented\n", debugstr_w(pName));
1449 SetLastError(ERROR_ACCESS_DENIED);
1454 if (!mi2w->pName || (! mi2w->pName[0])) {
1455 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1456 SetLastError(ERROR_INVALID_PARAMETER);
1459 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1460 WARN("Environment %s requested (we support only %s)\n",
1461 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1462 SetLastError(ERROR_INVALID_ENVIRONMENT);
1466 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1467 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1468 SetLastError(ERROR_INVALID_PARAMETER);
1472 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1477 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1478 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1482 if(RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1483 KEY_WRITE, NULL, &hentry, &disposition) == ERROR_SUCCESS) {
1485 if (disposition == REG_OPENED_EXISTING_KEY) {
1486 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1487 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1488 9x: ERROR_ALREADY_EXISTS (183) */
1489 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1494 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1495 res = (RegSetValueExW(hentry, DriverW, 0,
1496 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1498 RegCloseKey(hentry);
1505 /******************************************************************
1506 * DeletePrinterDriverA [WINSPOOL.@]
1510 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1512 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1513 debugstr_a(pDriverName));
1514 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1518 /******************************************************************
1519 * DeletePrinterDriverW [WINSPOOL.@]
1523 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1525 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1526 debugstr_w(pDriverName));
1527 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1531 /******************************************************************
1532 * DeleteMonitorA [WINSPOOL.@]
1534 * See DeleteMonitorW.
1537 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1539 LPWSTR nameW = NULL;
1540 LPWSTR EnvironmentW = NULL;
1541 LPWSTR MonitorNameW = NULL;
1546 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1547 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1548 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1552 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1553 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1554 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1557 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1558 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1559 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1562 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1564 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1565 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1566 HeapFree(GetProcessHeap(), 0, nameW);
1570 /******************************************************************
1571 * DeleteMonitorW [WINSPOOL.@]
1573 * Delete a specific Printmonitor from a Printing-Environment
1576 * pName [I] Servername or NULL (local Computer)
1577 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1578 * pMonitorName [I] Name of the Monitor, that should be deleted
1585 * pEnvironment is ignored in Windows for the local Computer.
1589 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1593 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1594 debugstr_w(pMonitorName));
1596 if (pName && (pName[0])) {
1597 FIXME("for server %s not implemented\n", debugstr_w(pName));
1598 SetLastError(ERROR_ACCESS_DENIED);
1602 /* pEnvironment is ignored in Windows for the local Computer */
1604 if (!pMonitorName || !pMonitorName[0]) {
1605 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1606 SetLastError(ERROR_INVALID_PARAMETER);
1610 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1611 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1615 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1616 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1617 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1622 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1625 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1626 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1630 /******************************************************************
1631 * DeletePortA [WINSPOOL.@]
1637 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1639 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1640 debugstr_a(pPortName));
1641 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1645 /******************************************************************
1646 * DeletePortW [WINSPOOL.@]
1648 * Delete a specific Port
1651 * pName [I] Servername or NULL (local Computer)
1652 * hWnd [I] Handle to parent Window for the Dialog-Box
1653 * pPortName [I] Name of the Port, that should be deleted
1664 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1666 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1667 debugstr_w(pPortName));
1668 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1672 /******************************************************************************
1673 * SetPrinterW [WINSPOOL.@]
1675 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1677 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1678 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1682 /******************************************************************************
1683 * WritePrinter [WINSPOOL.@]
1685 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1687 opened_printer_t *printer;
1690 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1692 EnterCriticalSection(&printer_handles_cs);
1693 printer = get_opened_printer(hPrinter);
1696 SetLastError(ERROR_INVALID_HANDLE);
1702 SetLastError(ERROR_SPL_NO_STARTDOC);
1706 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1708 LeaveCriticalSection(&printer_handles_cs);
1712 /*****************************************************************************
1713 * AddFormA [WINSPOOL.@]
1715 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1717 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1721 /*****************************************************************************
1722 * AddFormW [WINSPOOL.@]
1724 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1726 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1730 /*****************************************************************************
1731 * AddJobA [WINSPOOL.@]
1733 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1736 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1740 SetLastError(ERROR_INVALID_LEVEL);
1744 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1747 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1748 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1749 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1750 if(*pcbNeeded > cbBuf) {
1751 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1754 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1755 addjobA->JobId = addjobW->JobId;
1756 addjobA->Path = (char *)(addjobA + 1);
1757 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1763 /*****************************************************************************
1764 * AddJobW [WINSPOOL.@]
1766 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1768 opened_printer_t *printer;
1771 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1772 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1773 WCHAR path[MAX_PATH], filename[MAX_PATH];
1775 ADDJOB_INFO_1W *addjob;
1777 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1779 EnterCriticalSection(&printer_handles_cs);
1781 printer = get_opened_printer(hPrinter);
1784 SetLastError(ERROR_INVALID_HANDLE);
1789 SetLastError(ERROR_INVALID_LEVEL);
1793 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1797 job->job_id = InterlockedIncrement(&next_job_id);
1799 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1800 if(path[len - 1] != '\\')
1802 memcpy(path + len, spool_path, sizeof(spool_path));
1803 sprintfW(filename, fmtW, path, job->job_id);
1805 len = strlenW(filename);
1806 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1807 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1808 job->document_title = strdupW(default_doc_title);
1809 list_add_tail(&printer->queue->jobs, &job->entry);
1811 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1812 if(*pcbNeeded <= cbBuf) {
1813 addjob = (ADDJOB_INFO_1W*)pData;
1814 addjob->JobId = job->job_id;
1815 addjob->Path = (WCHAR *)(addjob + 1);
1816 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1819 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1822 LeaveCriticalSection(&printer_handles_cs);
1826 /*****************************************************************************
1827 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1829 * Return the PATH for the Print-Processors
1831 * See GetPrintProcessorDirectoryW.
1834 * On NT, the returned ANSI-Data need the same Size as the Unicode-Version
1837 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1838 DWORD level, LPBYTE Info,
1839 DWORD cbBuf, LPDWORD needed)
1841 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1842 level, Info, cbBuf);
1846 /*****************************************************************************
1847 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1849 * Return the PATH for the Print-Processors
1852 * server [I] Servername (NT only) or NULL (local Computer)
1853 * env [I] Printing-Environment (see below) or NULL (Default)
1854 * level [I] Structure-Level (must be 1)
1855 * Info [O] PTR to Buffer that receives the Result
1856 * cbBuf [I] Size of Buffer at "Info"
1857 * needed [O] PTR to DWORD that receives the size in Bytes used /
1858 * required for the Buffer at "Info"
1861 * Success: TRUE and in pcbNeeded the Bytes used in pPrintProcessorInfo
1862 * Failure: FALSE and in pcbNeeded the Bytes required for pPrintProcessorInfo,
1863 * if cbBuf is too small
1865 * Native Values returned in pPrintProcessorInfo on Success:
1866 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
1867 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
1868 *| win9x(Windows 4.0): "%winsysdir%"
1870 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1873 *- Only NULL or "" is supported for pName
1876 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1877 DWORD level, LPBYTE Info,
1878 DWORD cbBuf, LPDWORD needed)
1880 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1881 level, Info, cbBuf);
1885 /*****************************************************************************
1886 * WINSPOOL_OpenDriverReg [internal]
1888 * opens the registry for the printer drivers depending on the given input
1889 * variable pEnvironment
1892 * the opened hkey on success
1895 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1899 const printenv_t * env;
1902 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
1904 if (!pEnvironment || unicode) {
1905 /* pEnvironment was NULL or an Unicode-String: use it direct */
1906 env = validate_envW(pEnvironment);
1910 /* pEnvironment was an ANSI-String: convert to unicode first */
1912 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1913 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1914 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1915 env = validate_envW(buffer);
1916 HeapFree(GetProcessHeap(), 0, buffer);
1918 if (!env) return NULL;
1920 buffer = HeapAlloc( GetProcessHeap(), 0,
1921 (strlenW(DriversW) + strlenW(env->envname) +
1922 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
1924 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
1925 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1926 HeapFree(GetProcessHeap(), 0, buffer);
1931 /*****************************************************************************
1932 * AddPrinterW [WINSPOOL.@]
1934 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1936 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1940 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1943 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1946 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1947 SetLastError(ERROR_INVALID_PARAMETER);
1951 ERR("Level = %ld, unsupported!\n", Level);
1952 SetLastError(ERROR_INVALID_LEVEL);
1955 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1956 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1957 debugstr_w(pi->pPrinterName)
1959 SetLastError(ERROR_INVALID_LEVEL);
1963 SetLastError(ERROR_INVALID_PARAMETER);
1966 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
1968 ERR("Can't create Printers key\n");
1971 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1972 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1973 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1974 RegCloseKey(hkeyPrinter);
1975 RegCloseKey(hkeyPrinters);
1978 RegCloseKey(hkeyPrinter);
1980 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1982 ERR("Can't create Drivers key\n");
1983 RegCloseKey(hkeyPrinters);
1986 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1988 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1989 RegCloseKey(hkeyPrinters);
1990 RegCloseKey(hkeyDrivers);
1991 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1994 RegCloseKey(hkeyDriver);
1995 RegCloseKey(hkeyDrivers);
1997 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1998 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1999 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2000 RegCloseKey(hkeyPrinters);
2004 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2006 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2007 SetLastError(ERROR_INVALID_PRINTER_NAME);
2008 RegCloseKey(hkeyPrinters);
2011 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2012 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2013 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2015 /* See if we can load the driver. We may need the devmode structure anyway
2018 * Note that DocumentPropertiesW will briefly try to open the printer we
2019 * just create to find a DEVMODEA struct (it will use the WINEPS default
2020 * one in case it is not there, so we are ok).
2022 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2025 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2026 size = sizeof(DEVMODEW);
2032 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2033 ZeroMemory(dmW,size);
2035 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2037 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2038 HeapFree(GetProcessHeap(),0,dmW);
2043 /* set devmode to printer name */
2044 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
2048 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2049 and we support these drivers. NT writes DEVMODEW so somehow
2050 we'll need to distinguish between these when we support NT
2054 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2055 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2056 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2057 HeapFree(GetProcessHeap(), 0, dmA);
2059 HeapFree(GetProcessHeap(), 0, dmW);
2061 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2062 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2063 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2064 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2066 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2067 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2068 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2069 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2070 (LPBYTE)&pi->Priority, sizeof(DWORD));
2071 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2072 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2073 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2074 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2075 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2076 (LPBYTE)&pi->Status, sizeof(DWORD));
2077 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2078 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2080 RegCloseKey(hkeyPrinter);
2081 RegCloseKey(hkeyPrinters);
2082 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2083 ERR("OpenPrinter failing\n");
2089 /*****************************************************************************
2090 * AddPrinterA [WINSPOOL.@]
2092 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2094 UNICODE_STRING pNameW;
2096 PRINTER_INFO_2W *piW;
2097 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2100 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2102 ERR("Level = %ld, unsupported!\n", Level);
2103 SetLastError(ERROR_INVALID_LEVEL);
2106 pwstrNameW = asciitounicode(&pNameW,pName);
2107 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2109 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2111 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2112 RtlFreeUnicodeString(&pNameW);
2117 /*****************************************************************************
2118 * ClosePrinter [WINSPOOL.@]
2120 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2122 UINT_PTR i = (UINT_PTR)hPrinter;
2123 opened_printer_t *printer = NULL;
2126 TRACE("Handle %p\n", hPrinter);
2128 EnterCriticalSection(&printer_handles_cs);
2130 if ((i > 0) && (i <= nb_printer_handles))
2131 printer = printer_handles[i - 1];
2135 struct list *cursor, *cursor2;
2138 EndDocPrinter(hPrinter);
2140 if(InterlockedDecrement(&printer->queue->ref) == 0)
2142 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2144 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2145 ScheduleJob(hPrinter, job->job_id);
2147 HeapFree(GetProcessHeap(), 0, printer->queue);
2149 HeapFree(GetProcessHeap(), 0, printer->name);
2150 HeapFree(GetProcessHeap(), 0, printer);
2151 printer_handles[i - 1] = NULL;
2154 LeaveCriticalSection(&printer_handles_cs);
2158 /*****************************************************************************
2159 * DeleteFormA [WINSPOOL.@]
2161 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2163 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2167 /*****************************************************************************
2168 * DeleteFormW [WINSPOOL.@]
2170 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2172 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2176 /*****************************************************************************
2177 * WINSPOOL_SHRegDeleteKey
2179 * Recursively delete subkeys.
2180 * Cut & paste from shlwapi.
2183 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2185 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2186 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2189 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2192 /* Find how many subkeys there are */
2193 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2194 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2198 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2199 /* Name too big: alloc a buffer for it */
2200 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2203 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2206 /* Recursively delete all the subkeys */
2207 for(i = 0; i < dwKeyCount && !dwRet; i++)
2209 dwSize = dwMaxSubkeyLen;
2210 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2212 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2215 if (lpszName != szNameBuf)
2216 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2220 RegCloseKey(hSubKey);
2222 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2227 /*****************************************************************************
2228 * DeletePrinter [WINSPOOL.@]
2230 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2232 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2233 HKEY hkeyPrinters, hkey;
2236 SetLastError(ERROR_INVALID_HANDLE);
2239 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2240 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2241 RegCloseKey(hkeyPrinters);
2243 WriteProfileStringW(devicesW, lpNameW, NULL);
2244 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2245 RegDeleteValueW(hkey, lpNameW);
2251 /*****************************************************************************
2252 * SetPrinterA [WINSPOOL.@]
2254 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2257 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2261 /*****************************************************************************
2262 * SetJobA [WINSPOOL.@]
2264 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2265 LPBYTE pJob, DWORD Command)
2269 UNICODE_STRING usBuffer;
2271 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2273 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2274 are all ignored by SetJob, so we don't bother copying them */
2282 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2283 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2285 JobW = (LPBYTE)info1W;
2286 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2287 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2288 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2289 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2290 info1W->Status = info1A->Status;
2291 info1W->Priority = info1A->Priority;
2292 info1W->Position = info1A->Position;
2293 info1W->PagesPrinted = info1A->PagesPrinted;
2298 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2299 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2301 JobW = (LPBYTE)info2W;
2302 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2303 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2304 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2305 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2306 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2307 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2308 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2309 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2310 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2311 info2W->Status = info2A->Status;
2312 info2W->Priority = info2A->Priority;
2313 info2W->Position = info2A->Position;
2314 info2W->StartTime = info2A->StartTime;
2315 info2W->UntilTime = info2A->UntilTime;
2316 info2W->PagesPrinted = info2A->PagesPrinted;
2320 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2321 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2324 SetLastError(ERROR_INVALID_LEVEL);
2328 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2334 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2335 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2336 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2337 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2338 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2343 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2344 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2345 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2346 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2347 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2348 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2349 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2350 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2351 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2355 HeapFree(GetProcessHeap(), 0, JobW);
2360 /*****************************************************************************
2361 * SetJobW [WINSPOOL.@]
2363 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2364 LPBYTE pJob, DWORD Command)
2369 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2370 FIXME("Ignoring everything other than document title\n");
2372 EnterCriticalSection(&printer_handles_cs);
2373 job = get_job(hPrinter, JobId);
2383 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2384 HeapFree(GetProcessHeap(), 0, job->document_title);
2385 job->document_title = strdupW(info1->pDocument);
2390 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2391 HeapFree(GetProcessHeap(), 0, job->document_title);
2392 job->document_title = strdupW(info2->pDocument);
2398 SetLastError(ERROR_INVALID_LEVEL);
2403 LeaveCriticalSection(&printer_handles_cs);
2407 /*****************************************************************************
2408 * EndDocPrinter [WINSPOOL.@]
2410 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2412 opened_printer_t *printer;
2414 TRACE("(%p)\n", hPrinter);
2416 EnterCriticalSection(&printer_handles_cs);
2418 printer = get_opened_printer(hPrinter);
2421 SetLastError(ERROR_INVALID_HANDLE);
2427 SetLastError(ERROR_SPL_NO_STARTDOC);
2431 CloseHandle(printer->doc->hf);
2432 ScheduleJob(hPrinter, printer->doc->job_id);
2433 HeapFree(GetProcessHeap(), 0, printer->doc);
2434 printer->doc = NULL;
2437 LeaveCriticalSection(&printer_handles_cs);
2441 /*****************************************************************************
2442 * EndPagePrinter [WINSPOOL.@]
2444 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2446 FIXME("(%p): stub\n", hPrinter);
2450 /*****************************************************************************
2451 * StartDocPrinterA [WINSPOOL.@]
2453 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2455 UNICODE_STRING usBuffer;
2457 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2460 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2461 or one (DOC_INFO_3) extra DWORDs */
2465 doc2W.JobId = doc2->JobId;
2468 doc2W.dwMode = doc2->dwMode;
2471 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2472 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2473 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2477 SetLastError(ERROR_INVALID_LEVEL);
2481 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2483 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2484 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2485 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2490 /*****************************************************************************
2491 * StartDocPrinterW [WINSPOOL.@]
2493 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2495 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2496 opened_printer_t *printer;
2497 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2498 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2499 JOB_INFO_1W job_info;
2500 DWORD needed, ret = 0;
2504 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2505 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2506 debugstr_w(doc->pDatatype));
2508 if(Level < 1 || Level > 3)
2510 SetLastError(ERROR_INVALID_LEVEL);
2514 EnterCriticalSection(&printer_handles_cs);
2515 printer = get_opened_printer(hPrinter);
2518 SetLastError(ERROR_INVALID_HANDLE);
2524 SetLastError(ERROR_INVALID_PRINTER_STATE);
2528 /* Even if we're printing to a file we still add a print job, we'll
2529 just ignore the spool file name */
2531 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2533 ERR("AddJob failed gle %08lx\n", GetLastError());
2537 if(doc->pOutputFile)
2538 filename = doc->pOutputFile;
2540 filename = addjob->Path;
2542 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2543 if(hf == INVALID_HANDLE_VALUE)
2546 memset(&job_info, 0, sizeof(job_info));
2547 job_info.pDocument = doc->pDocName;
2548 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2550 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2551 printer->doc->hf = hf;
2552 ret = printer->doc->job_id = addjob->JobId;
2554 LeaveCriticalSection(&printer_handles_cs);
2559 /*****************************************************************************
2560 * StartPagePrinter [WINSPOOL.@]
2562 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2564 FIXME("(%p): stub\n", hPrinter);
2568 /*****************************************************************************
2569 * GetFormA [WINSPOOL.@]
2571 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2572 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2574 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2575 Level,pForm,cbBuf,pcbNeeded);
2579 /*****************************************************************************
2580 * GetFormW [WINSPOOL.@]
2582 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2583 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2585 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2586 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2590 /*****************************************************************************
2591 * SetFormA [WINSPOOL.@]
2593 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2596 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2600 /*****************************************************************************
2601 * SetFormW [WINSPOOL.@]
2603 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2606 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2610 /*****************************************************************************
2611 * ReadPrinter [WINSPOOL.@]
2613 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2614 LPDWORD pNoBytesRead)
2616 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2620 /*****************************************************************************
2621 * ResetPrinterA [WINSPOOL.@]
2623 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2625 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2629 /*****************************************************************************
2630 * ResetPrinterW [WINSPOOL.@]
2632 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2634 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2638 /*****************************************************************************
2639 * WINSPOOL_GetDWORDFromReg
2641 * Return DWORD associated with ValueName from hkey.
2643 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2645 DWORD sz = sizeof(DWORD), type, value = 0;
2648 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2650 if(ret != ERROR_SUCCESS) {
2651 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2654 if(type != REG_DWORD) {
2655 ERR("Got type %ld\n", type);
2661 /*****************************************************************************
2662 * WINSPOOL_GetStringFromReg
2664 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2665 * String is stored either as unicode or ascii.
2666 * Bit of a hack here to get the ValueName if we want ascii.
2668 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2669 DWORD buflen, DWORD *needed,
2672 DWORD sz = buflen, type;
2676 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2678 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2679 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2680 HeapFree(GetProcessHeap(),0,ValueNameA);
2682 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2683 WARN("Got ret = %ld\n", ret);
2687 /* add space for terminating '\0' */
2688 sz += unicode ? sizeof(WCHAR) : 1;
2692 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2697 /*****************************************************************************
2698 * WINSPOOL_GetDefaultDevMode
2700 * Get a default DevMode values for wineps.
2704 static void WINSPOOL_GetDefaultDevMode(
2706 DWORD buflen, DWORD *needed,
2710 static const char szwps[] = "wineps.drv";
2712 /* fill default DEVMODE - should be read from ppd... */
2713 ZeroMemory( &dm, sizeof(dm) );
2714 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2715 dm.dmSpecVersion = DM_SPECVERSION;
2716 dm.dmDriverVersion = 1;
2717 dm.dmSize = sizeof(DEVMODEA);
2718 dm.dmDriverExtra = 0;
2720 DM_ORIENTATION | DM_PAPERSIZE |
2721 DM_PAPERLENGTH | DM_PAPERWIDTH |
2724 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2725 DM_YRESOLUTION | DM_TTOPTION;
2727 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2728 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2729 dm.u1.s1.dmPaperLength = 2970;
2730 dm.u1.s1.dmPaperWidth = 2100;
2734 dm.dmDefaultSource = DMBIN_AUTO;
2735 dm.dmPrintQuality = DMRES_MEDIUM;
2738 dm.dmYResolution = 300; /* 300dpi */
2739 dm.dmTTOption = DMTT_BITMAP;
2742 /* dm.dmLogPixels */
2743 /* dm.dmBitsPerPel */
2744 /* dm.dmPelsWidth */
2745 /* dm.dmPelsHeight */
2746 /* dm.dmDisplayFlags */
2747 /* dm.dmDisplayFrequency */
2748 /* dm.dmICMMethod */
2749 /* dm.dmICMIntent */
2750 /* dm.dmMediaType */
2751 /* dm.dmDitherType */
2752 /* dm.dmReserved1 */
2753 /* dm.dmReserved2 */
2754 /* dm.dmPanningWidth */
2755 /* dm.dmPanningHeight */
2758 if(buflen >= sizeof(DEVMODEW)) {
2759 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2760 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2761 HeapFree(GetProcessHeap(),0,pdmW);
2763 *needed = sizeof(DEVMODEW);
2767 if(buflen >= sizeof(DEVMODEA)) {
2768 memcpy(ptr, &dm, sizeof(DEVMODEA));
2770 *needed = sizeof(DEVMODEA);
2774 /*****************************************************************************
2775 * WINSPOOL_GetDevModeFromReg
2777 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2778 * DevMode is stored either as unicode or ascii.
2780 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2782 DWORD buflen, DWORD *needed,
2785 DWORD sz = buflen, type;
2788 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2789 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2790 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2791 if (sz < sizeof(DEVMODEA))
2793 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2796 /* ensures that dmSize is not erratically bogus if registry is invalid */
2797 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2798 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2800 sz += (CCHDEVICENAME + CCHFORMNAME);
2802 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2803 memcpy(ptr, dmW, sz);
2804 HeapFree(GetProcessHeap(),0,dmW);
2811 /*********************************************************************
2812 * WINSPOOL_GetPrinter_2
2814 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2815 * The strings are either stored as unicode or ascii.
2817 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2818 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2821 DWORD size, left = cbBuf;
2822 BOOL space = (cbBuf > 0);
2827 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2829 if(space && size <= left) {
2830 pi2->pPrinterName = (LPWSTR)ptr;
2837 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2839 if(space && size <= left) {
2840 pi2->pShareName = (LPWSTR)ptr;
2847 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2849 if(space && size <= left) {
2850 pi2->pPortName = (LPWSTR)ptr;
2857 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2859 if(space && size <= left) {
2860 pi2->pDriverName = (LPWSTR)ptr;
2867 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2869 if(space && size <= left) {
2870 pi2->pComment = (LPWSTR)ptr;
2877 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2879 if(space && size <= left) {
2880 pi2->pLocation = (LPWSTR)ptr;
2887 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2889 if(space && size <= left) {
2890 pi2->pDevMode = (LPDEVMODEW)ptr;
2899 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2900 if(space && size <= left) {
2901 pi2->pDevMode = (LPDEVMODEW)ptr;
2908 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2910 if(space && size <= left) {
2911 pi2->pSepFile = (LPWSTR)ptr;
2918 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2920 if(space && size <= left) {
2921 pi2->pPrintProcessor = (LPWSTR)ptr;
2928 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2930 if(space && size <= left) {
2931 pi2->pDatatype = (LPWSTR)ptr;
2938 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2940 if(space && size <= left) {
2941 pi2->pParameters = (LPWSTR)ptr;
2949 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2950 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2951 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2952 "Default Priority");
2953 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2954 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2957 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2958 memset(pi2, 0, sizeof(*pi2));
2963 /*********************************************************************
2964 * WINSPOOL_GetPrinter_4
2966 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2968 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2969 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2972 DWORD size, left = cbBuf;
2973 BOOL space = (cbBuf > 0);
2978 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2980 if(space && size <= left) {
2981 pi4->pPrinterName = (LPWSTR)ptr;
2989 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2992 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2993 memset(pi4, 0, sizeof(*pi4));
2998 /*********************************************************************
2999 * WINSPOOL_GetPrinter_5
3001 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3003 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3004 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3007 DWORD size, left = cbBuf;
3008 BOOL space = (cbBuf > 0);
3013 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3015 if(space && size <= left) {
3016 pi5->pPrinterName = (LPWSTR)ptr;
3023 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3025 if(space && size <= left) {
3026 pi5->pPortName = (LPWSTR)ptr;
3034 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3035 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3037 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3041 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3042 memset(pi5, 0, sizeof(*pi5));
3047 /*****************************************************************************
3048 * WINSPOOL_GetPrinter
3050 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3051 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3052 * just a collection of pointers to strings.
3054 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3055 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3058 DWORD size, needed = 0;
3060 HKEY hkeyPrinter, hkeyPrinters;
3063 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3065 if (!(name = get_opened_printer_name(hPrinter))) {
3066 SetLastError(ERROR_INVALID_HANDLE);
3070 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3072 ERR("Can't create Printers key\n");
3075 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3077 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3078 RegCloseKey(hkeyPrinters);
3079 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3086 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3088 size = sizeof(PRINTER_INFO_2W);
3090 ptr = pPrinter + size;
3092 memset(pPrinter, 0, size);
3097 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3105 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3107 size = sizeof(PRINTER_INFO_4W);
3109 ptr = pPrinter + size;
3111 memset(pPrinter, 0, size);
3116 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3125 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3127 size = sizeof(PRINTER_INFO_5W);
3129 ptr = pPrinter + size;
3131 memset(pPrinter, 0, size);
3137 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3144 FIXME("Unimplemented level %ld\n", Level);
3145 SetLastError(ERROR_INVALID_LEVEL);
3146 RegCloseKey(hkeyPrinters);
3147 RegCloseKey(hkeyPrinter);
3151 RegCloseKey(hkeyPrinter);
3152 RegCloseKey(hkeyPrinters);
3154 TRACE("returning %d needed = %ld\n", ret, needed);
3155 if(pcbNeeded) *pcbNeeded = needed;
3157 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3161 /*****************************************************************************
3162 * GetPrinterW [WINSPOOL.@]
3164 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3165 DWORD cbBuf, LPDWORD pcbNeeded)
3167 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3171 /*****************************************************************************
3172 * GetPrinterA [WINSPOOL.@]
3174 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3175 DWORD cbBuf, LPDWORD pcbNeeded)
3177 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3181 /*****************************************************************************
3182 * WINSPOOL_EnumPrinters
3184 * Implementation of EnumPrintersA|W
3186 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3187 DWORD dwLevel, LPBYTE lpbPrinters,
3188 DWORD cbBuf, LPDWORD lpdwNeeded,
3189 LPDWORD lpdwReturned, BOOL unicode)
3192 HKEY hkeyPrinters, hkeyPrinter;
3193 WCHAR PrinterName[255];
3194 DWORD needed = 0, number = 0;
3195 DWORD used, i, left;
3199 memset(lpbPrinters, 0, cbBuf);
3205 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3206 if(dwType == PRINTER_ENUM_DEFAULT)
3209 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3210 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3211 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3212 if(!dwType) return TRUE;
3215 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3216 FIXME("dwType = %08lx\n", dwType);
3217 SetLastError(ERROR_INVALID_FLAGS);
3221 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3223 ERR("Can't create Printers key\n");
3227 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3228 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3229 RegCloseKey(hkeyPrinters);
3230 ERR("Can't query Printers key\n");
3233 TRACE("Found %ld printers\n", number);
3237 RegCloseKey(hkeyPrinters);
3239 *lpdwReturned = number;
3243 used = number * sizeof(PRINTER_INFO_2W);
3246 used = number * sizeof(PRINTER_INFO_4W);
3249 used = number * sizeof(PRINTER_INFO_5W);
3253 SetLastError(ERROR_INVALID_LEVEL);
3254 RegCloseKey(hkeyPrinters);
3257 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3259 for(i = 0; i < number; i++) {
3260 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3262 ERR("Can't enum key number %ld\n", i);
3263 RegCloseKey(hkeyPrinters);
3266 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3267 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3269 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3270 RegCloseKey(hkeyPrinters);
3275 buf = lpbPrinters + used;
3276 left = cbBuf - used;
3284 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3285 left, &needed, unicode);
3287 if(pi) pi += sizeof(PRINTER_INFO_2W);
3290 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3291 left, &needed, unicode);
3293 if(pi) pi += sizeof(PRINTER_INFO_4W);
3296 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3297 left, &needed, unicode);
3299 if(pi) pi += sizeof(PRINTER_INFO_5W);
3302 ERR("Shouldn't be here!\n");
3303 RegCloseKey(hkeyPrinter);
3304 RegCloseKey(hkeyPrinters);
3307 RegCloseKey(hkeyPrinter);
3309 RegCloseKey(hkeyPrinters);
3316 memset(lpbPrinters, 0, cbBuf);
3317 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3321 *lpdwReturned = number;
3322 SetLastError(ERROR_SUCCESS);
3327 /******************************************************************
3328 * EnumPrintersW [WINSPOOL.@]
3330 * Enumerates the available printers, print servers and print
3331 * providers, depending on the specified flags, name and level.
3335 * If level is set to 1:
3336 * Not implemented yet!
3337 * Returns TRUE with an empty list.
3339 * If level is set to 2:
3340 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3341 * Returns an array of PRINTER_INFO_2 data structures in the
3342 * lpbPrinters buffer. Note that according to MSDN also an
3343 * OpenPrinter should be performed on every remote printer.
3345 * If level is set to 4 (officially WinNT only):
3346 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3347 * Fast: Only the registry is queried to retrieve printer names,
3348 * no connection to the driver is made.
3349 * Returns an array of PRINTER_INFO_4 data structures in the
3350 * lpbPrinters buffer.
3352 * If level is set to 5 (officially WinNT4/Win9x only):
3353 * Fast: Only the registry is queried to retrieve printer names,
3354 * no connection to the driver is made.
3355 * Returns an array of PRINTER_INFO_5 data structures in the
3356 * lpbPrinters buffer.
3358 * If level set to 3 or 6+:
3359 * returns zero (failure!)
3361 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3365 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3366 * - Only levels 2, 4 and 5 are implemented at the moment.
3367 * - 16-bit printer drivers are not enumerated.
3368 * - Returned amount of bytes used/needed does not match the real Windoze
3369 * implementation (as in this implementation, all strings are part
3370 * of the buffer, whereas Win32 keeps them somewhere else)
3371 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3374 * - In a regular Wine installation, no registry settings for printers
3375 * exist, which makes this function return an empty list.
3377 BOOL WINAPI EnumPrintersW(
3378 DWORD dwType, /* [in] Types of print objects to enumerate */
3379 LPWSTR lpszName, /* [in] name of objects to enumerate */
3380 DWORD dwLevel, /* [in] type of printer info structure */
3381 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3382 DWORD cbBuf, /* [in] max size of buffer in bytes */
3383 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3384 LPDWORD lpdwReturned /* [out] number of entries returned */
3387 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3388 lpdwNeeded, lpdwReturned, TRUE);
3391 /******************************************************************
3392 * EnumPrintersA [WINSPOOL.@]
3395 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3396 DWORD dwLevel, LPBYTE lpbPrinters,
3397 DWORD cbBuf, LPDWORD lpdwNeeded,
3398 LPDWORD lpdwReturned)
3401 UNICODE_STRING lpszNameW;
3404 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3405 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3406 lpdwNeeded, lpdwReturned, FALSE);
3407 RtlFreeUnicodeString(&lpszNameW);
3411 /*****************************************************************************
3412 * WINSPOOL_GetDriverInfoFromReg [internal]
3414 * Enters the information from the registry into the DRIVER_INFO struct
3417 * zero if the printer driver does not exist in the registry
3418 * (only if Level > 1) otherwise nonzero
3420 static BOOL WINSPOOL_GetDriverInfoFromReg(
3423 LPWSTR pEnvironment,
3425 LPBYTE ptr, /* DRIVER_INFO */
3426 LPBYTE pDriverStrings, /* strings buffer */
3427 DWORD cbBuf, /* size of string buffer */
3428 LPDWORD pcbNeeded, /* space needed for str. */
3429 BOOL unicode) /* type of strings */
3433 LPBYTE strPtr = pDriverStrings;
3435 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3436 debugstr_w(DriverName), debugstr_w(pEnvironment),
3437 Level, ptr, pDriverStrings, cbBuf, unicode);
3440 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3441 if (*pcbNeeded <= cbBuf)
3442 strcpyW((LPWSTR)strPtr, DriverName);
3444 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3446 if(*pcbNeeded <= cbBuf)
3447 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3448 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3452 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3456 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3457 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3460 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3461 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3462 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3467 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3470 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3472 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3474 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3477 if(*pcbNeeded <= cbBuf) {
3479 strcpyW((LPWSTR)strPtr, pEnvironment);
3481 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3482 (LPSTR)strPtr, size, NULL, NULL);
3484 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3485 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3488 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3491 if(*pcbNeeded <= cbBuf)
3492 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3495 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3496 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3499 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3502 if(*pcbNeeded <= cbBuf)
3503 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3506 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3507 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3510 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3511 0, &size, unicode)) {
3513 if(*pcbNeeded <= cbBuf)
3514 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3515 size, &tmp, unicode);
3517 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3518 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3522 RegCloseKey(hkeyDriver);
3523 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3527 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3530 if(*pcbNeeded <= cbBuf)
3531 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3532 size, &tmp, unicode);
3534 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3535 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3538 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3541 if(*pcbNeeded <= cbBuf)
3542 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3543 size, &tmp, unicode);
3545 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3546 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3549 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3552 if(*pcbNeeded <= cbBuf)
3553 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3554 size, &tmp, unicode);
3556 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3557 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3560 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3563 if(*pcbNeeded <= cbBuf)
3564 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3565 size, &tmp, unicode);
3567 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3568 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3571 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3572 RegCloseKey(hkeyDriver);
3576 /*****************************************************************************
3577 * WINSPOOL_GetPrinterDriver
3579 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3580 DWORD Level, LPBYTE pDriverInfo,
3581 DWORD cbBuf, LPDWORD pcbNeeded,
3585 WCHAR DriverName[100];
3586 DWORD ret, type, size, needed = 0;
3588 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3590 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3591 Level,pDriverInfo,cbBuf, pcbNeeded);
3593 ZeroMemory(pDriverInfo, cbBuf);
3595 if (!(name = get_opened_printer_name(hPrinter))) {
3596 SetLastError(ERROR_INVALID_HANDLE);
3599 if(Level < 1 || Level > 6) {
3600 SetLastError(ERROR_INVALID_LEVEL);
3603 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3605 ERR("Can't create Printers key\n");
3608 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3610 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3611 RegCloseKey(hkeyPrinters);
3612 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3615 size = sizeof(DriverName);
3617 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3618 (LPBYTE)DriverName, &size);
3619 RegCloseKey(hkeyPrinter);
3620 RegCloseKey(hkeyPrinters);
3621 if(ret != ERROR_SUCCESS) {
3622 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3626 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3628 ERR("Can't create Drivers key\n");
3634 size = sizeof(DRIVER_INFO_1W);
3637 size = sizeof(DRIVER_INFO_2W);
3640 size = sizeof(DRIVER_INFO_3W);
3643 size = sizeof(DRIVER_INFO_4W);
3646 size = sizeof(DRIVER_INFO_5W);
3649 size = sizeof(DRIVER_INFO_6W);
3652 ERR("Invalid level\n");
3657 ptr = pDriverInfo + size;
3659 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3660 pEnvironment, Level, pDriverInfo,
3661 (cbBuf < size) ? NULL : ptr,
3662 (cbBuf < size) ? 0 : cbBuf - size,
3663 &needed, unicode)) {
3664 RegCloseKey(hkeyDrivers);
3668 RegCloseKey(hkeyDrivers);
3670 if(pcbNeeded) *pcbNeeded = size + needed;
3671 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3672 if(cbBuf >= needed) return TRUE;
3673 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3677 /*****************************************************************************
3678 * GetPrinterDriverA [WINSPOOL.@]
3680 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3681 DWORD Level, LPBYTE pDriverInfo,
3682 DWORD cbBuf, LPDWORD pcbNeeded)
3685 UNICODE_STRING pEnvW;
3688 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3689 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3690 cbBuf, pcbNeeded, FALSE);
3691 RtlFreeUnicodeString(&pEnvW);
3694 /*****************************************************************************
3695 * GetPrinterDriverW [WINSPOOL.@]
3697 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3698 DWORD Level, LPBYTE pDriverInfo,
3699 DWORD cbBuf, LPDWORD pcbNeeded)
3701 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3702 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3705 /*****************************************************************************
3706 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3708 * Return the PATH for the Printer-Drivers (UNICODE)
3711 * pName [I] Servername (NT only) or NULL (local Computer)
3712 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3713 * Level [I] Structure-Level (must be 1)
3714 * pDriverDirectory [O] PTR to Buffer that receives the Result
3715 * cbBuf [I] Size of Buffer at pDriverDirectory
3716 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3717 * required for pDriverDirectory
3720 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3721 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3722 * if cbBuf is too small
3724 * Native Values returned in pDriverDirectory on Success:
3725 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3726 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3727 *| win9x(Windows 4.0): "%winsysdir%"
3729 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3732 *- Only NULL or "" is supported for pName
3735 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3736 DWORD Level, LPBYTE pDriverDirectory,
3737 DWORD cbBuf, LPDWORD pcbNeeded)
3740 const printenv_t * env;
3742 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3743 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3744 if(pName != NULL && pName[0]) {
3745 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3746 SetLastError(ERROR_INVALID_PARAMETER);
3750 env = validate_envW(pEnvironment);
3751 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3754 WARN("(Level: %ld) is ignored in win9x\n", Level);
3755 SetLastError(ERROR_INVALID_LEVEL);
3759 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3760 needed = GetSystemDirectoryW(NULL, 0);
3761 /* add the Size for the Subdirectories */
3762 needed += lstrlenW(spooldriversW);
3763 needed += lstrlenW(env->subdir);
3764 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3767 *pcbNeeded = needed;
3768 TRACE("required: 0x%lx/%ld\n", needed, needed);
3769 if(needed > cbBuf) {
3770 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3773 if(pcbNeeded == NULL) {
3774 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3775 SetLastError(RPC_X_NULL_REF_POINTER);
3778 if(pDriverDirectory == NULL) {
3779 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3780 SetLastError(ERROR_INVALID_USER_BUFFER);
3784 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3785 /* add the Subdirectories */
3786 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3787 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3788 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3793 /*****************************************************************************
3794 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3796 * Return the PATH for the Printer-Drivers (ANSI)
3798 * See GetPrinterDriverDirectoryW.
3801 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3804 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3805 DWORD Level, LPBYTE pDriverDirectory,
3806 DWORD cbBuf, LPDWORD pcbNeeded)
3808 UNICODE_STRING nameW, environmentW;
3811 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3812 WCHAR *driverDirectoryW = NULL;
3814 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3815 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3817 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3819 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3820 else nameW.Buffer = NULL;
3821 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3822 else environmentW.Buffer = NULL;
3824 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3825 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3828 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3829 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3831 *pcbNeeded = needed;
3832 ret = (needed <= cbBuf) ? TRUE : FALSE;
3834 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3836 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3838 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3839 RtlFreeUnicodeString(&environmentW);
3840 RtlFreeUnicodeString(&nameW);
3845 /*****************************************************************************
3846 * AddPrinterDriverA [WINSPOOL.@]
3848 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3851 HKEY hkeyDrivers, hkeyName;
3853 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3855 if(level != 2 && level != 3) {
3856 SetLastError(ERROR_INVALID_LEVEL);
3860 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3861 SetLastError(ERROR_INVALID_PARAMETER);
3865 WARN("pDriverInfo == NULL\n");
3866 SetLastError(ERROR_INVALID_PARAMETER);
3871 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3873 memset(&di3, 0, sizeof(di3));
3874 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3877 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3879 SetLastError(ERROR_INVALID_PARAMETER);
3882 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3883 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3884 if(!di3.pHelpFile) di3.pHelpFile = "";
3885 if(!di3.pMonitorName) di3.pMonitorName = "";
3887 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3890 ERR("Can't create Drivers key\n");
3894 if(level == 2) { /* apparently can't overwrite with level2 */
3895 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3896 RegCloseKey(hkeyName);
3897 RegCloseKey(hkeyDrivers);
3898 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3899 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3903 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3904 RegCloseKey(hkeyDrivers);
3905 ERR("Can't create Name key\n");
3908 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3910 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3911 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3912 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3914 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3915 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3916 (LPBYTE) di3.pDependentFiles, 0);
3917 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3918 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3919 RegCloseKey(hkeyName);
3920 RegCloseKey(hkeyDrivers);
3925 /*****************************************************************************
3926 * AddPrinterDriverW [WINSPOOL.@]
3928 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3931 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3936 /*****************************************************************************
3937 * AddPrintProcessorA [WINSPOOL.@]
3939 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3940 LPSTR pPrintProcessorName)
3942 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3943 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3947 /*****************************************************************************
3948 * AddPrintProcessorW [WINSPOOL.@]
3950 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3951 LPWSTR pPrintProcessorName)
3953 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3954 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3958 /*****************************************************************************
3959 * AddPrintProvidorA [WINSPOOL.@]
3961 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3963 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3967 /*****************************************************************************
3968 * AddPrintProvidorW [WINSPOOL.@]
3970 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3972 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3976 /*****************************************************************************
3977 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3979 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3980 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3982 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3983 pDevModeOutput, pDevModeInput);
3987 /*****************************************************************************
3988 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3990 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3991 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3993 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3994 pDevModeOutput, pDevModeInput);
3998 /*****************************************************************************
3999 * PrinterProperties [WINSPOOL.@]
4001 * Displays a dialog to set the properties of the printer.
4004 * nonzero on success or zero on failure
4007 * implemented as stub only
4009 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4010 HANDLE hPrinter /* [in] handle to printer object */
4012 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4013 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4017 /*****************************************************************************
4018 * EnumJobsA [WINSPOOL.@]
4021 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4022 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4025 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4026 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4028 if(pcbNeeded) *pcbNeeded = 0;
4029 if(pcReturned) *pcReturned = 0;
4034 /*****************************************************************************
4035 * EnumJobsW [WINSPOOL.@]
4038 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4039 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4042 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4043 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4045 if(pcbNeeded) *pcbNeeded = 0;
4046 if(pcReturned) *pcReturned = 0;
4050 /*****************************************************************************
4051 * WINSPOOL_EnumPrinterDrivers [internal]
4053 * Delivers information about all printer drivers installed on the
4054 * localhost or a given server
4057 * nonzero on success or zero on failure. If the buffer for the returned
4058 * information is too small the function will return an error
4061 * - only implemented for localhost, foreign hosts will return an error
4063 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4064 DWORD Level, LPBYTE pDriverInfo,
4065 DWORD cbBuf, LPDWORD pcbNeeded,
4066 LPDWORD pcReturned, BOOL unicode)
4069 DWORD i, needed, number = 0, size = 0;
4070 WCHAR DriverNameW[255];
4073 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4074 debugstr_w(pName), debugstr_w(pEnvironment),
4075 Level, pDriverInfo, cbBuf, unicode);
4077 /* check for local drivers */
4078 if((pName) && (pName[0])) {
4079 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4080 SetLastError(ERROR_ACCESS_DENIED);
4084 /* check input parameter */
4085 if((Level < 1) || (Level > 3)) {
4086 ERR("unsupported level %ld\n", Level);
4087 SetLastError(ERROR_INVALID_LEVEL);
4091 /* initialize return values */
4093 memset( pDriverInfo, 0, cbBuf);
4097 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4099 ERR("Can't open Drivers key\n");
4103 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4104 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4105 RegCloseKey(hkeyDrivers);
4106 ERR("Can't query Drivers key\n");
4109 TRACE("Found %ld Drivers\n", number);
4111 /* get size of single struct
4112 * unicode and ascii structure have the same size
4116 size = sizeof(DRIVER_INFO_1A);
4119 size = sizeof(DRIVER_INFO_2A);
4122 size = sizeof(DRIVER_INFO_3A);
4126 /* calculate required buffer size */
4127 *pcbNeeded = size * number;
4129 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4131 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4132 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4134 ERR("Can't enum key number %ld\n", i);
4135 RegCloseKey(hkeyDrivers);
4138 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4139 pEnvironment, Level, ptr,
4140 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4141 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4142 &needed, unicode)) {
4143 RegCloseKey(hkeyDrivers);
4146 (*pcbNeeded) += needed;
4149 RegCloseKey(hkeyDrivers);
4151 if(cbBuf < *pcbNeeded){
4152 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4156 *pcReturned = number;
4160 /*****************************************************************************
4161 * EnumPrinterDriversW [WINSPOOL.@]
4163 * see function EnumPrinterDrivers for RETURNS, BUGS
4165 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4166 LPBYTE pDriverInfo, DWORD cbBuf,
4167 LPDWORD pcbNeeded, LPDWORD pcReturned)
4169 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4170 cbBuf, pcbNeeded, pcReturned, TRUE);
4173 /*****************************************************************************
4174 * EnumPrinterDriversA [WINSPOOL.@]
4176 * see function EnumPrinterDrivers for RETURNS, BUGS
4178 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4179 LPBYTE pDriverInfo, DWORD cbBuf,
4180 LPDWORD pcbNeeded, LPDWORD pcReturned)
4182 UNICODE_STRING pNameW, pEnvironmentW;
4183 PWSTR pwstrNameW, pwstrEnvironmentW;
4185 pwstrNameW = asciitounicode(&pNameW, pName);
4186 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4188 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4189 Level, pDriverInfo, cbBuf, pcbNeeded,
4191 RtlFreeUnicodeString(&pNameW);
4192 RtlFreeUnicodeString(&pEnvironmentW);
4197 static CHAR PortMonitor[] = "Wine Port Monitor";
4198 static CHAR PortDescription[] = "Wine Port";
4200 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4204 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4205 NULL, OPEN_EXISTING, 0, NULL );
4206 if (handle == INVALID_HANDLE_VALUE)
4208 TRACE("Checking %s exists\n", name );
4209 CloseHandle( handle );
4213 static DWORD WINSPOOL_CountSerialPorts(void)
4220 strcpy( name, "COMx:" );
4222 if (WINSPOOL_ComPortExists( name ))
4229 /******************************************************************************
4230 * EnumPortsA (WINSPOOL.@)
4235 * ANSI-Version did not call the UNICODE-Version
4238 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4239 LPDWORD bufneeded,LPDWORD bufreturned)
4242 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4243 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4247 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4248 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4253 info_size = sizeof (PORT_INFO_1A);
4256 info_size = sizeof (PORT_INFO_2A);
4259 SetLastError(ERROR_INVALID_LEVEL);
4263 /* see how many exist */
4266 serial_count = WINSPOOL_CountSerialPorts();
4269 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4270 if ( r == ERROR_SUCCESS )
4272 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4273 &printer_count, NULL, NULL, NULL, NULL);
4275 count = serial_count + printer_count;
4277 /* then fill in the structure info structure once
4278 we know the offset to the first string */
4280 memset( buffer, 0, bufsize );
4282 ofs = info_size*count;
4283 for ( i=0; i<count; i++)
4285 DWORD vallen = sizeof(portname) - 1;
4287 /* get the serial port values, then the printer values */
4288 if ( i < serial_count )
4290 strcpy( portname, "COMx:" );
4291 portname[3] = '1' + i;
4292 if (!WINSPOOL_ComPortExists( portname ))
4295 TRACE("Found %s\n", portname );
4296 vallen = strlen( portname );
4300 r = RegEnumValueA( hkey_printer, i-serial_count,
4301 portname, &vallen, NULL, NULL, NULL, 0 );
4306 /* add a colon if necessary, and make it upper case */
4307 CharUpperBuffA(portname,vallen);
4308 if (strcasecmp(portname,"nul")!=0)
4309 if (vallen && (portname[vallen-1] != ':') )
4310 lstrcatA(portname,":");
4312 /* add the port info structure if we can fit it */
4313 if ( info_size*(n+1) < bufsize )
4317 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4318 info->pName = (LPSTR) &buffer[ofs];
4320 else if ( level == 2)
4322 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4323 info->pPortName = (LPSTR) &buffer[ofs];
4324 /* FIXME: fill in more stuff here */
4325 info->pMonitorName = PortMonitor;
4326 info->pDescription = PortDescription;
4327 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4330 /* add the name of the port if we can fit it */
4331 if ( ofs < bufsize )
4332 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4338 ofs += lstrlenA(portname)+1;
4341 RegCloseKey(hkey_printer);
4352 /******************************************************************************
4353 * EnumPortsW (WINSPOOL.@)
4355 * Enumerate available Ports
4358 * name [I] Servername or NULL (local Computer)
4359 * level [I] Structure-Level (1 or 2)
4360 * buffer [O] PTR to Buffer that receives the Result
4361 * bufsize [I] Size of Buffer at buffer
4362 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4363 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4367 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4370 * UNICODE-Version is a stub
4373 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4374 LPDWORD bufneeded,LPDWORD bufreturned)
4376 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4377 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4381 /******************************************************************************
4382 * GetDefaultPrinterW (WINSPOOL.@)
4385 * This function must read the value from data 'device' of key
4386 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4388 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4392 WCHAR *buffer, *ptr;
4396 SetLastError(ERROR_INVALID_PARAMETER);
4400 /* make the buffer big enough for the stuff from the profile/registry,
4401 * the content must fit into the local buffer to compute the correct
4402 * size even if the extern buffer is too small or not given.
4403 * (20 for ,driver,port) */
4405 len = max(100, (insize + 20));
4406 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4408 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4410 SetLastError (ERROR_FILE_NOT_FOUND);
4414 TRACE("%s\n", debugstr_w(buffer));
4416 if ((ptr = strchrW(buffer, ',')) == NULL)
4418 SetLastError(ERROR_INVALID_NAME);
4424 *namesize = strlenW(buffer) + 1;
4425 if(!name || (*namesize > insize))
4427 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4431 strcpyW(name, buffer);
4434 HeapFree( GetProcessHeap(), 0, buffer);
4439 /******************************************************************************
4440 * GetDefaultPrinterA (WINSPOOL.@)
4442 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4446 WCHAR *bufferW = NULL;
4450 SetLastError(ERROR_INVALID_PARAMETER);
4454 if(name && *namesize) {
4456 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4459 if(!GetDefaultPrinterW( bufferW, namesize)) {
4464 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4468 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4471 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4474 HeapFree( GetProcessHeap(), 0, bufferW);
4479 /******************************************************************************
4480 * SetDefaultPrinterW (WINSPOOL.204)
4482 * Set the Name of the Default Printer
4485 * pszPrinter [I] Name of the Printer or NULL
4492 * When the Parameter is NULL or points to an Empty String and
4493 * a Default Printer was already present, then this Function changes nothing.
4494 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4495 * the First enumerated local Printer is used.
4498 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4501 TRACE("(%s)\n", debugstr_w(pszPrinter));
4503 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4507 /******************************************************************************
4508 * SetDefaultPrinterA (WINSPOOL.202)
4510 * See SetDefaultPrinterW.
4513 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4516 TRACE("(%s)\n", debugstr_a(pszPrinter));
4518 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4523 /******************************************************************************
4524 * SetPrinterDataExA (WINSPOOL.@)
4526 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4527 LPCSTR pValueName, DWORD Type,
4528 LPBYTE pData, DWORD cbData)
4530 HKEY hkeyPrinter, hkeySubkey;
4533 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4534 debugstr_a(pValueName), Type, pData, cbData);
4536 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4540 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4542 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4543 RegCloseKey(hkeyPrinter);
4546 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4547 RegCloseKey(hkeySubkey);
4548 RegCloseKey(hkeyPrinter);
4552 /******************************************************************************
4553 * SetPrinterDataExW (WINSPOOL.@)
4555 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4556 LPCWSTR pValueName, DWORD Type,
4557 LPBYTE pData, DWORD cbData)
4559 HKEY hkeyPrinter, hkeySubkey;
4562 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4563 debugstr_w(pValueName), Type, pData, cbData);
4565 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4569 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4571 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4572 RegCloseKey(hkeyPrinter);
4575 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4576 RegCloseKey(hkeySubkey);
4577 RegCloseKey(hkeyPrinter);
4581 /******************************************************************************
4582 * SetPrinterDataA (WINSPOOL.@)
4584 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4585 LPBYTE pData, DWORD cbData)
4587 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4591 /******************************************************************************
4592 * SetPrinterDataW (WINSPOOL.@)
4594 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4595 LPBYTE pData, DWORD cbData)
4597 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4601 /******************************************************************************
4602 * GetPrinterDataExA (WINSPOOL.@)
4604 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4605 LPCSTR pValueName, LPDWORD pType,
4606 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4608 HKEY hkeyPrinter, hkeySubkey;
4611 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4612 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4615 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4619 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4621 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4622 RegCloseKey(hkeyPrinter);
4626 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4627 RegCloseKey(hkeySubkey);
4628 RegCloseKey(hkeyPrinter);
4632 /******************************************************************************
4633 * GetPrinterDataExW (WINSPOOL.@)
4635 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4636 LPCWSTR pValueName, LPDWORD pType,
4637 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4639 HKEY hkeyPrinter, hkeySubkey;
4642 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4643 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4646 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4650 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4652 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4653 RegCloseKey(hkeyPrinter);
4657 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4658 RegCloseKey(hkeySubkey);
4659 RegCloseKey(hkeyPrinter);
4663 /******************************************************************************
4664 * GetPrinterDataA (WINSPOOL.@)
4666 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4667 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4669 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4670 pData, nSize, pcbNeeded);
4673 /******************************************************************************
4674 * GetPrinterDataW (WINSPOOL.@)
4676 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4677 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4679 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4680 pData, nSize, pcbNeeded);
4683 /*******************************************************************************
4684 * EnumPrinterDataExW [WINSPOOL.@]
4686 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4687 LPBYTE pEnumValues, DWORD cbEnumValues,
4688 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4690 HKEY hkPrinter, hkSubKey;
4691 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4692 cbValueNameLen, cbMaxValueLen, cbValueLen,
4697 PPRINTER_ENUM_VALUESW ppev;
4699 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4701 if (pKeyName == NULL || *pKeyName == 0)
4702 return ERROR_INVALID_PARAMETER;
4704 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4705 if (ret != ERROR_SUCCESS)
4707 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4712 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4713 if (ret != ERROR_SUCCESS)
4715 r = RegCloseKey (hkPrinter);
4716 if (r != ERROR_SUCCESS)
4717 WARN ("RegCloseKey returned %li\n", r);
4718 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4719 debugstr_w (pKeyName), ret);
4723 ret = RegCloseKey (hkPrinter);
4724 if (ret != ERROR_SUCCESS)
4726 ERR ("RegCloseKey returned %li\n", ret);
4727 r = RegCloseKey (hkSubKey);
4728 if (r != ERROR_SUCCESS)
4729 WARN ("RegCloseKey returned %li\n", r);
4733 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4734 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4735 if (ret != ERROR_SUCCESS)
4737 r = RegCloseKey (hkSubKey);
4738 if (r != ERROR_SUCCESS)
4739 WARN ("RegCloseKey returned %li\n", r);
4740 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4744 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4745 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4747 if (cValues == 0) /* empty key */
4749 r = RegCloseKey (hkSubKey);
4750 if (r != ERROR_SUCCESS)
4751 WARN ("RegCloseKey returned %li\n", r);
4752 *pcbEnumValues = *pnEnumValues = 0;
4753 return ERROR_SUCCESS;
4756 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4758 hHeap = GetProcessHeap ();
4761 ERR ("GetProcessHeap failed\n");
4762 r = RegCloseKey (hkSubKey);
4763 if (r != ERROR_SUCCESS)
4764 WARN ("RegCloseKey returned %li\n", r);
4765 return ERROR_OUTOFMEMORY;
4768 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4769 if (lpValueName == NULL)
4771 ERR ("Failed to allocate %li bytes from process heap\n",
4772 cbMaxValueNameLen * sizeof (WCHAR));
4773 r = RegCloseKey (hkSubKey);
4774 if (r != ERROR_SUCCESS)
4775 WARN ("RegCloseKey returned %li\n", r);
4776 return ERROR_OUTOFMEMORY;
4779 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4780 if (lpValue == NULL)
4782 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4783 if (HeapFree (hHeap, 0, lpValueName) == 0)
4784 WARN ("HeapFree failed with code %li\n", GetLastError ());
4785 r = RegCloseKey (hkSubKey);
4786 if (r != ERROR_SUCCESS)
4787 WARN ("RegCloseKey returned %li\n", r);
4788 return ERROR_OUTOFMEMORY;
4791 TRACE ("pass 1: calculating buffer required for all names and values\n");
4793 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4795 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4797 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4799 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4800 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4801 NULL, NULL, lpValue, &cbValueLen);
4802 if (ret != ERROR_SUCCESS)
4804 if (HeapFree (hHeap, 0, lpValue) == 0)
4805 WARN ("HeapFree failed with code %li\n", GetLastError ());
4806 if (HeapFree (hHeap, 0, lpValueName) == 0)
4807 WARN ("HeapFree failed with code %li\n", GetLastError ());
4808 r = RegCloseKey (hkSubKey);
4809 if (r != ERROR_SUCCESS)
4810 WARN ("RegCloseKey returned %li\n", r);
4811 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4815 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4816 debugstr_w (lpValueName), dwIndex,
4817 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4819 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4820 cbBufSize += cbValueLen;
4823 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4825 *pcbEnumValues = cbBufSize;
4826 *pnEnumValues = cValues;
4828 if (cbEnumValues < cbBufSize) /* buffer too small */
4830 if (HeapFree (hHeap, 0, lpValue) == 0)
4831 WARN ("HeapFree failed with code %li\n", GetLastError ());
4832 if (HeapFree (hHeap, 0, lpValueName) == 0)
4833 WARN ("HeapFree failed with code %li\n", GetLastError ());
4834 r = RegCloseKey (hkSubKey);
4835 if (r != ERROR_SUCCESS)
4836 WARN ("RegCloseKey returned %li\n", r);
4837 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4838 return ERROR_MORE_DATA;
4841 TRACE ("pass 2: copying all names and values to buffer\n");
4843 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4844 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4846 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4848 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4849 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4850 NULL, &dwType, lpValue, &cbValueLen);
4851 if (ret != ERROR_SUCCESS)
4853 if (HeapFree (hHeap, 0, lpValue) == 0)
4854 WARN ("HeapFree failed with code %li\n", GetLastError ());
4855 if (HeapFree (hHeap, 0, lpValueName) == 0)
4856 WARN ("HeapFree failed with code %li\n", GetLastError ());
4857 r = RegCloseKey (hkSubKey);
4858 if (r != ERROR_SUCCESS)
4859 WARN ("RegCloseKey returned %li\n", r);
4860 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4864 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4865 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4866 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4867 pEnumValues += cbValueNameLen;
4869 /* return # of *bytes* (including trailing \0), not # of chars */
4870 ppev[dwIndex].cbValueName = cbValueNameLen;
4872 ppev[dwIndex].dwType = dwType;
4874 memcpy (pEnumValues, lpValue, cbValueLen);
4875 ppev[dwIndex].pData = pEnumValues;
4876 pEnumValues += cbValueLen;
4878 ppev[dwIndex].cbData = cbValueLen;
4880 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4881 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4884 if (HeapFree (hHeap, 0, lpValue) == 0)
4886 ret = GetLastError ();
4887 ERR ("HeapFree failed with code %li\n", ret);
4888 if (HeapFree (hHeap, 0, lpValueName) == 0)
4889 WARN ("HeapFree failed with code %li\n", GetLastError ());
4890 r = RegCloseKey (hkSubKey);
4891 if (r != ERROR_SUCCESS)
4892 WARN ("RegCloseKey returned %li\n", r);
4896 if (HeapFree (hHeap, 0, lpValueName) == 0)
4898 ret = GetLastError ();
4899 ERR ("HeapFree failed with code %li\n", ret);
4900 r = RegCloseKey (hkSubKey);
4901 if (r != ERROR_SUCCESS)
4902 WARN ("RegCloseKey returned %li\n", r);
4906 ret = RegCloseKey (hkSubKey);
4907 if (ret != ERROR_SUCCESS)
4909 ERR ("RegCloseKey returned %li\n", ret);
4913 return ERROR_SUCCESS;
4916 /*******************************************************************************
4917 * EnumPrinterDataExA [WINSPOOL.@]
4919 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4920 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4921 * what Windows 2000 SP1 does.
4924 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4925 LPBYTE pEnumValues, DWORD cbEnumValues,
4926 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4930 DWORD ret, dwIndex, dwBufSize;
4934 TRACE ("%p %s\n", hPrinter, pKeyName);
4936 if (pKeyName == NULL || *pKeyName == 0)
4937 return ERROR_INVALID_PARAMETER;
4939 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4942 ret = GetLastError ();
4943 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4947 hHeap = GetProcessHeap ();
4950 ERR ("GetProcessHeap failed\n");
4951 return ERROR_OUTOFMEMORY;
4954 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4955 if (pKeyNameW == NULL)
4957 ERR ("Failed to allocate %li bytes from process heap\n",
4958 (LONG) len * sizeof (WCHAR));
4959 return ERROR_OUTOFMEMORY;
4962 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4964 ret = GetLastError ();
4965 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4966 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4967 WARN ("HeapFree failed with code %li\n", GetLastError ());
4971 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4972 pcbEnumValues, pnEnumValues);
4973 if (ret != ERROR_SUCCESS)
4975 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4976 WARN ("HeapFree failed with code %li\n", GetLastError ());
4977 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4981 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4983 ret = GetLastError ();
4984 ERR ("HeapFree failed with code %li\n", ret);
4988 if (*pnEnumValues == 0) /* empty key */
4989 return ERROR_SUCCESS;
4992 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4994 PPRINTER_ENUM_VALUESW ppev =
4995 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4997 if (dwBufSize < ppev->cbValueName)
4998 dwBufSize = ppev->cbValueName;
5000 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5001 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5002 dwBufSize = ppev->cbData;
5005 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5007 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5008 if (pBuffer == NULL)
5010 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5011 return ERROR_OUTOFMEMORY;
5014 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5016 PPRINTER_ENUM_VALUESW ppev =
5017 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5019 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5020 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5024 ret = GetLastError ();
5025 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5026 if (HeapFree (hHeap, 0, pBuffer) == 0)
5027 WARN ("HeapFree failed with code %li\n", GetLastError ());
5031 memcpy (ppev->pValueName, pBuffer, len);
5033 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5035 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5036 ppev->dwType != REG_MULTI_SZ)
5039 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5040 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5043 ret = GetLastError ();
5044 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5045 if (HeapFree (hHeap, 0, pBuffer) == 0)
5046 WARN ("HeapFree failed with code %li\n", GetLastError ());
5050 memcpy (ppev->pData, pBuffer, len);
5052 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5053 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5056 if (HeapFree (hHeap, 0, pBuffer) == 0)
5058 ret = GetLastError ();
5059 ERR ("HeapFree failed with code %li\n", ret);
5063 return ERROR_SUCCESS;
5066 /******************************************************************************
5067 * AbortPrinter (WINSPOOL.@)
5069 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5071 FIXME("(%p), stub!\n", hPrinter);
5075 /******************************************************************************
5076 * AddPortA (WINSPOOL.@)
5081 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5083 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5087 /******************************************************************************
5088 * AddPortW (WINSPOOL.@)
5090 * Add a Port for a specific Monitor
5093 * pName [I] Servername or NULL (local Computer)
5094 * hWnd [I] Handle to parent Window for the Dialog-Box
5095 * pMonitorName [I] Name of the Monitor that manage the Port
5105 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5107 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5111 /******************************************************************************
5112 * AddPortExA (WINSPOOL.@)
5117 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5119 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5120 lpBuffer, debugstr_a(lpMonitorName));
5124 /******************************************************************************
5125 * AddPortExW (WINSPOOL.@)
5127 * Add a Port for a specific Monitor, without presenting a user interface
5130 * hMonitor [I] Handle from InitializePrintMonitor2()
5131 * pName [I] Servername or NULL (local Computer)
5132 * Level [I] Structure-Level (1 or 2) for lpBuffer
5133 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5134 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5144 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5146 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5147 lpBuffer, debugstr_w(lpMonitorName));
5151 /******************************************************************************
5152 * AddPrinterConnectionA (WINSPOOL.@)
5154 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5156 FIXME("%s\n", debugstr_a(pName));
5160 /******************************************************************************
5161 * AddPrinterConnectionW (WINSPOOL.@)
5163 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5165 FIXME("%s\n", debugstr_w(pName));
5169 /******************************************************************************
5170 * AddPrinterDriverExW (WINSPOOL.@)
5172 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5173 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5175 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5176 Level, pDriverInfo, dwFileCopyFlags);
5177 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5181 /******************************************************************************
5182 * AddPrinterDriverExA (WINSPOOL.@)
5184 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5185 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5187 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5188 Level, pDriverInfo, dwFileCopyFlags);
5189 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5193 /******************************************************************************
5194 * ConfigurePortA (WINSPOOL.@)
5196 * See ConfigurePortW.
5199 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5201 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5205 /******************************************************************************
5206 * ConfigurePortW (WINSPOOL.@)
5208 * Display the Configuration-Dialog for a specific Port
5211 * pName [I] Servername or NULL (local Computer)
5212 * hWnd [I] Handle to parent Window for the Dialog-Box
5213 * pPortName [I] Name of the Port, that should be configured
5223 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5225 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5229 /******************************************************************************
5230 * ConnectToPrinterDlg (WINSPOOL.@)
5232 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5234 FIXME("%p %lx\n", hWnd, Flags);
5238 /******************************************************************************
5239 * DeletePrinterConnectionA (WINSPOOL.@)
5241 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5243 FIXME("%s\n", debugstr_a(pName));
5247 /******************************************************************************
5248 * DeletePrinterConnectionW (WINSPOOL.@)
5250 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5252 FIXME("%s\n", debugstr_w(pName));
5256 /******************************************************************************
5257 * DeletePrinterDriverExW (WINSPOOL.@)
5259 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5260 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5262 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5263 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5267 /******************************************************************************
5268 * DeletePrinterDriverExA (WINSPOOL.@)
5270 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5271 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5273 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5274 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5278 /******************************************************************************
5279 * DeletePrinterDataExW (WINSPOOL.@)
5281 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5284 FIXME("%p %s %s\n", hPrinter,
5285 debugstr_w(pKeyName), debugstr_w(pValueName));
5286 return ERROR_INVALID_PARAMETER;
5289 /******************************************************************************
5290 * DeletePrinterDataExA (WINSPOOL.@)
5292 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5295 FIXME("%p %s %s\n", hPrinter,
5296 debugstr_a(pKeyName), debugstr_a(pValueName));
5297 return ERROR_INVALID_PARAMETER;
5300 /******************************************************************************
5301 * DeletePrintProcessorA (WINSPOOL.@)
5303 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5305 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5306 debugstr_a(pPrintProcessorName));
5310 /******************************************************************************
5311 * DeletePrintProcessorW (WINSPOOL.@)
5313 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5315 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5316 debugstr_w(pPrintProcessorName));
5320 /******************************************************************************
5321 * DeletePrintProvidorA (WINSPOOL.@)
5323 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5325 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5326 debugstr_a(pPrintProviderName));
5330 /******************************************************************************
5331 * DeletePrintProvidorW (WINSPOOL.@)
5333 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5335 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5336 debugstr_w(pPrintProviderName));
5340 /******************************************************************************
5341 * EnumFormsA (WINSPOOL.@)
5343 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5344 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5346 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5350 /******************************************************************************
5351 * EnumFormsW (WINSPOOL.@)
5353 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5354 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5356 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5360 /*****************************************************************************
5361 * EnumMonitorsA [WINSPOOL.@]
5363 * See EnumMonitorsW.
5366 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5367 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5370 LPBYTE bufferW = NULL;
5371 LPWSTR nameW = NULL;
5373 DWORD numentries = 0;
5376 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5377 cbBuf, pcbNeeded, pcReturned);
5379 /* convert servername to unicode */
5381 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5382 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5383 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5385 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5386 needed = cbBuf * sizeof(WCHAR);
5387 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5388 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5390 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5391 if (pcbNeeded) needed = *pcbNeeded;
5392 /* HeapReAlloc return NULL, when bufferW was NULL */
5393 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5394 HeapAlloc(GetProcessHeap(), 0, needed);
5396 /* Try again with the large Buffer */
5397 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5399 numentries = pcReturned ? *pcReturned : 0;
5402 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5403 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5406 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5407 DWORD entrysize = 0;
5410 LPMONITOR_INFO_2W mi2w;
5411 LPMONITOR_INFO_2A mi2a;
5413 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5414 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5416 /* First pass: calculate the size for all Entries */
5417 mi2w = (LPMONITOR_INFO_2W) bufferW;
5418 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5420 while (index < numentries) {
5422 needed += entrysize; /* MONITOR_INFO_?A */
5423 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5425 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5426 NULL, 0, NULL, NULL);
5428 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5429 NULL, 0, NULL, NULL);
5430 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5431 NULL, 0, NULL, NULL);
5433 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5434 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5435 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5438 /* check for errors and quit on failure */
5439 if (cbBuf < needed) {
5440 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5444 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5445 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5446 cbBuf -= len ; /* free Bytes in the user-Buffer */
5447 mi2w = (LPMONITOR_INFO_2W) bufferW;
5448 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5450 /* Second Pass: Fill the User Buffer (if we have one) */
5451 while ((index < numentries) && pMonitors) {
5453 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5455 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5456 ptr, cbBuf , NULL, NULL);
5460 mi2a->pEnvironment = ptr;
5461 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5462 ptr, cbBuf, NULL, NULL);
5466 mi2a->pDLLName = ptr;
5467 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5468 ptr, cbBuf, NULL, NULL);
5472 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5473 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5474 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5478 if (pcbNeeded) *pcbNeeded = needed;
5479 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5481 HeapFree(GetProcessHeap(), 0, nameW);
5482 HeapFree(GetProcessHeap(), 0, bufferW);
5484 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5485 (res), GetLastError(), needed, numentries);
5491 /*****************************************************************************
5492 * EnumMonitorsW [WINSPOOL.@]
5494 * Enumerate available Port-Monitors
5497 * pName [I] Servername or NULL (local Computer)
5498 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5499 * pMonitors [O] PTR to Buffer that receives the Result
5500 * cbBuf [I] Size of Buffer at pMonitors
5501 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5502 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5506 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5509 * Windows reads the Registry once and cache the Results.
5511 *| Language-Monitors are also installed in the same Registry-Location but
5512 *| they are filtered in Windows (not returned by EnumMonitors).
5513 *| We do no filtering to simplify our Code.
5516 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5517 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5520 DWORD numentries = 0;
5523 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5524 cbBuf, pcbNeeded, pcReturned);
5526 if (pName && (lstrlenW(pName))) {
5527 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5528 SetLastError(ERROR_ACCESS_DENIED);
5532 /* Level is not checked in win9x */
5533 if (!Level || (Level > 2)) {
5534 WARN("level (%ld) is ignored in win9x\n", Level);
5535 SetLastError(ERROR_INVALID_LEVEL);
5539 SetLastError(RPC_X_NULL_REF_POINTER);
5543 /* Scan all Monitor-Keys */
5545 needed = get_local_monitors(Level, NULL, 0, &numentries);
5547 /* we calculated the needed buffersize. now do the error-checks */
5548 if (cbBuf < needed) {
5549 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5552 else if (!pMonitors || !pcReturned) {
5553 SetLastError(RPC_X_NULL_REF_POINTER);
5557 /* fill the Buffer with the Monitor-Keys */
5558 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5562 if (pcbNeeded) *pcbNeeded = needed;
5563 if (pcReturned) *pcReturned = numentries;
5565 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5566 res, GetLastError(), needed, numentries);
5571 /******************************************************************************
5572 * XcvDataW (WINSPOOL.@)
5575 * There doesn't seem to be an A version...
5577 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5578 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5579 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5581 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5582 pInputData, cbInputData, pOutputData,
5583 cbOutputData, pcbOutputNeeded, pdwStatus);
5587 /*****************************************************************************
5588 * EnumPrinterDataA [WINSPOOL.@]
5591 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5592 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5593 DWORD cbData, LPDWORD pcbData )
5595 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5596 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5597 return ERROR_NO_MORE_ITEMS;
5600 /*****************************************************************************
5601 * EnumPrinterDataW [WINSPOOL.@]
5604 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5605 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5606 DWORD cbData, LPDWORD pcbData )
5608 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5609 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5610 return ERROR_NO_MORE_ITEMS;
5613 /*****************************************************************************
5614 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5617 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5618 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5619 LPDWORD pcbNeeded, LPDWORD pcReturned)
5621 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5622 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5623 pcbNeeded, pcReturned);
5627 /*****************************************************************************
5628 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5631 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5632 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5633 LPDWORD pcbNeeded, LPDWORD pcReturned)
5635 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5636 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5637 pcbNeeded, pcReturned);
5641 /*****************************************************************************
5642 * EnumPrintProcessorsA [WINSPOOL.@]
5645 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5646 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5648 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5649 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5653 /*****************************************************************************
5654 * EnumPrintProcessorsW [WINSPOOL.@]
5657 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5658 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5660 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5661 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5662 cbBuf, pcbNeeded, pcbReturned);
5666 /*****************************************************************************
5667 * ExtDeviceMode [WINSPOOL.@]
5670 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5671 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5674 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5675 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5676 debugstr_a(pProfile), fMode);
5680 /*****************************************************************************
5681 * FindClosePrinterChangeNotification [WINSPOOL.@]
5684 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5686 FIXME("Stub: %p\n", hChange);
5690 /*****************************************************************************
5691 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5694 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5695 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5697 FIXME("Stub: %p %lx %lx %p\n",
5698 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5699 return INVALID_HANDLE_VALUE;
5702 /*****************************************************************************
5703 * FindNextPrinterChangeNotification [WINSPOOL.@]
5706 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5707 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5709 FIXME("Stub: %p %p %p %p\n",
5710 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5714 /*****************************************************************************
5715 * FreePrinterNotifyInfo [WINSPOOL.@]
5718 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5720 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5724 /*****************************************************************************
5727 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5728 * ansi depending on the unicode parameter.
5730 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5740 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5743 memcpy(ptr, str, *size);
5750 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5753 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5760 /*****************************************************************************
5763 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5764 LPDWORD pcbNeeded, BOOL unicode)
5766 DWORD size, left = cbBuf;
5767 BOOL space = (cbBuf > 0);
5774 ji1->JobId = job->job_id;
5777 string_to_buf(job->document_title, ptr, left, &size, unicode);
5778 if(space && size <= left)
5780 ji1->pDocument = (LPWSTR)ptr;
5791 /*****************************************************************************
5794 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5795 LPDWORD pcbNeeded, BOOL unicode)
5797 DWORD size, left = cbBuf;
5798 BOOL space = (cbBuf > 0);
5805 ji2->JobId = job->job_id;
5808 string_to_buf(job->document_title, ptr, left, &size, unicode);
5809 if(space && size <= left)
5811 ji2->pDocument = (LPWSTR)ptr;
5822 /*****************************************************************************
5825 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5826 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5829 DWORD needed = 0, size;
5833 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5835 EnterCriticalSection(&printer_handles_cs);
5836 job = get_job(hPrinter, JobId);
5843 size = sizeof(JOB_INFO_1W);
5848 memset(pJob, 0, size);
5852 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5857 size = sizeof(JOB_INFO_2W);
5862 memset(pJob, 0, size);
5866 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5871 size = sizeof(JOB_INFO_3);
5875 memset(pJob, 0, size);
5884 SetLastError(ERROR_INVALID_LEVEL);
5888 *pcbNeeded = needed;
5890 LeaveCriticalSection(&printer_handles_cs);
5894 /*****************************************************************************
5895 * GetJobA [WINSPOOL.@]
5898 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5899 DWORD cbBuf, LPDWORD pcbNeeded)
5901 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5904 /*****************************************************************************
5905 * GetJobW [WINSPOOL.@]
5908 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5909 DWORD cbBuf, LPDWORD pcbNeeded)
5911 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5914 /*****************************************************************************
5917 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5919 char *unixname, *queue, *cmd;
5920 char fmt[] = "lpr -P%s %s";
5923 if(!(unixname = wine_get_unix_file_name(filename)))
5926 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5927 queue = HeapAlloc(GetProcessHeap(), 0, len);
5928 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5930 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5931 sprintf(cmd, fmt, queue, unixname);
5933 TRACE("printing with: %s\n", cmd);
5936 HeapFree(GetProcessHeap(), 0, cmd);
5937 HeapFree(GetProcessHeap(), 0, queue);
5938 HeapFree(GetProcessHeap(), 0, unixname);
5942 /*****************************************************************************
5945 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5947 #if HAVE_CUPS_CUPS_H
5950 char *unixname, *queue, *doc_titleA;
5954 if(!(unixname = wine_get_unix_file_name(filename)))
5957 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5958 queue = HeapAlloc(GetProcessHeap(), 0, len);
5959 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5961 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5962 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5963 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5965 TRACE("printing via cups\n");
5966 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5967 HeapFree(GetProcessHeap(), 0, doc_titleA);
5968 HeapFree(GetProcessHeap(), 0, queue);
5969 HeapFree(GetProcessHeap(), 0, unixname);
5975 return schedule_lpr(printer_name, filename);
5979 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5986 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5990 if(HIWORD(wparam) == BN_CLICKED)
5992 if(LOWORD(wparam) == IDOK)
5995 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5998 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5999 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6001 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6003 WCHAR caption[200], message[200];
6006 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6007 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6008 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6009 if(mb_ret == IDCANCEL)
6011 HeapFree(GetProcessHeap(), 0, filename);
6015 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6016 if(hf == INVALID_HANDLE_VALUE)
6018 WCHAR caption[200], message[200];
6020 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6021 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6022 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6023 HeapFree(GetProcessHeap(), 0, filename);
6027 DeleteFileW(filename);
6028 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6030 EndDialog(hwnd, IDOK);
6033 if(LOWORD(wparam) == IDCANCEL)
6035 EndDialog(hwnd, IDCANCEL);
6044 /*****************************************************************************
6047 static BOOL get_filename(LPWSTR *filename)
6049 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6050 file_dlg_proc, (LPARAM)filename) == IDOK;
6053 /*****************************************************************************
6056 static BOOL schedule_file(LPCWSTR filename)
6058 LPWSTR output = NULL;
6060 if(get_filename(&output))
6062 TRACE("copy to %s\n", debugstr_w(output));
6063 CopyFileW(filename, output, FALSE);
6064 HeapFree(GetProcessHeap(), 0, output);
6070 /*****************************************************************************
6073 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6076 char *unixname, *cmdA;
6078 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6082 if(!(unixname = wine_get_unix_file_name(filename)))
6085 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6086 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6087 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6089 TRACE("printing with: %s\n", cmdA);
6091 if((file_fd = open(unixname, O_RDONLY)) == -1)
6096 ERR("pipe() failed!\n");
6106 /* reset signals that we previously set to SIG_IGN */
6107 signal(SIGPIPE, SIG_DFL);
6108 signal(SIGCHLD, SIG_DFL);
6114 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6115 write(fds[1], buf, no_read);
6120 if(file_fd != -1) close(file_fd);
6121 if(fds[0] != -1) close(fds[0]);
6122 if(fds[1] != -1) close(fds[1]);
6124 HeapFree(GetProcessHeap(), 0, cmdA);
6125 HeapFree(GetProcessHeap(), 0, unixname);
6132 /*****************************************************************************
6135 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6137 int in_fd, out_fd, no_read;
6140 char *unixname, *outputA;
6143 if(!(unixname = wine_get_unix_file_name(filename)))
6146 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6147 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6148 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6150 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6151 in_fd = open(unixname, O_RDONLY);
6152 if(out_fd == -1 || in_fd == -1)
6155 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6156 write(out_fd, buf, no_read);
6160 if(in_fd != -1) close(in_fd);
6161 if(out_fd != -1) close(out_fd);
6162 HeapFree(GetProcessHeap(), 0, outputA);
6163 HeapFree(GetProcessHeap(), 0, unixname);
6167 /*****************************************************************************
6168 * ScheduleJob [WINSPOOL.@]
6171 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6173 opened_printer_t *printer;
6175 struct list *cursor, *cursor2;
6177 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6178 EnterCriticalSection(&printer_handles_cs);
6179 printer = get_opened_printer(hPrinter);
6183 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6185 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6188 if(job->job_id != dwJobID) continue;
6190 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6191 if(hf != INVALID_HANDLE_VALUE)
6193 PRINTER_INFO_5W *pi5;
6197 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6198 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6200 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6201 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6202 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6203 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6204 debugstr_w(pi5->pPortName));
6208 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6209 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6211 DWORD type, count = sizeof(output);
6212 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6215 if(output[0] == '|')
6217 schedule_pipe(output + 1, job->filename);
6221 schedule_unixfile(output, job->filename);
6223 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6225 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6227 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6229 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6231 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6233 schedule_file(job->filename);
6237 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6239 HeapFree(GetProcessHeap(), 0, pi5);
6241 DeleteFileW(job->filename);
6243 list_remove(cursor);
6244 HeapFree(GetProcessHeap(), 0, job->document_title);
6245 HeapFree(GetProcessHeap(), 0, job->filename);
6246 HeapFree(GetProcessHeap(), 0, job);
6251 LeaveCriticalSection(&printer_handles_cs);
6255 /*****************************************************************************
6256 * StartDocDlgA [WINSPOOL.@]
6258 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6260 UNICODE_STRING usBuffer;
6265 docW.cbSize = sizeof(docW);
6266 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6267 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6268 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6269 docW.fwType = doc->fwType;
6271 retW = StartDocDlgW(hPrinter, &docW);
6275 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6276 ret = HeapAlloc(GetProcessHeap(), 0, len);
6277 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6278 HeapFree(GetProcessHeap(), 0, retW);
6281 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6282 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6283 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6288 /*****************************************************************************
6289 * StartDocDlgW [WINSPOOL.@]
6291 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6292 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6293 * port is "FILE:". Also returns the full path if passed a relative path.
6295 * The caller should free the returned string from the process heap.
6297 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6302 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6304 PRINTER_INFO_5W *pi5;
6305 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6306 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6308 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6309 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6310 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6312 HeapFree(GetProcessHeap(), 0, pi5);
6315 HeapFree(GetProcessHeap(), 0, pi5);
6318 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6321 get_filename(&name);
6324 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6326 HeapFree(GetProcessHeap(), 0, name);
6329 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6330 GetFullPathNameW(name, len, ret, NULL);
6331 HeapFree(GetProcessHeap(), 0, name);
6336 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6339 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6340 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6342 attr = GetFileAttributesW(ret);
6343 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6345 HeapFree(GetProcessHeap(), 0, ret);