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 | KEY_QUERY_VALUE, NULL, &hentry,
1485 &disposition) == ERROR_SUCCESS) {
1487 /* Some installers set options for the port before calling AddMonitor.
1488 We query the "Driver" entry to verify that the monitor is installed,
1489 before we return an error.
1490 When a user installs two print monitors at the same time with the
1491 same name but with a different driver DLL and a task switch comes
1492 between RegQueryValueExW and RegSetValueExW, a race condition
1493 is possible but silently ignored. */
1497 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1498 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
1499 &namesize) == ERROR_SUCCESS)) {
1500 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1501 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1502 9x: ERROR_ALREADY_EXISTS (183) */
1503 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1508 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1509 res = (RegSetValueExW(hentry, DriverW, 0,
1510 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1512 RegCloseKey(hentry);
1519 /******************************************************************
1520 * DeletePrinterDriverA [WINSPOOL.@]
1524 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1526 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1527 debugstr_a(pDriverName));
1528 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1532 /******************************************************************
1533 * DeletePrinterDriverW [WINSPOOL.@]
1537 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1539 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1540 debugstr_w(pDriverName));
1541 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1545 /******************************************************************
1546 * DeleteMonitorA [WINSPOOL.@]
1548 * See DeleteMonitorW.
1551 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1553 LPWSTR nameW = NULL;
1554 LPWSTR EnvironmentW = NULL;
1555 LPWSTR MonitorNameW = NULL;
1560 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1561 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1562 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1566 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1567 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1568 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1571 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1572 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1573 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1576 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1578 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1579 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1580 HeapFree(GetProcessHeap(), 0, nameW);
1584 /******************************************************************
1585 * DeleteMonitorW [WINSPOOL.@]
1587 * Delete a specific Printmonitor from a Printing-Environment
1590 * pName [I] Servername or NULL (local Computer)
1591 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1592 * pMonitorName [I] Name of the Monitor, that should be deleted
1599 * pEnvironment is ignored in Windows for the local Computer.
1603 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1607 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1608 debugstr_w(pMonitorName));
1610 if (pName && (pName[0])) {
1611 FIXME("for server %s not implemented\n", debugstr_w(pName));
1612 SetLastError(ERROR_ACCESS_DENIED);
1616 /* pEnvironment is ignored in Windows for the local Computer */
1618 if (!pMonitorName || !pMonitorName[0]) {
1619 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1620 SetLastError(ERROR_INVALID_PARAMETER);
1624 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1625 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1629 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1630 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1631 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1636 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1639 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1640 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1644 /******************************************************************
1645 * DeletePortA [WINSPOOL.@]
1651 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1653 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1654 debugstr_a(pPortName));
1655 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1659 /******************************************************************
1660 * DeletePortW [WINSPOOL.@]
1662 * Delete a specific Port
1665 * pName [I] Servername or NULL (local Computer)
1666 * hWnd [I] Handle to parent Window for the Dialog-Box
1667 * pPortName [I] Name of the Port, that should be deleted
1678 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1680 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1681 debugstr_w(pPortName));
1682 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1686 /******************************************************************************
1687 * SetPrinterW [WINSPOOL.@]
1689 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1691 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1692 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1696 /******************************************************************************
1697 * WritePrinter [WINSPOOL.@]
1699 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1701 opened_printer_t *printer;
1704 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1706 EnterCriticalSection(&printer_handles_cs);
1707 printer = get_opened_printer(hPrinter);
1710 SetLastError(ERROR_INVALID_HANDLE);
1716 SetLastError(ERROR_SPL_NO_STARTDOC);
1720 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1722 LeaveCriticalSection(&printer_handles_cs);
1726 /*****************************************************************************
1727 * AddFormA [WINSPOOL.@]
1729 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1731 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1735 /*****************************************************************************
1736 * AddFormW [WINSPOOL.@]
1738 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1740 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1744 /*****************************************************************************
1745 * AddJobA [WINSPOOL.@]
1747 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1750 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1754 SetLastError(ERROR_INVALID_LEVEL);
1758 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1761 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1762 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1763 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1764 if(*pcbNeeded > cbBuf) {
1765 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1768 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1769 addjobA->JobId = addjobW->JobId;
1770 addjobA->Path = (char *)(addjobA + 1);
1771 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1777 /*****************************************************************************
1778 * AddJobW [WINSPOOL.@]
1780 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1782 opened_printer_t *printer;
1785 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1786 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1787 WCHAR path[MAX_PATH], filename[MAX_PATH];
1789 ADDJOB_INFO_1W *addjob;
1791 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1793 EnterCriticalSection(&printer_handles_cs);
1795 printer = get_opened_printer(hPrinter);
1798 SetLastError(ERROR_INVALID_HANDLE);
1803 SetLastError(ERROR_INVALID_LEVEL);
1807 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1811 job->job_id = InterlockedIncrement(&next_job_id);
1813 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1814 if(path[len - 1] != '\\')
1816 memcpy(path + len, spool_path, sizeof(spool_path));
1817 sprintfW(filename, fmtW, path, job->job_id);
1819 len = strlenW(filename);
1820 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1821 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1822 job->document_title = strdupW(default_doc_title);
1823 list_add_tail(&printer->queue->jobs, &job->entry);
1825 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1826 if(*pcbNeeded <= cbBuf) {
1827 addjob = (ADDJOB_INFO_1W*)pData;
1828 addjob->JobId = job->job_id;
1829 addjob->Path = (WCHAR *)(addjob + 1);
1830 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1833 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1836 LeaveCriticalSection(&printer_handles_cs);
1840 /*****************************************************************************
1841 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1843 * Return the PATH for the Print-Processors
1845 * See GetPrintProcessorDirectoryW.
1849 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1850 DWORD level, LPBYTE Info,
1851 DWORD cbBuf, LPDWORD pcbNeeded)
1853 LPWSTR serverW = NULL;
1858 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(server),
1859 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
1863 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
1864 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1865 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
1869 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
1870 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1871 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
1874 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
1875 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
1877 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
1880 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
1881 cbBuf, NULL, NULL) > 0;
1884 TRACE(" required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
1885 HeapFree(GetProcessHeap(), 0, envW);
1886 HeapFree(GetProcessHeap(), 0, serverW);
1890 /*****************************************************************************
1891 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1893 * Return the PATH for the Print-Processors
1896 * server [I] Servername (NT only) or NULL (local Computer)
1897 * env [I] Printing-Environment (see below) or NULL (Default)
1898 * level [I] Structure-Level (must be 1)
1899 * Info [O] PTR to Buffer that receives the Result
1900 * cbBuf [I] Size of Buffer at "Info"
1901 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1902 * required for the Buffer at "Info"
1905 * Success: TRUE and in pcbNeeded the Bytes used in Info
1906 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
1907 * if cbBuf is too small
1909 * Native Values returned in Info on Success:
1910 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
1911 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
1912 *| win9x(Windows 4.0): "%winsysdir%"
1914 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1917 * Only NULL or "" is supported for server
1920 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1921 DWORD level, LPBYTE Info,
1922 DWORD cbBuf, LPDWORD pcbNeeded)
1925 const printenv_t * env_t;
1927 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
1928 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
1930 if(server != NULL && server[0]) {
1931 FIXME("server not supported: %s\n", debugstr_w(server));
1932 SetLastError(ERROR_INVALID_PARAMETER);
1936 env_t = validate_envW(env);
1937 if(!env_t) return FALSE; /* environment invalid or unsupported */
1940 WARN("(Level: %ld) is ignored in win9x\n", level);
1941 SetLastError(ERROR_INVALID_LEVEL);
1945 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1946 needed = GetSystemDirectoryW(NULL, 0);
1947 /* add the Size for the Subdirectories */
1948 needed += lstrlenW(spoolprtprocsW);
1949 needed += lstrlenW(env_t->subdir);
1950 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1952 if(pcbNeeded) *pcbNeeded = needed;
1953 TRACE ("required: 0x%lx/%ld\n", needed, needed);
1954 if (needed > cbBuf) {
1955 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1958 if(pcbNeeded == NULL) {
1959 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
1960 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
1961 SetLastError(RPC_X_NULL_REF_POINTER);
1965 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
1966 SetLastError(RPC_X_NULL_REF_POINTER);
1970 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
1971 /* add the Subdirectories */
1972 lstrcatW((LPWSTR) Info, spoolprtprocsW);
1973 lstrcatW((LPWSTR) Info, env_t->subdir);
1974 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
1978 /*****************************************************************************
1979 * WINSPOOL_OpenDriverReg [internal]
1981 * opens the registry for the printer drivers depending on the given input
1982 * variable pEnvironment
1985 * the opened hkey on success
1988 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1992 const printenv_t * env;
1995 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
1997 if (!pEnvironment || unicode) {
1998 /* pEnvironment was NULL or an Unicode-String: use it direct */
1999 env = validate_envW(pEnvironment);
2003 /* pEnvironment was an ANSI-String: convert to unicode first */
2005 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2006 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2007 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2008 env = validate_envW(buffer);
2009 HeapFree(GetProcessHeap(), 0, buffer);
2011 if (!env) return NULL;
2013 buffer = HeapAlloc( GetProcessHeap(), 0,
2014 (strlenW(DriversW) + strlenW(env->envname) +
2015 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2017 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2018 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2019 HeapFree(GetProcessHeap(), 0, buffer);
2024 /*****************************************************************************
2025 * AddPrinterW [WINSPOOL.@]
2027 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2029 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2033 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2036 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
2039 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2040 SetLastError(ERROR_INVALID_PARAMETER);
2044 ERR("Level = %ld, unsupported!\n", Level);
2045 SetLastError(ERROR_INVALID_LEVEL);
2049 SetLastError(ERROR_INVALID_PARAMETER);
2052 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2054 ERR("Can't create Printers key\n");
2057 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2058 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2059 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2060 RegCloseKey(hkeyPrinter);
2061 RegCloseKey(hkeyPrinters);
2064 RegCloseKey(hkeyPrinter);
2066 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2068 ERR("Can't create Drivers key\n");
2069 RegCloseKey(hkeyPrinters);
2072 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2074 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2075 RegCloseKey(hkeyPrinters);
2076 RegCloseKey(hkeyDrivers);
2077 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2080 RegCloseKey(hkeyDriver);
2081 RegCloseKey(hkeyDrivers);
2083 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2084 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2085 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2086 RegCloseKey(hkeyPrinters);
2090 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2092 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2093 SetLastError(ERROR_INVALID_PRINTER_NAME);
2094 RegCloseKey(hkeyPrinters);
2097 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2098 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2099 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2101 /* See if we can load the driver. We may need the devmode structure anyway
2104 * Note that DocumentPropertiesW will briefly try to open the printer we
2105 * just create to find a DEVMODEA struct (it will use the WINEPS default
2106 * one in case it is not there, so we are ok).
2108 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2111 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2112 size = sizeof(DEVMODEW);
2118 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2119 ZeroMemory(dmW,size);
2121 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2123 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2124 HeapFree(GetProcessHeap(),0,dmW);
2129 /* set devmode to printer name */
2130 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2134 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2135 and we support these drivers. NT writes DEVMODEW so somehow
2136 we'll need to distinguish between these when we support NT
2140 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2141 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2142 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2143 HeapFree(GetProcessHeap(), 0, dmA);
2145 HeapFree(GetProcessHeap(), 0, dmW);
2147 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2148 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2149 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2150 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2152 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2153 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2154 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2155 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2156 (LPBYTE)&pi->Priority, sizeof(DWORD));
2157 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2158 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2159 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2160 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2161 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2162 (LPBYTE)&pi->Status, sizeof(DWORD));
2163 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2164 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2166 RegCloseKey(hkeyPrinter);
2167 RegCloseKey(hkeyPrinters);
2168 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2169 ERR("OpenPrinter failing\n");
2175 /*****************************************************************************
2176 * AddPrinterA [WINSPOOL.@]
2178 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2180 UNICODE_STRING pNameW;
2182 PRINTER_INFO_2W *piW;
2183 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2186 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2188 ERR("Level = %ld, unsupported!\n", Level);
2189 SetLastError(ERROR_INVALID_LEVEL);
2192 pwstrNameW = asciitounicode(&pNameW,pName);
2193 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2195 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2197 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2198 RtlFreeUnicodeString(&pNameW);
2203 /*****************************************************************************
2204 * ClosePrinter [WINSPOOL.@]
2206 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2208 UINT_PTR i = (UINT_PTR)hPrinter;
2209 opened_printer_t *printer = NULL;
2212 TRACE("Handle %p\n", hPrinter);
2214 EnterCriticalSection(&printer_handles_cs);
2216 if ((i > 0) && (i <= nb_printer_handles))
2217 printer = printer_handles[i - 1];
2221 struct list *cursor, *cursor2;
2224 EndDocPrinter(hPrinter);
2226 if(InterlockedDecrement(&printer->queue->ref) == 0)
2228 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2230 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2231 ScheduleJob(hPrinter, job->job_id);
2233 HeapFree(GetProcessHeap(), 0, printer->queue);
2235 HeapFree(GetProcessHeap(), 0, printer->name);
2236 HeapFree(GetProcessHeap(), 0, printer);
2237 printer_handles[i - 1] = NULL;
2240 LeaveCriticalSection(&printer_handles_cs);
2244 /*****************************************************************************
2245 * DeleteFormA [WINSPOOL.@]
2247 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2249 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2253 /*****************************************************************************
2254 * DeleteFormW [WINSPOOL.@]
2256 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2258 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2262 /*****************************************************************************
2263 * WINSPOOL_SHRegDeleteKey
2265 * Recursively delete subkeys.
2266 * Cut & paste from shlwapi.
2269 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2271 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2272 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2275 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2278 /* Find how many subkeys there are */
2279 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2280 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2284 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2285 /* Name too big: alloc a buffer for it */
2286 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2289 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2292 /* Recursively delete all the subkeys */
2293 for(i = 0; i < dwKeyCount && !dwRet; i++)
2295 dwSize = dwMaxSubkeyLen;
2296 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2298 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2301 if (lpszName != szNameBuf)
2302 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2306 RegCloseKey(hSubKey);
2308 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2313 /*****************************************************************************
2314 * DeletePrinter [WINSPOOL.@]
2316 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2318 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2319 HKEY hkeyPrinters, hkey;
2322 SetLastError(ERROR_INVALID_HANDLE);
2325 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2326 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2327 RegCloseKey(hkeyPrinters);
2329 WriteProfileStringW(devicesW, lpNameW, NULL);
2330 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2331 RegDeleteValueW(hkey, lpNameW);
2337 /*****************************************************************************
2338 * SetPrinterA [WINSPOOL.@]
2340 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2343 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2347 /*****************************************************************************
2348 * SetJobA [WINSPOOL.@]
2350 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2351 LPBYTE pJob, DWORD Command)
2355 UNICODE_STRING usBuffer;
2357 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2359 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2360 are all ignored by SetJob, so we don't bother copying them */
2368 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2369 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2371 JobW = (LPBYTE)info1W;
2372 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2373 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2374 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2375 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2376 info1W->Status = info1A->Status;
2377 info1W->Priority = info1A->Priority;
2378 info1W->Position = info1A->Position;
2379 info1W->PagesPrinted = info1A->PagesPrinted;
2384 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2385 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2387 JobW = (LPBYTE)info2W;
2388 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2389 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2390 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2391 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2392 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2393 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2394 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2395 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2396 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2397 info2W->Status = info2A->Status;
2398 info2W->Priority = info2A->Priority;
2399 info2W->Position = info2A->Position;
2400 info2W->StartTime = info2A->StartTime;
2401 info2W->UntilTime = info2A->UntilTime;
2402 info2W->PagesPrinted = info2A->PagesPrinted;
2406 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2407 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2410 SetLastError(ERROR_INVALID_LEVEL);
2414 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2420 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2421 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2422 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2423 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2424 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2429 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2430 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2431 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2432 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2433 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2434 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2435 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2436 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2437 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2441 HeapFree(GetProcessHeap(), 0, JobW);
2446 /*****************************************************************************
2447 * SetJobW [WINSPOOL.@]
2449 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2450 LPBYTE pJob, DWORD Command)
2455 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2456 FIXME("Ignoring everything other than document title\n");
2458 EnterCriticalSection(&printer_handles_cs);
2459 job = get_job(hPrinter, JobId);
2469 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2470 HeapFree(GetProcessHeap(), 0, job->document_title);
2471 job->document_title = strdupW(info1->pDocument);
2476 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2477 HeapFree(GetProcessHeap(), 0, job->document_title);
2478 job->document_title = strdupW(info2->pDocument);
2484 SetLastError(ERROR_INVALID_LEVEL);
2489 LeaveCriticalSection(&printer_handles_cs);
2493 /*****************************************************************************
2494 * EndDocPrinter [WINSPOOL.@]
2496 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2498 opened_printer_t *printer;
2500 TRACE("(%p)\n", hPrinter);
2502 EnterCriticalSection(&printer_handles_cs);
2504 printer = get_opened_printer(hPrinter);
2507 SetLastError(ERROR_INVALID_HANDLE);
2513 SetLastError(ERROR_SPL_NO_STARTDOC);
2517 CloseHandle(printer->doc->hf);
2518 ScheduleJob(hPrinter, printer->doc->job_id);
2519 HeapFree(GetProcessHeap(), 0, printer->doc);
2520 printer->doc = NULL;
2523 LeaveCriticalSection(&printer_handles_cs);
2527 /*****************************************************************************
2528 * EndPagePrinter [WINSPOOL.@]
2530 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2532 FIXME("(%p): stub\n", hPrinter);
2536 /*****************************************************************************
2537 * StartDocPrinterA [WINSPOOL.@]
2539 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2541 UNICODE_STRING usBuffer;
2543 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2546 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2547 or one (DOC_INFO_3) extra DWORDs */
2551 doc2W.JobId = doc2->JobId;
2554 doc2W.dwMode = doc2->dwMode;
2557 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2558 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2559 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2563 SetLastError(ERROR_INVALID_LEVEL);
2567 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2569 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2570 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2571 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2576 /*****************************************************************************
2577 * StartDocPrinterW [WINSPOOL.@]
2579 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2581 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2582 opened_printer_t *printer;
2583 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2584 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2585 JOB_INFO_1W job_info;
2586 DWORD needed, ret = 0;
2590 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2591 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2592 debugstr_w(doc->pDatatype));
2594 if(Level < 1 || Level > 3)
2596 SetLastError(ERROR_INVALID_LEVEL);
2600 EnterCriticalSection(&printer_handles_cs);
2601 printer = get_opened_printer(hPrinter);
2604 SetLastError(ERROR_INVALID_HANDLE);
2610 SetLastError(ERROR_INVALID_PRINTER_STATE);
2614 /* Even if we're printing to a file we still add a print job, we'll
2615 just ignore the spool file name */
2617 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2619 ERR("AddJob failed gle %08lx\n", GetLastError());
2623 if(doc->pOutputFile)
2624 filename = doc->pOutputFile;
2626 filename = addjob->Path;
2628 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2629 if(hf == INVALID_HANDLE_VALUE)
2632 memset(&job_info, 0, sizeof(job_info));
2633 job_info.pDocument = doc->pDocName;
2634 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2636 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2637 printer->doc->hf = hf;
2638 ret = printer->doc->job_id = addjob->JobId;
2640 LeaveCriticalSection(&printer_handles_cs);
2645 /*****************************************************************************
2646 * StartPagePrinter [WINSPOOL.@]
2648 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2650 FIXME("(%p): stub\n", hPrinter);
2654 /*****************************************************************************
2655 * GetFormA [WINSPOOL.@]
2657 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2658 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2660 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2661 Level,pForm,cbBuf,pcbNeeded);
2665 /*****************************************************************************
2666 * GetFormW [WINSPOOL.@]
2668 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2669 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2671 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2672 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2676 /*****************************************************************************
2677 * SetFormA [WINSPOOL.@]
2679 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2682 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2686 /*****************************************************************************
2687 * SetFormW [WINSPOOL.@]
2689 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2692 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2696 /*****************************************************************************
2697 * ReadPrinter [WINSPOOL.@]
2699 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2700 LPDWORD pNoBytesRead)
2702 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2706 /*****************************************************************************
2707 * ResetPrinterA [WINSPOOL.@]
2709 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2711 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2715 /*****************************************************************************
2716 * ResetPrinterW [WINSPOOL.@]
2718 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2720 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2724 /*****************************************************************************
2725 * WINSPOOL_GetDWORDFromReg
2727 * Return DWORD associated with ValueName from hkey.
2729 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2731 DWORD sz = sizeof(DWORD), type, value = 0;
2734 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2736 if(ret != ERROR_SUCCESS) {
2737 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2740 if(type != REG_DWORD) {
2741 ERR("Got type %ld\n", type);
2747 /*****************************************************************************
2748 * WINSPOOL_GetStringFromReg
2750 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2751 * String is stored either as unicode or ascii.
2752 * Bit of a hack here to get the ValueName if we want ascii.
2754 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2755 DWORD buflen, DWORD *needed,
2758 DWORD sz = buflen, type;
2762 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2764 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2765 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2766 HeapFree(GetProcessHeap(),0,ValueNameA);
2768 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2769 WARN("Got ret = %ld\n", ret);
2773 /* add space for terminating '\0' */
2774 sz += unicode ? sizeof(WCHAR) : 1;
2778 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2783 /*****************************************************************************
2784 * WINSPOOL_GetDefaultDevMode
2786 * Get a default DevMode values for wineps.
2790 static void WINSPOOL_GetDefaultDevMode(
2792 DWORD buflen, DWORD *needed,
2796 static const char szwps[] = "wineps.drv";
2798 /* fill default DEVMODE - should be read from ppd... */
2799 ZeroMemory( &dm, sizeof(dm) );
2800 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2801 dm.dmSpecVersion = DM_SPECVERSION;
2802 dm.dmDriverVersion = 1;
2803 dm.dmSize = sizeof(DEVMODEA);
2804 dm.dmDriverExtra = 0;
2806 DM_ORIENTATION | DM_PAPERSIZE |
2807 DM_PAPERLENGTH | DM_PAPERWIDTH |
2810 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2811 DM_YRESOLUTION | DM_TTOPTION;
2813 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2814 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2815 dm.u1.s1.dmPaperLength = 2970;
2816 dm.u1.s1.dmPaperWidth = 2100;
2820 dm.dmDefaultSource = DMBIN_AUTO;
2821 dm.dmPrintQuality = DMRES_MEDIUM;
2824 dm.dmYResolution = 300; /* 300dpi */
2825 dm.dmTTOption = DMTT_BITMAP;
2828 /* dm.dmLogPixels */
2829 /* dm.dmBitsPerPel */
2830 /* dm.dmPelsWidth */
2831 /* dm.dmPelsHeight */
2832 /* dm.dmDisplayFlags */
2833 /* dm.dmDisplayFrequency */
2834 /* dm.dmICMMethod */
2835 /* dm.dmICMIntent */
2836 /* dm.dmMediaType */
2837 /* dm.dmDitherType */
2838 /* dm.dmReserved1 */
2839 /* dm.dmReserved2 */
2840 /* dm.dmPanningWidth */
2841 /* dm.dmPanningHeight */
2844 if(buflen >= sizeof(DEVMODEW)) {
2845 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2846 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2847 HeapFree(GetProcessHeap(),0,pdmW);
2849 *needed = sizeof(DEVMODEW);
2853 if(buflen >= sizeof(DEVMODEA)) {
2854 memcpy(ptr, &dm, sizeof(DEVMODEA));
2856 *needed = sizeof(DEVMODEA);
2860 /*****************************************************************************
2861 * WINSPOOL_GetDevModeFromReg
2863 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2864 * DevMode is stored either as unicode or ascii.
2866 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2868 DWORD buflen, DWORD *needed,
2871 DWORD sz = buflen, type;
2874 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2875 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2876 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2877 if (sz < sizeof(DEVMODEA))
2879 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2882 /* ensures that dmSize is not erratically bogus if registry is invalid */
2883 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2884 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2886 sz += (CCHDEVICENAME + CCHFORMNAME);
2888 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2889 memcpy(ptr, dmW, sz);
2890 HeapFree(GetProcessHeap(),0,dmW);
2897 /*********************************************************************
2898 * WINSPOOL_GetPrinter_2
2900 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2901 * The strings are either stored as unicode or ascii.
2903 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2904 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2907 DWORD size, left = cbBuf;
2908 BOOL space = (cbBuf > 0);
2913 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2915 if(space && size <= left) {
2916 pi2->pPrinterName = (LPWSTR)ptr;
2923 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2925 if(space && size <= left) {
2926 pi2->pShareName = (LPWSTR)ptr;
2933 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2935 if(space && size <= left) {
2936 pi2->pPortName = (LPWSTR)ptr;
2943 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2945 if(space && size <= left) {
2946 pi2->pDriverName = (LPWSTR)ptr;
2953 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2955 if(space && size <= left) {
2956 pi2->pComment = (LPWSTR)ptr;
2963 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2965 if(space && size <= left) {
2966 pi2->pLocation = (LPWSTR)ptr;
2973 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2975 if(space && size <= left) {
2976 pi2->pDevMode = (LPDEVMODEW)ptr;
2985 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2986 if(space && size <= left) {
2987 pi2->pDevMode = (LPDEVMODEW)ptr;
2994 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2996 if(space && size <= left) {
2997 pi2->pSepFile = (LPWSTR)ptr;
3004 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3006 if(space && size <= left) {
3007 pi2->pPrintProcessor = (LPWSTR)ptr;
3014 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3016 if(space && size <= left) {
3017 pi2->pDatatype = (LPWSTR)ptr;
3024 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3026 if(space && size <= left) {
3027 pi2->pParameters = (LPWSTR)ptr;
3035 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3036 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3037 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3038 "Default Priority");
3039 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3040 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3043 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3044 memset(pi2, 0, sizeof(*pi2));
3049 /*********************************************************************
3050 * WINSPOOL_GetPrinter_4
3052 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3054 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3055 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3058 DWORD size, left = cbBuf;
3059 BOOL space = (cbBuf > 0);
3064 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3066 if(space && size <= left) {
3067 pi4->pPrinterName = (LPWSTR)ptr;
3075 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3078 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3079 memset(pi4, 0, sizeof(*pi4));
3084 /*********************************************************************
3085 * WINSPOOL_GetPrinter_5
3087 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3089 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3090 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3093 DWORD size, left = cbBuf;
3094 BOOL space = (cbBuf > 0);
3099 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3101 if(space && size <= left) {
3102 pi5->pPrinterName = (LPWSTR)ptr;
3109 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3111 if(space && size <= left) {
3112 pi5->pPortName = (LPWSTR)ptr;
3120 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3121 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3123 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3127 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3128 memset(pi5, 0, sizeof(*pi5));
3133 /*****************************************************************************
3134 * WINSPOOL_GetPrinter
3136 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3137 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3138 * just a collection of pointers to strings.
3140 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3141 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3144 DWORD size, needed = 0;
3146 HKEY hkeyPrinter, hkeyPrinters;
3149 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3151 if (!(name = get_opened_printer_name(hPrinter))) {
3152 SetLastError(ERROR_INVALID_HANDLE);
3156 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3158 ERR("Can't create Printers key\n");
3161 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3163 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3164 RegCloseKey(hkeyPrinters);
3165 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3172 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3174 size = sizeof(PRINTER_INFO_2W);
3176 ptr = pPrinter + size;
3178 memset(pPrinter, 0, size);
3183 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3191 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3193 size = sizeof(PRINTER_INFO_4W);
3195 ptr = pPrinter + size;
3197 memset(pPrinter, 0, size);
3202 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3211 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3213 size = sizeof(PRINTER_INFO_5W);
3215 ptr = pPrinter + size;
3217 memset(pPrinter, 0, size);
3223 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3230 FIXME("Unimplemented level %ld\n", Level);
3231 SetLastError(ERROR_INVALID_LEVEL);
3232 RegCloseKey(hkeyPrinters);
3233 RegCloseKey(hkeyPrinter);
3237 RegCloseKey(hkeyPrinter);
3238 RegCloseKey(hkeyPrinters);
3240 TRACE("returning %d needed = %ld\n", ret, needed);
3241 if(pcbNeeded) *pcbNeeded = needed;
3243 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3247 /*****************************************************************************
3248 * GetPrinterW [WINSPOOL.@]
3250 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3251 DWORD cbBuf, LPDWORD pcbNeeded)
3253 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3257 /*****************************************************************************
3258 * GetPrinterA [WINSPOOL.@]
3260 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3261 DWORD cbBuf, LPDWORD pcbNeeded)
3263 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3267 /*****************************************************************************
3268 * WINSPOOL_EnumPrinters
3270 * Implementation of EnumPrintersA|W
3272 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3273 DWORD dwLevel, LPBYTE lpbPrinters,
3274 DWORD cbBuf, LPDWORD lpdwNeeded,
3275 LPDWORD lpdwReturned, BOOL unicode)
3278 HKEY hkeyPrinters, hkeyPrinter;
3279 WCHAR PrinterName[255];
3280 DWORD needed = 0, number = 0;
3281 DWORD used, i, left;
3285 memset(lpbPrinters, 0, cbBuf);
3291 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3292 if(dwType == PRINTER_ENUM_DEFAULT)
3295 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3296 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3297 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3298 if(!dwType) return TRUE;
3301 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3302 FIXME("dwType = %08lx\n", dwType);
3303 SetLastError(ERROR_INVALID_FLAGS);
3307 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3309 ERR("Can't create Printers key\n");
3313 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3314 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3315 RegCloseKey(hkeyPrinters);
3316 ERR("Can't query Printers key\n");
3319 TRACE("Found %ld printers\n", number);
3323 RegCloseKey(hkeyPrinters);
3325 *lpdwReturned = number;
3329 used = number * sizeof(PRINTER_INFO_2W);
3332 used = number * sizeof(PRINTER_INFO_4W);
3335 used = number * sizeof(PRINTER_INFO_5W);
3339 SetLastError(ERROR_INVALID_LEVEL);
3340 RegCloseKey(hkeyPrinters);
3343 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3345 for(i = 0; i < number; i++) {
3346 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3348 ERR("Can't enum key number %ld\n", i);
3349 RegCloseKey(hkeyPrinters);
3352 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3353 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3355 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3356 RegCloseKey(hkeyPrinters);
3361 buf = lpbPrinters + used;
3362 left = cbBuf - used;
3370 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3371 left, &needed, unicode);
3373 if(pi) pi += sizeof(PRINTER_INFO_2W);
3376 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3377 left, &needed, unicode);
3379 if(pi) pi += sizeof(PRINTER_INFO_4W);
3382 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3383 left, &needed, unicode);
3385 if(pi) pi += sizeof(PRINTER_INFO_5W);
3388 ERR("Shouldn't be here!\n");
3389 RegCloseKey(hkeyPrinter);
3390 RegCloseKey(hkeyPrinters);
3393 RegCloseKey(hkeyPrinter);
3395 RegCloseKey(hkeyPrinters);
3402 memset(lpbPrinters, 0, cbBuf);
3403 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3407 *lpdwReturned = number;
3408 SetLastError(ERROR_SUCCESS);
3413 /******************************************************************
3414 * EnumPrintersW [WINSPOOL.@]
3416 * Enumerates the available printers, print servers and print
3417 * providers, depending on the specified flags, name and level.
3421 * If level is set to 1:
3422 * Not implemented yet!
3423 * Returns TRUE with an empty list.
3425 * If level is set to 2:
3426 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3427 * Returns an array of PRINTER_INFO_2 data structures in the
3428 * lpbPrinters buffer. Note that according to MSDN also an
3429 * OpenPrinter should be performed on every remote printer.
3431 * If level is set to 4 (officially WinNT only):
3432 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3433 * Fast: Only the registry is queried to retrieve printer names,
3434 * no connection to the driver is made.
3435 * Returns an array of PRINTER_INFO_4 data structures in the
3436 * lpbPrinters buffer.
3438 * If level is set to 5 (officially WinNT4/Win9x only):
3439 * Fast: Only the registry is queried to retrieve printer names,
3440 * no connection to the driver is made.
3441 * Returns an array of PRINTER_INFO_5 data structures in the
3442 * lpbPrinters buffer.
3444 * If level set to 3 or 6+:
3445 * returns zero (failure!)
3447 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3451 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3452 * - Only levels 2, 4 and 5 are implemented at the moment.
3453 * - 16-bit printer drivers are not enumerated.
3454 * - Returned amount of bytes used/needed does not match the real Windoze
3455 * implementation (as in this implementation, all strings are part
3456 * of the buffer, whereas Win32 keeps them somewhere else)
3457 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3460 * - In a regular Wine installation, no registry settings for printers
3461 * exist, which makes this function return an empty list.
3463 BOOL WINAPI EnumPrintersW(
3464 DWORD dwType, /* [in] Types of print objects to enumerate */
3465 LPWSTR lpszName, /* [in] name of objects to enumerate */
3466 DWORD dwLevel, /* [in] type of printer info structure */
3467 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3468 DWORD cbBuf, /* [in] max size of buffer in bytes */
3469 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3470 LPDWORD lpdwReturned /* [out] number of entries returned */
3473 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3474 lpdwNeeded, lpdwReturned, TRUE);
3477 /******************************************************************
3478 * EnumPrintersA [WINSPOOL.@]
3481 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3482 DWORD dwLevel, LPBYTE lpbPrinters,
3483 DWORD cbBuf, LPDWORD lpdwNeeded,
3484 LPDWORD lpdwReturned)
3487 UNICODE_STRING lpszNameW;
3490 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3491 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3492 lpdwNeeded, lpdwReturned, FALSE);
3493 RtlFreeUnicodeString(&lpszNameW);
3497 /*****************************************************************************
3498 * WINSPOOL_GetDriverInfoFromReg [internal]
3500 * Enters the information from the registry into the DRIVER_INFO struct
3503 * zero if the printer driver does not exist in the registry
3504 * (only if Level > 1) otherwise nonzero
3506 static BOOL WINSPOOL_GetDriverInfoFromReg(
3509 LPWSTR pEnvironment,
3511 LPBYTE ptr, /* DRIVER_INFO */
3512 LPBYTE pDriverStrings, /* strings buffer */
3513 DWORD cbBuf, /* size of string buffer */
3514 LPDWORD pcbNeeded, /* space needed for str. */
3515 BOOL unicode) /* type of strings */
3519 LPBYTE strPtr = pDriverStrings;
3521 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3522 debugstr_w(DriverName), debugstr_w(pEnvironment),
3523 Level, ptr, pDriverStrings, cbBuf, unicode);
3526 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3527 if (*pcbNeeded <= cbBuf)
3528 strcpyW((LPWSTR)strPtr, DriverName);
3530 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3532 if(*pcbNeeded <= cbBuf)
3533 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3534 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3538 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3542 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3543 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3546 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3547 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3548 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3553 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3556 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3558 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3560 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3563 if(*pcbNeeded <= cbBuf) {
3565 strcpyW((LPWSTR)strPtr, pEnvironment);
3567 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3568 (LPSTR)strPtr, size, NULL, NULL);
3570 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3571 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3574 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3577 if(*pcbNeeded <= cbBuf)
3578 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3581 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3582 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3585 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3588 if(*pcbNeeded <= cbBuf)
3589 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3592 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3593 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3596 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3597 0, &size, unicode)) {
3599 if(*pcbNeeded <= cbBuf)
3600 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3601 size, &tmp, unicode);
3603 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3604 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3608 RegCloseKey(hkeyDriver);
3609 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3613 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3616 if(*pcbNeeded <= cbBuf)
3617 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3618 size, &tmp, unicode);
3620 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3621 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3624 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3627 if(*pcbNeeded <= cbBuf)
3628 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3629 size, &tmp, unicode);
3631 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3632 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3635 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3638 if(*pcbNeeded <= cbBuf)
3639 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3640 size, &tmp, unicode);
3642 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3643 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3646 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3649 if(*pcbNeeded <= cbBuf)
3650 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3651 size, &tmp, unicode);
3653 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3654 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3657 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3658 RegCloseKey(hkeyDriver);
3662 /*****************************************************************************
3663 * WINSPOOL_GetPrinterDriver
3665 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3666 DWORD Level, LPBYTE pDriverInfo,
3667 DWORD cbBuf, LPDWORD pcbNeeded,
3671 WCHAR DriverName[100];
3672 DWORD ret, type, size, needed = 0;
3674 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3676 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3677 Level,pDriverInfo,cbBuf, pcbNeeded);
3679 ZeroMemory(pDriverInfo, cbBuf);
3681 if (!(name = get_opened_printer_name(hPrinter))) {
3682 SetLastError(ERROR_INVALID_HANDLE);
3685 if(Level < 1 || Level > 6) {
3686 SetLastError(ERROR_INVALID_LEVEL);
3689 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3691 ERR("Can't create Printers key\n");
3694 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3696 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3697 RegCloseKey(hkeyPrinters);
3698 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3701 size = sizeof(DriverName);
3703 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3704 (LPBYTE)DriverName, &size);
3705 RegCloseKey(hkeyPrinter);
3706 RegCloseKey(hkeyPrinters);
3707 if(ret != ERROR_SUCCESS) {
3708 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3712 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3714 ERR("Can't create Drivers key\n");
3720 size = sizeof(DRIVER_INFO_1W);
3723 size = sizeof(DRIVER_INFO_2W);
3726 size = sizeof(DRIVER_INFO_3W);
3729 size = sizeof(DRIVER_INFO_4W);
3732 size = sizeof(DRIVER_INFO_5W);
3735 size = sizeof(DRIVER_INFO_6W);
3738 ERR("Invalid level\n");
3743 ptr = pDriverInfo + size;
3745 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3746 pEnvironment, Level, pDriverInfo,
3747 (cbBuf < size) ? NULL : ptr,
3748 (cbBuf < size) ? 0 : cbBuf - size,
3749 &needed, unicode)) {
3750 RegCloseKey(hkeyDrivers);
3754 RegCloseKey(hkeyDrivers);
3756 if(pcbNeeded) *pcbNeeded = size + needed;
3757 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3758 if(cbBuf >= needed) return TRUE;
3759 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3763 /*****************************************************************************
3764 * GetPrinterDriverA [WINSPOOL.@]
3766 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3767 DWORD Level, LPBYTE pDriverInfo,
3768 DWORD cbBuf, LPDWORD pcbNeeded)
3771 UNICODE_STRING pEnvW;
3774 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3775 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3776 cbBuf, pcbNeeded, FALSE);
3777 RtlFreeUnicodeString(&pEnvW);
3780 /*****************************************************************************
3781 * GetPrinterDriverW [WINSPOOL.@]
3783 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3784 DWORD Level, LPBYTE pDriverInfo,
3785 DWORD cbBuf, LPDWORD pcbNeeded)
3787 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3788 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3791 /*****************************************************************************
3792 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3794 * Return the PATH for the Printer-Drivers (UNICODE)
3797 * pName [I] Servername (NT only) or NULL (local Computer)
3798 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3799 * Level [I] Structure-Level (must be 1)
3800 * pDriverDirectory [O] PTR to Buffer that receives the Result
3801 * cbBuf [I] Size of Buffer at pDriverDirectory
3802 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3803 * required for pDriverDirectory
3806 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3807 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3808 * if cbBuf is too small
3810 * Native Values returned in pDriverDirectory on Success:
3811 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3812 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3813 *| win9x(Windows 4.0): "%winsysdir%"
3815 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3818 *- Only NULL or "" is supported for pName
3821 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3822 DWORD Level, LPBYTE pDriverDirectory,
3823 DWORD cbBuf, LPDWORD pcbNeeded)
3826 const printenv_t * env;
3828 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3829 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3830 if(pName != NULL && pName[0]) {
3831 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3832 SetLastError(ERROR_INVALID_PARAMETER);
3836 env = validate_envW(pEnvironment);
3837 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3840 WARN("(Level: %ld) is ignored in win9x\n", Level);
3841 SetLastError(ERROR_INVALID_LEVEL);
3845 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3846 needed = GetSystemDirectoryW(NULL, 0);
3847 /* add the Size for the Subdirectories */
3848 needed += lstrlenW(spooldriversW);
3849 needed += lstrlenW(env->subdir);
3850 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3853 *pcbNeeded = needed;
3854 TRACE("required: 0x%lx/%ld\n", needed, needed);
3855 if(needed > cbBuf) {
3856 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3859 if(pcbNeeded == NULL) {
3860 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3861 SetLastError(RPC_X_NULL_REF_POINTER);
3864 if(pDriverDirectory == NULL) {
3865 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3866 SetLastError(ERROR_INVALID_USER_BUFFER);
3870 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3871 /* add the Subdirectories */
3872 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3873 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3874 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3879 /*****************************************************************************
3880 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3882 * Return the PATH for the Printer-Drivers (ANSI)
3884 * See GetPrinterDriverDirectoryW.
3887 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3890 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3891 DWORD Level, LPBYTE pDriverDirectory,
3892 DWORD cbBuf, LPDWORD pcbNeeded)
3894 UNICODE_STRING nameW, environmentW;
3897 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3898 WCHAR *driverDirectoryW = NULL;
3900 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3901 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3903 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3905 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3906 else nameW.Buffer = NULL;
3907 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3908 else environmentW.Buffer = NULL;
3910 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3911 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3914 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3915 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3917 *pcbNeeded = needed;
3918 ret = (needed <= cbBuf) ? TRUE : FALSE;
3920 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3922 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3924 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3925 RtlFreeUnicodeString(&environmentW);
3926 RtlFreeUnicodeString(&nameW);
3931 /*****************************************************************************
3932 * AddPrinterDriverA [WINSPOOL.@]
3934 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3937 HKEY hkeyDrivers, hkeyName;
3939 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3941 if(level != 2 && level != 3) {
3942 SetLastError(ERROR_INVALID_LEVEL);
3945 if ((pName) && (pName[0])) {
3946 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3947 SetLastError(ERROR_INVALID_PARAMETER);
3951 WARN("pDriverInfo == NULL\n");
3952 SetLastError(ERROR_INVALID_PARAMETER);
3957 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3959 memset(&di3, 0, sizeof(di3));
3960 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3963 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3965 SetLastError(ERROR_INVALID_PARAMETER);
3968 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3969 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3970 if(!di3.pHelpFile) di3.pHelpFile = "";
3971 if(!di3.pMonitorName) di3.pMonitorName = "";
3973 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3976 ERR("Can't create Drivers key\n");
3980 if(level == 2) { /* apparently can't overwrite with level2 */
3981 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3982 RegCloseKey(hkeyName);
3983 RegCloseKey(hkeyDrivers);
3984 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3985 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3989 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3990 RegCloseKey(hkeyDrivers);
3991 ERR("Can't create Name key\n");
3994 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3996 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3997 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3998 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4000 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
4001 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4002 (LPBYTE) di3.pDependentFiles, 0);
4003 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
4004 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
4005 RegCloseKey(hkeyName);
4006 RegCloseKey(hkeyDrivers);
4011 /*****************************************************************************
4012 * AddPrinterDriverW [WINSPOOL.@]
4014 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4017 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
4022 /*****************************************************************************
4023 * AddPrintProcessorA [WINSPOOL.@]
4025 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4026 LPSTR pPrintProcessorName)
4028 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4029 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4033 /*****************************************************************************
4034 * AddPrintProcessorW [WINSPOOL.@]
4036 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4037 LPWSTR pPrintProcessorName)
4039 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4040 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4044 /*****************************************************************************
4045 * AddPrintProvidorA [WINSPOOL.@]
4047 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4049 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4053 /*****************************************************************************
4054 * AddPrintProvidorW [WINSPOOL.@]
4056 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4058 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4062 /*****************************************************************************
4063 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4065 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4066 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4068 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4069 pDevModeOutput, pDevModeInput);
4073 /*****************************************************************************
4074 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4076 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4077 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4079 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4080 pDevModeOutput, pDevModeInput);
4084 /*****************************************************************************
4085 * PrinterProperties [WINSPOOL.@]
4087 * Displays a dialog to set the properties of the printer.
4090 * nonzero on success or zero on failure
4093 * implemented as stub only
4095 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4096 HANDLE hPrinter /* [in] handle to printer object */
4098 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4099 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4103 /*****************************************************************************
4104 * EnumJobsA [WINSPOOL.@]
4107 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4108 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4111 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4112 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4114 if(pcbNeeded) *pcbNeeded = 0;
4115 if(pcReturned) *pcReturned = 0;
4120 /*****************************************************************************
4121 * EnumJobsW [WINSPOOL.@]
4124 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4125 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4128 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4129 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4131 if(pcbNeeded) *pcbNeeded = 0;
4132 if(pcReturned) *pcReturned = 0;
4136 /*****************************************************************************
4137 * WINSPOOL_EnumPrinterDrivers [internal]
4139 * Delivers information about all printer drivers installed on the
4140 * localhost or a given server
4143 * nonzero on success or zero on failure. If the buffer for the returned
4144 * information is too small the function will return an error
4147 * - only implemented for localhost, foreign hosts will return an error
4149 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4150 DWORD Level, LPBYTE pDriverInfo,
4151 DWORD cbBuf, LPDWORD pcbNeeded,
4152 LPDWORD pcReturned, BOOL unicode)
4155 DWORD i, needed, number = 0, size = 0;
4156 WCHAR DriverNameW[255];
4159 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4160 debugstr_w(pName), debugstr_w(pEnvironment),
4161 Level, pDriverInfo, cbBuf, unicode);
4163 /* check for local drivers */
4164 if((pName) && (pName[0])) {
4165 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4166 SetLastError(ERROR_ACCESS_DENIED);
4170 /* check input parameter */
4171 if((Level < 1) || (Level > 3)) {
4172 ERR("unsupported level %ld\n", Level);
4173 SetLastError(ERROR_INVALID_LEVEL);
4177 /* initialize return values */
4179 memset( pDriverInfo, 0, cbBuf);
4183 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4185 ERR("Can't open Drivers key\n");
4189 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4190 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4191 RegCloseKey(hkeyDrivers);
4192 ERR("Can't query Drivers key\n");
4195 TRACE("Found %ld Drivers\n", number);
4197 /* get size of single struct
4198 * unicode and ascii structure have the same size
4202 size = sizeof(DRIVER_INFO_1A);
4205 size = sizeof(DRIVER_INFO_2A);
4208 size = sizeof(DRIVER_INFO_3A);
4212 /* calculate required buffer size */
4213 *pcbNeeded = size * number;
4215 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4217 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4218 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4220 ERR("Can't enum key number %ld\n", i);
4221 RegCloseKey(hkeyDrivers);
4224 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4225 pEnvironment, Level, ptr,
4226 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4227 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4228 &needed, unicode)) {
4229 RegCloseKey(hkeyDrivers);
4232 (*pcbNeeded) += needed;
4235 RegCloseKey(hkeyDrivers);
4237 if(cbBuf < *pcbNeeded){
4238 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4242 *pcReturned = number;
4246 /*****************************************************************************
4247 * EnumPrinterDriversW [WINSPOOL.@]
4249 * see function EnumPrinterDrivers for RETURNS, BUGS
4251 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4252 LPBYTE pDriverInfo, DWORD cbBuf,
4253 LPDWORD pcbNeeded, LPDWORD pcReturned)
4255 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4256 cbBuf, pcbNeeded, pcReturned, TRUE);
4259 /*****************************************************************************
4260 * EnumPrinterDriversA [WINSPOOL.@]
4262 * see function EnumPrinterDrivers for RETURNS, BUGS
4264 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4265 LPBYTE pDriverInfo, DWORD cbBuf,
4266 LPDWORD pcbNeeded, LPDWORD pcReturned)
4268 UNICODE_STRING pNameW, pEnvironmentW;
4269 PWSTR pwstrNameW, pwstrEnvironmentW;
4271 pwstrNameW = asciitounicode(&pNameW, pName);
4272 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4274 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4275 Level, pDriverInfo, cbBuf, pcbNeeded,
4277 RtlFreeUnicodeString(&pNameW);
4278 RtlFreeUnicodeString(&pEnvironmentW);
4283 static CHAR PortMonitor[] = "Wine Port Monitor";
4284 static CHAR PortDescription[] = "Wine Port";
4286 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4290 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4291 NULL, OPEN_EXISTING, 0, NULL );
4292 if (handle == INVALID_HANDLE_VALUE)
4294 TRACE("Checking %s exists\n", name );
4295 CloseHandle( handle );
4299 static DWORD WINSPOOL_CountSerialPorts(void)
4306 strcpy( name, "COMx:" );
4308 if (WINSPOOL_ComPortExists( name ))
4315 /******************************************************************************
4316 * EnumPortsA (WINSPOOL.@)
4321 * ANSI-Version did not call the UNICODE-Version
4324 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4325 LPDWORD bufneeded,LPDWORD bufreturned)
4328 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4329 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4333 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4334 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4339 info_size = sizeof (PORT_INFO_1A);
4342 info_size = sizeof (PORT_INFO_2A);
4345 SetLastError(ERROR_INVALID_LEVEL);
4349 /* see how many exist */
4352 serial_count = WINSPOOL_CountSerialPorts();
4355 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4356 if ( r == ERROR_SUCCESS )
4358 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4359 &printer_count, NULL, NULL, NULL, NULL);
4361 count = serial_count + printer_count;
4363 /* then fill in the structure info structure once
4364 we know the offset to the first string */
4366 memset( buffer, 0, bufsize );
4368 ofs = info_size*count;
4369 for ( i=0; i<count; i++)
4371 DWORD vallen = sizeof(portname) - 1;
4373 /* get the serial port values, then the printer values */
4374 if ( i < serial_count )
4376 strcpy( portname, "COMx:" );
4377 portname[3] = '1' + i;
4378 if (!WINSPOOL_ComPortExists( portname ))
4381 TRACE("Found %s\n", portname );
4382 vallen = strlen( portname );
4386 r = RegEnumValueA( hkey_printer, i-serial_count,
4387 portname, &vallen, NULL, NULL, NULL, 0 );
4392 /* add a colon if necessary, and make it upper case */
4393 CharUpperBuffA(portname,vallen);
4394 if (strcasecmp(portname,"nul")!=0)
4395 if (vallen && (portname[vallen-1] != ':') )
4396 lstrcatA(portname,":");
4398 /* add the port info structure if we can fit it */
4399 if ( info_size*(n+1) < bufsize )
4403 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4404 info->pName = (LPSTR) &buffer[ofs];
4406 else if ( level == 2)
4408 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4409 info->pPortName = (LPSTR) &buffer[ofs];
4410 /* FIXME: fill in more stuff here */
4411 info->pMonitorName = PortMonitor;
4412 info->pDescription = PortDescription;
4413 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4416 /* add the name of the port if we can fit it */
4417 if ( ofs < bufsize )
4418 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4424 ofs += lstrlenA(portname)+1;
4427 RegCloseKey(hkey_printer);
4438 /******************************************************************************
4439 * EnumPortsW (WINSPOOL.@)
4441 * Enumerate available Ports
4444 * name [I] Servername or NULL (local Computer)
4445 * level [I] Structure-Level (1 or 2)
4446 * buffer [O] PTR to Buffer that receives the Result
4447 * bufsize [I] Size of Buffer at buffer
4448 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4449 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4453 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4456 * UNICODE-Version is a stub
4459 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4460 LPDWORD bufneeded,LPDWORD bufreturned)
4462 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4463 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4467 /******************************************************************************
4468 * GetDefaultPrinterW (WINSPOOL.@)
4471 * This function must read the value from data 'device' of key
4472 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4474 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4478 WCHAR *buffer, *ptr;
4482 SetLastError(ERROR_INVALID_PARAMETER);
4486 /* make the buffer big enough for the stuff from the profile/registry,
4487 * the content must fit into the local buffer to compute the correct
4488 * size even if the extern buffer is too small or not given.
4489 * (20 for ,driver,port) */
4491 len = max(100, (insize + 20));
4492 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4494 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4496 SetLastError (ERROR_FILE_NOT_FOUND);
4500 TRACE("%s\n", debugstr_w(buffer));
4502 if ((ptr = strchrW(buffer, ',')) == NULL)
4504 SetLastError(ERROR_INVALID_NAME);
4510 *namesize = strlenW(buffer) + 1;
4511 if(!name || (*namesize > insize))
4513 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4517 strcpyW(name, buffer);
4520 HeapFree( GetProcessHeap(), 0, buffer);
4525 /******************************************************************************
4526 * GetDefaultPrinterA (WINSPOOL.@)
4528 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4532 WCHAR *bufferW = NULL;
4536 SetLastError(ERROR_INVALID_PARAMETER);
4540 if(name && *namesize) {
4542 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4545 if(!GetDefaultPrinterW( bufferW, namesize)) {
4550 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4554 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4557 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4560 HeapFree( GetProcessHeap(), 0, bufferW);
4565 /******************************************************************************
4566 * SetDefaultPrinterW (WINSPOOL.204)
4568 * Set the Name of the Default Printer
4571 * pszPrinter [I] Name of the Printer or NULL
4578 * When the Parameter is NULL or points to an Empty String and
4579 * a Default Printer was already present, then this Function changes nothing.
4580 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4581 * the First enumerated local Printer is used.
4584 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4587 TRACE("(%s)\n", debugstr_w(pszPrinter));
4589 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4593 /******************************************************************************
4594 * SetDefaultPrinterA (WINSPOOL.202)
4596 * See SetDefaultPrinterW.
4599 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4602 TRACE("(%s)\n", debugstr_a(pszPrinter));
4604 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4609 /******************************************************************************
4610 * SetPrinterDataExA (WINSPOOL.@)
4612 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4613 LPCSTR pValueName, DWORD Type,
4614 LPBYTE pData, DWORD cbData)
4616 HKEY hkeyPrinter, hkeySubkey;
4619 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4620 debugstr_a(pValueName), Type, pData, cbData);
4622 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4626 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4628 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4629 RegCloseKey(hkeyPrinter);
4632 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4633 RegCloseKey(hkeySubkey);
4634 RegCloseKey(hkeyPrinter);
4638 /******************************************************************************
4639 * SetPrinterDataExW (WINSPOOL.@)
4641 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4642 LPCWSTR pValueName, DWORD Type,
4643 LPBYTE pData, DWORD cbData)
4645 HKEY hkeyPrinter, hkeySubkey;
4648 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4649 debugstr_w(pValueName), Type, pData, cbData);
4651 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4655 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4657 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4658 RegCloseKey(hkeyPrinter);
4661 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4662 RegCloseKey(hkeySubkey);
4663 RegCloseKey(hkeyPrinter);
4667 /******************************************************************************
4668 * SetPrinterDataA (WINSPOOL.@)
4670 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4671 LPBYTE pData, DWORD cbData)
4673 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4677 /******************************************************************************
4678 * SetPrinterDataW (WINSPOOL.@)
4680 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4681 LPBYTE pData, DWORD cbData)
4683 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4687 /******************************************************************************
4688 * GetPrinterDataExA (WINSPOOL.@)
4690 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4691 LPCSTR pValueName, LPDWORD pType,
4692 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4694 HKEY hkeyPrinter, hkeySubkey;
4697 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4698 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4701 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4705 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4707 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4708 RegCloseKey(hkeyPrinter);
4712 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4713 RegCloseKey(hkeySubkey);
4714 RegCloseKey(hkeyPrinter);
4718 /******************************************************************************
4719 * GetPrinterDataExW (WINSPOOL.@)
4721 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4722 LPCWSTR pValueName, LPDWORD pType,
4723 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4725 HKEY hkeyPrinter, hkeySubkey;
4728 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4729 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4732 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4736 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4738 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4739 RegCloseKey(hkeyPrinter);
4743 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4744 RegCloseKey(hkeySubkey);
4745 RegCloseKey(hkeyPrinter);
4749 /******************************************************************************
4750 * GetPrinterDataA (WINSPOOL.@)
4752 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4753 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4755 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4756 pData, nSize, pcbNeeded);
4759 /******************************************************************************
4760 * GetPrinterDataW (WINSPOOL.@)
4762 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4763 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4765 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4766 pData, nSize, pcbNeeded);
4769 /*******************************************************************************
4770 * EnumPrinterDataExW [WINSPOOL.@]
4772 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4773 LPBYTE pEnumValues, DWORD cbEnumValues,
4774 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4776 HKEY hkPrinter, hkSubKey;
4777 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4778 cbValueNameLen, cbMaxValueLen, cbValueLen,
4783 PPRINTER_ENUM_VALUESW ppev;
4785 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4787 if (pKeyName == NULL || *pKeyName == 0)
4788 return ERROR_INVALID_PARAMETER;
4790 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4791 if (ret != ERROR_SUCCESS)
4793 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4798 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4799 if (ret != ERROR_SUCCESS)
4801 r = RegCloseKey (hkPrinter);
4802 if (r != ERROR_SUCCESS)
4803 WARN ("RegCloseKey returned %li\n", r);
4804 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4805 debugstr_w (pKeyName), ret);
4809 ret = RegCloseKey (hkPrinter);
4810 if (ret != ERROR_SUCCESS)
4812 ERR ("RegCloseKey returned %li\n", ret);
4813 r = RegCloseKey (hkSubKey);
4814 if (r != ERROR_SUCCESS)
4815 WARN ("RegCloseKey returned %li\n", r);
4819 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4820 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4821 if (ret != ERROR_SUCCESS)
4823 r = RegCloseKey (hkSubKey);
4824 if (r != ERROR_SUCCESS)
4825 WARN ("RegCloseKey returned %li\n", r);
4826 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4830 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4831 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4833 if (cValues == 0) /* empty key */
4835 r = RegCloseKey (hkSubKey);
4836 if (r != ERROR_SUCCESS)
4837 WARN ("RegCloseKey returned %li\n", r);
4838 *pcbEnumValues = *pnEnumValues = 0;
4839 return ERROR_SUCCESS;
4842 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4844 hHeap = GetProcessHeap ();
4847 ERR ("GetProcessHeap failed\n");
4848 r = RegCloseKey (hkSubKey);
4849 if (r != ERROR_SUCCESS)
4850 WARN ("RegCloseKey returned %li\n", r);
4851 return ERROR_OUTOFMEMORY;
4854 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4855 if (lpValueName == NULL)
4857 ERR ("Failed to allocate %li bytes from process heap\n",
4858 cbMaxValueNameLen * sizeof (WCHAR));
4859 r = RegCloseKey (hkSubKey);
4860 if (r != ERROR_SUCCESS)
4861 WARN ("RegCloseKey returned %li\n", r);
4862 return ERROR_OUTOFMEMORY;
4865 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4866 if (lpValue == NULL)
4868 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4869 if (HeapFree (hHeap, 0, lpValueName) == 0)
4870 WARN ("HeapFree failed with code %li\n", GetLastError ());
4871 r = RegCloseKey (hkSubKey);
4872 if (r != ERROR_SUCCESS)
4873 WARN ("RegCloseKey returned %li\n", r);
4874 return ERROR_OUTOFMEMORY;
4877 TRACE ("pass 1: calculating buffer required for all names and values\n");
4879 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4881 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4883 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4885 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4886 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4887 NULL, NULL, lpValue, &cbValueLen);
4888 if (ret != ERROR_SUCCESS)
4890 if (HeapFree (hHeap, 0, lpValue) == 0)
4891 WARN ("HeapFree failed with code %li\n", GetLastError ());
4892 if (HeapFree (hHeap, 0, lpValueName) == 0)
4893 WARN ("HeapFree failed with code %li\n", GetLastError ());
4894 r = RegCloseKey (hkSubKey);
4895 if (r != ERROR_SUCCESS)
4896 WARN ("RegCloseKey returned %li\n", r);
4897 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4901 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4902 debugstr_w (lpValueName), dwIndex,
4903 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4905 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4906 cbBufSize += cbValueLen;
4909 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4911 *pcbEnumValues = cbBufSize;
4912 *pnEnumValues = cValues;
4914 if (cbEnumValues < cbBufSize) /* buffer too small */
4916 if (HeapFree (hHeap, 0, lpValue) == 0)
4917 WARN ("HeapFree failed with code %li\n", GetLastError ());
4918 if (HeapFree (hHeap, 0, lpValueName) == 0)
4919 WARN ("HeapFree failed with code %li\n", GetLastError ());
4920 r = RegCloseKey (hkSubKey);
4921 if (r != ERROR_SUCCESS)
4922 WARN ("RegCloseKey returned %li\n", r);
4923 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4924 return ERROR_MORE_DATA;
4927 TRACE ("pass 2: copying all names and values to buffer\n");
4929 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4930 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4932 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4934 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4935 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4936 NULL, &dwType, lpValue, &cbValueLen);
4937 if (ret != ERROR_SUCCESS)
4939 if (HeapFree (hHeap, 0, lpValue) == 0)
4940 WARN ("HeapFree failed with code %li\n", GetLastError ());
4941 if (HeapFree (hHeap, 0, lpValueName) == 0)
4942 WARN ("HeapFree failed with code %li\n", GetLastError ());
4943 r = RegCloseKey (hkSubKey);
4944 if (r != ERROR_SUCCESS)
4945 WARN ("RegCloseKey returned %li\n", r);
4946 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4950 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4951 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4952 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4953 pEnumValues += cbValueNameLen;
4955 /* return # of *bytes* (including trailing \0), not # of chars */
4956 ppev[dwIndex].cbValueName = cbValueNameLen;
4958 ppev[dwIndex].dwType = dwType;
4960 memcpy (pEnumValues, lpValue, cbValueLen);
4961 ppev[dwIndex].pData = pEnumValues;
4962 pEnumValues += cbValueLen;
4964 ppev[dwIndex].cbData = cbValueLen;
4966 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4967 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4970 if (HeapFree (hHeap, 0, lpValue) == 0)
4972 ret = GetLastError ();
4973 ERR ("HeapFree failed with code %li\n", ret);
4974 if (HeapFree (hHeap, 0, lpValueName) == 0)
4975 WARN ("HeapFree failed with code %li\n", GetLastError ());
4976 r = RegCloseKey (hkSubKey);
4977 if (r != ERROR_SUCCESS)
4978 WARN ("RegCloseKey returned %li\n", r);
4982 if (HeapFree (hHeap, 0, lpValueName) == 0)
4984 ret = GetLastError ();
4985 ERR ("HeapFree failed with code %li\n", ret);
4986 r = RegCloseKey (hkSubKey);
4987 if (r != ERROR_SUCCESS)
4988 WARN ("RegCloseKey returned %li\n", r);
4992 ret = RegCloseKey (hkSubKey);
4993 if (ret != ERROR_SUCCESS)
4995 ERR ("RegCloseKey returned %li\n", ret);
4999 return ERROR_SUCCESS;
5002 /*******************************************************************************
5003 * EnumPrinterDataExA [WINSPOOL.@]
5005 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5006 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5007 * what Windows 2000 SP1 does.
5010 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5011 LPBYTE pEnumValues, DWORD cbEnumValues,
5012 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5016 DWORD ret, dwIndex, dwBufSize;
5020 TRACE ("%p %s\n", hPrinter, pKeyName);
5022 if (pKeyName == NULL || *pKeyName == 0)
5023 return ERROR_INVALID_PARAMETER;
5025 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5028 ret = GetLastError ();
5029 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5033 hHeap = GetProcessHeap ();
5036 ERR ("GetProcessHeap failed\n");
5037 return ERROR_OUTOFMEMORY;
5040 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5041 if (pKeyNameW == NULL)
5043 ERR ("Failed to allocate %li bytes from process heap\n",
5044 (LONG) len * sizeof (WCHAR));
5045 return ERROR_OUTOFMEMORY;
5048 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5050 ret = GetLastError ();
5051 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5052 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5053 WARN ("HeapFree failed with code %li\n", GetLastError ());
5057 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5058 pcbEnumValues, pnEnumValues);
5059 if (ret != ERROR_SUCCESS)
5061 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5062 WARN ("HeapFree failed with code %li\n", GetLastError ());
5063 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5067 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5069 ret = GetLastError ();
5070 ERR ("HeapFree failed with code %li\n", ret);
5074 if (*pnEnumValues == 0) /* empty key */
5075 return ERROR_SUCCESS;
5078 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5080 PPRINTER_ENUM_VALUESW ppev =
5081 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5083 if (dwBufSize < ppev->cbValueName)
5084 dwBufSize = ppev->cbValueName;
5086 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5087 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5088 dwBufSize = ppev->cbData;
5091 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5093 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5094 if (pBuffer == NULL)
5096 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5097 return ERROR_OUTOFMEMORY;
5100 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5102 PPRINTER_ENUM_VALUESW ppev =
5103 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5105 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5106 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5110 ret = GetLastError ();
5111 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5112 if (HeapFree (hHeap, 0, pBuffer) == 0)
5113 WARN ("HeapFree failed with code %li\n", GetLastError ());
5117 memcpy (ppev->pValueName, pBuffer, len);
5119 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5121 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5122 ppev->dwType != REG_MULTI_SZ)
5125 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5126 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5129 ret = GetLastError ();
5130 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5131 if (HeapFree (hHeap, 0, pBuffer) == 0)
5132 WARN ("HeapFree failed with code %li\n", GetLastError ());
5136 memcpy (ppev->pData, pBuffer, len);
5138 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5139 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5142 if (HeapFree (hHeap, 0, pBuffer) == 0)
5144 ret = GetLastError ();
5145 ERR ("HeapFree failed with code %li\n", ret);
5149 return ERROR_SUCCESS;
5152 /******************************************************************************
5153 * AbortPrinter (WINSPOOL.@)
5155 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5157 FIXME("(%p), stub!\n", hPrinter);
5161 /******************************************************************************
5162 * AddPortA (WINSPOOL.@)
5167 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5169 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5173 /******************************************************************************
5174 * AddPortW (WINSPOOL.@)
5176 * Add a Port for a specific Monitor
5179 * pName [I] Servername or NULL (local Computer)
5180 * hWnd [I] Handle to parent Window for the Dialog-Box
5181 * pMonitorName [I] Name of the Monitor that manage the Port
5191 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5193 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5197 /******************************************************************************
5198 * AddPortExA (WINSPOOL.@)
5203 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5205 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5206 lpBuffer, debugstr_a(lpMonitorName));
5210 /******************************************************************************
5211 * AddPortExW (WINSPOOL.@)
5213 * Add a Port for a specific Monitor, without presenting a user interface
5216 * hMonitor [I] Handle from InitializePrintMonitor2()
5217 * pName [I] Servername or NULL (local Computer)
5218 * Level [I] Structure-Level (1 or 2) for lpBuffer
5219 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5220 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5230 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5232 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5233 lpBuffer, debugstr_w(lpMonitorName));
5237 /******************************************************************************
5238 * AddPrinterConnectionA (WINSPOOL.@)
5240 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5242 FIXME("%s\n", debugstr_a(pName));
5246 /******************************************************************************
5247 * AddPrinterConnectionW (WINSPOOL.@)
5249 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5251 FIXME("%s\n", debugstr_w(pName));
5255 /******************************************************************************
5256 * AddPrinterDriverExW (WINSPOOL.@)
5258 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5259 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5261 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5262 Level, pDriverInfo, dwFileCopyFlags);
5263 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5267 /******************************************************************************
5268 * AddPrinterDriverExA (WINSPOOL.@)
5270 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5271 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5273 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5274 Level, pDriverInfo, dwFileCopyFlags);
5275 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5279 /******************************************************************************
5280 * ConfigurePortA (WINSPOOL.@)
5282 * See ConfigurePortW.
5285 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5287 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5291 /******************************************************************************
5292 * ConfigurePortW (WINSPOOL.@)
5294 * Display the Configuration-Dialog for a specific Port
5297 * pName [I] Servername or NULL (local Computer)
5298 * hWnd [I] Handle to parent Window for the Dialog-Box
5299 * pPortName [I] Name of the Port, that should be configured
5309 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5311 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5315 /******************************************************************************
5316 * ConnectToPrinterDlg (WINSPOOL.@)
5318 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5320 FIXME("%p %lx\n", hWnd, Flags);
5324 /******************************************************************************
5325 * DeletePrinterConnectionA (WINSPOOL.@)
5327 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5329 FIXME("%s\n", debugstr_a(pName));
5333 /******************************************************************************
5334 * DeletePrinterConnectionW (WINSPOOL.@)
5336 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5338 FIXME("%s\n", debugstr_w(pName));
5342 /******************************************************************************
5343 * DeletePrinterDriverExW (WINSPOOL.@)
5345 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5346 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5348 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5349 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5353 /******************************************************************************
5354 * DeletePrinterDriverExA (WINSPOOL.@)
5356 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5357 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5359 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5360 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5364 /******************************************************************************
5365 * DeletePrinterDataExW (WINSPOOL.@)
5367 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5370 FIXME("%p %s %s\n", hPrinter,
5371 debugstr_w(pKeyName), debugstr_w(pValueName));
5372 return ERROR_INVALID_PARAMETER;
5375 /******************************************************************************
5376 * DeletePrinterDataExA (WINSPOOL.@)
5378 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5381 FIXME("%p %s %s\n", hPrinter,
5382 debugstr_a(pKeyName), debugstr_a(pValueName));
5383 return ERROR_INVALID_PARAMETER;
5386 /******************************************************************************
5387 * DeletePrintProcessorA (WINSPOOL.@)
5389 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5391 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5392 debugstr_a(pPrintProcessorName));
5396 /******************************************************************************
5397 * DeletePrintProcessorW (WINSPOOL.@)
5399 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5401 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5402 debugstr_w(pPrintProcessorName));
5406 /******************************************************************************
5407 * DeletePrintProvidorA (WINSPOOL.@)
5409 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5411 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5412 debugstr_a(pPrintProviderName));
5416 /******************************************************************************
5417 * DeletePrintProvidorW (WINSPOOL.@)
5419 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5421 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5422 debugstr_w(pPrintProviderName));
5426 /******************************************************************************
5427 * EnumFormsA (WINSPOOL.@)
5429 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5430 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5432 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5433 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5437 /******************************************************************************
5438 * EnumFormsW (WINSPOOL.@)
5440 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5441 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5443 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5444 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5448 /*****************************************************************************
5449 * EnumMonitorsA [WINSPOOL.@]
5451 * See EnumMonitorsW.
5454 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5455 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5458 LPBYTE bufferW = NULL;
5459 LPWSTR nameW = NULL;
5461 DWORD numentries = 0;
5464 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5465 cbBuf, pcbNeeded, pcReturned);
5467 /* convert servername to unicode */
5469 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5470 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5471 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5473 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5474 needed = cbBuf * sizeof(WCHAR);
5475 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5476 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5478 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5479 if (pcbNeeded) needed = *pcbNeeded;
5480 /* HeapReAlloc return NULL, when bufferW was NULL */
5481 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5482 HeapAlloc(GetProcessHeap(), 0, needed);
5484 /* Try again with the large Buffer */
5485 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5487 numentries = pcReturned ? *pcReturned : 0;
5490 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5491 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5494 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5495 DWORD entrysize = 0;
5498 LPMONITOR_INFO_2W mi2w;
5499 LPMONITOR_INFO_2A mi2a;
5501 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5502 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5504 /* First pass: calculate the size for all Entries */
5505 mi2w = (LPMONITOR_INFO_2W) bufferW;
5506 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5508 while (index < numentries) {
5510 needed += entrysize; /* MONITOR_INFO_?A */
5511 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5513 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5514 NULL, 0, NULL, NULL);
5516 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5517 NULL, 0, NULL, NULL);
5518 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5519 NULL, 0, NULL, NULL);
5521 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5522 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5523 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5526 /* check for errors and quit on failure */
5527 if (cbBuf < needed) {
5528 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5532 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5533 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5534 cbBuf -= len ; /* free Bytes in the user-Buffer */
5535 mi2w = (LPMONITOR_INFO_2W) bufferW;
5536 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5538 /* Second Pass: Fill the User Buffer (if we have one) */
5539 while ((index < numentries) && pMonitors) {
5541 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5543 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5544 ptr, cbBuf , NULL, NULL);
5548 mi2a->pEnvironment = ptr;
5549 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5550 ptr, cbBuf, NULL, NULL);
5554 mi2a->pDLLName = ptr;
5555 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5556 ptr, cbBuf, NULL, NULL);
5560 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5561 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5562 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5566 if (pcbNeeded) *pcbNeeded = needed;
5567 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5569 HeapFree(GetProcessHeap(), 0, nameW);
5570 HeapFree(GetProcessHeap(), 0, bufferW);
5572 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5573 (res), GetLastError(), needed, numentries);
5579 /*****************************************************************************
5580 * EnumMonitorsW [WINSPOOL.@]
5582 * Enumerate available Port-Monitors
5585 * pName [I] Servername or NULL (local Computer)
5586 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5587 * pMonitors [O] PTR to Buffer that receives the Result
5588 * cbBuf [I] Size of Buffer at pMonitors
5589 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5590 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5594 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5597 * Windows reads the Registry once and cache the Results.
5599 *| Language-Monitors are also installed in the same Registry-Location but
5600 *| they are filtered in Windows (not returned by EnumMonitors).
5601 *| We do no filtering to simplify our Code.
5604 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5605 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5608 DWORD numentries = 0;
5611 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5612 cbBuf, pcbNeeded, pcReturned);
5614 if (pName && (lstrlenW(pName))) {
5615 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5616 SetLastError(ERROR_ACCESS_DENIED);
5620 /* Level is not checked in win9x */
5621 if (!Level || (Level > 2)) {
5622 WARN("level (%ld) is ignored in win9x\n", Level);
5623 SetLastError(ERROR_INVALID_LEVEL);
5627 SetLastError(RPC_X_NULL_REF_POINTER);
5631 /* Scan all Monitor-Keys */
5633 needed = get_local_monitors(Level, NULL, 0, &numentries);
5635 /* we calculated the needed buffersize. now do the error-checks */
5636 if (cbBuf < needed) {
5637 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5640 else if (!pMonitors || !pcReturned) {
5641 SetLastError(RPC_X_NULL_REF_POINTER);
5645 /* fill the Buffer with the Monitor-Keys */
5646 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5650 if (pcbNeeded) *pcbNeeded = needed;
5651 if (pcReturned) *pcReturned = numentries;
5653 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5654 res, GetLastError(), needed, numentries);
5659 /******************************************************************************
5660 * XcvDataW (WINSPOOL.@)
5663 * There doesn't seem to be an A version...
5665 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5666 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5667 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5669 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5670 pInputData, cbInputData, pOutputData,
5671 cbOutputData, pcbOutputNeeded, pdwStatus);
5675 /*****************************************************************************
5676 * EnumPrinterDataA [WINSPOOL.@]
5679 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5680 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5681 DWORD cbData, LPDWORD pcbData )
5683 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5684 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5685 return ERROR_NO_MORE_ITEMS;
5688 /*****************************************************************************
5689 * EnumPrinterDataW [WINSPOOL.@]
5692 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5693 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5694 DWORD cbData, LPDWORD pcbData )
5696 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5697 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5698 return ERROR_NO_MORE_ITEMS;
5701 /*****************************************************************************
5702 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5705 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5706 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5707 LPDWORD pcbNeeded, LPDWORD pcReturned)
5709 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5710 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5711 pcbNeeded, pcReturned);
5715 /*****************************************************************************
5716 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5719 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5720 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5721 LPDWORD pcbNeeded, LPDWORD pcReturned)
5723 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5724 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5725 pcbNeeded, pcReturned);
5729 /*****************************************************************************
5730 * EnumPrintProcessorsA [WINSPOOL.@]
5733 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5734 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5736 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5737 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5741 /*****************************************************************************
5742 * EnumPrintProcessorsW [WINSPOOL.@]
5745 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5746 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5748 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5749 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5750 cbBuf, pcbNeeded, pcbReturned);
5754 /*****************************************************************************
5755 * ExtDeviceMode [WINSPOOL.@]
5758 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5759 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5762 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5763 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5764 debugstr_a(pProfile), fMode);
5768 /*****************************************************************************
5769 * FindClosePrinterChangeNotification [WINSPOOL.@]
5772 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5774 FIXME("Stub: %p\n", hChange);
5778 /*****************************************************************************
5779 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5782 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5783 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5785 FIXME("Stub: %p %lx %lx %p\n",
5786 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5787 return INVALID_HANDLE_VALUE;
5790 /*****************************************************************************
5791 * FindNextPrinterChangeNotification [WINSPOOL.@]
5794 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5795 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5797 FIXME("Stub: %p %p %p %p\n",
5798 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5802 /*****************************************************************************
5803 * FreePrinterNotifyInfo [WINSPOOL.@]
5806 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5808 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5812 /*****************************************************************************
5815 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5816 * ansi depending on the unicode parameter.
5818 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5828 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5831 memcpy(ptr, str, *size);
5838 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5841 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5848 /*****************************************************************************
5851 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5852 LPDWORD pcbNeeded, BOOL unicode)
5854 DWORD size, left = cbBuf;
5855 BOOL space = (cbBuf > 0);
5862 ji1->JobId = job->job_id;
5865 string_to_buf(job->document_title, ptr, left, &size, unicode);
5866 if(space && size <= left)
5868 ji1->pDocument = (LPWSTR)ptr;
5879 /*****************************************************************************
5882 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5883 LPDWORD pcbNeeded, BOOL unicode)
5885 DWORD size, left = cbBuf;
5886 BOOL space = (cbBuf > 0);
5893 ji2->JobId = job->job_id;
5896 string_to_buf(job->document_title, ptr, left, &size, unicode);
5897 if(space && size <= left)
5899 ji2->pDocument = (LPWSTR)ptr;
5910 /*****************************************************************************
5913 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5914 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5917 DWORD needed = 0, size;
5921 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5923 EnterCriticalSection(&printer_handles_cs);
5924 job = get_job(hPrinter, JobId);
5931 size = sizeof(JOB_INFO_1W);
5936 memset(pJob, 0, size);
5940 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5945 size = sizeof(JOB_INFO_2W);
5950 memset(pJob, 0, size);
5954 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5959 size = sizeof(JOB_INFO_3);
5963 memset(pJob, 0, size);
5972 SetLastError(ERROR_INVALID_LEVEL);
5976 *pcbNeeded = needed;
5978 LeaveCriticalSection(&printer_handles_cs);
5982 /*****************************************************************************
5983 * GetJobA [WINSPOOL.@]
5986 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5987 DWORD cbBuf, LPDWORD pcbNeeded)
5989 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5992 /*****************************************************************************
5993 * GetJobW [WINSPOOL.@]
5996 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5997 DWORD cbBuf, LPDWORD pcbNeeded)
5999 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6002 /*****************************************************************************
6005 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
6007 char *unixname, *queue, *cmd;
6008 char fmt[] = "lpr -P%s %s";
6011 if(!(unixname = wine_get_unix_file_name(filename)))
6014 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6015 queue = HeapAlloc(GetProcessHeap(), 0, len);
6016 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6018 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
6019 sprintf(cmd, fmt, queue, unixname);
6021 TRACE("printing with: %s\n", cmd);
6024 HeapFree(GetProcessHeap(), 0, cmd);
6025 HeapFree(GetProcessHeap(), 0, queue);
6026 HeapFree(GetProcessHeap(), 0, unixname);
6030 /*****************************************************************************
6033 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
6035 #if HAVE_CUPS_CUPS_H
6038 char *unixname, *queue, *doc_titleA;
6042 if(!(unixname = wine_get_unix_file_name(filename)))
6045 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6046 queue = HeapAlloc(GetProcessHeap(), 0, len);
6047 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6049 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6050 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6051 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6053 TRACE("printing via cups\n");
6054 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6055 HeapFree(GetProcessHeap(), 0, doc_titleA);
6056 HeapFree(GetProcessHeap(), 0, queue);
6057 HeapFree(GetProcessHeap(), 0, unixname);
6063 return schedule_lpr(printer_name, filename);
6067 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6074 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6078 if(HIWORD(wparam) == BN_CLICKED)
6080 if(LOWORD(wparam) == IDOK)
6083 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6086 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6087 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6089 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6091 WCHAR caption[200], message[200];
6094 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6095 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6096 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6097 if(mb_ret == IDCANCEL)
6099 HeapFree(GetProcessHeap(), 0, filename);
6103 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6104 if(hf == INVALID_HANDLE_VALUE)
6106 WCHAR caption[200], message[200];
6108 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6109 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6110 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6111 HeapFree(GetProcessHeap(), 0, filename);
6115 DeleteFileW(filename);
6116 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6118 EndDialog(hwnd, IDOK);
6121 if(LOWORD(wparam) == IDCANCEL)
6123 EndDialog(hwnd, IDCANCEL);
6132 /*****************************************************************************
6135 static BOOL get_filename(LPWSTR *filename)
6137 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6138 file_dlg_proc, (LPARAM)filename) == IDOK;
6141 /*****************************************************************************
6144 static BOOL schedule_file(LPCWSTR filename)
6146 LPWSTR output = NULL;
6148 if(get_filename(&output))
6150 TRACE("copy to %s\n", debugstr_w(output));
6151 CopyFileW(filename, output, FALSE);
6152 HeapFree(GetProcessHeap(), 0, output);
6158 /*****************************************************************************
6161 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6164 char *unixname, *cmdA;
6166 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6170 if(!(unixname = wine_get_unix_file_name(filename)))
6173 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6174 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6175 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6177 TRACE("printing with: %s\n", cmdA);
6179 if((file_fd = open(unixname, O_RDONLY)) == -1)
6184 ERR("pipe() failed!\n");
6194 /* reset signals that we previously set to SIG_IGN */
6195 signal(SIGPIPE, SIG_DFL);
6196 signal(SIGCHLD, SIG_DFL);
6202 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6203 write(fds[1], buf, no_read);
6208 if(file_fd != -1) close(file_fd);
6209 if(fds[0] != -1) close(fds[0]);
6210 if(fds[1] != -1) close(fds[1]);
6212 HeapFree(GetProcessHeap(), 0, cmdA);
6213 HeapFree(GetProcessHeap(), 0, unixname);
6220 /*****************************************************************************
6223 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6225 int in_fd, out_fd, no_read;
6228 char *unixname, *outputA;
6231 if(!(unixname = wine_get_unix_file_name(filename)))
6234 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6235 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6236 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6238 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6239 in_fd = open(unixname, O_RDONLY);
6240 if(out_fd == -1 || in_fd == -1)
6243 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6244 write(out_fd, buf, no_read);
6248 if(in_fd != -1) close(in_fd);
6249 if(out_fd != -1) close(out_fd);
6250 HeapFree(GetProcessHeap(), 0, outputA);
6251 HeapFree(GetProcessHeap(), 0, unixname);
6255 /*****************************************************************************
6256 * ScheduleJob [WINSPOOL.@]
6259 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6261 opened_printer_t *printer;
6263 struct list *cursor, *cursor2;
6265 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6266 EnterCriticalSection(&printer_handles_cs);
6267 printer = get_opened_printer(hPrinter);
6271 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6273 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6276 if(job->job_id != dwJobID) continue;
6278 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6279 if(hf != INVALID_HANDLE_VALUE)
6281 PRINTER_INFO_5W *pi5;
6285 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6286 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6288 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6289 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6290 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6291 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6292 debugstr_w(pi5->pPortName));
6296 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6297 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6299 DWORD type, count = sizeof(output);
6300 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6303 if(output[0] == '|')
6305 schedule_pipe(output + 1, job->filename);
6309 schedule_unixfile(output, job->filename);
6311 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6313 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6315 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6317 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6319 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6321 schedule_file(job->filename);
6325 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6327 HeapFree(GetProcessHeap(), 0, pi5);
6329 DeleteFileW(job->filename);
6331 list_remove(cursor);
6332 HeapFree(GetProcessHeap(), 0, job->document_title);
6333 HeapFree(GetProcessHeap(), 0, job->filename);
6334 HeapFree(GetProcessHeap(), 0, job);
6339 LeaveCriticalSection(&printer_handles_cs);
6343 /*****************************************************************************
6344 * StartDocDlgA [WINSPOOL.@]
6346 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6348 UNICODE_STRING usBuffer;
6353 docW.cbSize = sizeof(docW);
6354 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6355 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6356 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6357 docW.fwType = doc->fwType;
6359 retW = StartDocDlgW(hPrinter, &docW);
6363 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6364 ret = HeapAlloc(GetProcessHeap(), 0, len);
6365 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6366 HeapFree(GetProcessHeap(), 0, retW);
6369 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6370 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6371 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6376 /*****************************************************************************
6377 * StartDocDlgW [WINSPOOL.@]
6379 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6380 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6381 * port is "FILE:". Also returns the full path if passed a relative path.
6383 * The caller should free the returned string from the process heap.
6385 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6390 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6392 PRINTER_INFO_5W *pi5;
6393 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6394 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6396 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6397 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6398 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6400 HeapFree(GetProcessHeap(), 0, pi5);
6403 HeapFree(GetProcessHeap(), 0, pi5);
6406 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6409 get_filename(&name);
6412 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6414 HeapFree(GetProcessHeap(), 0, name);
6417 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6418 GetFullPathNameW(name, len, ret, NULL);
6419 HeapFree(GetProcessHeap(), 0, name);
6424 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6427 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6428 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6430 attr = GetFileAttributesW(ret);
6431 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6433 HeapFree(GetProcessHeap(), 0, ret);