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};
165 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
167 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
168 'i','o','n',' ','F','i','l','e',0};
169 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
170 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
171 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
173 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
175 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
176 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
177 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
178 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
179 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
180 static const WCHAR NameW[] = {'N','a','m','e',0};
181 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
182 static const WCHAR PortW[] = {'P','o','r','t',0};
183 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
185 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
187 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
188 'v','e','r','D','a','t','a',0};
189 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
191 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
192 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
193 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
194 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
195 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
196 static const WCHAR emptyStringW[] = {0};
198 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
200 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
201 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
202 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
204 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
205 'D','o','c','u','m','e','n','t',0};
207 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
208 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
209 DWORD Level, LPBYTE pDriverInfo,
210 DWORD cbBuf, LPDWORD pcbNeeded,
212 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
213 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
215 /******************************************************************
216 * validate the user-supplied printing-environment [internal]
219 * env [I] PTR to Environment-String or NULL
223 * Success: PTR to printenv_t
226 * An empty string is handled the same way as NULL.
227 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
231 static const printenv_t * validate_envW(LPCWSTR env)
233 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
234 3, Version3_RegPathW, Version3_SubdirW};
235 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
236 0, emptyStringW, emptyStringW};
237 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
239 const printenv_t *result = NULL;
242 TRACE("testing %s\n", debugstr_w(env));
245 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
247 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
249 result = all_printenv[i];
254 if (result == NULL) {
255 FIXME("unsupported Environment: %s\n", debugstr_w(env));
256 SetLastError(ERROR_INVALID_ENVIRONMENT);
258 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
262 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
264 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
270 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
271 if passed a NULL string. This returns NULLs to the result.
273 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
277 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
278 return usBufferPtr->Buffer;
280 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
284 static LPWSTR strdupW(LPCWSTR p)
290 len = (strlenW(p) + 1) * sizeof(WCHAR);
291 ret = HeapAlloc(GetProcessHeap(), 0, len);
297 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
300 /* If forcing, or no profile string entry for device yet, set the entry
302 * The always change entry if not WINEPS yet is discussable.
305 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
307 !strstr(qbuf,"WINEPS.DRV")
309 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
312 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
313 WriteProfileStringA("windows","device",buf);
314 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
315 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
318 HeapFree(GetProcessHeap(),0,buf);
322 #ifdef HAVE_CUPS_CUPS_H
323 static typeof(cupsGetDests) *pcupsGetDests;
324 static typeof(cupsGetPPD) *pcupsGetPPD;
325 static typeof(cupsPrintFile) *pcupsPrintFile;
326 static void *cupshandle;
328 static BOOL CUPS_LoadPrinters(void)
331 BOOL hadprinter = FALSE;
333 PRINTER_INFO_2A pinfo2a;
335 HKEY hkeyPrinter, hkeyPrinters, hkey;
337 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
340 TRACE("loaded %s\n", SONAME_LIBCUPS);
343 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
344 if (!p##x) return FALSE;
347 DYNCUPS(cupsGetDests);
348 DYNCUPS(cupsPrintFile);
351 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
353 ERR("Can't create Printers key\n");
357 nrofdests = pcupsGetDests(&dests);
358 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
359 for (i=0;i<nrofdests;i++) {
360 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
361 sprintf(port,"LPR:%s",dests[i].name);
362 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
363 sprintf(devline,"WINEPS.DRV,%s",port);
364 WriteProfileStringA("devices",dests[i].name,devline);
365 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
366 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
369 HeapFree(GetProcessHeap(),0,devline);
371 TRACE("Printer %d: %s\n", i, dests[i].name);
372 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
373 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
375 TRACE("Printer already exists\n");
376 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
377 RegCloseKey(hkeyPrinter);
379 memset(&pinfo2a,0,sizeof(pinfo2a));
380 pinfo2a.pPrinterName = dests[i].name;
381 pinfo2a.pDatatype = "RAW";
382 pinfo2a.pPrintProcessor = "WinPrint";
383 pinfo2a.pDriverName = "PS Driver";
384 pinfo2a.pComment = "WINEPS Printer using CUPS";
385 pinfo2a.pLocation = "<physical location of printer>";
386 pinfo2a.pPortName = port;
387 pinfo2a.pParameters = "<parameters?>";
388 pinfo2a.pShareName = "<share name?>";
389 pinfo2a.pSepFile = "<sep file?>";
391 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
392 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
393 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
396 HeapFree(GetProcessHeap(),0,port);
399 if (dests[i].is_default)
400 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
402 RegCloseKey(hkeyPrinters);
408 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
409 PRINTER_INFO_2A pinfo2a;
410 char *e,*s,*name,*prettyname,*devname;
411 BOOL ret = FALSE, set_default = FALSE;
412 char *port,*devline,*env_default;
413 HKEY hkeyPrinter, hkeyPrinters, hkey;
415 while (isspace(*pent)) pent++;
416 s = strchr(pent,':');
418 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
426 TRACE("name=%s entry=%s\n",name, pent);
428 if(ispunct(*name)) { /* a tc entry, not a real printer */
429 TRACE("skipping tc entry\n");
433 if(strstr(pent,":server")) { /* server only version so skip */
434 TRACE("skipping server entry\n");
438 /* Determine whether this is a postscript printer. */
441 env_default = getenv("PRINTER");
443 /* Get longest name, usually the one at the right for later display. */
444 while((s=strchr(prettyname,'|'))) {
447 while(isspace(*--e)) *e = '\0';
448 TRACE("\t%s\n", debugstr_a(prettyname));
449 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
450 for(prettyname = s+1; isspace(*prettyname); prettyname++)
453 e = prettyname + strlen(prettyname);
454 while(isspace(*--e)) *e = '\0';
455 TRACE("\t%s\n", debugstr_a(prettyname));
456 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
458 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
459 * if it is too long, we use it as comment below. */
460 devname = prettyname;
461 if (strlen(devname)>=CCHDEVICENAME-1)
463 if (strlen(devname)>=CCHDEVICENAME-1) {
468 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
469 sprintf(port,"LPR:%s",name);
471 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
472 sprintf(devline,"WINEPS.DRV,%s",port);
473 WriteProfileStringA("devices",devname,devline);
474 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
475 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
478 HeapFree(GetProcessHeap(),0,devline);
480 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
482 ERR("Can't create Printers key\n");
486 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
487 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
489 TRACE("Printer already exists\n");
490 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
491 RegCloseKey(hkeyPrinter);
493 memset(&pinfo2a,0,sizeof(pinfo2a));
494 pinfo2a.pPrinterName = devname;
495 pinfo2a.pDatatype = "RAW";
496 pinfo2a.pPrintProcessor = "WinPrint";
497 pinfo2a.pDriverName = "PS Driver";
498 pinfo2a.pComment = "WINEPS Printer using LPR";
499 pinfo2a.pLocation = prettyname;
500 pinfo2a.pPortName = port;
501 pinfo2a.pParameters = "<parameters?>";
502 pinfo2a.pShareName = "<share name?>";
503 pinfo2a.pSepFile = "<sep file?>";
505 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
506 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
507 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
510 RegCloseKey(hkeyPrinters);
512 if (isfirst || set_default)
513 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
515 HeapFree(GetProcessHeap(), 0, port);
517 HeapFree(GetProcessHeap(), 0, name);
522 PRINTCAP_LoadPrinters(void) {
523 BOOL hadprinter = FALSE;
527 BOOL had_bash = FALSE;
529 f = fopen("/etc/printcap","r");
533 while(fgets(buf,sizeof(buf),f)) {
536 end=strchr(buf,'\n');
540 while(isspace(*start)) start++;
541 if(*start == '#' || *start == '\0')
544 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
545 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
546 HeapFree(GetProcessHeap(),0,pent);
550 if (end && *--end == '\\') {
557 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
560 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
566 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
567 HeapFree(GetProcessHeap(),0,pent);
573 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
576 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
577 lstrlenW(value) * sizeof(WCHAR));
579 return ERROR_FILE_NOT_FOUND;
582 void WINSPOOL_LoadSystemPrinters(void)
584 HKEY hkey, hkeyPrinters;
587 DWORD needed, num, i;
588 WCHAR PrinterName[256];
591 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
592 di3a.pName = "PS Driver";
593 di3a.pEnvironment = NULL; /* NULL means auto */
594 di3a.pDriverPath = "wineps16";
595 di3a.pDataFile = "<datafile?>";
596 di3a.pConfigFile = "wineps16";
597 di3a.pHelpFile = "<helpfile?>";
598 di3a.pDependentFiles = "<dependend files?>";
599 di3a.pMonitorName = "<monitor name?>";
600 di3a.pDefaultDataType = "RAW";
602 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
603 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
607 /* This ensures that all printer entries have a valid Name value. If causes
608 problems later if they don't. If one is found to be missed we create one
609 and set it equal to the name of the key */
610 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
611 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
612 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
613 for(i = 0; i < num; i++) {
614 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
615 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
616 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
617 set_reg_szW(hkey, NameW, PrinterName);
624 RegCloseKey(hkeyPrinters);
627 /* We want to avoid calling AddPrinter on printers as much as
628 possible, because on cups printers this will (eventually) lead
629 to a call to cupsGetPPD which takes forever, even with non-cups
630 printers AddPrinter takes a while. So we'll tag all printers that
631 were automatically added last time around, if they still exist
632 we'll leave them be otherwise we'll delete them. */
633 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
635 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
636 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
637 for(i = 0; i < num; i++) {
638 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
639 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
640 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
642 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
650 HeapFree(GetProcessHeap(), 0, pi);
654 #ifdef HAVE_CUPS_CUPS_H
655 done = CUPS_LoadPrinters();
658 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
659 /* Check for [ppd] section in config file before parsing /etc/printcap */
660 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
661 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
662 &hkey) == ERROR_SUCCESS) {
664 PRINTCAP_LoadPrinters();
668 /* Now enumerate the list again and delete any printers that a still tagged */
669 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
671 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
672 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
673 for(i = 0; i < num; i++) {
674 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
675 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
676 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
677 DWORD dw, type, size = sizeof(dw);
678 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
679 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
689 HeapFree(GetProcessHeap(), 0, pi);
696 /*****************************************************************************
697 * enumerate the local monitors (INTERNAL)
699 * returns the needed size (in bytes) for pMonitors
700 * and *lpreturned is set to number of entries returned in pMonitors
703 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
708 LPMONITOR_INFO_2W mi;
709 WCHAR buffer[MAX_PATH];
710 WCHAR dllname[MAX_PATH];
718 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
720 numentries = *lpreturned; /* this is 0, when we scan the registry */
721 len = entrysize * numentries;
722 ptr = (LPWSTR) &pMonitors[len];
725 len = sizeof(buffer);
728 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
729 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
730 /* Scan all Monitor-Registry-Keys */
731 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
732 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
733 dllsize = sizeof(dllname);
736 /* The Monitor must have a Driver-DLL */
737 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
738 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
739 /* We found a valid DLL for this Monitor. */
740 TRACE("using Driver: %s\n", debugstr_w(dllname));
745 /* Windows returns only Port-Monitors here, but to simplify our code,
746 we do no filtering for Language-Monitors */
750 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
752 /* we install and return only monitors for "Windows NT x86" */
753 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
757 /* required size is calculated. Now fill the user-buffer */
758 if (pMonitors && (cbBuf >= needed)){
759 mi = (LPMONITOR_INFO_2W) pMonitors;
760 pMonitors += entrysize;
762 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
764 lstrcpyW(ptr, buffer); /* Name of the Monitor */
765 ptr += (len+1); /* len is lstrlenW(monitorname) */
767 mi->pEnvironment = ptr;
768 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
769 ptr += (lstrlenW(envname_x86W)+1);
772 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
773 ptr += (dllsize / sizeof(WCHAR));
778 len = sizeof(buffer);
783 *lpreturned = numentries;
784 TRACE("need %ld byte for %ld entries\n", needed, numentries);
788 /******************************************************************
789 * get_opened_printer_entry
790 * Get the first place empty in the opened printer table
793 * - pDefault is ignored
795 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
797 UINT_PTR handle = nb_printer_handles, i;
798 jobqueue_t *queue = NULL;
799 opened_printer_t *printer = NULL;
801 EnterCriticalSection(&printer_handles_cs);
803 for (i = 0; i < nb_printer_handles; i++)
805 if (!printer_handles[i])
807 if(handle == nb_printer_handles)
812 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
813 queue = printer_handles[i]->queue;
817 if (handle >= nb_printer_handles)
819 opened_printer_t **new_array;
821 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
822 (nb_printer_handles + 16) * sizeof(*new_array) );
824 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
825 (nb_printer_handles + 16) * sizeof(*new_array) );
832 printer_handles = new_array;
833 nb_printer_handles += 16;
836 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
843 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
844 if (!printer->name) {
848 strcpyW(printer->name, name);
852 printer->queue = queue;
855 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
856 if (!printer->queue) {
860 list_init(&printer->queue->jobs);
861 printer->queue->ref = 0;
863 InterlockedIncrement(&printer->queue->ref);
865 printer_handles[handle] = printer;
868 LeaveCriticalSection(&printer_handles_cs);
869 if (!handle && printer) {
870 /* Something Failed: Free the Buffers */
871 HeapFree(GetProcessHeap(), 0, printer->name);
872 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
873 HeapFree(GetProcessHeap(), 0, printer);
876 return (HANDLE)handle;
879 /******************************************************************
881 * Get the pointer to the opened printer referred by the handle
883 static opened_printer_t *get_opened_printer(HANDLE hprn)
885 UINT_PTR idx = (UINT_PTR)hprn;
886 opened_printer_t *ret = NULL;
888 EnterCriticalSection(&printer_handles_cs);
890 if ((idx <= 0) || (idx > nb_printer_handles))
893 ret = printer_handles[idx - 1];
895 LeaveCriticalSection(&printer_handles_cs);
899 /******************************************************************
900 * get_opened_printer_name
901 * Get the pointer to the opened printer name referred by the handle
903 static LPCWSTR get_opened_printer_name(HANDLE hprn)
905 opened_printer_t *printer = get_opened_printer(hprn);
906 if(!printer) return NULL;
907 return printer->name;
910 /******************************************************************
911 * WINSPOOL_GetOpenedPrinterRegKey
914 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
916 LPCWSTR name = get_opened_printer_name(hPrinter);
920 if(!name) return ERROR_INVALID_HANDLE;
922 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
926 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
928 ERR("Can't find opened printer %s in registry\n",
930 RegCloseKey(hkeyPrinters);
931 return ERROR_INVALID_PRINTER_NAME; /* ? */
933 RegCloseKey(hkeyPrinters);
934 return ERROR_SUCCESS;
937 /******************************************************************
940 * Get the pointer to the specified job.
941 * Should hold the printer_handles_cs before calling.
943 static job_t *get_job(HANDLE hprn, DWORD JobId)
945 opened_printer_t *printer = get_opened_printer(hprn);
948 if(!printer) return NULL;
949 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
951 if(job->job_id == JobId)
957 /***********************************************************
960 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
963 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
966 Formname = (dmA->dmSize > off_formname);
967 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
968 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
969 dmW->dmDeviceName, CCHDEVICENAME);
971 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
972 dmA->dmSize - CCHDEVICENAME);
974 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
975 off_formname - CCHDEVICENAME);
976 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
977 dmW->dmFormName, CCHFORMNAME);
978 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
979 (off_formname + CCHFORMNAME));
982 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
987 /***********************************************************
989 * Creates an ascii copy of supplied devmode on heap
991 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
996 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
998 if(!dmW) return NULL;
999 Formname = (dmW->dmSize > off_formname);
1000 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1001 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1002 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1003 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1005 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1006 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1008 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1009 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1010 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1011 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1012 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1013 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1016 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1017 dmW->dmDriverExtra);
1021 /***********************************************************
1022 * PRINTER_INFO_2AtoW
1023 * Creates a unicode copy of PRINTER_INFO_2A on heap
1025 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1027 LPPRINTER_INFO_2W piW;
1028 UNICODE_STRING usBuffer;
1030 if(!piA) return NULL;
1031 piW = HeapAlloc(heap, 0, sizeof(*piW));
1032 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1034 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1035 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1036 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1037 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1038 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1039 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1040 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1041 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1042 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1043 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1044 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1045 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1049 /***********************************************************
1050 * FREE_PRINTER_INFO_2W
1051 * Free PRINTER_INFO_2W and all strings
1053 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1057 HeapFree(heap,0,piW->pServerName);
1058 HeapFree(heap,0,piW->pPrinterName);
1059 HeapFree(heap,0,piW->pShareName);
1060 HeapFree(heap,0,piW->pPortName);
1061 HeapFree(heap,0,piW->pDriverName);
1062 HeapFree(heap,0,piW->pComment);
1063 HeapFree(heap,0,piW->pLocation);
1064 HeapFree(heap,0,piW->pDevMode);
1065 HeapFree(heap,0,piW->pSepFile);
1066 HeapFree(heap,0,piW->pPrintProcessor);
1067 HeapFree(heap,0,piW->pDatatype);
1068 HeapFree(heap,0,piW->pParameters);
1069 HeapFree(heap,0,piW);
1073 /******************************************************************
1074 * DeviceCapabilities [WINSPOOL.@]
1075 * DeviceCapabilitiesA [WINSPOOL.@]
1078 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1079 LPSTR pOutput, LPDEVMODEA lpdm)
1083 if (!GDI_CallDeviceCapabilities16)
1085 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1087 if (!GDI_CallDeviceCapabilities16) return -1;
1089 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1091 /* If DC_PAPERSIZE map POINT16s to POINTs */
1092 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1093 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1094 POINT *pt = (POINT *)pOutput;
1096 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1097 for(i = 0; i < ret; i++, pt++)
1102 HeapFree( GetProcessHeap(), 0, tmp );
1108 /*****************************************************************************
1109 * DeviceCapabilitiesW [WINSPOOL.@]
1111 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1114 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1115 WORD fwCapability, LPWSTR pOutput,
1116 const DEVMODEW *pDevMode)
1118 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1119 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1120 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1123 if(pOutput && (fwCapability == DC_BINNAMES ||
1124 fwCapability == DC_FILEDEPENDENCIES ||
1125 fwCapability == DC_PAPERNAMES)) {
1126 /* These need A -> W translation */
1129 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1133 switch(fwCapability) {
1138 case DC_FILEDEPENDENCIES:
1142 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1143 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1145 for(i = 0; i < ret; i++)
1146 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1147 pOutput + (i * size), size);
1148 HeapFree(GetProcessHeap(), 0, pOutputA);
1150 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1151 (LPSTR)pOutput, dmA);
1153 HeapFree(GetProcessHeap(),0,pPortA);
1154 HeapFree(GetProcessHeap(),0,pDeviceA);
1155 HeapFree(GetProcessHeap(),0,dmA);
1159 /******************************************************************
1160 * DocumentPropertiesA [WINSPOOL.@]
1162 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1164 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1165 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1166 LPDEVMODEA pDevModeInput,DWORD fMode )
1168 LPSTR lpName = pDeviceName;
1171 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1172 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1176 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1178 ERR("no name from hPrinter?\n");
1179 SetLastError(ERROR_INVALID_HANDLE);
1182 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1185 if (!GDI_CallExtDeviceMode16)
1187 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1189 if (!GDI_CallExtDeviceMode16) {
1190 ERR("No CallExtDeviceMode16?\n");
1194 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1195 pDevModeInput, NULL, fMode);
1198 HeapFree(GetProcessHeap(),0,lpName);
1203 /*****************************************************************************
1204 * DocumentPropertiesW (WINSPOOL.@)
1206 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1208 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1210 LPDEVMODEW pDevModeOutput,
1211 LPDEVMODEW pDevModeInput, DWORD fMode)
1214 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1215 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1216 LPDEVMODEA pDevModeOutputA = NULL;
1219 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1220 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1222 if(pDevModeOutput) {
1223 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1224 if(ret < 0) return ret;
1225 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1227 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1228 pDevModeInputA, fMode);
1229 if(pDevModeOutput) {
1230 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1231 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1233 if(fMode == 0 && ret > 0)
1234 ret += (CCHDEVICENAME + CCHFORMNAME);
1235 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1236 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1240 /******************************************************************
1241 * OpenPrinterA [WINSPOOL.@]
1246 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1247 LPPRINTER_DEFAULTSA pDefault)
1249 UNICODE_STRING lpPrinterNameW;
1250 UNICODE_STRING usBuffer;
1251 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1252 PWSTR pwstrPrinterNameW;
1255 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1258 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1259 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1260 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1261 pDefaultW = &DefaultW;
1263 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1265 RtlFreeUnicodeString(&usBuffer);
1266 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1268 RtlFreeUnicodeString(&lpPrinterNameW);
1272 /******************************************************************
1273 * OpenPrinterW [WINSPOOL.@]
1275 * Open a Printer / Printserver or a Printer-Object
1278 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1279 * phPrinter [O] The resulting Handle is stored here
1280 * pDefault [I] PTR to Default Printer Settings or NULL
1287 * lpPrinterName is one of:
1288 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1289 *| Printer: "PrinterName"
1290 *| Printer-Object: "PrinterName,Job xxx"
1291 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1292 *| XcvPort: "Servername,XcvPort PortName"
1295 *| Printer-Object not supported
1296 *| XcvMonitor not supported
1297 *| XcvPort not supported
1298 *| pDefaults is ignored
1301 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1303 HKEY hkeyPrinters = NULL;
1304 HKEY hkeyPrinter = NULL;
1306 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1308 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1309 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1312 if(lpPrinterName != NULL)
1314 /* Check any Printer exists */
1315 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1316 ERR("Can't create Printers key\n");
1317 SetLastError(ERROR_FILE_NOT_FOUND);
1320 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1321 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1323 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1324 RegCloseKey(hkeyPrinters);
1325 SetLastError(ERROR_INVALID_PRINTER_NAME);
1328 RegCloseKey(hkeyPrinter);
1329 RegCloseKey(hkeyPrinters);
1332 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1333 SetLastError(ERROR_INVALID_PARAMETER);
1337 /* Get the unique handle of the printer or Printserver */
1338 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1339 return (*phPrinter != 0);
1342 /******************************************************************
1343 * AddMonitorA [WINSPOOL.@]
1348 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1350 LPWSTR nameW = NULL;
1353 LPMONITOR_INFO_2A mi2a;
1354 MONITOR_INFO_2W mi2w;
1356 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1357 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1358 mi2a ? debugstr_a(mi2a->pName) : NULL,
1359 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1360 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1363 SetLastError(ERROR_INVALID_LEVEL);
1367 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1373 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1374 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1375 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1378 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1380 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1381 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1382 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1384 if (mi2a->pEnvironment) {
1385 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1386 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1387 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1389 if (mi2a->pDLLName) {
1390 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1391 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1392 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1395 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1397 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1398 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1399 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1401 HeapFree(GetProcessHeap(), 0, nameW);
1405 /******************************************************************************
1406 * AddMonitorW [WINSPOOL.@]
1408 * Install a Printmonitor
1411 * pName [I] Servername or NULL (local Computer)
1412 * Level [I] Structure-Level (Must be 2)
1413 * pMonitors [I] PTR to MONITOR_INFO_2
1420 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1423 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1425 LPMONITOR_INFO_2W mi2w;
1428 HMODULE hdll = NULL;
1432 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1433 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1434 mi2w ? debugstr_w(mi2w->pName) : NULL,
1435 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1436 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1439 SetLastError(ERROR_INVALID_LEVEL);
1443 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1448 if (pName && (pName[0])) {
1449 FIXME("for server %s not implemented\n", debugstr_w(pName));
1450 SetLastError(ERROR_ACCESS_DENIED);
1455 if (!mi2w->pName || (! mi2w->pName[0])) {
1456 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1457 SetLastError(ERROR_INVALID_PARAMETER);
1460 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1461 WARN("Environment %s requested (we support only %s)\n",
1462 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1463 SetLastError(ERROR_INVALID_ENVIRONMENT);
1467 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1468 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1469 SetLastError(ERROR_INVALID_PARAMETER);
1473 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1478 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1479 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1483 if(RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1484 KEY_WRITE, NULL, &hentry, &disposition) == ERROR_SUCCESS) {
1486 if (disposition == REG_OPENED_EXISTING_KEY) {
1487 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1488 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1489 9x: ERROR_ALREADY_EXISTS (183) */
1490 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1495 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1496 res = (RegSetValueExW(hentry, DriverW, 0,
1497 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1499 RegCloseKey(hentry);
1506 /******************************************************************
1507 * DeletePrinterDriverA [WINSPOOL.@]
1511 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1513 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1514 debugstr_a(pDriverName));
1515 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1519 /******************************************************************
1520 * DeletePrinterDriverW [WINSPOOL.@]
1524 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1526 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1527 debugstr_w(pDriverName));
1528 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1532 /******************************************************************
1533 * DeleteMonitorA [WINSPOOL.@]
1535 * See DeleteMonitorW.
1538 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1540 LPWSTR nameW = NULL;
1541 LPWSTR EnvironmentW = NULL;
1542 LPWSTR MonitorNameW = NULL;
1547 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1548 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1549 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1553 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1554 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1555 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1558 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1559 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1560 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1563 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1565 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1566 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1567 HeapFree(GetProcessHeap(), 0, nameW);
1571 /******************************************************************
1572 * DeleteMonitorW [WINSPOOL.@]
1574 * Delete a specific Printmonitor from a Printing-Environment
1577 * pName [I] Servername or NULL (local Computer)
1578 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1579 * pMonitorName [I] Name of the Monitor, that should be deleted
1586 * pEnvironment is ignored in Windows for the local Computer.
1590 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1594 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1595 debugstr_w(pMonitorName));
1597 if (pName && (pName[0])) {
1598 FIXME("for server %s not implemented\n", debugstr_w(pName));
1599 SetLastError(ERROR_ACCESS_DENIED);
1603 /* pEnvironment is ignored in Windows for the local Computer */
1605 if (!pMonitorName || !pMonitorName[0]) {
1606 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1607 SetLastError(ERROR_INVALID_PARAMETER);
1611 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1612 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1616 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1617 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1618 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1623 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1626 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1627 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1631 /******************************************************************
1632 * DeletePortA [WINSPOOL.@]
1638 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1640 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1641 debugstr_a(pPortName));
1642 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1646 /******************************************************************
1647 * DeletePortW [WINSPOOL.@]
1649 * Delete a specific Port
1652 * pName [I] Servername or NULL (local Computer)
1653 * hWnd [I] Handle to parent Window for the Dialog-Box
1654 * pPortName [I] Name of the Port, that should be deleted
1665 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1667 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1668 debugstr_w(pPortName));
1669 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1673 /******************************************************************************
1674 * SetPrinterW [WINSPOOL.@]
1676 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1678 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1679 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1683 /******************************************************************************
1684 * WritePrinter [WINSPOOL.@]
1686 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1688 opened_printer_t *printer;
1691 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1693 EnterCriticalSection(&printer_handles_cs);
1694 printer = get_opened_printer(hPrinter);
1697 SetLastError(ERROR_INVALID_HANDLE);
1703 SetLastError(ERROR_SPL_NO_STARTDOC);
1707 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1709 LeaveCriticalSection(&printer_handles_cs);
1713 /*****************************************************************************
1714 * AddFormA [WINSPOOL.@]
1716 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1718 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1722 /*****************************************************************************
1723 * AddFormW [WINSPOOL.@]
1725 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1727 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1731 /*****************************************************************************
1732 * AddJobA [WINSPOOL.@]
1734 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1737 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1741 SetLastError(ERROR_INVALID_LEVEL);
1745 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1748 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1749 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1750 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1751 if(*pcbNeeded > cbBuf) {
1752 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1755 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1756 addjobA->JobId = addjobW->JobId;
1757 addjobA->Path = (char *)(addjobA + 1);
1758 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1764 /*****************************************************************************
1765 * AddJobW [WINSPOOL.@]
1767 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1769 opened_printer_t *printer;
1772 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1773 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1774 WCHAR path[MAX_PATH], filename[MAX_PATH];
1776 ADDJOB_INFO_1W *addjob;
1778 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1780 EnterCriticalSection(&printer_handles_cs);
1782 printer = get_opened_printer(hPrinter);
1785 SetLastError(ERROR_INVALID_HANDLE);
1790 SetLastError(ERROR_INVALID_LEVEL);
1794 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1798 job->job_id = InterlockedIncrement(&next_job_id);
1800 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1801 if(path[len - 1] != '\\')
1803 memcpy(path + len, spool_path, sizeof(spool_path));
1804 sprintfW(filename, fmtW, path, job->job_id);
1806 len = strlenW(filename);
1807 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1808 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1809 job->document_title = strdupW(default_doc_title);
1810 list_add_tail(&printer->queue->jobs, &job->entry);
1812 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1813 if(*pcbNeeded <= cbBuf) {
1814 addjob = (ADDJOB_INFO_1W*)pData;
1815 addjob->JobId = job->job_id;
1816 addjob->Path = (WCHAR *)(addjob + 1);
1817 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1820 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1823 LeaveCriticalSection(&printer_handles_cs);
1827 /*****************************************************************************
1828 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1830 * Return the PATH for the Print-Processors
1832 * See GetPrintProcessorDirectoryW.
1836 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1837 DWORD level, LPBYTE Info,
1838 DWORD cbBuf, LPDWORD pcbNeeded)
1840 LPWSTR serverW = NULL;
1845 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
1846 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
1850 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
1851 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1852 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
1856 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
1857 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1858 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
1861 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
1862 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
1864 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
1867 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
1868 cbBuf, NULL, NULL) > 0;
1871 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
1872 HeapFree(GetProcessHeap(), 0, envW);
1873 HeapFree(GetProcessHeap(), 0, serverW);
1877 /*****************************************************************************
1878 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1880 * Return the PATH for the Print-Processors
1883 * server [I] Servername (NT only) or NULL (local Computer)
1884 * env [I] Printing-Environment (see below) or NULL (Default)
1885 * level [I] Structure-Level (must be 1)
1886 * Info [O] PTR to Buffer that receives the Result
1887 * cbBuf [I] Size of Buffer at "Info"
1888 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1889 * required for the Buffer at "Info"
1892 * Success: TRUE and in pcbNeeded the Bytes used in Info
1893 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
1894 * if cbBuf is too small
1896 * Native Values returned in Info on Success:
1897 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
1898 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
1899 *| win9x(Windows 4.0): "%winsysdir%"
1901 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1904 * Only NULL or "" is supported for server
1907 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1908 DWORD level, LPBYTE Info,
1909 DWORD cbBuf, LPDWORD pcbNeeded)
1912 const printenv_t * env_t;
1914 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
1915 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
1917 if(server != NULL && server[0]) {
1918 FIXME("server not supported: %s\n", debugstr_w(server));
1919 SetLastError(ERROR_INVALID_PARAMETER);
1923 env_t = validate_envW(env);
1924 if(!env_t) return FALSE; /* environment invalid or unsupported */
1927 WARN("(Level: %ld) is ignored in win9x\n", level);
1928 SetLastError(ERROR_INVALID_LEVEL);
1932 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1933 needed = GetSystemDirectoryW(NULL, 0);
1934 /* add the Size for the Subdirectories */
1935 needed += lstrlenW(spoolprtprocsW);
1936 needed += lstrlenW(env_t->subdir);
1937 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1939 if(pcbNeeded) *pcbNeeded = needed;
1940 TRACE ("required: 0x%lx/%ld\n", needed, needed);
1941 if (needed > cbBuf) {
1942 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1945 if(pcbNeeded == NULL) {
1946 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
1947 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
1948 SetLastError(RPC_X_NULL_REF_POINTER);
1952 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
1953 SetLastError(RPC_X_NULL_REF_POINTER);
1957 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
1958 /* add the Subdirectories */
1959 lstrcatW((LPWSTR) Info, spoolprtprocsW);
1960 lstrcatW((LPWSTR) Info, env_t->subdir);
1961 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
1965 /*****************************************************************************
1966 * WINSPOOL_OpenDriverReg [internal]
1968 * opens the registry for the printer drivers depending on the given input
1969 * variable pEnvironment
1972 * the opened hkey on success
1975 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1979 const printenv_t * env;
1982 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
1984 if (!pEnvironment || unicode) {
1985 /* pEnvironment was NULL or an Unicode-String: use it direct */
1986 env = validate_envW(pEnvironment);
1990 /* pEnvironment was an ANSI-String: convert to unicode first */
1992 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1993 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1994 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1995 env = validate_envW(buffer);
1996 HeapFree(GetProcessHeap(), 0, buffer);
1998 if (!env) return NULL;
2000 buffer = HeapAlloc( GetProcessHeap(), 0,
2001 (strlenW(DriversW) + strlenW(env->envname) +
2002 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2004 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2005 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2006 HeapFree(GetProcessHeap(), 0, buffer);
2011 /*****************************************************************************
2012 * AddPrinterW [WINSPOOL.@]
2014 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2016 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2020 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2023 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2026 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2027 SetLastError(ERROR_INVALID_PARAMETER);
2031 ERR("Level = %ld, unsupported!\n", Level);
2032 SetLastError(ERROR_INVALID_LEVEL);
2036 SetLastError(ERROR_INVALID_PARAMETER);
2039 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2041 ERR("Can't create Printers key\n");
2044 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2045 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2046 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2047 RegCloseKey(hkeyPrinter);
2048 RegCloseKey(hkeyPrinters);
2051 RegCloseKey(hkeyPrinter);
2053 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2055 ERR("Can't create Drivers key\n");
2056 RegCloseKey(hkeyPrinters);
2059 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2061 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2062 RegCloseKey(hkeyPrinters);
2063 RegCloseKey(hkeyDrivers);
2064 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2067 RegCloseKey(hkeyDriver);
2068 RegCloseKey(hkeyDrivers);
2070 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2071 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2072 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2073 RegCloseKey(hkeyPrinters);
2077 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2079 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2080 SetLastError(ERROR_INVALID_PRINTER_NAME);
2081 RegCloseKey(hkeyPrinters);
2084 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2085 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2086 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2088 /* See if we can load the driver. We may need the devmode structure anyway
2091 * Note that DocumentPropertiesW will briefly try to open the printer we
2092 * just create to find a DEVMODEA struct (it will use the WINEPS default
2093 * one in case it is not there, so we are ok).
2095 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2098 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2099 size = sizeof(DEVMODEW);
2105 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2106 ZeroMemory(dmW,size);
2108 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2110 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2111 HeapFree(GetProcessHeap(),0,dmW);
2116 /* set devmode to printer name */
2117 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2121 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2122 and we support these drivers. NT writes DEVMODEW so somehow
2123 we'll need to distinguish between these when we support NT
2127 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2128 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2129 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2130 HeapFree(GetProcessHeap(), 0, dmA);
2132 HeapFree(GetProcessHeap(), 0, dmW);
2134 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2135 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2136 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2137 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2139 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2140 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2141 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2142 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2143 (LPBYTE)&pi->Priority, sizeof(DWORD));
2144 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2145 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2146 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2147 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2148 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2149 (LPBYTE)&pi->Status, sizeof(DWORD));
2150 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2151 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2153 RegCloseKey(hkeyPrinter);
2154 RegCloseKey(hkeyPrinters);
2155 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2156 ERR("OpenPrinter failing\n");
2162 /*****************************************************************************
2163 * AddPrinterA [WINSPOOL.@]
2165 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2167 UNICODE_STRING pNameW;
2169 PRINTER_INFO_2W *piW;
2170 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2173 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2175 ERR("Level = %ld, unsupported!\n", Level);
2176 SetLastError(ERROR_INVALID_LEVEL);
2179 pwstrNameW = asciitounicode(&pNameW,pName);
2180 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2182 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2184 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2185 RtlFreeUnicodeString(&pNameW);
2190 /*****************************************************************************
2191 * ClosePrinter [WINSPOOL.@]
2193 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2195 UINT_PTR i = (UINT_PTR)hPrinter;
2196 opened_printer_t *printer = NULL;
2199 TRACE("Handle %p\n", hPrinter);
2201 EnterCriticalSection(&printer_handles_cs);
2203 if ((i > 0) && (i <= nb_printer_handles))
2204 printer = printer_handles[i - 1];
2208 struct list *cursor, *cursor2;
2211 EndDocPrinter(hPrinter);
2213 if(InterlockedDecrement(&printer->queue->ref) == 0)
2215 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2217 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2218 ScheduleJob(hPrinter, job->job_id);
2220 HeapFree(GetProcessHeap(), 0, printer->queue);
2222 HeapFree(GetProcessHeap(), 0, printer->name);
2223 HeapFree(GetProcessHeap(), 0, printer);
2224 printer_handles[i - 1] = NULL;
2227 LeaveCriticalSection(&printer_handles_cs);
2231 /*****************************************************************************
2232 * DeleteFormA [WINSPOOL.@]
2234 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2236 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2240 /*****************************************************************************
2241 * DeleteFormW [WINSPOOL.@]
2243 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2245 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2249 /*****************************************************************************
2250 * WINSPOOL_SHRegDeleteKey
2252 * Recursively delete subkeys.
2253 * Cut & paste from shlwapi.
2256 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2258 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2259 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2262 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2265 /* Find how many subkeys there are */
2266 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2267 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2271 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2272 /* Name too big: alloc a buffer for it */
2273 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2276 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2279 /* Recursively delete all the subkeys */
2280 for(i = 0; i < dwKeyCount && !dwRet; i++)
2282 dwSize = dwMaxSubkeyLen;
2283 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2285 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2288 if (lpszName != szNameBuf)
2289 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2293 RegCloseKey(hSubKey);
2295 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2300 /*****************************************************************************
2301 * DeletePrinter [WINSPOOL.@]
2303 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2305 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2306 HKEY hkeyPrinters, hkey;
2309 SetLastError(ERROR_INVALID_HANDLE);
2312 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2313 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2314 RegCloseKey(hkeyPrinters);
2316 WriteProfileStringW(devicesW, lpNameW, NULL);
2317 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2318 RegDeleteValueW(hkey, lpNameW);
2324 /*****************************************************************************
2325 * SetPrinterA [WINSPOOL.@]
2327 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2330 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2334 /*****************************************************************************
2335 * SetJobA [WINSPOOL.@]
2337 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2338 LPBYTE pJob, DWORD Command)
2342 UNICODE_STRING usBuffer;
2344 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2346 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2347 are all ignored by SetJob, so we don't bother copying them */
2355 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2356 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2358 JobW = (LPBYTE)info1W;
2359 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2360 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2361 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2362 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2363 info1W->Status = info1A->Status;
2364 info1W->Priority = info1A->Priority;
2365 info1W->Position = info1A->Position;
2366 info1W->PagesPrinted = info1A->PagesPrinted;
2371 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2372 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2374 JobW = (LPBYTE)info2W;
2375 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2376 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2377 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2378 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2379 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2380 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2381 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2382 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2383 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2384 info2W->Status = info2A->Status;
2385 info2W->Priority = info2A->Priority;
2386 info2W->Position = info2A->Position;
2387 info2W->StartTime = info2A->StartTime;
2388 info2W->UntilTime = info2A->UntilTime;
2389 info2W->PagesPrinted = info2A->PagesPrinted;
2393 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2394 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2397 SetLastError(ERROR_INVALID_LEVEL);
2401 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2407 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2408 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2409 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2410 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2411 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2416 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2417 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2418 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2419 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2420 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2421 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2422 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2423 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2424 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2428 HeapFree(GetProcessHeap(), 0, JobW);
2433 /*****************************************************************************
2434 * SetJobW [WINSPOOL.@]
2436 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2437 LPBYTE pJob, DWORD Command)
2442 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2443 FIXME("Ignoring everything other than document title\n");
2445 EnterCriticalSection(&printer_handles_cs);
2446 job = get_job(hPrinter, JobId);
2456 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2457 HeapFree(GetProcessHeap(), 0, job->document_title);
2458 job->document_title = strdupW(info1->pDocument);
2463 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2464 HeapFree(GetProcessHeap(), 0, job->document_title);
2465 job->document_title = strdupW(info2->pDocument);
2471 SetLastError(ERROR_INVALID_LEVEL);
2476 LeaveCriticalSection(&printer_handles_cs);
2480 /*****************************************************************************
2481 * EndDocPrinter [WINSPOOL.@]
2483 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2485 opened_printer_t *printer;
2487 TRACE("(%p)\n", hPrinter);
2489 EnterCriticalSection(&printer_handles_cs);
2491 printer = get_opened_printer(hPrinter);
2494 SetLastError(ERROR_INVALID_HANDLE);
2500 SetLastError(ERROR_SPL_NO_STARTDOC);
2504 CloseHandle(printer->doc->hf);
2505 ScheduleJob(hPrinter, printer->doc->job_id);
2506 HeapFree(GetProcessHeap(), 0, printer->doc);
2507 printer->doc = NULL;
2510 LeaveCriticalSection(&printer_handles_cs);
2514 /*****************************************************************************
2515 * EndPagePrinter [WINSPOOL.@]
2517 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2519 FIXME("(%p): stub\n", hPrinter);
2523 /*****************************************************************************
2524 * StartDocPrinterA [WINSPOOL.@]
2526 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2528 UNICODE_STRING usBuffer;
2530 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2533 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2534 or one (DOC_INFO_3) extra DWORDs */
2538 doc2W.JobId = doc2->JobId;
2541 doc2W.dwMode = doc2->dwMode;
2544 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2545 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2546 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2550 SetLastError(ERROR_INVALID_LEVEL);
2554 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2556 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2557 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2558 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2563 /*****************************************************************************
2564 * StartDocPrinterW [WINSPOOL.@]
2566 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2568 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2569 opened_printer_t *printer;
2570 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2571 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2572 JOB_INFO_1W job_info;
2573 DWORD needed, ret = 0;
2577 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2578 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2579 debugstr_w(doc->pDatatype));
2581 if(Level < 1 || Level > 3)
2583 SetLastError(ERROR_INVALID_LEVEL);
2587 EnterCriticalSection(&printer_handles_cs);
2588 printer = get_opened_printer(hPrinter);
2591 SetLastError(ERROR_INVALID_HANDLE);
2597 SetLastError(ERROR_INVALID_PRINTER_STATE);
2601 /* Even if we're printing to a file we still add a print job, we'll
2602 just ignore the spool file name */
2604 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2606 ERR("AddJob failed gle %08lx\n", GetLastError());
2610 if(doc->pOutputFile)
2611 filename = doc->pOutputFile;
2613 filename = addjob->Path;
2615 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2616 if(hf == INVALID_HANDLE_VALUE)
2619 memset(&job_info, 0, sizeof(job_info));
2620 job_info.pDocument = doc->pDocName;
2621 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2623 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2624 printer->doc->hf = hf;
2625 ret = printer->doc->job_id = addjob->JobId;
2627 LeaveCriticalSection(&printer_handles_cs);
2632 /*****************************************************************************
2633 * StartPagePrinter [WINSPOOL.@]
2635 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2637 FIXME("(%p): stub\n", hPrinter);
2641 /*****************************************************************************
2642 * GetFormA [WINSPOOL.@]
2644 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2645 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2647 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2648 Level,pForm,cbBuf,pcbNeeded);
2652 /*****************************************************************************
2653 * GetFormW [WINSPOOL.@]
2655 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2656 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2658 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2659 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2663 /*****************************************************************************
2664 * SetFormA [WINSPOOL.@]
2666 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2669 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2673 /*****************************************************************************
2674 * SetFormW [WINSPOOL.@]
2676 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2679 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2683 /*****************************************************************************
2684 * ReadPrinter [WINSPOOL.@]
2686 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2687 LPDWORD pNoBytesRead)
2689 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2693 /*****************************************************************************
2694 * ResetPrinterA [WINSPOOL.@]
2696 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2698 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2702 /*****************************************************************************
2703 * ResetPrinterW [WINSPOOL.@]
2705 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2707 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2711 /*****************************************************************************
2712 * WINSPOOL_GetDWORDFromReg
2714 * Return DWORD associated with ValueName from hkey.
2716 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2718 DWORD sz = sizeof(DWORD), type, value = 0;
2721 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2723 if(ret != ERROR_SUCCESS) {
2724 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2727 if(type != REG_DWORD) {
2728 ERR("Got type %ld\n", type);
2734 /*****************************************************************************
2735 * WINSPOOL_GetStringFromReg
2737 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2738 * String is stored either as unicode or ascii.
2739 * Bit of a hack here to get the ValueName if we want ascii.
2741 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2742 DWORD buflen, DWORD *needed,
2745 DWORD sz = buflen, type;
2749 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2751 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2752 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2753 HeapFree(GetProcessHeap(),0,ValueNameA);
2755 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2756 WARN("Got ret = %ld\n", ret);
2760 /* add space for terminating '\0' */
2761 sz += unicode ? sizeof(WCHAR) : 1;
2765 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2770 /*****************************************************************************
2771 * WINSPOOL_GetDefaultDevMode
2773 * Get a default DevMode values for wineps.
2777 static void WINSPOOL_GetDefaultDevMode(
2779 DWORD buflen, DWORD *needed,
2783 static const char szwps[] = "wineps.drv";
2785 /* fill default DEVMODE - should be read from ppd... */
2786 ZeroMemory( &dm, sizeof(dm) );
2787 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2788 dm.dmSpecVersion = DM_SPECVERSION;
2789 dm.dmDriverVersion = 1;
2790 dm.dmSize = sizeof(DEVMODEA);
2791 dm.dmDriverExtra = 0;
2793 DM_ORIENTATION | DM_PAPERSIZE |
2794 DM_PAPERLENGTH | DM_PAPERWIDTH |
2797 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2798 DM_YRESOLUTION | DM_TTOPTION;
2800 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2801 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2802 dm.u1.s1.dmPaperLength = 2970;
2803 dm.u1.s1.dmPaperWidth = 2100;
2807 dm.dmDefaultSource = DMBIN_AUTO;
2808 dm.dmPrintQuality = DMRES_MEDIUM;
2811 dm.dmYResolution = 300; /* 300dpi */
2812 dm.dmTTOption = DMTT_BITMAP;
2815 /* dm.dmLogPixels */
2816 /* dm.dmBitsPerPel */
2817 /* dm.dmPelsWidth */
2818 /* dm.dmPelsHeight */
2819 /* dm.dmDisplayFlags */
2820 /* dm.dmDisplayFrequency */
2821 /* dm.dmICMMethod */
2822 /* dm.dmICMIntent */
2823 /* dm.dmMediaType */
2824 /* dm.dmDitherType */
2825 /* dm.dmReserved1 */
2826 /* dm.dmReserved2 */
2827 /* dm.dmPanningWidth */
2828 /* dm.dmPanningHeight */
2831 if(buflen >= sizeof(DEVMODEW)) {
2832 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2833 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2834 HeapFree(GetProcessHeap(),0,pdmW);
2836 *needed = sizeof(DEVMODEW);
2840 if(buflen >= sizeof(DEVMODEA)) {
2841 memcpy(ptr, &dm, sizeof(DEVMODEA));
2843 *needed = sizeof(DEVMODEA);
2847 /*****************************************************************************
2848 * WINSPOOL_GetDevModeFromReg
2850 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2851 * DevMode is stored either as unicode or ascii.
2853 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2855 DWORD buflen, DWORD *needed,
2858 DWORD sz = buflen, type;
2861 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2862 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2863 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2864 if (sz < sizeof(DEVMODEA))
2866 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2869 /* ensures that dmSize is not erratically bogus if registry is invalid */
2870 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2871 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2873 sz += (CCHDEVICENAME + CCHFORMNAME);
2875 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2876 memcpy(ptr, dmW, sz);
2877 HeapFree(GetProcessHeap(),0,dmW);
2884 /*********************************************************************
2885 * WINSPOOL_GetPrinter_2
2887 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2888 * The strings are either stored as unicode or ascii.
2890 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2891 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2894 DWORD size, left = cbBuf;
2895 BOOL space = (cbBuf > 0);
2900 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2902 if(space && size <= left) {
2903 pi2->pPrinterName = (LPWSTR)ptr;
2910 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2912 if(space && size <= left) {
2913 pi2->pShareName = (LPWSTR)ptr;
2920 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2922 if(space && size <= left) {
2923 pi2->pPortName = (LPWSTR)ptr;
2930 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2932 if(space && size <= left) {
2933 pi2->pDriverName = (LPWSTR)ptr;
2940 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2942 if(space && size <= left) {
2943 pi2->pComment = (LPWSTR)ptr;
2950 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2952 if(space && size <= left) {
2953 pi2->pLocation = (LPWSTR)ptr;
2960 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2962 if(space && size <= left) {
2963 pi2->pDevMode = (LPDEVMODEW)ptr;
2972 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2973 if(space && size <= left) {
2974 pi2->pDevMode = (LPDEVMODEW)ptr;
2981 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2983 if(space && size <= left) {
2984 pi2->pSepFile = (LPWSTR)ptr;
2991 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2993 if(space && size <= left) {
2994 pi2->pPrintProcessor = (LPWSTR)ptr;
3001 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3003 if(space && size <= left) {
3004 pi2->pDatatype = (LPWSTR)ptr;
3011 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3013 if(space && size <= left) {
3014 pi2->pParameters = (LPWSTR)ptr;
3022 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3023 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3024 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3025 "Default Priority");
3026 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3027 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3030 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3031 memset(pi2, 0, sizeof(*pi2));
3036 /*********************************************************************
3037 * WINSPOOL_GetPrinter_4
3039 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3041 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3042 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3045 DWORD size, left = cbBuf;
3046 BOOL space = (cbBuf > 0);
3051 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3053 if(space && size <= left) {
3054 pi4->pPrinterName = (LPWSTR)ptr;
3062 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3065 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3066 memset(pi4, 0, sizeof(*pi4));
3071 /*********************************************************************
3072 * WINSPOOL_GetPrinter_5
3074 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3076 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3077 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3080 DWORD size, left = cbBuf;
3081 BOOL space = (cbBuf > 0);
3086 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3088 if(space && size <= left) {
3089 pi5->pPrinterName = (LPWSTR)ptr;
3096 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3098 if(space && size <= left) {
3099 pi5->pPortName = (LPWSTR)ptr;
3107 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3108 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3110 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3114 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3115 memset(pi5, 0, sizeof(*pi5));
3120 /*****************************************************************************
3121 * WINSPOOL_GetPrinter
3123 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3124 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3125 * just a collection of pointers to strings.
3127 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3128 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3131 DWORD size, needed = 0;
3133 HKEY hkeyPrinter, hkeyPrinters;
3136 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3138 if (!(name = get_opened_printer_name(hPrinter))) {
3139 SetLastError(ERROR_INVALID_HANDLE);
3143 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3145 ERR("Can't create Printers key\n");
3148 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3150 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3151 RegCloseKey(hkeyPrinters);
3152 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3159 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3161 size = sizeof(PRINTER_INFO_2W);
3163 ptr = pPrinter + size;
3165 memset(pPrinter, 0, size);
3170 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3178 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3180 size = sizeof(PRINTER_INFO_4W);
3182 ptr = pPrinter + size;
3184 memset(pPrinter, 0, size);
3189 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3198 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3200 size = sizeof(PRINTER_INFO_5W);
3202 ptr = pPrinter + size;
3204 memset(pPrinter, 0, size);
3210 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3217 FIXME("Unimplemented level %ld\n", Level);
3218 SetLastError(ERROR_INVALID_LEVEL);
3219 RegCloseKey(hkeyPrinters);
3220 RegCloseKey(hkeyPrinter);
3224 RegCloseKey(hkeyPrinter);
3225 RegCloseKey(hkeyPrinters);
3227 TRACE("returning %d needed = %ld\n", ret, needed);
3228 if(pcbNeeded) *pcbNeeded = needed;
3230 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3234 /*****************************************************************************
3235 * GetPrinterW [WINSPOOL.@]
3237 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3238 DWORD cbBuf, LPDWORD pcbNeeded)
3240 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3244 /*****************************************************************************
3245 * GetPrinterA [WINSPOOL.@]
3247 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3248 DWORD cbBuf, LPDWORD pcbNeeded)
3250 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3254 /*****************************************************************************
3255 * WINSPOOL_EnumPrinters
3257 * Implementation of EnumPrintersA|W
3259 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3260 DWORD dwLevel, LPBYTE lpbPrinters,
3261 DWORD cbBuf, LPDWORD lpdwNeeded,
3262 LPDWORD lpdwReturned, BOOL unicode)
3265 HKEY hkeyPrinters, hkeyPrinter;
3266 WCHAR PrinterName[255];
3267 DWORD needed = 0, number = 0;
3268 DWORD used, i, left;
3272 memset(lpbPrinters, 0, cbBuf);
3278 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3279 if(dwType == PRINTER_ENUM_DEFAULT)
3282 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3283 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3284 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3285 if(!dwType) return TRUE;
3288 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3289 FIXME("dwType = %08lx\n", dwType);
3290 SetLastError(ERROR_INVALID_FLAGS);
3294 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3296 ERR("Can't create Printers key\n");
3300 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3301 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3302 RegCloseKey(hkeyPrinters);
3303 ERR("Can't query Printers key\n");
3306 TRACE("Found %ld printers\n", number);
3310 RegCloseKey(hkeyPrinters);
3312 *lpdwReturned = number;
3316 used = number * sizeof(PRINTER_INFO_2W);
3319 used = number * sizeof(PRINTER_INFO_4W);
3322 used = number * sizeof(PRINTER_INFO_5W);
3326 SetLastError(ERROR_INVALID_LEVEL);
3327 RegCloseKey(hkeyPrinters);
3330 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3332 for(i = 0; i < number; i++) {
3333 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3335 ERR("Can't enum key number %ld\n", i);
3336 RegCloseKey(hkeyPrinters);
3339 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3340 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3342 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3343 RegCloseKey(hkeyPrinters);
3348 buf = lpbPrinters + used;
3349 left = cbBuf - used;
3357 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3358 left, &needed, unicode);
3360 if(pi) pi += sizeof(PRINTER_INFO_2W);
3363 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3364 left, &needed, unicode);
3366 if(pi) pi += sizeof(PRINTER_INFO_4W);
3369 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3370 left, &needed, unicode);
3372 if(pi) pi += sizeof(PRINTER_INFO_5W);
3375 ERR("Shouldn't be here!\n");
3376 RegCloseKey(hkeyPrinter);
3377 RegCloseKey(hkeyPrinters);
3380 RegCloseKey(hkeyPrinter);
3382 RegCloseKey(hkeyPrinters);
3389 memset(lpbPrinters, 0, cbBuf);
3390 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3394 *lpdwReturned = number;
3395 SetLastError(ERROR_SUCCESS);
3400 /******************************************************************
3401 * EnumPrintersW [WINSPOOL.@]
3403 * Enumerates the available printers, print servers and print
3404 * providers, depending on the specified flags, name and level.
3408 * If level is set to 1:
3409 * Not implemented yet!
3410 * Returns TRUE with an empty list.
3412 * If level is set to 2:
3413 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3414 * Returns an array of PRINTER_INFO_2 data structures in the
3415 * lpbPrinters buffer. Note that according to MSDN also an
3416 * OpenPrinter should be performed on every remote printer.
3418 * If level is set to 4 (officially WinNT only):
3419 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3420 * Fast: Only the registry is queried to retrieve printer names,
3421 * no connection to the driver is made.
3422 * Returns an array of PRINTER_INFO_4 data structures in the
3423 * lpbPrinters buffer.
3425 * If level is set to 5 (officially WinNT4/Win9x only):
3426 * Fast: Only the registry is queried to retrieve printer names,
3427 * no connection to the driver is made.
3428 * Returns an array of PRINTER_INFO_5 data structures in the
3429 * lpbPrinters buffer.
3431 * If level set to 3 or 6+:
3432 * returns zero (failure!)
3434 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3438 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3439 * - Only levels 2, 4 and 5 are implemented at the moment.
3440 * - 16-bit printer drivers are not enumerated.
3441 * - Returned amount of bytes used/needed does not match the real Windoze
3442 * implementation (as in this implementation, all strings are part
3443 * of the buffer, whereas Win32 keeps them somewhere else)
3444 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3447 * - In a regular Wine installation, no registry settings for printers
3448 * exist, which makes this function return an empty list.
3450 BOOL WINAPI EnumPrintersW(
3451 DWORD dwType, /* [in] Types of print objects to enumerate */
3452 LPWSTR lpszName, /* [in] name of objects to enumerate */
3453 DWORD dwLevel, /* [in] type of printer info structure */
3454 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3455 DWORD cbBuf, /* [in] max size of buffer in bytes */
3456 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3457 LPDWORD lpdwReturned /* [out] number of entries returned */
3460 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3461 lpdwNeeded, lpdwReturned, TRUE);
3464 /******************************************************************
3465 * EnumPrintersA [WINSPOOL.@]
3468 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3469 DWORD dwLevel, LPBYTE lpbPrinters,
3470 DWORD cbBuf, LPDWORD lpdwNeeded,
3471 LPDWORD lpdwReturned)
3474 UNICODE_STRING lpszNameW;
3477 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3478 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3479 lpdwNeeded, lpdwReturned, FALSE);
3480 RtlFreeUnicodeString(&lpszNameW);
3484 /*****************************************************************************
3485 * WINSPOOL_GetDriverInfoFromReg [internal]
3487 * Enters the information from the registry into the DRIVER_INFO struct
3490 * zero if the printer driver does not exist in the registry
3491 * (only if Level > 1) otherwise nonzero
3493 static BOOL WINSPOOL_GetDriverInfoFromReg(
3496 LPWSTR pEnvironment,
3498 LPBYTE ptr, /* DRIVER_INFO */
3499 LPBYTE pDriverStrings, /* strings buffer */
3500 DWORD cbBuf, /* size of string buffer */
3501 LPDWORD pcbNeeded, /* space needed for str. */
3502 BOOL unicode) /* type of strings */
3506 LPBYTE strPtr = pDriverStrings;
3508 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3509 debugstr_w(DriverName), debugstr_w(pEnvironment),
3510 Level, ptr, pDriverStrings, cbBuf, unicode);
3513 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3514 if (*pcbNeeded <= cbBuf)
3515 strcpyW((LPWSTR)strPtr, DriverName);
3517 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3519 if(*pcbNeeded <= cbBuf)
3520 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3521 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3525 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3529 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3530 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3533 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3534 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3535 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3540 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3543 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3545 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3547 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3550 if(*pcbNeeded <= cbBuf) {
3552 strcpyW((LPWSTR)strPtr, pEnvironment);
3554 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3555 (LPSTR)strPtr, size, NULL, NULL);
3557 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3558 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3561 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3564 if(*pcbNeeded <= cbBuf)
3565 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3568 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3569 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3572 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3575 if(*pcbNeeded <= cbBuf)
3576 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3579 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3580 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3583 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3584 0, &size, unicode)) {
3586 if(*pcbNeeded <= cbBuf)
3587 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3588 size, &tmp, unicode);
3590 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3591 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3595 RegCloseKey(hkeyDriver);
3596 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3600 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3603 if(*pcbNeeded <= cbBuf)
3604 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3605 size, &tmp, unicode);
3607 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3608 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3611 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3614 if(*pcbNeeded <= cbBuf)
3615 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3616 size, &tmp, unicode);
3618 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3619 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3622 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3625 if(*pcbNeeded <= cbBuf)
3626 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3627 size, &tmp, unicode);
3629 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3630 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3633 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3636 if(*pcbNeeded <= cbBuf)
3637 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3638 size, &tmp, unicode);
3640 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3641 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3644 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3645 RegCloseKey(hkeyDriver);
3649 /*****************************************************************************
3650 * WINSPOOL_GetPrinterDriver
3652 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3653 DWORD Level, LPBYTE pDriverInfo,
3654 DWORD cbBuf, LPDWORD pcbNeeded,
3658 WCHAR DriverName[100];
3659 DWORD ret, type, size, needed = 0;
3661 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3663 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3664 Level,pDriverInfo,cbBuf, pcbNeeded);
3666 ZeroMemory(pDriverInfo, cbBuf);
3668 if (!(name = get_opened_printer_name(hPrinter))) {
3669 SetLastError(ERROR_INVALID_HANDLE);
3672 if(Level < 1 || Level > 6) {
3673 SetLastError(ERROR_INVALID_LEVEL);
3676 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3678 ERR("Can't create Printers key\n");
3681 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3683 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3684 RegCloseKey(hkeyPrinters);
3685 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3688 size = sizeof(DriverName);
3690 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3691 (LPBYTE)DriverName, &size);
3692 RegCloseKey(hkeyPrinter);
3693 RegCloseKey(hkeyPrinters);
3694 if(ret != ERROR_SUCCESS) {
3695 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3699 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3701 ERR("Can't create Drivers key\n");
3707 size = sizeof(DRIVER_INFO_1W);
3710 size = sizeof(DRIVER_INFO_2W);
3713 size = sizeof(DRIVER_INFO_3W);
3716 size = sizeof(DRIVER_INFO_4W);
3719 size = sizeof(DRIVER_INFO_5W);
3722 size = sizeof(DRIVER_INFO_6W);
3725 ERR("Invalid level\n");
3730 ptr = pDriverInfo + size;
3732 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3733 pEnvironment, Level, pDriverInfo,
3734 (cbBuf < size) ? NULL : ptr,
3735 (cbBuf < size) ? 0 : cbBuf - size,
3736 &needed, unicode)) {
3737 RegCloseKey(hkeyDrivers);
3741 RegCloseKey(hkeyDrivers);
3743 if(pcbNeeded) *pcbNeeded = size + needed;
3744 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3745 if(cbBuf >= needed) return TRUE;
3746 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3750 /*****************************************************************************
3751 * GetPrinterDriverA [WINSPOOL.@]
3753 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3754 DWORD Level, LPBYTE pDriverInfo,
3755 DWORD cbBuf, LPDWORD pcbNeeded)
3758 UNICODE_STRING pEnvW;
3761 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3762 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3763 cbBuf, pcbNeeded, FALSE);
3764 RtlFreeUnicodeString(&pEnvW);
3767 /*****************************************************************************
3768 * GetPrinterDriverW [WINSPOOL.@]
3770 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3771 DWORD Level, LPBYTE pDriverInfo,
3772 DWORD cbBuf, LPDWORD pcbNeeded)
3774 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3775 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3778 /*****************************************************************************
3779 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3781 * Return the PATH for the Printer-Drivers (UNICODE)
3784 * pName [I] Servername (NT only) or NULL (local Computer)
3785 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3786 * Level [I] Structure-Level (must be 1)
3787 * pDriverDirectory [O] PTR to Buffer that receives the Result
3788 * cbBuf [I] Size of Buffer at pDriverDirectory
3789 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3790 * required for pDriverDirectory
3793 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3794 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3795 * if cbBuf is too small
3797 * Native Values returned in pDriverDirectory on Success:
3798 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3799 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3800 *| win9x(Windows 4.0): "%winsysdir%"
3802 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3805 *- Only NULL or "" is supported for pName
3808 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3809 DWORD Level, LPBYTE pDriverDirectory,
3810 DWORD cbBuf, LPDWORD pcbNeeded)
3813 const printenv_t * env;
3815 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3816 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3817 if(pName != NULL && pName[0]) {
3818 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3819 SetLastError(ERROR_INVALID_PARAMETER);
3823 env = validate_envW(pEnvironment);
3824 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3827 WARN("(Level: %ld) is ignored in win9x\n", Level);
3828 SetLastError(ERROR_INVALID_LEVEL);
3832 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3833 needed = GetSystemDirectoryW(NULL, 0);
3834 /* add the Size for the Subdirectories */
3835 needed += lstrlenW(spooldriversW);
3836 needed += lstrlenW(env->subdir);
3837 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3840 *pcbNeeded = needed;
3841 TRACE("required: 0x%lx/%ld\n", needed, needed);
3842 if(needed > cbBuf) {
3843 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3846 if(pcbNeeded == NULL) {
3847 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3848 SetLastError(RPC_X_NULL_REF_POINTER);
3851 if(pDriverDirectory == NULL) {
3852 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3853 SetLastError(ERROR_INVALID_USER_BUFFER);
3857 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3858 /* add the Subdirectories */
3859 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3860 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3861 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3866 /*****************************************************************************
3867 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3869 * Return the PATH for the Printer-Drivers (ANSI)
3871 * See GetPrinterDriverDirectoryW.
3874 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3877 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3878 DWORD Level, LPBYTE pDriverDirectory,
3879 DWORD cbBuf, LPDWORD pcbNeeded)
3881 UNICODE_STRING nameW, environmentW;
3884 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3885 WCHAR *driverDirectoryW = NULL;
3887 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3888 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3890 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3892 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3893 else nameW.Buffer = NULL;
3894 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3895 else environmentW.Buffer = NULL;
3897 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3898 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3901 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3902 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3904 *pcbNeeded = needed;
3905 ret = (needed <= cbBuf) ? TRUE : FALSE;
3907 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3909 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3911 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3912 RtlFreeUnicodeString(&environmentW);
3913 RtlFreeUnicodeString(&nameW);
3918 /*****************************************************************************
3919 * AddPrinterDriverA [WINSPOOL.@]
3921 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3924 HKEY hkeyDrivers, hkeyName;
3926 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3928 if(level != 2 && level != 3) {
3929 SetLastError(ERROR_INVALID_LEVEL);
3933 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3934 SetLastError(ERROR_INVALID_PARAMETER);
3938 WARN("pDriverInfo == NULL\n");
3939 SetLastError(ERROR_INVALID_PARAMETER);
3944 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3946 memset(&di3, 0, sizeof(di3));
3947 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3950 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3952 SetLastError(ERROR_INVALID_PARAMETER);
3955 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3956 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3957 if(!di3.pHelpFile) di3.pHelpFile = "";
3958 if(!di3.pMonitorName) di3.pMonitorName = "";
3960 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3963 ERR("Can't create Drivers key\n");
3967 if(level == 2) { /* apparently can't overwrite with level2 */
3968 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3969 RegCloseKey(hkeyName);
3970 RegCloseKey(hkeyDrivers);
3971 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3972 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3976 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3977 RegCloseKey(hkeyDrivers);
3978 ERR("Can't create Name key\n");
3981 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3983 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3984 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3985 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3987 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3988 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3989 (LPBYTE) di3.pDependentFiles, 0);
3990 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3991 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3992 RegCloseKey(hkeyName);
3993 RegCloseKey(hkeyDrivers);
3998 /*****************************************************************************
3999 * AddPrinterDriverW [WINSPOOL.@]
4001 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4004 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
4009 /*****************************************************************************
4010 * AddPrintProcessorA [WINSPOOL.@]
4012 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4013 LPSTR pPrintProcessorName)
4015 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4016 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4020 /*****************************************************************************
4021 * AddPrintProcessorW [WINSPOOL.@]
4023 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4024 LPWSTR pPrintProcessorName)
4026 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4027 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4031 /*****************************************************************************
4032 * AddPrintProvidorA [WINSPOOL.@]
4034 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4036 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4040 /*****************************************************************************
4041 * AddPrintProvidorW [WINSPOOL.@]
4043 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4045 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4049 /*****************************************************************************
4050 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4052 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4053 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4055 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4056 pDevModeOutput, pDevModeInput);
4060 /*****************************************************************************
4061 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4063 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4064 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4066 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4067 pDevModeOutput, pDevModeInput);
4071 /*****************************************************************************
4072 * PrinterProperties [WINSPOOL.@]
4074 * Displays a dialog to set the properties of the printer.
4077 * nonzero on success or zero on failure
4080 * implemented as stub only
4082 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4083 HANDLE hPrinter /* [in] handle to printer object */
4085 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4086 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4090 /*****************************************************************************
4091 * EnumJobsA [WINSPOOL.@]
4094 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4095 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4098 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4099 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4101 if(pcbNeeded) *pcbNeeded = 0;
4102 if(pcReturned) *pcReturned = 0;
4107 /*****************************************************************************
4108 * EnumJobsW [WINSPOOL.@]
4111 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4112 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4115 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4116 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4118 if(pcbNeeded) *pcbNeeded = 0;
4119 if(pcReturned) *pcReturned = 0;
4123 /*****************************************************************************
4124 * WINSPOOL_EnumPrinterDrivers [internal]
4126 * Delivers information about all printer drivers installed on the
4127 * localhost or a given server
4130 * nonzero on success or zero on failure. If the buffer for the returned
4131 * information is too small the function will return an error
4134 * - only implemented for localhost, foreign hosts will return an error
4136 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4137 DWORD Level, LPBYTE pDriverInfo,
4138 DWORD cbBuf, LPDWORD pcbNeeded,
4139 LPDWORD pcReturned, BOOL unicode)
4142 DWORD i, needed, number = 0, size = 0;
4143 WCHAR DriverNameW[255];
4146 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4147 debugstr_w(pName), debugstr_w(pEnvironment),
4148 Level, pDriverInfo, cbBuf, unicode);
4150 /* check for local drivers */
4151 if((pName) && (pName[0])) {
4152 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4153 SetLastError(ERROR_ACCESS_DENIED);
4157 /* check input parameter */
4158 if((Level < 1) || (Level > 3)) {
4159 ERR("unsupported level %ld\n", Level);
4160 SetLastError(ERROR_INVALID_LEVEL);
4164 /* initialize return values */
4166 memset( pDriverInfo, 0, cbBuf);
4170 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4172 ERR("Can't open Drivers key\n");
4176 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4177 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4178 RegCloseKey(hkeyDrivers);
4179 ERR("Can't query Drivers key\n");
4182 TRACE("Found %ld Drivers\n", number);
4184 /* get size of single struct
4185 * unicode and ascii structure have the same size
4189 size = sizeof(DRIVER_INFO_1A);
4192 size = sizeof(DRIVER_INFO_2A);
4195 size = sizeof(DRIVER_INFO_3A);
4199 /* calculate required buffer size */
4200 *pcbNeeded = size * number;
4202 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4204 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4205 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4207 ERR("Can't enum key number %ld\n", i);
4208 RegCloseKey(hkeyDrivers);
4211 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4212 pEnvironment, Level, ptr,
4213 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4214 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4215 &needed, unicode)) {
4216 RegCloseKey(hkeyDrivers);
4219 (*pcbNeeded) += needed;
4222 RegCloseKey(hkeyDrivers);
4224 if(cbBuf < *pcbNeeded){
4225 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4229 *pcReturned = number;
4233 /*****************************************************************************
4234 * EnumPrinterDriversW [WINSPOOL.@]
4236 * see function EnumPrinterDrivers for RETURNS, BUGS
4238 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4239 LPBYTE pDriverInfo, DWORD cbBuf,
4240 LPDWORD pcbNeeded, LPDWORD pcReturned)
4242 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4243 cbBuf, pcbNeeded, pcReturned, TRUE);
4246 /*****************************************************************************
4247 * EnumPrinterDriversA [WINSPOOL.@]
4249 * see function EnumPrinterDrivers for RETURNS, BUGS
4251 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4252 LPBYTE pDriverInfo, DWORD cbBuf,
4253 LPDWORD pcbNeeded, LPDWORD pcReturned)
4255 UNICODE_STRING pNameW, pEnvironmentW;
4256 PWSTR pwstrNameW, pwstrEnvironmentW;
4258 pwstrNameW = asciitounicode(&pNameW, pName);
4259 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4261 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4262 Level, pDriverInfo, cbBuf, pcbNeeded,
4264 RtlFreeUnicodeString(&pNameW);
4265 RtlFreeUnicodeString(&pEnvironmentW);
4270 static CHAR PortMonitor[] = "Wine Port Monitor";
4271 static CHAR PortDescription[] = "Wine Port";
4273 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4277 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4278 NULL, OPEN_EXISTING, 0, NULL );
4279 if (handle == INVALID_HANDLE_VALUE)
4281 TRACE("Checking %s exists\n", name );
4282 CloseHandle( handle );
4286 static DWORD WINSPOOL_CountSerialPorts(void)
4293 strcpy( name, "COMx:" );
4295 if (WINSPOOL_ComPortExists( name ))
4302 /******************************************************************************
4303 * EnumPortsA (WINSPOOL.@)
4308 * ANSI-Version did not call the UNICODE-Version
4311 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4312 LPDWORD bufneeded,LPDWORD bufreturned)
4315 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4316 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4320 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4321 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4326 info_size = sizeof (PORT_INFO_1A);
4329 info_size = sizeof (PORT_INFO_2A);
4332 SetLastError(ERROR_INVALID_LEVEL);
4336 /* see how many exist */
4339 serial_count = WINSPOOL_CountSerialPorts();
4342 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4343 if ( r == ERROR_SUCCESS )
4345 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4346 &printer_count, NULL, NULL, NULL, NULL);
4348 count = serial_count + printer_count;
4350 /* then fill in the structure info structure once
4351 we know the offset to the first string */
4353 memset( buffer, 0, bufsize );
4355 ofs = info_size*count;
4356 for ( i=0; i<count; i++)
4358 DWORD vallen = sizeof(portname) - 1;
4360 /* get the serial port values, then the printer values */
4361 if ( i < serial_count )
4363 strcpy( portname, "COMx:" );
4364 portname[3] = '1' + i;
4365 if (!WINSPOOL_ComPortExists( portname ))
4368 TRACE("Found %s\n", portname );
4369 vallen = strlen( portname );
4373 r = RegEnumValueA( hkey_printer, i-serial_count,
4374 portname, &vallen, NULL, NULL, NULL, 0 );
4379 /* add a colon if necessary, and make it upper case */
4380 CharUpperBuffA(portname,vallen);
4381 if (strcasecmp(portname,"nul")!=0)
4382 if (vallen && (portname[vallen-1] != ':') )
4383 lstrcatA(portname,":");
4385 /* add the port info structure if we can fit it */
4386 if ( info_size*(n+1) < bufsize )
4390 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4391 info->pName = (LPSTR) &buffer[ofs];
4393 else if ( level == 2)
4395 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4396 info->pPortName = (LPSTR) &buffer[ofs];
4397 /* FIXME: fill in more stuff here */
4398 info->pMonitorName = PortMonitor;
4399 info->pDescription = PortDescription;
4400 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4403 /* add the name of the port if we can fit it */
4404 if ( ofs < bufsize )
4405 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4411 ofs += lstrlenA(portname)+1;
4414 RegCloseKey(hkey_printer);
4425 /******************************************************************************
4426 * EnumPortsW (WINSPOOL.@)
4428 * Enumerate available Ports
4431 * name [I] Servername or NULL (local Computer)
4432 * level [I] Structure-Level (1 or 2)
4433 * buffer [O] PTR to Buffer that receives the Result
4434 * bufsize [I] Size of Buffer at buffer
4435 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4436 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4440 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4443 * UNICODE-Version is a stub
4446 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4447 LPDWORD bufneeded,LPDWORD bufreturned)
4449 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4450 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4454 /******************************************************************************
4455 * GetDefaultPrinterW (WINSPOOL.@)
4458 * This function must read the value from data 'device' of key
4459 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4461 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4465 WCHAR *buffer, *ptr;
4469 SetLastError(ERROR_INVALID_PARAMETER);
4473 /* make the buffer big enough for the stuff from the profile/registry,
4474 * the content must fit into the local buffer to compute the correct
4475 * size even if the extern buffer is too small or not given.
4476 * (20 for ,driver,port) */
4478 len = max(100, (insize + 20));
4479 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4481 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4483 SetLastError (ERROR_FILE_NOT_FOUND);
4487 TRACE("%s\n", debugstr_w(buffer));
4489 if ((ptr = strchrW(buffer, ',')) == NULL)
4491 SetLastError(ERROR_INVALID_NAME);
4497 *namesize = strlenW(buffer) + 1;
4498 if(!name || (*namesize > insize))
4500 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4504 strcpyW(name, buffer);
4507 HeapFree( GetProcessHeap(), 0, buffer);
4512 /******************************************************************************
4513 * GetDefaultPrinterA (WINSPOOL.@)
4515 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4519 WCHAR *bufferW = NULL;
4523 SetLastError(ERROR_INVALID_PARAMETER);
4527 if(name && *namesize) {
4529 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4532 if(!GetDefaultPrinterW( bufferW, namesize)) {
4537 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4541 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4544 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4547 HeapFree( GetProcessHeap(), 0, bufferW);
4552 /******************************************************************************
4553 * SetDefaultPrinterW (WINSPOOL.204)
4555 * Set the Name of the Default Printer
4558 * pszPrinter [I] Name of the Printer or NULL
4565 * When the Parameter is NULL or points to an Empty String and
4566 * a Default Printer was already present, then this Function changes nothing.
4567 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4568 * the First enumerated local Printer is used.
4571 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4574 TRACE("(%s)\n", debugstr_w(pszPrinter));
4576 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4580 /******************************************************************************
4581 * SetDefaultPrinterA (WINSPOOL.202)
4583 * See SetDefaultPrinterW.
4586 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4589 TRACE("(%s)\n", debugstr_a(pszPrinter));
4591 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4596 /******************************************************************************
4597 * SetPrinterDataExA (WINSPOOL.@)
4599 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4600 LPCSTR pValueName, DWORD Type,
4601 LPBYTE pData, DWORD cbData)
4603 HKEY hkeyPrinter, hkeySubkey;
4606 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4607 debugstr_a(pValueName), Type, pData, cbData);
4609 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4613 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4615 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4616 RegCloseKey(hkeyPrinter);
4619 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4620 RegCloseKey(hkeySubkey);
4621 RegCloseKey(hkeyPrinter);
4625 /******************************************************************************
4626 * SetPrinterDataExW (WINSPOOL.@)
4628 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4629 LPCWSTR pValueName, DWORD Type,
4630 LPBYTE pData, DWORD cbData)
4632 HKEY hkeyPrinter, hkeySubkey;
4635 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4636 debugstr_w(pValueName), Type, pData, cbData);
4638 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4642 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4644 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4645 RegCloseKey(hkeyPrinter);
4648 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4649 RegCloseKey(hkeySubkey);
4650 RegCloseKey(hkeyPrinter);
4654 /******************************************************************************
4655 * SetPrinterDataA (WINSPOOL.@)
4657 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4658 LPBYTE pData, DWORD cbData)
4660 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4664 /******************************************************************************
4665 * SetPrinterDataW (WINSPOOL.@)
4667 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4668 LPBYTE pData, DWORD cbData)
4670 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4674 /******************************************************************************
4675 * GetPrinterDataExA (WINSPOOL.@)
4677 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4678 LPCSTR pValueName, LPDWORD pType,
4679 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4681 HKEY hkeyPrinter, hkeySubkey;
4684 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4685 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4688 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4692 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4694 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4695 RegCloseKey(hkeyPrinter);
4699 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4700 RegCloseKey(hkeySubkey);
4701 RegCloseKey(hkeyPrinter);
4705 /******************************************************************************
4706 * GetPrinterDataExW (WINSPOOL.@)
4708 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4709 LPCWSTR pValueName, LPDWORD pType,
4710 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4712 HKEY hkeyPrinter, hkeySubkey;
4715 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4716 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4719 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4723 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4725 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4726 RegCloseKey(hkeyPrinter);
4730 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4731 RegCloseKey(hkeySubkey);
4732 RegCloseKey(hkeyPrinter);
4736 /******************************************************************************
4737 * GetPrinterDataA (WINSPOOL.@)
4739 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4740 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4742 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4743 pData, nSize, pcbNeeded);
4746 /******************************************************************************
4747 * GetPrinterDataW (WINSPOOL.@)
4749 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4750 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4752 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4753 pData, nSize, pcbNeeded);
4756 /*******************************************************************************
4757 * EnumPrinterDataExW [WINSPOOL.@]
4759 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4760 LPBYTE pEnumValues, DWORD cbEnumValues,
4761 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4763 HKEY hkPrinter, hkSubKey;
4764 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4765 cbValueNameLen, cbMaxValueLen, cbValueLen,
4770 PPRINTER_ENUM_VALUESW ppev;
4772 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4774 if (pKeyName == NULL || *pKeyName == 0)
4775 return ERROR_INVALID_PARAMETER;
4777 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4778 if (ret != ERROR_SUCCESS)
4780 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4785 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4786 if (ret != ERROR_SUCCESS)
4788 r = RegCloseKey (hkPrinter);
4789 if (r != ERROR_SUCCESS)
4790 WARN ("RegCloseKey returned %li\n", r);
4791 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4792 debugstr_w (pKeyName), ret);
4796 ret = RegCloseKey (hkPrinter);
4797 if (ret != ERROR_SUCCESS)
4799 ERR ("RegCloseKey returned %li\n", ret);
4800 r = RegCloseKey (hkSubKey);
4801 if (r != ERROR_SUCCESS)
4802 WARN ("RegCloseKey returned %li\n", r);
4806 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4807 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4808 if (ret != ERROR_SUCCESS)
4810 r = RegCloseKey (hkSubKey);
4811 if (r != ERROR_SUCCESS)
4812 WARN ("RegCloseKey returned %li\n", r);
4813 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4817 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4818 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4820 if (cValues == 0) /* empty key */
4822 r = RegCloseKey (hkSubKey);
4823 if (r != ERROR_SUCCESS)
4824 WARN ("RegCloseKey returned %li\n", r);
4825 *pcbEnumValues = *pnEnumValues = 0;
4826 return ERROR_SUCCESS;
4829 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4831 hHeap = GetProcessHeap ();
4834 ERR ("GetProcessHeap failed\n");
4835 r = RegCloseKey (hkSubKey);
4836 if (r != ERROR_SUCCESS)
4837 WARN ("RegCloseKey returned %li\n", r);
4838 return ERROR_OUTOFMEMORY;
4841 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4842 if (lpValueName == NULL)
4844 ERR ("Failed to allocate %li bytes from process heap\n",
4845 cbMaxValueNameLen * sizeof (WCHAR));
4846 r = RegCloseKey (hkSubKey);
4847 if (r != ERROR_SUCCESS)
4848 WARN ("RegCloseKey returned %li\n", r);
4849 return ERROR_OUTOFMEMORY;
4852 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4853 if (lpValue == NULL)
4855 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4856 if (HeapFree (hHeap, 0, lpValueName) == 0)
4857 WARN ("HeapFree failed with code %li\n", GetLastError ());
4858 r = RegCloseKey (hkSubKey);
4859 if (r != ERROR_SUCCESS)
4860 WARN ("RegCloseKey returned %li\n", r);
4861 return ERROR_OUTOFMEMORY;
4864 TRACE ("pass 1: calculating buffer required for all names and values\n");
4866 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4868 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4870 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4872 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4873 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4874 NULL, NULL, lpValue, &cbValueLen);
4875 if (ret != ERROR_SUCCESS)
4877 if (HeapFree (hHeap, 0, lpValue) == 0)
4878 WARN ("HeapFree failed with code %li\n", GetLastError ());
4879 if (HeapFree (hHeap, 0, lpValueName) == 0)
4880 WARN ("HeapFree failed with code %li\n", GetLastError ());
4881 r = RegCloseKey (hkSubKey);
4882 if (r != ERROR_SUCCESS)
4883 WARN ("RegCloseKey returned %li\n", r);
4884 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4888 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4889 debugstr_w (lpValueName), dwIndex,
4890 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4892 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4893 cbBufSize += cbValueLen;
4896 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4898 *pcbEnumValues = cbBufSize;
4899 *pnEnumValues = cValues;
4901 if (cbEnumValues < cbBufSize) /* buffer too small */
4903 if (HeapFree (hHeap, 0, lpValue) == 0)
4904 WARN ("HeapFree failed with code %li\n", GetLastError ());
4905 if (HeapFree (hHeap, 0, lpValueName) == 0)
4906 WARN ("HeapFree failed with code %li\n", GetLastError ());
4907 r = RegCloseKey (hkSubKey);
4908 if (r != ERROR_SUCCESS)
4909 WARN ("RegCloseKey returned %li\n", r);
4910 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4911 return ERROR_MORE_DATA;
4914 TRACE ("pass 2: copying all names and values to buffer\n");
4916 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4917 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4919 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4921 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4922 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4923 NULL, &dwType, lpValue, &cbValueLen);
4924 if (ret != ERROR_SUCCESS)
4926 if (HeapFree (hHeap, 0, lpValue) == 0)
4927 WARN ("HeapFree failed with code %li\n", GetLastError ());
4928 if (HeapFree (hHeap, 0, lpValueName) == 0)
4929 WARN ("HeapFree failed with code %li\n", GetLastError ());
4930 r = RegCloseKey (hkSubKey);
4931 if (r != ERROR_SUCCESS)
4932 WARN ("RegCloseKey returned %li\n", r);
4933 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4937 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4938 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4939 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4940 pEnumValues += cbValueNameLen;
4942 /* return # of *bytes* (including trailing \0), not # of chars */
4943 ppev[dwIndex].cbValueName = cbValueNameLen;
4945 ppev[dwIndex].dwType = dwType;
4947 memcpy (pEnumValues, lpValue, cbValueLen);
4948 ppev[dwIndex].pData = pEnumValues;
4949 pEnumValues += cbValueLen;
4951 ppev[dwIndex].cbData = cbValueLen;
4953 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4954 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4957 if (HeapFree (hHeap, 0, lpValue) == 0)
4959 ret = GetLastError ();
4960 ERR ("HeapFree failed with code %li\n", ret);
4961 if (HeapFree (hHeap, 0, lpValueName) == 0)
4962 WARN ("HeapFree failed with code %li\n", GetLastError ());
4963 r = RegCloseKey (hkSubKey);
4964 if (r != ERROR_SUCCESS)
4965 WARN ("RegCloseKey returned %li\n", r);
4969 if (HeapFree (hHeap, 0, lpValueName) == 0)
4971 ret = GetLastError ();
4972 ERR ("HeapFree failed with code %li\n", ret);
4973 r = RegCloseKey (hkSubKey);
4974 if (r != ERROR_SUCCESS)
4975 WARN ("RegCloseKey returned %li\n", r);
4979 ret = RegCloseKey (hkSubKey);
4980 if (ret != ERROR_SUCCESS)
4982 ERR ("RegCloseKey returned %li\n", ret);
4986 return ERROR_SUCCESS;
4989 /*******************************************************************************
4990 * EnumPrinterDataExA [WINSPOOL.@]
4992 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4993 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4994 * what Windows 2000 SP1 does.
4997 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4998 LPBYTE pEnumValues, DWORD cbEnumValues,
4999 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5003 DWORD ret, dwIndex, dwBufSize;
5007 TRACE ("%p %s\n", hPrinter, pKeyName);
5009 if (pKeyName == NULL || *pKeyName == 0)
5010 return ERROR_INVALID_PARAMETER;
5012 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5015 ret = GetLastError ();
5016 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5020 hHeap = GetProcessHeap ();
5023 ERR ("GetProcessHeap failed\n");
5024 return ERROR_OUTOFMEMORY;
5027 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5028 if (pKeyNameW == NULL)
5030 ERR ("Failed to allocate %li bytes from process heap\n",
5031 (LONG) len * sizeof (WCHAR));
5032 return ERROR_OUTOFMEMORY;
5035 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5037 ret = GetLastError ();
5038 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5039 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5040 WARN ("HeapFree failed with code %li\n", GetLastError ());
5044 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5045 pcbEnumValues, pnEnumValues);
5046 if (ret != ERROR_SUCCESS)
5048 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5049 WARN ("HeapFree failed with code %li\n", GetLastError ());
5050 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5054 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5056 ret = GetLastError ();
5057 ERR ("HeapFree failed with code %li\n", ret);
5061 if (*pnEnumValues == 0) /* empty key */
5062 return ERROR_SUCCESS;
5065 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5067 PPRINTER_ENUM_VALUESW ppev =
5068 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5070 if (dwBufSize < ppev->cbValueName)
5071 dwBufSize = ppev->cbValueName;
5073 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5074 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5075 dwBufSize = ppev->cbData;
5078 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5080 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5081 if (pBuffer == NULL)
5083 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5084 return ERROR_OUTOFMEMORY;
5087 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5089 PPRINTER_ENUM_VALUESW ppev =
5090 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5092 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5093 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5097 ret = GetLastError ();
5098 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5099 if (HeapFree (hHeap, 0, pBuffer) == 0)
5100 WARN ("HeapFree failed with code %li\n", GetLastError ());
5104 memcpy (ppev->pValueName, pBuffer, len);
5106 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5108 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5109 ppev->dwType != REG_MULTI_SZ)
5112 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5113 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5116 ret = GetLastError ();
5117 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5118 if (HeapFree (hHeap, 0, pBuffer) == 0)
5119 WARN ("HeapFree failed with code %li\n", GetLastError ());
5123 memcpy (ppev->pData, pBuffer, len);
5125 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5126 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5129 if (HeapFree (hHeap, 0, pBuffer) == 0)
5131 ret = GetLastError ();
5132 ERR ("HeapFree failed with code %li\n", ret);
5136 return ERROR_SUCCESS;
5139 /******************************************************************************
5140 * AbortPrinter (WINSPOOL.@)
5142 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5144 FIXME("(%p), stub!\n", hPrinter);
5148 /******************************************************************************
5149 * AddPortA (WINSPOOL.@)
5154 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5156 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5160 /******************************************************************************
5161 * AddPortW (WINSPOOL.@)
5163 * Add a Port for a specific Monitor
5166 * pName [I] Servername or NULL (local Computer)
5167 * hWnd [I] Handle to parent Window for the Dialog-Box
5168 * pMonitorName [I] Name of the Monitor that manage the Port
5178 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5180 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5184 /******************************************************************************
5185 * AddPortExA (WINSPOOL.@)
5190 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5192 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5193 lpBuffer, debugstr_a(lpMonitorName));
5197 /******************************************************************************
5198 * AddPortExW (WINSPOOL.@)
5200 * Add a Port for a specific Monitor, without presenting a user interface
5203 * hMonitor [I] Handle from InitializePrintMonitor2()
5204 * pName [I] Servername or NULL (local Computer)
5205 * Level [I] Structure-Level (1 or 2) for lpBuffer
5206 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5207 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5217 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5219 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5220 lpBuffer, debugstr_w(lpMonitorName));
5224 /******************************************************************************
5225 * AddPrinterConnectionA (WINSPOOL.@)
5227 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5229 FIXME("%s\n", debugstr_a(pName));
5233 /******************************************************************************
5234 * AddPrinterConnectionW (WINSPOOL.@)
5236 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5238 FIXME("%s\n", debugstr_w(pName));
5242 /******************************************************************************
5243 * AddPrinterDriverExW (WINSPOOL.@)
5245 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5246 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5248 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5249 Level, pDriverInfo, dwFileCopyFlags);
5250 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5254 /******************************************************************************
5255 * AddPrinterDriverExA (WINSPOOL.@)
5257 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5258 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5260 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5261 Level, pDriverInfo, dwFileCopyFlags);
5262 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5266 /******************************************************************************
5267 * ConfigurePortA (WINSPOOL.@)
5269 * See ConfigurePortW.
5272 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5274 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5278 /******************************************************************************
5279 * ConfigurePortW (WINSPOOL.@)
5281 * Display the Configuration-Dialog for a specific Port
5284 * pName [I] Servername or NULL (local Computer)
5285 * hWnd [I] Handle to parent Window for the Dialog-Box
5286 * pPortName [I] Name of the Port, that should be configured
5296 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5298 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5302 /******************************************************************************
5303 * ConnectToPrinterDlg (WINSPOOL.@)
5305 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5307 FIXME("%p %lx\n", hWnd, Flags);
5311 /******************************************************************************
5312 * DeletePrinterConnectionA (WINSPOOL.@)
5314 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5316 FIXME("%s\n", debugstr_a(pName));
5320 /******************************************************************************
5321 * DeletePrinterConnectionW (WINSPOOL.@)
5323 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5325 FIXME("%s\n", debugstr_w(pName));
5329 /******************************************************************************
5330 * DeletePrinterDriverExW (WINSPOOL.@)
5332 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5333 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5335 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5336 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5340 /******************************************************************************
5341 * DeletePrinterDriverExA (WINSPOOL.@)
5343 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5344 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5346 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5347 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5351 /******************************************************************************
5352 * DeletePrinterDataExW (WINSPOOL.@)
5354 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5357 FIXME("%p %s %s\n", hPrinter,
5358 debugstr_w(pKeyName), debugstr_w(pValueName));
5359 return ERROR_INVALID_PARAMETER;
5362 /******************************************************************************
5363 * DeletePrinterDataExA (WINSPOOL.@)
5365 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5368 FIXME("%p %s %s\n", hPrinter,
5369 debugstr_a(pKeyName), debugstr_a(pValueName));
5370 return ERROR_INVALID_PARAMETER;
5373 /******************************************************************************
5374 * DeletePrintProcessorA (WINSPOOL.@)
5376 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5378 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5379 debugstr_a(pPrintProcessorName));
5383 /******************************************************************************
5384 * DeletePrintProcessorW (WINSPOOL.@)
5386 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5388 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5389 debugstr_w(pPrintProcessorName));
5393 /******************************************************************************
5394 * DeletePrintProvidorA (WINSPOOL.@)
5396 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5398 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5399 debugstr_a(pPrintProviderName));
5403 /******************************************************************************
5404 * DeletePrintProvidorW (WINSPOOL.@)
5406 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5408 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5409 debugstr_w(pPrintProviderName));
5413 /******************************************************************************
5414 * EnumFormsA (WINSPOOL.@)
5416 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5417 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5419 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5423 /******************************************************************************
5424 * EnumFormsW (WINSPOOL.@)
5426 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5427 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5429 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5433 /*****************************************************************************
5434 * EnumMonitorsA [WINSPOOL.@]
5436 * See EnumMonitorsW.
5439 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5440 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5443 LPBYTE bufferW = NULL;
5444 LPWSTR nameW = NULL;
5446 DWORD numentries = 0;
5449 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5450 cbBuf, pcbNeeded, pcReturned);
5452 /* convert servername to unicode */
5454 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5455 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5456 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5458 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5459 needed = cbBuf * sizeof(WCHAR);
5460 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5461 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5463 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5464 if (pcbNeeded) needed = *pcbNeeded;
5465 /* HeapReAlloc return NULL, when bufferW was NULL */
5466 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5467 HeapAlloc(GetProcessHeap(), 0, needed);
5469 /* Try again with the large Buffer */
5470 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5472 numentries = pcReturned ? *pcReturned : 0;
5475 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5476 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5479 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5480 DWORD entrysize = 0;
5483 LPMONITOR_INFO_2W mi2w;
5484 LPMONITOR_INFO_2A mi2a;
5486 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5487 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5489 /* First pass: calculate the size for all Entries */
5490 mi2w = (LPMONITOR_INFO_2W) bufferW;
5491 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5493 while (index < numentries) {
5495 needed += entrysize; /* MONITOR_INFO_?A */
5496 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5498 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5499 NULL, 0, NULL, NULL);
5501 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5502 NULL, 0, NULL, NULL);
5503 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5504 NULL, 0, NULL, NULL);
5506 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5507 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5508 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5511 /* check for errors and quit on failure */
5512 if (cbBuf < needed) {
5513 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5517 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5518 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5519 cbBuf -= len ; /* free Bytes in the user-Buffer */
5520 mi2w = (LPMONITOR_INFO_2W) bufferW;
5521 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5523 /* Second Pass: Fill the User Buffer (if we have one) */
5524 while ((index < numentries) && pMonitors) {
5526 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5528 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5529 ptr, cbBuf , NULL, NULL);
5533 mi2a->pEnvironment = ptr;
5534 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5535 ptr, cbBuf, NULL, NULL);
5539 mi2a->pDLLName = ptr;
5540 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5541 ptr, cbBuf, NULL, NULL);
5545 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5546 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5547 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5551 if (pcbNeeded) *pcbNeeded = needed;
5552 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5554 HeapFree(GetProcessHeap(), 0, nameW);
5555 HeapFree(GetProcessHeap(), 0, bufferW);
5557 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5558 (res), GetLastError(), needed, numentries);
5564 /*****************************************************************************
5565 * EnumMonitorsW [WINSPOOL.@]
5567 * Enumerate available Port-Monitors
5570 * pName [I] Servername or NULL (local Computer)
5571 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5572 * pMonitors [O] PTR to Buffer that receives the Result
5573 * cbBuf [I] Size of Buffer at pMonitors
5574 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5575 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5579 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5582 * Windows reads the Registry once and cache the Results.
5584 *| Language-Monitors are also installed in the same Registry-Location but
5585 *| they are filtered in Windows (not returned by EnumMonitors).
5586 *| We do no filtering to simplify our Code.
5589 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5590 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5593 DWORD numentries = 0;
5596 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5597 cbBuf, pcbNeeded, pcReturned);
5599 if (pName && (lstrlenW(pName))) {
5600 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5601 SetLastError(ERROR_ACCESS_DENIED);
5605 /* Level is not checked in win9x */
5606 if (!Level || (Level > 2)) {
5607 WARN("level (%ld) is ignored in win9x\n", Level);
5608 SetLastError(ERROR_INVALID_LEVEL);
5612 SetLastError(RPC_X_NULL_REF_POINTER);
5616 /* Scan all Monitor-Keys */
5618 needed = get_local_monitors(Level, NULL, 0, &numentries);
5620 /* we calculated the needed buffersize. now do the error-checks */
5621 if (cbBuf < needed) {
5622 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5625 else if (!pMonitors || !pcReturned) {
5626 SetLastError(RPC_X_NULL_REF_POINTER);
5630 /* fill the Buffer with the Monitor-Keys */
5631 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5635 if (pcbNeeded) *pcbNeeded = needed;
5636 if (pcReturned) *pcReturned = numentries;
5638 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5639 res, GetLastError(), needed, numentries);
5644 /******************************************************************************
5645 * XcvDataW (WINSPOOL.@)
5648 * There doesn't seem to be an A version...
5650 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5651 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5652 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5654 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5655 pInputData, cbInputData, pOutputData,
5656 cbOutputData, pcbOutputNeeded, pdwStatus);
5660 /*****************************************************************************
5661 * EnumPrinterDataA [WINSPOOL.@]
5664 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5665 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5666 DWORD cbData, LPDWORD pcbData )
5668 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5669 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5670 return ERROR_NO_MORE_ITEMS;
5673 /*****************************************************************************
5674 * EnumPrinterDataW [WINSPOOL.@]
5677 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5678 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5679 DWORD cbData, LPDWORD pcbData )
5681 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5682 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5683 return ERROR_NO_MORE_ITEMS;
5686 /*****************************************************************************
5687 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5690 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5691 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5692 LPDWORD pcbNeeded, LPDWORD pcReturned)
5694 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5695 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5696 pcbNeeded, pcReturned);
5700 /*****************************************************************************
5701 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5704 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5705 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5706 LPDWORD pcbNeeded, LPDWORD pcReturned)
5708 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5709 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5710 pcbNeeded, pcReturned);
5714 /*****************************************************************************
5715 * EnumPrintProcessorsA [WINSPOOL.@]
5718 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5719 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5721 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5722 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5726 /*****************************************************************************
5727 * EnumPrintProcessorsW [WINSPOOL.@]
5730 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5731 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5733 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5734 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5735 cbBuf, pcbNeeded, pcbReturned);
5739 /*****************************************************************************
5740 * ExtDeviceMode [WINSPOOL.@]
5743 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5744 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5747 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5748 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5749 debugstr_a(pProfile), fMode);
5753 /*****************************************************************************
5754 * FindClosePrinterChangeNotification [WINSPOOL.@]
5757 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5759 FIXME("Stub: %p\n", hChange);
5763 /*****************************************************************************
5764 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5767 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5768 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5770 FIXME("Stub: %p %lx %lx %p\n",
5771 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5772 return INVALID_HANDLE_VALUE;
5775 /*****************************************************************************
5776 * FindNextPrinterChangeNotification [WINSPOOL.@]
5779 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5780 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5782 FIXME("Stub: %p %p %p %p\n",
5783 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5787 /*****************************************************************************
5788 * FreePrinterNotifyInfo [WINSPOOL.@]
5791 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5793 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5797 /*****************************************************************************
5800 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5801 * ansi depending on the unicode parameter.
5803 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5813 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5816 memcpy(ptr, str, *size);
5823 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5826 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5833 /*****************************************************************************
5836 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5837 LPDWORD pcbNeeded, BOOL unicode)
5839 DWORD size, left = cbBuf;
5840 BOOL space = (cbBuf > 0);
5847 ji1->JobId = job->job_id;
5850 string_to_buf(job->document_title, ptr, left, &size, unicode);
5851 if(space && size <= left)
5853 ji1->pDocument = (LPWSTR)ptr;
5864 /*****************************************************************************
5867 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5868 LPDWORD pcbNeeded, BOOL unicode)
5870 DWORD size, left = cbBuf;
5871 BOOL space = (cbBuf > 0);
5878 ji2->JobId = job->job_id;
5881 string_to_buf(job->document_title, ptr, left, &size, unicode);
5882 if(space && size <= left)
5884 ji2->pDocument = (LPWSTR)ptr;
5895 /*****************************************************************************
5898 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5899 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5902 DWORD needed = 0, size;
5906 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5908 EnterCriticalSection(&printer_handles_cs);
5909 job = get_job(hPrinter, JobId);
5916 size = sizeof(JOB_INFO_1W);
5921 memset(pJob, 0, size);
5925 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5930 size = sizeof(JOB_INFO_2W);
5935 memset(pJob, 0, size);
5939 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5944 size = sizeof(JOB_INFO_3);
5948 memset(pJob, 0, size);
5957 SetLastError(ERROR_INVALID_LEVEL);
5961 *pcbNeeded = needed;
5963 LeaveCriticalSection(&printer_handles_cs);
5967 /*****************************************************************************
5968 * GetJobA [WINSPOOL.@]
5971 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5972 DWORD cbBuf, LPDWORD pcbNeeded)
5974 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5977 /*****************************************************************************
5978 * GetJobW [WINSPOOL.@]
5981 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5982 DWORD cbBuf, LPDWORD pcbNeeded)
5984 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5987 /*****************************************************************************
5990 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5992 char *unixname, *queue, *cmd;
5993 char fmt[] = "lpr -P%s %s";
5996 if(!(unixname = wine_get_unix_file_name(filename)))
5999 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6000 queue = HeapAlloc(GetProcessHeap(), 0, len);
6001 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6003 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6004 sprintf(cmd, fmt, queue, unixname);
6006 TRACE("printing with: %s\n", cmd);
6009 HeapFree(GetProcessHeap(), 0, cmd);
6010 HeapFree(GetProcessHeap(), 0, queue);
6011 HeapFree(GetProcessHeap(), 0, unixname);
6015 /*****************************************************************************
6018 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6020 #if HAVE_CUPS_CUPS_H
6023 char *unixname, *queue, *doc_titleA;
6027 if(!(unixname = wine_get_unix_file_name(filename)))
6030 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6031 queue = HeapAlloc(GetProcessHeap(), 0, len);
6032 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6034 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6035 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6036 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6038 TRACE("printing via cups\n");
6039 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6040 HeapFree(GetProcessHeap(), 0, doc_titleA);
6041 HeapFree(GetProcessHeap(), 0, queue);
6042 HeapFree(GetProcessHeap(), 0, unixname);
6048 return schedule_lpr(printer_name, filename);
6052 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6059 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6063 if(HIWORD(wparam) == BN_CLICKED)
6065 if(LOWORD(wparam) == IDOK)
6068 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6071 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6072 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6074 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6076 WCHAR caption[200], message[200];
6079 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6080 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6081 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6082 if(mb_ret == IDCANCEL)
6084 HeapFree(GetProcessHeap(), 0, filename);
6088 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6089 if(hf == INVALID_HANDLE_VALUE)
6091 WCHAR caption[200], message[200];
6093 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6094 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6095 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6096 HeapFree(GetProcessHeap(), 0, filename);
6100 DeleteFileW(filename);
6101 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6103 EndDialog(hwnd, IDOK);
6106 if(LOWORD(wparam) == IDCANCEL)
6108 EndDialog(hwnd, IDCANCEL);
6117 /*****************************************************************************
6120 static BOOL get_filename(LPWSTR *filename)
6122 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6123 file_dlg_proc, (LPARAM)filename) == IDOK;
6126 /*****************************************************************************
6129 static BOOL schedule_file(LPCWSTR filename)
6131 LPWSTR output = NULL;
6133 if(get_filename(&output))
6135 TRACE("copy to %s\n", debugstr_w(output));
6136 CopyFileW(filename, output, FALSE);
6137 HeapFree(GetProcessHeap(), 0, output);
6143 /*****************************************************************************
6146 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6149 char *unixname, *cmdA;
6151 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6155 if(!(unixname = wine_get_unix_file_name(filename)))
6158 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6159 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6160 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6162 TRACE("printing with: %s\n", cmdA);
6164 if((file_fd = open(unixname, O_RDONLY)) == -1)
6169 ERR("pipe() failed!\n");
6179 /* reset signals that we previously set to SIG_IGN */
6180 signal(SIGPIPE, SIG_DFL);
6181 signal(SIGCHLD, SIG_DFL);
6187 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6188 write(fds[1], buf, no_read);
6193 if(file_fd != -1) close(file_fd);
6194 if(fds[0] != -1) close(fds[0]);
6195 if(fds[1] != -1) close(fds[1]);
6197 HeapFree(GetProcessHeap(), 0, cmdA);
6198 HeapFree(GetProcessHeap(), 0, unixname);
6205 /*****************************************************************************
6208 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6210 int in_fd, out_fd, no_read;
6213 char *unixname, *outputA;
6216 if(!(unixname = wine_get_unix_file_name(filename)))
6219 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6220 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6221 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6223 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6224 in_fd = open(unixname, O_RDONLY);
6225 if(out_fd == -1 || in_fd == -1)
6228 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6229 write(out_fd, buf, no_read);
6233 if(in_fd != -1) close(in_fd);
6234 if(out_fd != -1) close(out_fd);
6235 HeapFree(GetProcessHeap(), 0, outputA);
6236 HeapFree(GetProcessHeap(), 0, unixname);
6240 /*****************************************************************************
6241 * ScheduleJob [WINSPOOL.@]
6244 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6246 opened_printer_t *printer;
6248 struct list *cursor, *cursor2;
6250 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6251 EnterCriticalSection(&printer_handles_cs);
6252 printer = get_opened_printer(hPrinter);
6256 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6258 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6261 if(job->job_id != dwJobID) continue;
6263 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6264 if(hf != INVALID_HANDLE_VALUE)
6266 PRINTER_INFO_5W *pi5;
6270 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6271 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6273 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6274 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6275 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6276 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6277 debugstr_w(pi5->pPortName));
6281 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6282 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6284 DWORD type, count = sizeof(output);
6285 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6288 if(output[0] == '|')
6290 schedule_pipe(output + 1, job->filename);
6294 schedule_unixfile(output, job->filename);
6296 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6298 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6300 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6302 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6304 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6306 schedule_file(job->filename);
6310 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6312 HeapFree(GetProcessHeap(), 0, pi5);
6314 DeleteFileW(job->filename);
6316 list_remove(cursor);
6317 HeapFree(GetProcessHeap(), 0, job->document_title);
6318 HeapFree(GetProcessHeap(), 0, job->filename);
6319 HeapFree(GetProcessHeap(), 0, job);
6324 LeaveCriticalSection(&printer_handles_cs);
6328 /*****************************************************************************
6329 * StartDocDlgA [WINSPOOL.@]
6331 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6333 UNICODE_STRING usBuffer;
6338 docW.cbSize = sizeof(docW);
6339 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6340 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6341 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6342 docW.fwType = doc->fwType;
6344 retW = StartDocDlgW(hPrinter, &docW);
6348 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6349 ret = HeapAlloc(GetProcessHeap(), 0, len);
6350 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6351 HeapFree(GetProcessHeap(), 0, retW);
6354 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6355 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6356 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6361 /*****************************************************************************
6362 * StartDocDlgW [WINSPOOL.@]
6364 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6365 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6366 * port is "FILE:". Also returns the full path if passed a relative path.
6368 * The caller should free the returned string from the process heap.
6370 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6375 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6377 PRINTER_INFO_5W *pi5;
6378 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6379 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6381 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6382 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6383 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6385 HeapFree(GetProcessHeap(), 0, pi5);
6388 HeapFree(GetProcessHeap(), 0, pi5);
6391 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6394 get_filename(&name);
6397 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6399 HeapFree(GetProcessHeap(), 0, name);
6402 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6403 GetFullPathNameW(name, len, ret, NULL);
6404 HeapFree(GetProcessHeap(), 0, name);
6409 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6412 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6413 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6415 attr = GetFileAttributesW(ret);
6416 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6418 HeapFree(GetProcessHeap(), 0, ret);