4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
68 static CRITICAL_SECTION printer_handles_cs;
69 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
71 0, 0, &printer_handles_cs,
72 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
75 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
97 WCHAR *document_title;
105 LPCWSTR versionregpath;
106 LPCWSTR versionsubdir;
109 /* ############################### */
111 static opened_printer_t **printer_handles;
112 static int nb_printer_handles;
113 static LONG next_job_id = 1;
115 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
116 WORD fwCapability, LPSTR lpszOutput,
118 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
119 LPSTR lpszDevice, LPSTR lpszPort,
120 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
123 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
124 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
125 'c','o','n','t','r','o','l','\\',
126 'P','r','i','n','t','\\',
127 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
128 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
130 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'C','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'M','o','n','i','t','o','r','s',0};
136 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
137 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
138 'C','o','n','t','r','o','l','\\',
139 'P','r','i','n','t','\\',
140 'P','r','i','n','t','e','r','s',0};
142 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
144 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
145 'M','i','c','r','o','s','o','f','t','\\',
146 'W','i','n','d','o','w','s',' ','N','T','\\',
147 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
148 'W','i','n','d','o','w','s',0};
150 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
151 'M','i','c','r','o','s','o','f','t','\\',
152 'W','i','n','d','o','w','s',' ','N','T','\\',
153 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
154 'D','e','v','i','c','e','s',0};
156 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
157 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
158 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
159 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
160 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
161 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
162 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
164 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
165 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
167 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
168 'i','o','n',' ','F','i','l','e',0};
169 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
170 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
171 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
173 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
175 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
176 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
177 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
178 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
179 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
180 static const WCHAR NameW[] = {'N','a','m','e',0};
181 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
182 static const WCHAR PortW[] = {'P','o','r','t',0};
183 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
185 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
187 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
188 'v','e','r','D','a','t','a',0};
189 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
191 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
192 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
193 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
194 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
195 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
196 static const WCHAR emptyStringW[] = {0};
198 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
200 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
201 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
202 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
204 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
205 'D','o','c','u','m','e','n','t',0};
207 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
208 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
209 DWORD Level, LPBYTE pDriverInfo,
210 DWORD cbBuf, LPDWORD pcbNeeded,
212 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
213 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
215 /******************************************************************
216 * validate the user-supplied printing-environment [internal]
219 * env [I] PTR to Environment-String or NULL
223 * Success: PTR to printenv_t
226 * An empty string is handled the same way as NULL.
227 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
231 static const printenv_t * validate_envW(LPCWSTR env)
233 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
234 3, Version3_RegPathW, Version3_SubdirW};
235 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
236 0, emptyStringW, emptyStringW};
237 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
239 const printenv_t *result = NULL;
242 TRACE("testing %s\n", debugstr_w(env));
245 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
247 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
249 result = all_printenv[i];
254 if (result == NULL) {
255 FIXME("unsupported Environment: %s\n", debugstr_w(env));
256 SetLastError(ERROR_INVALID_ENVIRONMENT);
258 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
262 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
264 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
270 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
271 if passed a NULL string. This returns NULLs to the result.
273 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
277 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
278 return usBufferPtr->Buffer;
280 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
284 static LPWSTR strdupW(LPCWSTR p)
290 len = (strlenW(p) + 1) * sizeof(WCHAR);
291 ret = HeapAlloc(GetProcessHeap(), 0, len);
297 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
300 /* If forcing, or no profile string entry for device yet, set the entry
302 * The always change entry if not WINEPS yet is discussable.
305 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
307 !strstr(qbuf,"WINEPS.DRV")
309 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
312 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
313 WriteProfileStringA("windows","device",buf);
314 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
315 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
318 HeapFree(GetProcessHeap(),0,buf);
322 #ifdef HAVE_CUPS_CUPS_H
323 static typeof(cupsGetDests) *pcupsGetDests;
324 static typeof(cupsGetPPD) *pcupsGetPPD;
325 static typeof(cupsPrintFile) *pcupsPrintFile;
326 static void *cupshandle;
328 static BOOL CUPS_LoadPrinters(void)
331 BOOL hadprinter = FALSE;
333 PRINTER_INFO_2A pinfo2a;
335 HKEY hkeyPrinter, hkeyPrinters, hkey;
337 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
340 TRACE("loaded %s\n", SONAME_LIBCUPS);
343 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
344 if (!p##x) return FALSE;
347 DYNCUPS(cupsGetDests);
348 DYNCUPS(cupsPrintFile);
351 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
353 ERR("Can't create Printers key\n");
357 nrofdests = pcupsGetDests(&dests);
358 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
359 for (i=0;i<nrofdests;i++) {
360 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
361 sprintf(port,"LPR:%s",dests[i].name);
362 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
363 sprintf(devline,"WINEPS.DRV,%s",port);
364 WriteProfileStringA("devices",dests[i].name,devline);
365 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
366 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
369 HeapFree(GetProcessHeap(),0,devline);
371 TRACE("Printer %d: %s\n", i, dests[i].name);
372 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
373 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
375 TRACE("Printer already exists\n");
376 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
377 RegCloseKey(hkeyPrinter);
379 memset(&pinfo2a,0,sizeof(pinfo2a));
380 pinfo2a.pPrinterName = dests[i].name;
381 pinfo2a.pDatatype = "RAW";
382 pinfo2a.pPrintProcessor = "WinPrint";
383 pinfo2a.pDriverName = "PS Driver";
384 pinfo2a.pComment = "WINEPS Printer using CUPS";
385 pinfo2a.pLocation = "<physical location of printer>";
386 pinfo2a.pPortName = port;
387 pinfo2a.pParameters = "<parameters?>";
388 pinfo2a.pShareName = "<share name?>";
389 pinfo2a.pSepFile = "<sep file?>";
391 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
392 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
393 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
396 HeapFree(GetProcessHeap(),0,port);
399 if (dests[i].is_default)
400 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
402 RegCloseKey(hkeyPrinters);
408 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
409 PRINTER_INFO_2A pinfo2a;
410 char *e,*s,*name,*prettyname,*devname;
411 BOOL ret = FALSE, set_default = FALSE;
412 char *port,*devline,*env_default;
413 HKEY hkeyPrinter, hkeyPrinters, hkey;
415 while (isspace(*pent)) pent++;
416 s = strchr(pent,':');
418 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
426 TRACE("name=%s entry=%s\n",name, pent);
428 if(ispunct(*name)) { /* a tc entry, not a real printer */
429 TRACE("skipping tc entry\n");
433 if(strstr(pent,":server")) { /* server only version so skip */
434 TRACE("skipping server entry\n");
438 /* Determine whether this is a postscript printer. */
441 env_default = getenv("PRINTER");
443 /* Get longest name, usually the one at the right for later display. */
444 while((s=strchr(prettyname,'|'))) {
447 while(isspace(*--e)) *e = '\0';
448 TRACE("\t%s\n", debugstr_a(prettyname));
449 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
450 for(prettyname = s+1; isspace(*prettyname); prettyname++)
453 e = prettyname + strlen(prettyname);
454 while(isspace(*--e)) *e = '\0';
455 TRACE("\t%s\n", debugstr_a(prettyname));
456 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
458 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
459 * if it is too long, we use it as comment below. */
460 devname = prettyname;
461 if (strlen(devname)>=CCHDEVICENAME-1)
463 if (strlen(devname)>=CCHDEVICENAME-1) {
468 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
469 sprintf(port,"LPR:%s",name);
471 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
472 sprintf(devline,"WINEPS.DRV,%s",port);
473 WriteProfileStringA("devices",devname,devline);
474 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
475 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
478 HeapFree(GetProcessHeap(),0,devline);
480 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
482 ERR("Can't create Printers key\n");
486 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
487 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
489 TRACE("Printer already exists\n");
490 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
491 RegCloseKey(hkeyPrinter);
493 memset(&pinfo2a,0,sizeof(pinfo2a));
494 pinfo2a.pPrinterName = devname;
495 pinfo2a.pDatatype = "RAW";
496 pinfo2a.pPrintProcessor = "WinPrint";
497 pinfo2a.pDriverName = "PS Driver";
498 pinfo2a.pComment = "WINEPS Printer using LPR";
499 pinfo2a.pLocation = prettyname;
500 pinfo2a.pPortName = port;
501 pinfo2a.pParameters = "<parameters?>";
502 pinfo2a.pShareName = "<share name?>";
503 pinfo2a.pSepFile = "<sep file?>";
505 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
506 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
507 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
510 RegCloseKey(hkeyPrinters);
512 if (isfirst || set_default)
513 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
515 HeapFree(GetProcessHeap(), 0, port);
517 HeapFree(GetProcessHeap(), 0, name);
522 PRINTCAP_LoadPrinters(void) {
523 BOOL hadprinter = FALSE;
527 BOOL had_bash = FALSE;
529 f = fopen("/etc/printcap","r");
533 while(fgets(buf,sizeof(buf),f)) {
536 end=strchr(buf,'\n');
540 while(isspace(*start)) start++;
541 if(*start == '#' || *start == '\0')
544 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
545 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
546 HeapFree(GetProcessHeap(),0,pent);
550 if (end && *--end == '\\') {
557 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
560 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
566 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
567 HeapFree(GetProcessHeap(),0,pent);
573 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
576 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
577 lstrlenW(value) * sizeof(WCHAR));
579 return ERROR_FILE_NOT_FOUND;
582 void WINSPOOL_LoadSystemPrinters(void)
584 HKEY hkey, hkeyPrinters;
587 DWORD needed, num, i;
588 WCHAR PrinterName[256];
591 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
592 di3a.pName = "PS Driver";
593 di3a.pEnvironment = NULL; /* NULL means auto */
594 di3a.pDriverPath = "wineps16";
595 di3a.pDataFile = "<datafile?>";
596 di3a.pConfigFile = "wineps16";
597 di3a.pHelpFile = "<helpfile?>";
598 di3a.pDependentFiles = "<dependend files?>";
599 di3a.pMonitorName = "<monitor name?>";
600 di3a.pDefaultDataType = "RAW";
602 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
603 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
607 /* This ensures that all printer entries have a valid Name value. If causes
608 problems later if they don't. If one is found to be missed we create one
609 and set it equal to the name of the key */
610 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
611 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
612 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
613 for(i = 0; i < num; i++) {
614 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
615 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
616 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
617 set_reg_szW(hkey, NameW, PrinterName);
624 RegCloseKey(hkeyPrinters);
627 /* We want to avoid calling AddPrinter on printers as much as
628 possible, because on cups printers this will (eventually) lead
629 to a call to cupsGetPPD which takes forever, even with non-cups
630 printers AddPrinter takes a while. So we'll tag all printers that
631 were automatically added last time around, if they still exist
632 we'll leave them be otherwise we'll delete them. */
633 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
635 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
636 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
637 for(i = 0; i < num; i++) {
638 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
639 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
640 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
642 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
650 HeapFree(GetProcessHeap(), 0, pi);
654 #ifdef HAVE_CUPS_CUPS_H
655 done = CUPS_LoadPrinters();
658 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
659 /* Check for [ppd] section in config file before parsing /etc/printcap */
660 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
661 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
662 &hkey) == ERROR_SUCCESS) {
664 PRINTCAP_LoadPrinters();
668 /* Now enumerate the list again and delete any printers that a still tagged */
669 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
671 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
672 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
673 for(i = 0; i < num; i++) {
674 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
675 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
676 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
677 DWORD dw, type, size = sizeof(dw);
678 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
679 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
689 HeapFree(GetProcessHeap(), 0, pi);
696 /*****************************************************************************
697 * enumerate the local monitors (INTERNAL)
699 * returns the needed size (in bytes) for pMonitors
700 * and *lpreturned is set to number of entries returned in pMonitors
703 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
708 LPMONITOR_INFO_2W mi;
709 WCHAR buffer[MAX_PATH];
710 WCHAR dllname[MAX_PATH];
718 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
720 numentries = *lpreturned; /* this is 0, when we scan the registry */
721 len = entrysize * numentries;
722 ptr = (LPWSTR) &pMonitors[len];
725 len = sizeof(buffer);
728 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
729 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
730 /* Scan all Monitor-Registry-Keys */
731 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
732 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
733 dllsize = sizeof(dllname);
736 /* The Monitor must have a Driver-DLL */
737 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
738 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
739 /* We found a valid DLL for this Monitor. */
740 TRACE("using Driver: %s\n", debugstr_w(dllname));
745 /* Windows returns only Port-Monitors here, but to simplify our code,
746 we do no filtering for Language-Monitors */
750 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
752 /* we install and return only monitors for "Windows NT x86" */
753 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
757 /* required size is calculated. Now fill the user-buffer */
758 if (pMonitors && (cbBuf >= needed)){
759 mi = (LPMONITOR_INFO_2W) pMonitors;
760 pMonitors += entrysize;
762 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
764 lstrcpyW(ptr, buffer); /* Name of the Monitor */
765 ptr += (len+1); /* len is lstrlenW(monitorname) */
767 mi->pEnvironment = ptr;
768 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
769 ptr += (lstrlenW(envname_x86W)+1);
772 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
773 ptr += (dllsize / sizeof(WCHAR));
778 len = sizeof(buffer);
783 *lpreturned = numentries;
784 TRACE("need %ld byte for %ld entries\n", needed, numentries);
788 /******************************************************************
789 * get_opened_printer_entry
790 * Get the first place empty in the opened printer table
793 * - pDefault is ignored
795 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
797 UINT_PTR handle = nb_printer_handles, i;
798 jobqueue_t *queue = NULL;
799 opened_printer_t *printer = NULL;
801 EnterCriticalSection(&printer_handles_cs);
803 for (i = 0; i < nb_printer_handles; i++)
805 if (!printer_handles[i])
807 if(handle == nb_printer_handles)
812 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
813 queue = printer_handles[i]->queue;
817 if (handle >= nb_printer_handles)
819 opened_printer_t **new_array;
821 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
822 (nb_printer_handles + 16) * sizeof(*new_array) );
824 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
825 (nb_printer_handles + 16) * sizeof(*new_array) );
832 printer_handles = new_array;
833 nb_printer_handles += 16;
836 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
843 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
844 if (!printer->name) {
848 strcpyW(printer->name, name);
852 printer->queue = queue;
855 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
856 if (!printer->queue) {
860 list_init(&printer->queue->jobs);
861 printer->queue->ref = 0;
863 InterlockedIncrement(&printer->queue->ref);
865 printer_handles[handle] = printer;
868 LeaveCriticalSection(&printer_handles_cs);
869 if (!handle && printer) {
870 /* Something Failed: Free the Buffers */
871 HeapFree(GetProcessHeap(), 0, printer->name);
872 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
873 HeapFree(GetProcessHeap(), 0, printer);
876 return (HANDLE)handle;
879 /******************************************************************
881 * Get the pointer to the opened printer referred by the handle
883 static opened_printer_t *get_opened_printer(HANDLE hprn)
885 UINT_PTR idx = (UINT_PTR)hprn;
886 opened_printer_t *ret = NULL;
888 EnterCriticalSection(&printer_handles_cs);
890 if ((idx <= 0) || (idx > nb_printer_handles))
893 ret = printer_handles[idx - 1];
895 LeaveCriticalSection(&printer_handles_cs);
899 /******************************************************************
900 * get_opened_printer_name
901 * Get the pointer to the opened printer name referred by the handle
903 static LPCWSTR get_opened_printer_name(HANDLE hprn)
905 opened_printer_t *printer = get_opened_printer(hprn);
906 if(!printer) return NULL;
907 return printer->name;
910 /******************************************************************
911 * WINSPOOL_GetOpenedPrinterRegKey
914 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
916 LPCWSTR name = get_opened_printer_name(hPrinter);
920 if(!name) return ERROR_INVALID_HANDLE;
922 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
926 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
928 ERR("Can't find opened printer %s in registry\n",
930 RegCloseKey(hkeyPrinters);
931 return ERROR_INVALID_PRINTER_NAME; /* ? */
933 RegCloseKey(hkeyPrinters);
934 return ERROR_SUCCESS;
937 /******************************************************************
940 * Get the pointer to the specified job.
941 * Should hold the printer_handles_cs before calling.
943 static job_t *get_job(HANDLE hprn, DWORD JobId)
945 opened_printer_t *printer = get_opened_printer(hprn);
948 if(!printer) return NULL;
949 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
951 if(job->job_id == JobId)
957 /***********************************************************
960 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
963 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
966 Formname = (dmA->dmSize > off_formname);
967 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
968 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
969 dmW->dmDeviceName, CCHDEVICENAME);
971 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
972 dmA->dmSize - CCHDEVICENAME);
974 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
975 off_formname - CCHDEVICENAME);
976 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
977 dmW->dmFormName, CCHFORMNAME);
978 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
979 (off_formname + CCHFORMNAME));
982 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
987 /***********************************************************
989 * Creates an ascii copy of supplied devmode on heap
991 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
996 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
998 if(!dmW) return NULL;
999 Formname = (dmW->dmSize > off_formname);
1000 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1001 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1002 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1003 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1005 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1006 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1008 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1009 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1010 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1011 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1012 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1013 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1016 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1017 dmW->dmDriverExtra);
1021 /***********************************************************
1022 * PRINTER_INFO_2AtoW
1023 * Creates a unicode copy of PRINTER_INFO_2A on heap
1025 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1027 LPPRINTER_INFO_2W piW;
1028 UNICODE_STRING usBuffer;
1030 if(!piA) return NULL;
1031 piW = HeapAlloc(heap, 0, sizeof(*piW));
1032 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1034 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1035 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1036 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1037 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1038 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1039 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1040 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1041 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1042 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1043 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1044 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1045 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1049 /***********************************************************
1050 * FREE_PRINTER_INFO_2W
1051 * Free PRINTER_INFO_2W and all strings
1053 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1057 HeapFree(heap,0,piW->pServerName);
1058 HeapFree(heap,0,piW->pPrinterName);
1059 HeapFree(heap,0,piW->pShareName);
1060 HeapFree(heap,0,piW->pPortName);
1061 HeapFree(heap,0,piW->pDriverName);
1062 HeapFree(heap,0,piW->pComment);
1063 HeapFree(heap,0,piW->pLocation);
1064 HeapFree(heap,0,piW->pDevMode);
1065 HeapFree(heap,0,piW->pSepFile);
1066 HeapFree(heap,0,piW->pPrintProcessor);
1067 HeapFree(heap,0,piW->pDatatype);
1068 HeapFree(heap,0,piW->pParameters);
1069 HeapFree(heap,0,piW);
1073 /******************************************************************
1074 * DeviceCapabilities [WINSPOOL.@]
1075 * DeviceCapabilitiesA [WINSPOOL.@]
1078 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1079 LPSTR pOutput, LPDEVMODEA lpdm)
1083 if (!GDI_CallDeviceCapabilities16)
1085 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1087 if (!GDI_CallDeviceCapabilities16) return -1;
1089 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1091 /* If DC_PAPERSIZE map POINT16s to POINTs */
1092 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1093 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1094 POINT *pt = (POINT *)pOutput;
1096 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1097 for(i = 0; i < ret; i++, pt++)
1102 HeapFree( GetProcessHeap(), 0, tmp );
1108 /*****************************************************************************
1109 * DeviceCapabilitiesW [WINSPOOL.@]
1111 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1114 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1115 WORD fwCapability, LPWSTR pOutput,
1116 const DEVMODEW *pDevMode)
1118 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1119 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1120 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1123 if(pOutput && (fwCapability == DC_BINNAMES ||
1124 fwCapability == DC_FILEDEPENDENCIES ||
1125 fwCapability == DC_PAPERNAMES)) {
1126 /* These need A -> W translation */
1129 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1133 switch(fwCapability) {
1138 case DC_FILEDEPENDENCIES:
1142 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1143 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1145 for(i = 0; i < ret; i++)
1146 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1147 pOutput + (i * size), size);
1148 HeapFree(GetProcessHeap(), 0, pOutputA);
1150 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1151 (LPSTR)pOutput, dmA);
1153 HeapFree(GetProcessHeap(),0,pPortA);
1154 HeapFree(GetProcessHeap(),0,pDeviceA);
1155 HeapFree(GetProcessHeap(),0,dmA);
1159 /******************************************************************
1160 * DocumentPropertiesA [WINSPOOL.@]
1162 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1164 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1165 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1166 LPDEVMODEA pDevModeInput,DWORD fMode )
1168 LPSTR lpName = pDeviceName;
1171 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1172 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1176 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1178 ERR("no name from hPrinter?\n");
1179 SetLastError(ERROR_INVALID_HANDLE);
1182 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1185 if (!GDI_CallExtDeviceMode16)
1187 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1189 if (!GDI_CallExtDeviceMode16) {
1190 ERR("No CallExtDeviceMode16?\n");
1194 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1195 pDevModeInput, NULL, fMode);
1198 HeapFree(GetProcessHeap(),0,lpName);
1203 /*****************************************************************************
1204 * DocumentPropertiesW (WINSPOOL.@)
1206 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1208 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1210 LPDEVMODEW pDevModeOutput,
1211 LPDEVMODEW pDevModeInput, DWORD fMode)
1214 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1215 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1216 LPDEVMODEA pDevModeOutputA = NULL;
1219 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1220 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1222 if(pDevModeOutput) {
1223 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1224 if(ret < 0) return ret;
1225 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1227 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1228 pDevModeInputA, fMode);
1229 if(pDevModeOutput) {
1230 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1231 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1233 if(fMode == 0 && ret > 0)
1234 ret += (CCHDEVICENAME + CCHFORMNAME);
1235 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1236 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1240 /******************************************************************
1241 * OpenPrinterA [WINSPOOL.@]
1246 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1247 LPPRINTER_DEFAULTSA pDefault)
1249 UNICODE_STRING lpPrinterNameW;
1250 UNICODE_STRING usBuffer;
1251 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1252 PWSTR pwstrPrinterNameW;
1255 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1258 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1259 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1260 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1261 pDefaultW = &DefaultW;
1263 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1265 RtlFreeUnicodeString(&usBuffer);
1266 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1268 RtlFreeUnicodeString(&lpPrinterNameW);
1272 /******************************************************************
1273 * OpenPrinterW [WINSPOOL.@]
1275 * Open a Printer / Printserver or a Printer-Object
1278 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1279 * phPrinter [O] The resulting Handle is stored here
1280 * pDefault [I] PTR to Default Printer Settings or NULL
1287 * lpPrinterName is one of:
1288 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1289 *| Printer: "PrinterName"
1290 *| Printer-Object: "PrinterName,Job xxx"
1291 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1292 *| XcvPort: "Servername,XcvPort PortName"
1295 *| Printer-Object not supported
1296 *| XcvMonitor not supported
1297 *| XcvPort not supported
1298 *| pDefaults is ignored
1301 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1303 HKEY hkeyPrinters = NULL;
1304 HKEY hkeyPrinter = NULL;
1306 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1308 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08lx\n",
1309 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1312 if(lpPrinterName != NULL)
1314 /* Check any Printer exists */
1315 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1316 ERR("Can't create Printers key\n");
1317 SetLastError(ERROR_FILE_NOT_FOUND);
1320 if((lpPrinterName[0] == '\0') || /* explicitly exclude "" */
1321 (RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)) {
1323 WARN("Printer not found in Registry: '%s'\n", debugstr_w(lpPrinterName));
1324 RegCloseKey(hkeyPrinters);
1325 SetLastError(ERROR_INVALID_PRINTER_NAME);
1328 RegCloseKey(hkeyPrinter);
1329 RegCloseKey(hkeyPrinters);
1332 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1333 SetLastError(ERROR_INVALID_PARAMETER);
1337 /* Get the unique handle of the printer or Printserver */
1338 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1339 return (*phPrinter != 0);
1342 /******************************************************************
1343 * AddMonitorA [WINSPOOL.@]
1348 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1350 LPWSTR nameW = NULL;
1353 LPMONITOR_INFO_2A mi2a;
1354 MONITOR_INFO_2W mi2w;
1356 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1357 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1358 mi2a ? debugstr_a(mi2a->pName) : NULL,
1359 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1360 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1363 SetLastError(ERROR_INVALID_LEVEL);
1367 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1373 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1374 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1375 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1378 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1380 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1381 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1382 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1384 if (mi2a->pEnvironment) {
1385 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1386 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1387 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1389 if (mi2a->pDLLName) {
1390 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1391 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1392 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1395 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1397 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1398 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1399 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1401 HeapFree(GetProcessHeap(), 0, nameW);
1405 /******************************************************************************
1406 * AddMonitorW [WINSPOOL.@]
1408 * Install a Printmonitor
1411 * pName [I] Servername or NULL (local Computer)
1412 * Level [I] Structure-Level (Must be 2)
1413 * pMonitors [I] PTR to MONITOR_INFO_2
1420 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1423 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1425 LPMONITOR_INFO_2W mi2w;
1428 HMODULE hdll = NULL;
1432 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1433 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1434 mi2w ? debugstr_w(mi2w->pName) : NULL,
1435 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1436 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1439 SetLastError(ERROR_INVALID_LEVEL);
1443 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1448 if (pName && (pName[0])) {
1449 FIXME("for server %s not implemented\n", debugstr_w(pName));
1450 SetLastError(ERROR_ACCESS_DENIED);
1455 if (!mi2w->pName || (! mi2w->pName[0])) {
1456 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1457 SetLastError(ERROR_INVALID_PARAMETER);
1460 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1461 WARN("Environment %s requested (we support only %s)\n",
1462 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1463 SetLastError(ERROR_INVALID_ENVIRONMENT);
1467 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1468 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1469 SetLastError(ERROR_INVALID_PARAMETER);
1473 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1478 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1479 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1483 if(RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1484 KEY_WRITE, NULL, &hentry, &disposition) == ERROR_SUCCESS) {
1486 if (disposition == REG_OPENED_EXISTING_KEY) {
1487 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1488 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1489 9x: ERROR_ALREADY_EXISTS (183) */
1490 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1495 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1496 res = (RegSetValueExW(hentry, DriverW, 0,
1497 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1499 RegCloseKey(hentry);
1506 /******************************************************************
1507 * DeletePrinterDriverA [WINSPOOL.@]
1511 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1513 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1514 debugstr_a(pDriverName));
1515 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1519 /******************************************************************
1520 * DeletePrinterDriverW [WINSPOOL.@]
1524 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1526 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1527 debugstr_w(pDriverName));
1528 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1532 /******************************************************************
1533 * DeleteMonitorA [WINSPOOL.@]
1535 * See DeleteMonitorW.
1538 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1540 LPWSTR nameW = NULL;
1541 LPWSTR EnvironmentW = NULL;
1542 LPWSTR MonitorNameW = NULL;
1547 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1548 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1549 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1553 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1554 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1555 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1558 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1559 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1560 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1563 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1565 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1566 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1567 HeapFree(GetProcessHeap(), 0, nameW);
1571 /******************************************************************
1572 * DeleteMonitorW [WINSPOOL.@]
1574 * Delete a specific Printmonitor from a Printing-Environment
1577 * pName [I] Servername or NULL (local Computer)
1578 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1579 * pMonitorName [I] Name of the Monitor, that should be deleted
1586 * pEnvironment is ignored in Windows for the local Computer.
1590 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1594 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1595 debugstr_w(pMonitorName));
1597 if (pName && (pName[0])) {
1598 FIXME("for server %s not implemented\n", debugstr_w(pName));
1599 SetLastError(ERROR_ACCESS_DENIED);
1603 /* pEnvironment is ignored in Windows for the local Computer */
1605 if (!pMonitorName || !pMonitorName[0]) {
1606 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1607 SetLastError(ERROR_INVALID_PARAMETER);
1611 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1612 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1616 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1617 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1618 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1623 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1626 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1627 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1631 /******************************************************************
1632 * DeletePortA [WINSPOOL.@]
1638 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1640 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1641 debugstr_a(pPortName));
1642 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1646 /******************************************************************
1647 * DeletePortW [WINSPOOL.@]
1649 * Delete a specific Port
1652 * pName [I] Servername or NULL (local Computer)
1653 * hWnd [I] Handle to parent Window for the Dialog-Box
1654 * pPortName [I] Name of the Port, that should be deleted
1665 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1667 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1668 debugstr_w(pPortName));
1669 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1673 /******************************************************************************
1674 * SetPrinterW [WINSPOOL.@]
1676 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
1678 FIXME("(%p, %ld, %p, %ld): stub\n", hPrinter, Level, pPrinter, Command);
1679 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1683 /******************************************************************************
1684 * WritePrinter [WINSPOOL.@]
1686 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1688 opened_printer_t *printer;
1691 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1693 EnterCriticalSection(&printer_handles_cs);
1694 printer = get_opened_printer(hPrinter);
1697 SetLastError(ERROR_INVALID_HANDLE);
1703 SetLastError(ERROR_SPL_NO_STARTDOC);
1707 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1709 LeaveCriticalSection(&printer_handles_cs);
1713 /*****************************************************************************
1714 * AddFormA [WINSPOOL.@]
1716 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1718 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1722 /*****************************************************************************
1723 * AddFormW [WINSPOOL.@]
1725 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1727 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1731 /*****************************************************************************
1732 * AddJobA [WINSPOOL.@]
1734 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1737 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1741 SetLastError(ERROR_INVALID_LEVEL);
1745 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1748 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1749 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1750 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1751 if(*pcbNeeded > cbBuf) {
1752 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1755 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1756 addjobA->JobId = addjobW->JobId;
1757 addjobA->Path = (char *)(addjobA + 1);
1758 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1764 /*****************************************************************************
1765 * AddJobW [WINSPOOL.@]
1767 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1769 opened_printer_t *printer;
1772 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1773 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1774 WCHAR path[MAX_PATH], filename[MAX_PATH];
1776 ADDJOB_INFO_1W *addjob;
1778 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1780 EnterCriticalSection(&printer_handles_cs);
1782 printer = get_opened_printer(hPrinter);
1785 SetLastError(ERROR_INVALID_HANDLE);
1790 SetLastError(ERROR_INVALID_LEVEL);
1794 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1798 job->job_id = InterlockedIncrement(&next_job_id);
1800 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1801 if(path[len - 1] != '\\')
1803 memcpy(path + len, spool_path, sizeof(spool_path));
1804 sprintfW(filename, fmtW, path, job->job_id);
1806 len = strlenW(filename);
1807 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1808 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1809 job->document_title = strdupW(default_doc_title);
1810 list_add_tail(&printer->queue->jobs, &job->entry);
1812 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1813 if(*pcbNeeded <= cbBuf) {
1814 addjob = (ADDJOB_INFO_1W*)pData;
1815 addjob->JobId = job->job_id;
1816 addjob->Path = (WCHAR *)(addjob + 1);
1817 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1820 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1823 LeaveCriticalSection(&printer_handles_cs);
1827 /*****************************************************************************
1828 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1830 * Return the PATH for the Print-Processors
1832 * See GetPrintProcessorDirectoryW.
1835 * On NT, the returned ANSI-Data need the same Size as the Unicode-Version
1838 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1839 DWORD level, LPBYTE Info,
1840 DWORD cbBuf, LPDWORD needed)
1842 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1843 level, Info, cbBuf);
1847 /*****************************************************************************
1848 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1850 * Return the PATH for the Print-Processors
1853 * server [I] Servername (NT only) or NULL (local Computer)
1854 * env [I] Printing-Environment (see below) or NULL (Default)
1855 * level [I] Structure-Level (must be 1)
1856 * Info [O] PTR to Buffer that receives the Result
1857 * cbBuf [I] Size of Buffer at "Info"
1858 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1859 * required for the Buffer at "Info"
1862 * Success: TRUE and in pcbNeeded the Bytes used in Info
1863 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
1864 * if cbBuf is too small
1866 * Native Values returned in Info on Success:
1867 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
1868 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
1869 *| win9x(Windows 4.0): "%winsysdir%"
1871 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1874 * Only NULL or "" is supported for server
1877 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1878 DWORD level, LPBYTE Info,
1879 DWORD cbBuf, LPDWORD pcbNeeded)
1882 const printenv_t * env_t;
1884 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(server),
1885 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
1887 if(server != NULL && server[0]) {
1888 FIXME("server not supported: %s\n", debugstr_w(server));
1889 SetLastError(ERROR_INVALID_PARAMETER);
1893 env_t = validate_envW(env);
1894 if(!env_t) return FALSE; /* environment invalid or unsupported */
1897 WARN("(Level: %ld) is ignored in win9x\n", level);
1898 SetLastError(ERROR_INVALID_LEVEL);
1902 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1903 needed = GetSystemDirectoryW(NULL, 0);
1904 /* add the Size for the Subdirectories */
1905 needed += lstrlenW(spoolprtprocsW);
1906 needed += lstrlenW(env_t->subdir);
1907 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1909 if(pcbNeeded) *pcbNeeded = needed;
1910 TRACE ("required: 0x%lx/%ld\n", needed, needed);
1911 if (needed > cbBuf) {
1912 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1915 if(pcbNeeded == NULL) {
1916 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
1917 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
1918 SetLastError(RPC_X_NULL_REF_POINTER);
1922 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
1923 SetLastError(RPC_X_NULL_REF_POINTER);
1927 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
1928 /* add the Subdirectories */
1929 lstrcatW((LPWSTR) Info, spoolprtprocsW);
1930 lstrcatW((LPWSTR) Info, env_t->subdir);
1931 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
1935 /*****************************************************************************
1936 * WINSPOOL_OpenDriverReg [internal]
1938 * opens the registry for the printer drivers depending on the given input
1939 * variable pEnvironment
1942 * the opened hkey on success
1945 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1949 const printenv_t * env;
1952 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
1954 if (!pEnvironment || unicode) {
1955 /* pEnvironment was NULL or an Unicode-String: use it direct */
1956 env = validate_envW(pEnvironment);
1960 /* pEnvironment was an ANSI-String: convert to unicode first */
1962 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1963 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1964 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1965 env = validate_envW(buffer);
1966 HeapFree(GetProcessHeap(), 0, buffer);
1968 if (!env) return NULL;
1970 buffer = HeapAlloc( GetProcessHeap(), 0,
1971 (strlenW(DriversW) + strlenW(env->envname) +
1972 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
1974 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
1975 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1976 HeapFree(GetProcessHeap(), 0, buffer);
1981 /*****************************************************************************
1982 * AddPrinterW [WINSPOOL.@]
1984 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1986 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1990 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1993 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1996 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1997 SetLastError(ERROR_INVALID_PARAMETER);
2001 ERR("Level = %ld, unsupported!\n", Level);
2002 SetLastError(ERROR_INVALID_LEVEL);
2005 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
2006 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
2007 debugstr_w(pi->pPrinterName)
2009 SetLastError(ERROR_INVALID_LEVEL);
2013 SetLastError(ERROR_INVALID_PARAMETER);
2016 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2018 ERR("Can't create Printers key\n");
2021 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2022 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2023 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2024 RegCloseKey(hkeyPrinter);
2025 RegCloseKey(hkeyPrinters);
2028 RegCloseKey(hkeyPrinter);
2030 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2032 ERR("Can't create Drivers key\n");
2033 RegCloseKey(hkeyPrinters);
2036 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2038 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2039 RegCloseKey(hkeyPrinters);
2040 RegCloseKey(hkeyDrivers);
2041 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2044 RegCloseKey(hkeyDriver);
2045 RegCloseKey(hkeyDrivers);
2047 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2048 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2049 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2050 RegCloseKey(hkeyPrinters);
2054 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2056 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2057 SetLastError(ERROR_INVALID_PRINTER_NAME);
2058 RegCloseKey(hkeyPrinters);
2061 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2062 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2063 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2065 /* See if we can load the driver. We may need the devmode structure anyway
2068 * Note that DocumentPropertiesW will briefly try to open the printer we
2069 * just create to find a DEVMODEA struct (it will use the WINEPS default
2070 * one in case it is not there, so we are ok).
2072 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2075 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2076 size = sizeof(DEVMODEW);
2082 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2083 ZeroMemory(dmW,size);
2085 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2087 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2088 HeapFree(GetProcessHeap(),0,dmW);
2093 /* set devmode to printer name */
2094 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
2098 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2099 and we support these drivers. NT writes DEVMODEW so somehow
2100 we'll need to distinguish between these when we support NT
2104 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2105 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2106 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2107 HeapFree(GetProcessHeap(), 0, dmA);
2109 HeapFree(GetProcessHeap(), 0, dmW);
2111 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2112 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2113 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2114 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2116 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2117 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2118 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2119 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2120 (LPBYTE)&pi->Priority, sizeof(DWORD));
2121 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2122 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2123 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2124 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2125 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2126 (LPBYTE)&pi->Status, sizeof(DWORD));
2127 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2128 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2130 RegCloseKey(hkeyPrinter);
2131 RegCloseKey(hkeyPrinters);
2132 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2133 ERR("OpenPrinter failing\n");
2139 /*****************************************************************************
2140 * AddPrinterA [WINSPOOL.@]
2142 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2144 UNICODE_STRING pNameW;
2146 PRINTER_INFO_2W *piW;
2147 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2150 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2152 ERR("Level = %ld, unsupported!\n", Level);
2153 SetLastError(ERROR_INVALID_LEVEL);
2156 pwstrNameW = asciitounicode(&pNameW,pName);
2157 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2159 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2161 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2162 RtlFreeUnicodeString(&pNameW);
2167 /*****************************************************************************
2168 * ClosePrinter [WINSPOOL.@]
2170 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2172 UINT_PTR i = (UINT_PTR)hPrinter;
2173 opened_printer_t *printer = NULL;
2176 TRACE("Handle %p\n", hPrinter);
2178 EnterCriticalSection(&printer_handles_cs);
2180 if ((i > 0) && (i <= nb_printer_handles))
2181 printer = printer_handles[i - 1];
2185 struct list *cursor, *cursor2;
2188 EndDocPrinter(hPrinter);
2190 if(InterlockedDecrement(&printer->queue->ref) == 0)
2192 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2194 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2195 ScheduleJob(hPrinter, job->job_id);
2197 HeapFree(GetProcessHeap(), 0, printer->queue);
2199 HeapFree(GetProcessHeap(), 0, printer->name);
2200 HeapFree(GetProcessHeap(), 0, printer);
2201 printer_handles[i - 1] = NULL;
2204 LeaveCriticalSection(&printer_handles_cs);
2208 /*****************************************************************************
2209 * DeleteFormA [WINSPOOL.@]
2211 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2213 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2217 /*****************************************************************************
2218 * DeleteFormW [WINSPOOL.@]
2220 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2222 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2226 /*****************************************************************************
2227 * WINSPOOL_SHRegDeleteKey
2229 * Recursively delete subkeys.
2230 * Cut & paste from shlwapi.
2233 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2235 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2236 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2239 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2242 /* Find how many subkeys there are */
2243 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2244 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2248 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2249 /* Name too big: alloc a buffer for it */
2250 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2253 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2256 /* Recursively delete all the subkeys */
2257 for(i = 0; i < dwKeyCount && !dwRet; i++)
2259 dwSize = dwMaxSubkeyLen;
2260 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2262 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2265 if (lpszName != szNameBuf)
2266 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2270 RegCloseKey(hSubKey);
2272 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2277 /*****************************************************************************
2278 * DeletePrinter [WINSPOOL.@]
2280 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2282 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2283 HKEY hkeyPrinters, hkey;
2286 SetLastError(ERROR_INVALID_HANDLE);
2289 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2290 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2291 RegCloseKey(hkeyPrinters);
2293 WriteProfileStringW(devicesW, lpNameW, NULL);
2294 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2295 RegDeleteValueW(hkey, lpNameW);
2301 /*****************************************************************************
2302 * SetPrinterA [WINSPOOL.@]
2304 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2307 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2311 /*****************************************************************************
2312 * SetJobA [WINSPOOL.@]
2314 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2315 LPBYTE pJob, DWORD Command)
2319 UNICODE_STRING usBuffer;
2321 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2323 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2324 are all ignored by SetJob, so we don't bother copying them */
2332 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2333 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2335 JobW = (LPBYTE)info1W;
2336 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2337 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2338 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2339 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2340 info1W->Status = info1A->Status;
2341 info1W->Priority = info1A->Priority;
2342 info1W->Position = info1A->Position;
2343 info1W->PagesPrinted = info1A->PagesPrinted;
2348 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2349 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2351 JobW = (LPBYTE)info2W;
2352 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2353 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2354 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2355 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2356 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2357 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2358 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2359 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2360 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2361 info2W->Status = info2A->Status;
2362 info2W->Priority = info2A->Priority;
2363 info2W->Position = info2A->Position;
2364 info2W->StartTime = info2A->StartTime;
2365 info2W->UntilTime = info2A->UntilTime;
2366 info2W->PagesPrinted = info2A->PagesPrinted;
2370 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2371 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2374 SetLastError(ERROR_INVALID_LEVEL);
2378 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2384 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2385 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2386 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2387 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2388 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2393 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2394 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2395 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2396 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2397 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2398 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2399 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2400 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2401 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2405 HeapFree(GetProcessHeap(), 0, JobW);
2410 /*****************************************************************************
2411 * SetJobW [WINSPOOL.@]
2413 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2414 LPBYTE pJob, DWORD Command)
2419 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2420 FIXME("Ignoring everything other than document title\n");
2422 EnterCriticalSection(&printer_handles_cs);
2423 job = get_job(hPrinter, JobId);
2433 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2434 HeapFree(GetProcessHeap(), 0, job->document_title);
2435 job->document_title = strdupW(info1->pDocument);
2440 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2441 HeapFree(GetProcessHeap(), 0, job->document_title);
2442 job->document_title = strdupW(info2->pDocument);
2448 SetLastError(ERROR_INVALID_LEVEL);
2453 LeaveCriticalSection(&printer_handles_cs);
2457 /*****************************************************************************
2458 * EndDocPrinter [WINSPOOL.@]
2460 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2462 opened_printer_t *printer;
2464 TRACE("(%p)\n", hPrinter);
2466 EnterCriticalSection(&printer_handles_cs);
2468 printer = get_opened_printer(hPrinter);
2471 SetLastError(ERROR_INVALID_HANDLE);
2477 SetLastError(ERROR_SPL_NO_STARTDOC);
2481 CloseHandle(printer->doc->hf);
2482 ScheduleJob(hPrinter, printer->doc->job_id);
2483 HeapFree(GetProcessHeap(), 0, printer->doc);
2484 printer->doc = NULL;
2487 LeaveCriticalSection(&printer_handles_cs);
2491 /*****************************************************************************
2492 * EndPagePrinter [WINSPOOL.@]
2494 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2496 FIXME("(%p): stub\n", hPrinter);
2500 /*****************************************************************************
2501 * StartDocPrinterA [WINSPOOL.@]
2503 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2505 UNICODE_STRING usBuffer;
2507 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2510 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2511 or one (DOC_INFO_3) extra DWORDs */
2515 doc2W.JobId = doc2->JobId;
2518 doc2W.dwMode = doc2->dwMode;
2521 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2522 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2523 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2527 SetLastError(ERROR_INVALID_LEVEL);
2531 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2533 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2534 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2535 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2540 /*****************************************************************************
2541 * StartDocPrinterW [WINSPOOL.@]
2543 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2545 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2546 opened_printer_t *printer;
2547 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2548 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2549 JOB_INFO_1W job_info;
2550 DWORD needed, ret = 0;
2554 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2555 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2556 debugstr_w(doc->pDatatype));
2558 if(Level < 1 || Level > 3)
2560 SetLastError(ERROR_INVALID_LEVEL);
2564 EnterCriticalSection(&printer_handles_cs);
2565 printer = get_opened_printer(hPrinter);
2568 SetLastError(ERROR_INVALID_HANDLE);
2574 SetLastError(ERROR_INVALID_PRINTER_STATE);
2578 /* Even if we're printing to a file we still add a print job, we'll
2579 just ignore the spool file name */
2581 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2583 ERR("AddJob failed gle %08lx\n", GetLastError());
2587 if(doc->pOutputFile)
2588 filename = doc->pOutputFile;
2590 filename = addjob->Path;
2592 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2593 if(hf == INVALID_HANDLE_VALUE)
2596 memset(&job_info, 0, sizeof(job_info));
2597 job_info.pDocument = doc->pDocName;
2598 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2600 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2601 printer->doc->hf = hf;
2602 ret = printer->doc->job_id = addjob->JobId;
2604 LeaveCriticalSection(&printer_handles_cs);
2609 /*****************************************************************************
2610 * StartPagePrinter [WINSPOOL.@]
2612 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2614 FIXME("(%p): stub\n", hPrinter);
2618 /*****************************************************************************
2619 * GetFormA [WINSPOOL.@]
2621 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2622 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2624 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2625 Level,pForm,cbBuf,pcbNeeded);
2629 /*****************************************************************************
2630 * GetFormW [WINSPOOL.@]
2632 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2633 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2635 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2636 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2640 /*****************************************************************************
2641 * SetFormA [WINSPOOL.@]
2643 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2646 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2650 /*****************************************************************************
2651 * SetFormW [WINSPOOL.@]
2653 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2656 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2660 /*****************************************************************************
2661 * ReadPrinter [WINSPOOL.@]
2663 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2664 LPDWORD pNoBytesRead)
2666 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2670 /*****************************************************************************
2671 * ResetPrinterA [WINSPOOL.@]
2673 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2675 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2679 /*****************************************************************************
2680 * ResetPrinterW [WINSPOOL.@]
2682 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2684 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2688 /*****************************************************************************
2689 * WINSPOOL_GetDWORDFromReg
2691 * Return DWORD associated with ValueName from hkey.
2693 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2695 DWORD sz = sizeof(DWORD), type, value = 0;
2698 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2700 if(ret != ERROR_SUCCESS) {
2701 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2704 if(type != REG_DWORD) {
2705 ERR("Got type %ld\n", type);
2711 /*****************************************************************************
2712 * WINSPOOL_GetStringFromReg
2714 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2715 * String is stored either as unicode or ascii.
2716 * Bit of a hack here to get the ValueName if we want ascii.
2718 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2719 DWORD buflen, DWORD *needed,
2722 DWORD sz = buflen, type;
2726 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2728 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2729 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2730 HeapFree(GetProcessHeap(),0,ValueNameA);
2732 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2733 WARN("Got ret = %ld\n", ret);
2737 /* add space for terminating '\0' */
2738 sz += unicode ? sizeof(WCHAR) : 1;
2742 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2747 /*****************************************************************************
2748 * WINSPOOL_GetDefaultDevMode
2750 * Get a default DevMode values for wineps.
2754 static void WINSPOOL_GetDefaultDevMode(
2756 DWORD buflen, DWORD *needed,
2760 static const char szwps[] = "wineps.drv";
2762 /* fill default DEVMODE - should be read from ppd... */
2763 ZeroMemory( &dm, sizeof(dm) );
2764 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2765 dm.dmSpecVersion = DM_SPECVERSION;
2766 dm.dmDriverVersion = 1;
2767 dm.dmSize = sizeof(DEVMODEA);
2768 dm.dmDriverExtra = 0;
2770 DM_ORIENTATION | DM_PAPERSIZE |
2771 DM_PAPERLENGTH | DM_PAPERWIDTH |
2774 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2775 DM_YRESOLUTION | DM_TTOPTION;
2777 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2778 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2779 dm.u1.s1.dmPaperLength = 2970;
2780 dm.u1.s1.dmPaperWidth = 2100;
2784 dm.dmDefaultSource = DMBIN_AUTO;
2785 dm.dmPrintQuality = DMRES_MEDIUM;
2788 dm.dmYResolution = 300; /* 300dpi */
2789 dm.dmTTOption = DMTT_BITMAP;
2792 /* dm.dmLogPixels */
2793 /* dm.dmBitsPerPel */
2794 /* dm.dmPelsWidth */
2795 /* dm.dmPelsHeight */
2796 /* dm.dmDisplayFlags */
2797 /* dm.dmDisplayFrequency */
2798 /* dm.dmICMMethod */
2799 /* dm.dmICMIntent */
2800 /* dm.dmMediaType */
2801 /* dm.dmDitherType */
2802 /* dm.dmReserved1 */
2803 /* dm.dmReserved2 */
2804 /* dm.dmPanningWidth */
2805 /* dm.dmPanningHeight */
2808 if(buflen >= sizeof(DEVMODEW)) {
2809 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2810 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2811 HeapFree(GetProcessHeap(),0,pdmW);
2813 *needed = sizeof(DEVMODEW);
2817 if(buflen >= sizeof(DEVMODEA)) {
2818 memcpy(ptr, &dm, sizeof(DEVMODEA));
2820 *needed = sizeof(DEVMODEA);
2824 /*****************************************************************************
2825 * WINSPOOL_GetDevModeFromReg
2827 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2828 * DevMode is stored either as unicode or ascii.
2830 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2832 DWORD buflen, DWORD *needed,
2835 DWORD sz = buflen, type;
2838 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2839 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2840 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2841 if (sz < sizeof(DEVMODEA))
2843 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2846 /* ensures that dmSize is not erratically bogus if registry is invalid */
2847 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2848 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2850 sz += (CCHDEVICENAME + CCHFORMNAME);
2852 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2853 memcpy(ptr, dmW, sz);
2854 HeapFree(GetProcessHeap(),0,dmW);
2861 /*********************************************************************
2862 * WINSPOOL_GetPrinter_2
2864 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2865 * The strings are either stored as unicode or ascii.
2867 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2868 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2871 DWORD size, left = cbBuf;
2872 BOOL space = (cbBuf > 0);
2877 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2879 if(space && size <= left) {
2880 pi2->pPrinterName = (LPWSTR)ptr;
2887 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2889 if(space && size <= left) {
2890 pi2->pShareName = (LPWSTR)ptr;
2897 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2899 if(space && size <= left) {
2900 pi2->pPortName = (LPWSTR)ptr;
2907 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2909 if(space && size <= left) {
2910 pi2->pDriverName = (LPWSTR)ptr;
2917 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2919 if(space && size <= left) {
2920 pi2->pComment = (LPWSTR)ptr;
2927 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2929 if(space && size <= left) {
2930 pi2->pLocation = (LPWSTR)ptr;
2937 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2939 if(space && size <= left) {
2940 pi2->pDevMode = (LPDEVMODEW)ptr;
2949 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2950 if(space && size <= left) {
2951 pi2->pDevMode = (LPDEVMODEW)ptr;
2958 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2960 if(space && size <= left) {
2961 pi2->pSepFile = (LPWSTR)ptr;
2968 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2970 if(space && size <= left) {
2971 pi2->pPrintProcessor = (LPWSTR)ptr;
2978 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2980 if(space && size <= left) {
2981 pi2->pDatatype = (LPWSTR)ptr;
2988 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2990 if(space && size <= left) {
2991 pi2->pParameters = (LPWSTR)ptr;
2999 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3000 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3001 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3002 "Default Priority");
3003 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3004 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3007 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3008 memset(pi2, 0, sizeof(*pi2));
3013 /*********************************************************************
3014 * WINSPOOL_GetPrinter_4
3016 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3018 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3019 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3022 DWORD size, left = cbBuf;
3023 BOOL space = (cbBuf > 0);
3028 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3030 if(space && size <= left) {
3031 pi4->pPrinterName = (LPWSTR)ptr;
3039 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3042 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3043 memset(pi4, 0, sizeof(*pi4));
3048 /*********************************************************************
3049 * WINSPOOL_GetPrinter_5
3051 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3053 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3054 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3057 DWORD size, left = cbBuf;
3058 BOOL space = (cbBuf > 0);
3063 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3065 if(space && size <= left) {
3066 pi5->pPrinterName = (LPWSTR)ptr;
3073 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3075 if(space && size <= left) {
3076 pi5->pPortName = (LPWSTR)ptr;
3084 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3085 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3087 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3091 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3092 memset(pi5, 0, sizeof(*pi5));
3097 /*****************************************************************************
3098 * WINSPOOL_GetPrinter
3100 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3101 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3102 * just a collection of pointers to strings.
3104 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3105 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3108 DWORD size, needed = 0;
3110 HKEY hkeyPrinter, hkeyPrinters;
3113 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3115 if (!(name = get_opened_printer_name(hPrinter))) {
3116 SetLastError(ERROR_INVALID_HANDLE);
3120 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3122 ERR("Can't create Printers key\n");
3125 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3127 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3128 RegCloseKey(hkeyPrinters);
3129 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3136 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3138 size = sizeof(PRINTER_INFO_2W);
3140 ptr = pPrinter + size;
3142 memset(pPrinter, 0, size);
3147 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3155 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3157 size = sizeof(PRINTER_INFO_4W);
3159 ptr = pPrinter + size;
3161 memset(pPrinter, 0, size);
3166 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3175 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3177 size = sizeof(PRINTER_INFO_5W);
3179 ptr = pPrinter + size;
3181 memset(pPrinter, 0, size);
3187 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3194 FIXME("Unimplemented level %ld\n", Level);
3195 SetLastError(ERROR_INVALID_LEVEL);
3196 RegCloseKey(hkeyPrinters);
3197 RegCloseKey(hkeyPrinter);
3201 RegCloseKey(hkeyPrinter);
3202 RegCloseKey(hkeyPrinters);
3204 TRACE("returning %d needed = %ld\n", ret, needed);
3205 if(pcbNeeded) *pcbNeeded = needed;
3207 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3211 /*****************************************************************************
3212 * GetPrinterW [WINSPOOL.@]
3214 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3215 DWORD cbBuf, LPDWORD pcbNeeded)
3217 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3221 /*****************************************************************************
3222 * GetPrinterA [WINSPOOL.@]
3224 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3225 DWORD cbBuf, LPDWORD pcbNeeded)
3227 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3231 /*****************************************************************************
3232 * WINSPOOL_EnumPrinters
3234 * Implementation of EnumPrintersA|W
3236 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3237 DWORD dwLevel, LPBYTE lpbPrinters,
3238 DWORD cbBuf, LPDWORD lpdwNeeded,
3239 LPDWORD lpdwReturned, BOOL unicode)
3242 HKEY hkeyPrinters, hkeyPrinter;
3243 WCHAR PrinterName[255];
3244 DWORD needed = 0, number = 0;
3245 DWORD used, i, left;
3249 memset(lpbPrinters, 0, cbBuf);
3255 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3256 if(dwType == PRINTER_ENUM_DEFAULT)
3259 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3260 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3261 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3262 if(!dwType) return TRUE;
3265 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3266 FIXME("dwType = %08lx\n", dwType);
3267 SetLastError(ERROR_INVALID_FLAGS);
3271 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3273 ERR("Can't create Printers key\n");
3277 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3278 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3279 RegCloseKey(hkeyPrinters);
3280 ERR("Can't query Printers key\n");
3283 TRACE("Found %ld printers\n", number);
3287 RegCloseKey(hkeyPrinters);
3289 *lpdwReturned = number;
3293 used = number * sizeof(PRINTER_INFO_2W);
3296 used = number * sizeof(PRINTER_INFO_4W);
3299 used = number * sizeof(PRINTER_INFO_5W);
3303 SetLastError(ERROR_INVALID_LEVEL);
3304 RegCloseKey(hkeyPrinters);
3307 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3309 for(i = 0; i < number; i++) {
3310 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3312 ERR("Can't enum key number %ld\n", i);
3313 RegCloseKey(hkeyPrinters);
3316 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3317 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3319 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3320 RegCloseKey(hkeyPrinters);
3325 buf = lpbPrinters + used;
3326 left = cbBuf - used;
3334 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3335 left, &needed, unicode);
3337 if(pi) pi += sizeof(PRINTER_INFO_2W);
3340 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3341 left, &needed, unicode);
3343 if(pi) pi += sizeof(PRINTER_INFO_4W);
3346 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3347 left, &needed, unicode);
3349 if(pi) pi += sizeof(PRINTER_INFO_5W);
3352 ERR("Shouldn't be here!\n");
3353 RegCloseKey(hkeyPrinter);
3354 RegCloseKey(hkeyPrinters);
3357 RegCloseKey(hkeyPrinter);
3359 RegCloseKey(hkeyPrinters);
3366 memset(lpbPrinters, 0, cbBuf);
3367 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3371 *lpdwReturned = number;
3372 SetLastError(ERROR_SUCCESS);
3377 /******************************************************************
3378 * EnumPrintersW [WINSPOOL.@]
3380 * Enumerates the available printers, print servers and print
3381 * providers, depending on the specified flags, name and level.
3385 * If level is set to 1:
3386 * Not implemented yet!
3387 * Returns TRUE with an empty list.
3389 * If level is set to 2:
3390 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3391 * Returns an array of PRINTER_INFO_2 data structures in the
3392 * lpbPrinters buffer. Note that according to MSDN also an
3393 * OpenPrinter should be performed on every remote printer.
3395 * If level is set to 4 (officially WinNT only):
3396 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3397 * Fast: Only the registry is queried to retrieve printer names,
3398 * no connection to the driver is made.
3399 * Returns an array of PRINTER_INFO_4 data structures in the
3400 * lpbPrinters buffer.
3402 * If level is set to 5 (officially WinNT4/Win9x only):
3403 * Fast: Only the registry is queried to retrieve printer names,
3404 * no connection to the driver is made.
3405 * Returns an array of PRINTER_INFO_5 data structures in the
3406 * lpbPrinters buffer.
3408 * If level set to 3 or 6+:
3409 * returns zero (failure!)
3411 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3415 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3416 * - Only levels 2, 4 and 5 are implemented at the moment.
3417 * - 16-bit printer drivers are not enumerated.
3418 * - Returned amount of bytes used/needed does not match the real Windoze
3419 * implementation (as in this implementation, all strings are part
3420 * of the buffer, whereas Win32 keeps them somewhere else)
3421 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3424 * - In a regular Wine installation, no registry settings for printers
3425 * exist, which makes this function return an empty list.
3427 BOOL WINAPI EnumPrintersW(
3428 DWORD dwType, /* [in] Types of print objects to enumerate */
3429 LPWSTR lpszName, /* [in] name of objects to enumerate */
3430 DWORD dwLevel, /* [in] type of printer info structure */
3431 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3432 DWORD cbBuf, /* [in] max size of buffer in bytes */
3433 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3434 LPDWORD lpdwReturned /* [out] number of entries returned */
3437 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3438 lpdwNeeded, lpdwReturned, TRUE);
3441 /******************************************************************
3442 * EnumPrintersA [WINSPOOL.@]
3445 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3446 DWORD dwLevel, LPBYTE lpbPrinters,
3447 DWORD cbBuf, LPDWORD lpdwNeeded,
3448 LPDWORD lpdwReturned)
3451 UNICODE_STRING lpszNameW;
3454 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3455 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3456 lpdwNeeded, lpdwReturned, FALSE);
3457 RtlFreeUnicodeString(&lpszNameW);
3461 /*****************************************************************************
3462 * WINSPOOL_GetDriverInfoFromReg [internal]
3464 * Enters the information from the registry into the DRIVER_INFO struct
3467 * zero if the printer driver does not exist in the registry
3468 * (only if Level > 1) otherwise nonzero
3470 static BOOL WINSPOOL_GetDriverInfoFromReg(
3473 LPWSTR pEnvironment,
3475 LPBYTE ptr, /* DRIVER_INFO */
3476 LPBYTE pDriverStrings, /* strings buffer */
3477 DWORD cbBuf, /* size of string buffer */
3478 LPDWORD pcbNeeded, /* space needed for str. */
3479 BOOL unicode) /* type of strings */
3483 LPBYTE strPtr = pDriverStrings;
3485 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3486 debugstr_w(DriverName), debugstr_w(pEnvironment),
3487 Level, ptr, pDriverStrings, cbBuf, unicode);
3490 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3491 if (*pcbNeeded <= cbBuf)
3492 strcpyW((LPWSTR)strPtr, DriverName);
3494 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3496 if(*pcbNeeded <= cbBuf)
3497 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3498 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3502 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3506 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3507 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3510 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3511 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3512 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3517 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3520 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3522 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3524 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3527 if(*pcbNeeded <= cbBuf) {
3529 strcpyW((LPWSTR)strPtr, pEnvironment);
3531 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3532 (LPSTR)strPtr, size, NULL, NULL);
3534 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3535 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3538 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3541 if(*pcbNeeded <= cbBuf)
3542 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3545 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3546 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3549 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3552 if(*pcbNeeded <= cbBuf)
3553 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3556 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3557 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3560 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3561 0, &size, unicode)) {
3563 if(*pcbNeeded <= cbBuf)
3564 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3565 size, &tmp, unicode);
3567 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3568 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3572 RegCloseKey(hkeyDriver);
3573 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3577 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3580 if(*pcbNeeded <= cbBuf)
3581 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3582 size, &tmp, unicode);
3584 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3585 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3588 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3591 if(*pcbNeeded <= cbBuf)
3592 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3593 size, &tmp, unicode);
3595 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3596 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3599 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3602 if(*pcbNeeded <= cbBuf)
3603 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3604 size, &tmp, unicode);
3606 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3607 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3610 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3613 if(*pcbNeeded <= cbBuf)
3614 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3615 size, &tmp, unicode);
3617 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3618 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3621 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3622 RegCloseKey(hkeyDriver);
3626 /*****************************************************************************
3627 * WINSPOOL_GetPrinterDriver
3629 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3630 DWORD Level, LPBYTE pDriverInfo,
3631 DWORD cbBuf, LPDWORD pcbNeeded,
3635 WCHAR DriverName[100];
3636 DWORD ret, type, size, needed = 0;
3638 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3640 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3641 Level,pDriverInfo,cbBuf, pcbNeeded);
3643 ZeroMemory(pDriverInfo, cbBuf);
3645 if (!(name = get_opened_printer_name(hPrinter))) {
3646 SetLastError(ERROR_INVALID_HANDLE);
3649 if(Level < 1 || Level > 6) {
3650 SetLastError(ERROR_INVALID_LEVEL);
3653 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3655 ERR("Can't create Printers key\n");
3658 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3660 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3661 RegCloseKey(hkeyPrinters);
3662 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3665 size = sizeof(DriverName);
3667 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3668 (LPBYTE)DriverName, &size);
3669 RegCloseKey(hkeyPrinter);
3670 RegCloseKey(hkeyPrinters);
3671 if(ret != ERROR_SUCCESS) {
3672 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3676 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3678 ERR("Can't create Drivers key\n");
3684 size = sizeof(DRIVER_INFO_1W);
3687 size = sizeof(DRIVER_INFO_2W);
3690 size = sizeof(DRIVER_INFO_3W);
3693 size = sizeof(DRIVER_INFO_4W);
3696 size = sizeof(DRIVER_INFO_5W);
3699 size = sizeof(DRIVER_INFO_6W);
3702 ERR("Invalid level\n");
3707 ptr = pDriverInfo + size;
3709 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3710 pEnvironment, Level, pDriverInfo,
3711 (cbBuf < size) ? NULL : ptr,
3712 (cbBuf < size) ? 0 : cbBuf - size,
3713 &needed, unicode)) {
3714 RegCloseKey(hkeyDrivers);
3718 RegCloseKey(hkeyDrivers);
3720 if(pcbNeeded) *pcbNeeded = size + needed;
3721 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3722 if(cbBuf >= needed) return TRUE;
3723 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3727 /*****************************************************************************
3728 * GetPrinterDriverA [WINSPOOL.@]
3730 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3731 DWORD Level, LPBYTE pDriverInfo,
3732 DWORD cbBuf, LPDWORD pcbNeeded)
3735 UNICODE_STRING pEnvW;
3738 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3739 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3740 cbBuf, pcbNeeded, FALSE);
3741 RtlFreeUnicodeString(&pEnvW);
3744 /*****************************************************************************
3745 * GetPrinterDriverW [WINSPOOL.@]
3747 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3748 DWORD Level, LPBYTE pDriverInfo,
3749 DWORD cbBuf, LPDWORD pcbNeeded)
3751 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3752 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3755 /*****************************************************************************
3756 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3758 * Return the PATH for the Printer-Drivers (UNICODE)
3761 * pName [I] Servername (NT only) or NULL (local Computer)
3762 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3763 * Level [I] Structure-Level (must be 1)
3764 * pDriverDirectory [O] PTR to Buffer that receives the Result
3765 * cbBuf [I] Size of Buffer at pDriverDirectory
3766 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3767 * required for pDriverDirectory
3770 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3771 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3772 * if cbBuf is too small
3774 * Native Values returned in pDriverDirectory on Success:
3775 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3776 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3777 *| win9x(Windows 4.0): "%winsysdir%"
3779 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3782 *- Only NULL or "" is supported for pName
3785 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3786 DWORD Level, LPBYTE pDriverDirectory,
3787 DWORD cbBuf, LPDWORD pcbNeeded)
3790 const printenv_t * env;
3792 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3793 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3794 if(pName != NULL && pName[0]) {
3795 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3796 SetLastError(ERROR_INVALID_PARAMETER);
3800 env = validate_envW(pEnvironment);
3801 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3804 WARN("(Level: %ld) is ignored in win9x\n", Level);
3805 SetLastError(ERROR_INVALID_LEVEL);
3809 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3810 needed = GetSystemDirectoryW(NULL, 0);
3811 /* add the Size for the Subdirectories */
3812 needed += lstrlenW(spooldriversW);
3813 needed += lstrlenW(env->subdir);
3814 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3817 *pcbNeeded = needed;
3818 TRACE("required: 0x%lx/%ld\n", needed, needed);
3819 if(needed > cbBuf) {
3820 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3823 if(pcbNeeded == NULL) {
3824 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3825 SetLastError(RPC_X_NULL_REF_POINTER);
3828 if(pDriverDirectory == NULL) {
3829 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3830 SetLastError(ERROR_INVALID_USER_BUFFER);
3834 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3835 /* add the Subdirectories */
3836 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3837 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3838 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3843 /*****************************************************************************
3844 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3846 * Return the PATH for the Printer-Drivers (ANSI)
3848 * See GetPrinterDriverDirectoryW.
3851 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3854 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3855 DWORD Level, LPBYTE pDriverDirectory,
3856 DWORD cbBuf, LPDWORD pcbNeeded)
3858 UNICODE_STRING nameW, environmentW;
3861 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3862 WCHAR *driverDirectoryW = NULL;
3864 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3865 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3867 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3869 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3870 else nameW.Buffer = NULL;
3871 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3872 else environmentW.Buffer = NULL;
3874 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3875 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3878 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3879 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3881 *pcbNeeded = needed;
3882 ret = (needed <= cbBuf) ? TRUE : FALSE;
3884 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3886 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3888 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3889 RtlFreeUnicodeString(&environmentW);
3890 RtlFreeUnicodeString(&nameW);
3895 /*****************************************************************************
3896 * AddPrinterDriverA [WINSPOOL.@]
3898 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3901 HKEY hkeyDrivers, hkeyName;
3903 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3905 if(level != 2 && level != 3) {
3906 SetLastError(ERROR_INVALID_LEVEL);
3910 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3911 SetLastError(ERROR_INVALID_PARAMETER);
3915 WARN("pDriverInfo == NULL\n");
3916 SetLastError(ERROR_INVALID_PARAMETER);
3921 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3923 memset(&di3, 0, sizeof(di3));
3924 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3927 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3929 SetLastError(ERROR_INVALID_PARAMETER);
3932 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3933 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3934 if(!di3.pHelpFile) di3.pHelpFile = "";
3935 if(!di3.pMonitorName) di3.pMonitorName = "";
3937 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3940 ERR("Can't create Drivers key\n");
3944 if(level == 2) { /* apparently can't overwrite with level2 */
3945 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3946 RegCloseKey(hkeyName);
3947 RegCloseKey(hkeyDrivers);
3948 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3949 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3953 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3954 RegCloseKey(hkeyDrivers);
3955 ERR("Can't create Name key\n");
3958 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3960 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3961 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3962 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3964 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3965 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3966 (LPBYTE) di3.pDependentFiles, 0);
3967 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3968 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3969 RegCloseKey(hkeyName);
3970 RegCloseKey(hkeyDrivers);
3975 /*****************************************************************************
3976 * AddPrinterDriverW [WINSPOOL.@]
3978 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3981 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3986 /*****************************************************************************
3987 * AddPrintProcessorA [WINSPOOL.@]
3989 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3990 LPSTR pPrintProcessorName)
3992 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3993 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3997 /*****************************************************************************
3998 * AddPrintProcessorW [WINSPOOL.@]
4000 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4001 LPWSTR pPrintProcessorName)
4003 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4004 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4008 /*****************************************************************************
4009 * AddPrintProvidorA [WINSPOOL.@]
4011 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4013 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4017 /*****************************************************************************
4018 * AddPrintProvidorW [WINSPOOL.@]
4020 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4022 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4026 /*****************************************************************************
4027 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4029 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4030 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4032 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4033 pDevModeOutput, pDevModeInput);
4037 /*****************************************************************************
4038 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4040 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4041 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4043 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4044 pDevModeOutput, pDevModeInput);
4048 /*****************************************************************************
4049 * PrinterProperties [WINSPOOL.@]
4051 * Displays a dialog to set the properties of the printer.
4054 * nonzero on success or zero on failure
4057 * implemented as stub only
4059 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4060 HANDLE hPrinter /* [in] handle to printer object */
4062 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4063 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4067 /*****************************************************************************
4068 * EnumJobsA [WINSPOOL.@]
4071 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4072 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4075 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4076 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4078 if(pcbNeeded) *pcbNeeded = 0;
4079 if(pcReturned) *pcReturned = 0;
4084 /*****************************************************************************
4085 * EnumJobsW [WINSPOOL.@]
4088 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4089 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4092 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4093 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4095 if(pcbNeeded) *pcbNeeded = 0;
4096 if(pcReturned) *pcReturned = 0;
4100 /*****************************************************************************
4101 * WINSPOOL_EnumPrinterDrivers [internal]
4103 * Delivers information about all printer drivers installed on the
4104 * localhost or a given server
4107 * nonzero on success or zero on failure. If the buffer for the returned
4108 * information is too small the function will return an error
4111 * - only implemented for localhost, foreign hosts will return an error
4113 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4114 DWORD Level, LPBYTE pDriverInfo,
4115 DWORD cbBuf, LPDWORD pcbNeeded,
4116 LPDWORD pcReturned, BOOL unicode)
4119 DWORD i, needed, number = 0, size = 0;
4120 WCHAR DriverNameW[255];
4123 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4124 debugstr_w(pName), debugstr_w(pEnvironment),
4125 Level, pDriverInfo, cbBuf, unicode);
4127 /* check for local drivers */
4128 if((pName) && (pName[0])) {
4129 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4130 SetLastError(ERROR_ACCESS_DENIED);
4134 /* check input parameter */
4135 if((Level < 1) || (Level > 3)) {
4136 ERR("unsupported level %ld\n", Level);
4137 SetLastError(ERROR_INVALID_LEVEL);
4141 /* initialize return values */
4143 memset( pDriverInfo, 0, cbBuf);
4147 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4149 ERR("Can't open Drivers key\n");
4153 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4154 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4155 RegCloseKey(hkeyDrivers);
4156 ERR("Can't query Drivers key\n");
4159 TRACE("Found %ld Drivers\n", number);
4161 /* get size of single struct
4162 * unicode and ascii structure have the same size
4166 size = sizeof(DRIVER_INFO_1A);
4169 size = sizeof(DRIVER_INFO_2A);
4172 size = sizeof(DRIVER_INFO_3A);
4176 /* calculate required buffer size */
4177 *pcbNeeded = size * number;
4179 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4181 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4182 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4184 ERR("Can't enum key number %ld\n", i);
4185 RegCloseKey(hkeyDrivers);
4188 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4189 pEnvironment, Level, ptr,
4190 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4191 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4192 &needed, unicode)) {
4193 RegCloseKey(hkeyDrivers);
4196 (*pcbNeeded) += needed;
4199 RegCloseKey(hkeyDrivers);
4201 if(cbBuf < *pcbNeeded){
4202 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4206 *pcReturned = number;
4210 /*****************************************************************************
4211 * EnumPrinterDriversW [WINSPOOL.@]
4213 * see function EnumPrinterDrivers for RETURNS, BUGS
4215 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4216 LPBYTE pDriverInfo, DWORD cbBuf,
4217 LPDWORD pcbNeeded, LPDWORD pcReturned)
4219 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4220 cbBuf, pcbNeeded, pcReturned, TRUE);
4223 /*****************************************************************************
4224 * EnumPrinterDriversA [WINSPOOL.@]
4226 * see function EnumPrinterDrivers for RETURNS, BUGS
4228 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4229 LPBYTE pDriverInfo, DWORD cbBuf,
4230 LPDWORD pcbNeeded, LPDWORD pcReturned)
4232 UNICODE_STRING pNameW, pEnvironmentW;
4233 PWSTR pwstrNameW, pwstrEnvironmentW;
4235 pwstrNameW = asciitounicode(&pNameW, pName);
4236 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4238 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4239 Level, pDriverInfo, cbBuf, pcbNeeded,
4241 RtlFreeUnicodeString(&pNameW);
4242 RtlFreeUnicodeString(&pEnvironmentW);
4247 static CHAR PortMonitor[] = "Wine Port Monitor";
4248 static CHAR PortDescription[] = "Wine Port";
4250 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4254 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4255 NULL, OPEN_EXISTING, 0, NULL );
4256 if (handle == INVALID_HANDLE_VALUE)
4258 TRACE("Checking %s exists\n", name );
4259 CloseHandle( handle );
4263 static DWORD WINSPOOL_CountSerialPorts(void)
4270 strcpy( name, "COMx:" );
4272 if (WINSPOOL_ComPortExists( name ))
4279 /******************************************************************************
4280 * EnumPortsA (WINSPOOL.@)
4285 * ANSI-Version did not call the UNICODE-Version
4288 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4289 LPDWORD bufneeded,LPDWORD bufreturned)
4292 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4293 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4297 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4298 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4303 info_size = sizeof (PORT_INFO_1A);
4306 info_size = sizeof (PORT_INFO_2A);
4309 SetLastError(ERROR_INVALID_LEVEL);
4313 /* see how many exist */
4316 serial_count = WINSPOOL_CountSerialPorts();
4319 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4320 if ( r == ERROR_SUCCESS )
4322 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4323 &printer_count, NULL, NULL, NULL, NULL);
4325 count = serial_count + printer_count;
4327 /* then fill in the structure info structure once
4328 we know the offset to the first string */
4330 memset( buffer, 0, bufsize );
4332 ofs = info_size*count;
4333 for ( i=0; i<count; i++)
4335 DWORD vallen = sizeof(portname) - 1;
4337 /* get the serial port values, then the printer values */
4338 if ( i < serial_count )
4340 strcpy( portname, "COMx:" );
4341 portname[3] = '1' + i;
4342 if (!WINSPOOL_ComPortExists( portname ))
4345 TRACE("Found %s\n", portname );
4346 vallen = strlen( portname );
4350 r = RegEnumValueA( hkey_printer, i-serial_count,
4351 portname, &vallen, NULL, NULL, NULL, 0 );
4356 /* add a colon if necessary, and make it upper case */
4357 CharUpperBuffA(portname,vallen);
4358 if (strcasecmp(portname,"nul")!=0)
4359 if (vallen && (portname[vallen-1] != ':') )
4360 lstrcatA(portname,":");
4362 /* add the port info structure if we can fit it */
4363 if ( info_size*(n+1) < bufsize )
4367 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4368 info->pName = (LPSTR) &buffer[ofs];
4370 else if ( level == 2)
4372 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4373 info->pPortName = (LPSTR) &buffer[ofs];
4374 /* FIXME: fill in more stuff here */
4375 info->pMonitorName = PortMonitor;
4376 info->pDescription = PortDescription;
4377 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4380 /* add the name of the port if we can fit it */
4381 if ( ofs < bufsize )
4382 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4388 ofs += lstrlenA(portname)+1;
4391 RegCloseKey(hkey_printer);
4402 /******************************************************************************
4403 * EnumPortsW (WINSPOOL.@)
4405 * Enumerate available Ports
4408 * name [I] Servername or NULL (local Computer)
4409 * level [I] Structure-Level (1 or 2)
4410 * buffer [O] PTR to Buffer that receives the Result
4411 * bufsize [I] Size of Buffer at buffer
4412 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4413 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4417 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4420 * UNICODE-Version is a stub
4423 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4424 LPDWORD bufneeded,LPDWORD bufreturned)
4426 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4427 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4431 /******************************************************************************
4432 * GetDefaultPrinterW (WINSPOOL.@)
4435 * This function must read the value from data 'device' of key
4436 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4438 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4442 WCHAR *buffer, *ptr;
4446 SetLastError(ERROR_INVALID_PARAMETER);
4450 /* make the buffer big enough for the stuff from the profile/registry,
4451 * the content must fit into the local buffer to compute the correct
4452 * size even if the extern buffer is too small or not given.
4453 * (20 for ,driver,port) */
4455 len = max(100, (insize + 20));
4456 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4458 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4460 SetLastError (ERROR_FILE_NOT_FOUND);
4464 TRACE("%s\n", debugstr_w(buffer));
4466 if ((ptr = strchrW(buffer, ',')) == NULL)
4468 SetLastError(ERROR_INVALID_NAME);
4474 *namesize = strlenW(buffer) + 1;
4475 if(!name || (*namesize > insize))
4477 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4481 strcpyW(name, buffer);
4484 HeapFree( GetProcessHeap(), 0, buffer);
4489 /******************************************************************************
4490 * GetDefaultPrinterA (WINSPOOL.@)
4492 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4496 WCHAR *bufferW = NULL;
4500 SetLastError(ERROR_INVALID_PARAMETER);
4504 if(name && *namesize) {
4506 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4509 if(!GetDefaultPrinterW( bufferW, namesize)) {
4514 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4518 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4521 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4524 HeapFree( GetProcessHeap(), 0, bufferW);
4529 /******************************************************************************
4530 * SetDefaultPrinterW (WINSPOOL.204)
4532 * Set the Name of the Default Printer
4535 * pszPrinter [I] Name of the Printer or NULL
4542 * When the Parameter is NULL or points to an Empty String and
4543 * a Default Printer was already present, then this Function changes nothing.
4544 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4545 * the First enumerated local Printer is used.
4548 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4551 TRACE("(%s)\n", debugstr_w(pszPrinter));
4553 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4557 /******************************************************************************
4558 * SetDefaultPrinterA (WINSPOOL.202)
4560 * See SetDefaultPrinterW.
4563 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4566 TRACE("(%s)\n", debugstr_a(pszPrinter));
4568 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4573 /******************************************************************************
4574 * SetPrinterDataExA (WINSPOOL.@)
4576 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4577 LPCSTR pValueName, DWORD Type,
4578 LPBYTE pData, DWORD cbData)
4580 HKEY hkeyPrinter, hkeySubkey;
4583 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4584 debugstr_a(pValueName), Type, pData, cbData);
4586 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4590 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4592 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4593 RegCloseKey(hkeyPrinter);
4596 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4597 RegCloseKey(hkeySubkey);
4598 RegCloseKey(hkeyPrinter);
4602 /******************************************************************************
4603 * SetPrinterDataExW (WINSPOOL.@)
4605 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4606 LPCWSTR pValueName, DWORD Type,
4607 LPBYTE pData, DWORD cbData)
4609 HKEY hkeyPrinter, hkeySubkey;
4612 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4613 debugstr_w(pValueName), Type, pData, cbData);
4615 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4619 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4621 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4622 RegCloseKey(hkeyPrinter);
4625 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4626 RegCloseKey(hkeySubkey);
4627 RegCloseKey(hkeyPrinter);
4631 /******************************************************************************
4632 * SetPrinterDataA (WINSPOOL.@)
4634 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4635 LPBYTE pData, DWORD cbData)
4637 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4641 /******************************************************************************
4642 * SetPrinterDataW (WINSPOOL.@)
4644 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4645 LPBYTE pData, DWORD cbData)
4647 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4651 /******************************************************************************
4652 * GetPrinterDataExA (WINSPOOL.@)
4654 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4655 LPCSTR pValueName, LPDWORD pType,
4656 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4658 HKEY hkeyPrinter, hkeySubkey;
4661 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4662 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4665 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4669 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4671 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4672 RegCloseKey(hkeyPrinter);
4676 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4677 RegCloseKey(hkeySubkey);
4678 RegCloseKey(hkeyPrinter);
4682 /******************************************************************************
4683 * GetPrinterDataExW (WINSPOOL.@)
4685 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4686 LPCWSTR pValueName, LPDWORD pType,
4687 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4689 HKEY hkeyPrinter, hkeySubkey;
4692 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4693 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4696 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4700 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4702 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4703 RegCloseKey(hkeyPrinter);
4707 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4708 RegCloseKey(hkeySubkey);
4709 RegCloseKey(hkeyPrinter);
4713 /******************************************************************************
4714 * GetPrinterDataA (WINSPOOL.@)
4716 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4717 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4719 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4720 pData, nSize, pcbNeeded);
4723 /******************************************************************************
4724 * GetPrinterDataW (WINSPOOL.@)
4726 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4727 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4729 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4730 pData, nSize, pcbNeeded);
4733 /*******************************************************************************
4734 * EnumPrinterDataExW [WINSPOOL.@]
4736 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4737 LPBYTE pEnumValues, DWORD cbEnumValues,
4738 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4740 HKEY hkPrinter, hkSubKey;
4741 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4742 cbValueNameLen, cbMaxValueLen, cbValueLen,
4747 PPRINTER_ENUM_VALUESW ppev;
4749 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4751 if (pKeyName == NULL || *pKeyName == 0)
4752 return ERROR_INVALID_PARAMETER;
4754 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4755 if (ret != ERROR_SUCCESS)
4757 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4762 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4763 if (ret != ERROR_SUCCESS)
4765 r = RegCloseKey (hkPrinter);
4766 if (r != ERROR_SUCCESS)
4767 WARN ("RegCloseKey returned %li\n", r);
4768 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4769 debugstr_w (pKeyName), ret);
4773 ret = RegCloseKey (hkPrinter);
4774 if (ret != ERROR_SUCCESS)
4776 ERR ("RegCloseKey returned %li\n", ret);
4777 r = RegCloseKey (hkSubKey);
4778 if (r != ERROR_SUCCESS)
4779 WARN ("RegCloseKey returned %li\n", r);
4783 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4784 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4785 if (ret != ERROR_SUCCESS)
4787 r = RegCloseKey (hkSubKey);
4788 if (r != ERROR_SUCCESS)
4789 WARN ("RegCloseKey returned %li\n", r);
4790 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4794 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4795 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4797 if (cValues == 0) /* empty key */
4799 r = RegCloseKey (hkSubKey);
4800 if (r != ERROR_SUCCESS)
4801 WARN ("RegCloseKey returned %li\n", r);
4802 *pcbEnumValues = *pnEnumValues = 0;
4803 return ERROR_SUCCESS;
4806 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4808 hHeap = GetProcessHeap ();
4811 ERR ("GetProcessHeap failed\n");
4812 r = RegCloseKey (hkSubKey);
4813 if (r != ERROR_SUCCESS)
4814 WARN ("RegCloseKey returned %li\n", r);
4815 return ERROR_OUTOFMEMORY;
4818 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4819 if (lpValueName == NULL)
4821 ERR ("Failed to allocate %li bytes from process heap\n",
4822 cbMaxValueNameLen * sizeof (WCHAR));
4823 r = RegCloseKey (hkSubKey);
4824 if (r != ERROR_SUCCESS)
4825 WARN ("RegCloseKey returned %li\n", r);
4826 return ERROR_OUTOFMEMORY;
4829 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4830 if (lpValue == NULL)
4832 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4833 if (HeapFree (hHeap, 0, lpValueName) == 0)
4834 WARN ("HeapFree failed with code %li\n", GetLastError ());
4835 r = RegCloseKey (hkSubKey);
4836 if (r != ERROR_SUCCESS)
4837 WARN ("RegCloseKey returned %li\n", r);
4838 return ERROR_OUTOFMEMORY;
4841 TRACE ("pass 1: calculating buffer required for all names and values\n");
4843 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4845 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4847 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4849 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4850 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4851 NULL, NULL, lpValue, &cbValueLen);
4852 if (ret != ERROR_SUCCESS)
4854 if (HeapFree (hHeap, 0, lpValue) == 0)
4855 WARN ("HeapFree failed with code %li\n", GetLastError ());
4856 if (HeapFree (hHeap, 0, lpValueName) == 0)
4857 WARN ("HeapFree failed with code %li\n", GetLastError ());
4858 r = RegCloseKey (hkSubKey);
4859 if (r != ERROR_SUCCESS)
4860 WARN ("RegCloseKey returned %li\n", r);
4861 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4865 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4866 debugstr_w (lpValueName), dwIndex,
4867 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4869 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4870 cbBufSize += cbValueLen;
4873 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4875 *pcbEnumValues = cbBufSize;
4876 *pnEnumValues = cValues;
4878 if (cbEnumValues < cbBufSize) /* buffer too small */
4880 if (HeapFree (hHeap, 0, lpValue) == 0)
4881 WARN ("HeapFree failed with code %li\n", GetLastError ());
4882 if (HeapFree (hHeap, 0, lpValueName) == 0)
4883 WARN ("HeapFree failed with code %li\n", GetLastError ());
4884 r = RegCloseKey (hkSubKey);
4885 if (r != ERROR_SUCCESS)
4886 WARN ("RegCloseKey returned %li\n", r);
4887 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4888 return ERROR_MORE_DATA;
4891 TRACE ("pass 2: copying all names and values to buffer\n");
4893 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4894 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4896 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4898 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4899 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4900 NULL, &dwType, lpValue, &cbValueLen);
4901 if (ret != ERROR_SUCCESS)
4903 if (HeapFree (hHeap, 0, lpValue) == 0)
4904 WARN ("HeapFree failed with code %li\n", GetLastError ());
4905 if (HeapFree (hHeap, 0, lpValueName) == 0)
4906 WARN ("HeapFree failed with code %li\n", GetLastError ());
4907 r = RegCloseKey (hkSubKey);
4908 if (r != ERROR_SUCCESS)
4909 WARN ("RegCloseKey returned %li\n", r);
4910 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4914 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4915 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4916 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4917 pEnumValues += cbValueNameLen;
4919 /* return # of *bytes* (including trailing \0), not # of chars */
4920 ppev[dwIndex].cbValueName = cbValueNameLen;
4922 ppev[dwIndex].dwType = dwType;
4924 memcpy (pEnumValues, lpValue, cbValueLen);
4925 ppev[dwIndex].pData = pEnumValues;
4926 pEnumValues += cbValueLen;
4928 ppev[dwIndex].cbData = cbValueLen;
4930 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4931 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4934 if (HeapFree (hHeap, 0, lpValue) == 0)
4936 ret = GetLastError ();
4937 ERR ("HeapFree failed with code %li\n", ret);
4938 if (HeapFree (hHeap, 0, lpValueName) == 0)
4939 WARN ("HeapFree failed with code %li\n", GetLastError ());
4940 r = RegCloseKey (hkSubKey);
4941 if (r != ERROR_SUCCESS)
4942 WARN ("RegCloseKey returned %li\n", r);
4946 if (HeapFree (hHeap, 0, lpValueName) == 0)
4948 ret = GetLastError ();
4949 ERR ("HeapFree failed with code %li\n", ret);
4950 r = RegCloseKey (hkSubKey);
4951 if (r != ERROR_SUCCESS)
4952 WARN ("RegCloseKey returned %li\n", r);
4956 ret = RegCloseKey (hkSubKey);
4957 if (ret != ERROR_SUCCESS)
4959 ERR ("RegCloseKey returned %li\n", ret);
4963 return ERROR_SUCCESS;
4966 /*******************************************************************************
4967 * EnumPrinterDataExA [WINSPOOL.@]
4969 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4970 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4971 * what Windows 2000 SP1 does.
4974 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4975 LPBYTE pEnumValues, DWORD cbEnumValues,
4976 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4980 DWORD ret, dwIndex, dwBufSize;
4984 TRACE ("%p %s\n", hPrinter, pKeyName);
4986 if (pKeyName == NULL || *pKeyName == 0)
4987 return ERROR_INVALID_PARAMETER;
4989 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4992 ret = GetLastError ();
4993 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4997 hHeap = GetProcessHeap ();
5000 ERR ("GetProcessHeap failed\n");
5001 return ERROR_OUTOFMEMORY;
5004 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5005 if (pKeyNameW == NULL)
5007 ERR ("Failed to allocate %li bytes from process heap\n",
5008 (LONG) len * sizeof (WCHAR));
5009 return ERROR_OUTOFMEMORY;
5012 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5014 ret = GetLastError ();
5015 ERR ("MultiByteToWideChar failed with code %li\n", ret);
5016 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5017 WARN ("HeapFree failed with code %li\n", GetLastError ());
5021 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5022 pcbEnumValues, pnEnumValues);
5023 if (ret != ERROR_SUCCESS)
5025 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5026 WARN ("HeapFree failed with code %li\n", GetLastError ());
5027 TRACE ("EnumPrinterDataExW returned %li\n", ret);
5031 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5033 ret = GetLastError ();
5034 ERR ("HeapFree failed with code %li\n", ret);
5038 if (*pnEnumValues == 0) /* empty key */
5039 return ERROR_SUCCESS;
5042 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5044 PPRINTER_ENUM_VALUESW ppev =
5045 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5047 if (dwBufSize < ppev->cbValueName)
5048 dwBufSize = ppev->cbValueName;
5050 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5051 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5052 dwBufSize = ppev->cbData;
5055 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
5057 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5058 if (pBuffer == NULL)
5060 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
5061 return ERROR_OUTOFMEMORY;
5064 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5066 PPRINTER_ENUM_VALUESW ppev =
5067 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5069 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5070 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5074 ret = GetLastError ();
5075 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5076 if (HeapFree (hHeap, 0, pBuffer) == 0)
5077 WARN ("HeapFree failed with code %li\n", GetLastError ());
5081 memcpy (ppev->pValueName, pBuffer, len);
5083 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5085 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5086 ppev->dwType != REG_MULTI_SZ)
5089 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5090 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5093 ret = GetLastError ();
5094 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5095 if (HeapFree (hHeap, 0, pBuffer) == 0)
5096 WARN ("HeapFree failed with code %li\n", GetLastError ());
5100 memcpy (ppev->pData, pBuffer, len);
5102 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5103 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5106 if (HeapFree (hHeap, 0, pBuffer) == 0)
5108 ret = GetLastError ();
5109 ERR ("HeapFree failed with code %li\n", ret);
5113 return ERROR_SUCCESS;
5116 /******************************************************************************
5117 * AbortPrinter (WINSPOOL.@)
5119 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5121 FIXME("(%p), stub!\n", hPrinter);
5125 /******************************************************************************
5126 * AddPortA (WINSPOOL.@)
5131 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5133 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5137 /******************************************************************************
5138 * AddPortW (WINSPOOL.@)
5140 * Add a Port for a specific Monitor
5143 * pName [I] Servername or NULL (local Computer)
5144 * hWnd [I] Handle to parent Window for the Dialog-Box
5145 * pMonitorName [I] Name of the Monitor that manage the Port
5155 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5157 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5161 /******************************************************************************
5162 * AddPortExA (WINSPOOL.@)
5167 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5169 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5170 lpBuffer, debugstr_a(lpMonitorName));
5174 /******************************************************************************
5175 * AddPortExW (WINSPOOL.@)
5177 * Add a Port for a specific Monitor, without presenting a user interface
5180 * hMonitor [I] Handle from InitializePrintMonitor2()
5181 * pName [I] Servername or NULL (local Computer)
5182 * Level [I] Structure-Level (1 or 2) for lpBuffer
5183 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5184 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5194 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5196 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5197 lpBuffer, debugstr_w(lpMonitorName));
5201 /******************************************************************************
5202 * AddPrinterConnectionA (WINSPOOL.@)
5204 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5206 FIXME("%s\n", debugstr_a(pName));
5210 /******************************************************************************
5211 * AddPrinterConnectionW (WINSPOOL.@)
5213 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5215 FIXME("%s\n", debugstr_w(pName));
5219 /******************************************************************************
5220 * AddPrinterDriverExW (WINSPOOL.@)
5222 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5223 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5225 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5226 Level, pDriverInfo, dwFileCopyFlags);
5227 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5231 /******************************************************************************
5232 * AddPrinterDriverExA (WINSPOOL.@)
5234 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5235 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5237 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5238 Level, pDriverInfo, dwFileCopyFlags);
5239 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5243 /******************************************************************************
5244 * ConfigurePortA (WINSPOOL.@)
5246 * See ConfigurePortW.
5249 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5251 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5255 /******************************************************************************
5256 * ConfigurePortW (WINSPOOL.@)
5258 * Display the Configuration-Dialog for a specific Port
5261 * pName [I] Servername or NULL (local Computer)
5262 * hWnd [I] Handle to parent Window for the Dialog-Box
5263 * pPortName [I] Name of the Port, that should be configured
5273 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5275 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5279 /******************************************************************************
5280 * ConnectToPrinterDlg (WINSPOOL.@)
5282 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5284 FIXME("%p %lx\n", hWnd, Flags);
5288 /******************************************************************************
5289 * DeletePrinterConnectionA (WINSPOOL.@)
5291 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5293 FIXME("%s\n", debugstr_a(pName));
5297 /******************************************************************************
5298 * DeletePrinterConnectionW (WINSPOOL.@)
5300 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5302 FIXME("%s\n", debugstr_w(pName));
5306 /******************************************************************************
5307 * DeletePrinterDriverExW (WINSPOOL.@)
5309 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5310 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5312 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5313 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5317 /******************************************************************************
5318 * DeletePrinterDriverExA (WINSPOOL.@)
5320 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5321 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5323 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5324 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5328 /******************************************************************************
5329 * DeletePrinterDataExW (WINSPOOL.@)
5331 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5334 FIXME("%p %s %s\n", hPrinter,
5335 debugstr_w(pKeyName), debugstr_w(pValueName));
5336 return ERROR_INVALID_PARAMETER;
5339 /******************************************************************************
5340 * DeletePrinterDataExA (WINSPOOL.@)
5342 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5345 FIXME("%p %s %s\n", hPrinter,
5346 debugstr_a(pKeyName), debugstr_a(pValueName));
5347 return ERROR_INVALID_PARAMETER;
5350 /******************************************************************************
5351 * DeletePrintProcessorA (WINSPOOL.@)
5353 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5355 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5356 debugstr_a(pPrintProcessorName));
5360 /******************************************************************************
5361 * DeletePrintProcessorW (WINSPOOL.@)
5363 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5365 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5366 debugstr_w(pPrintProcessorName));
5370 /******************************************************************************
5371 * DeletePrintProvidorA (WINSPOOL.@)
5373 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5375 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5376 debugstr_a(pPrintProviderName));
5380 /******************************************************************************
5381 * DeletePrintProvidorW (WINSPOOL.@)
5383 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5385 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5386 debugstr_w(pPrintProviderName));
5390 /******************************************************************************
5391 * EnumFormsA (WINSPOOL.@)
5393 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5394 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5396 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5400 /******************************************************************************
5401 * EnumFormsW (WINSPOOL.@)
5403 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5404 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5406 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5410 /*****************************************************************************
5411 * EnumMonitorsA [WINSPOOL.@]
5413 * See EnumMonitorsW.
5416 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5417 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5420 LPBYTE bufferW = NULL;
5421 LPWSTR nameW = NULL;
5423 DWORD numentries = 0;
5426 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5427 cbBuf, pcbNeeded, pcReturned);
5429 /* convert servername to unicode */
5431 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5432 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5433 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5435 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5436 needed = cbBuf * sizeof(WCHAR);
5437 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5438 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5440 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5441 if (pcbNeeded) needed = *pcbNeeded;
5442 /* HeapReAlloc return NULL, when bufferW was NULL */
5443 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5444 HeapAlloc(GetProcessHeap(), 0, needed);
5446 /* Try again with the large Buffer */
5447 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5449 numentries = pcReturned ? *pcReturned : 0;
5452 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5453 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5456 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5457 DWORD entrysize = 0;
5460 LPMONITOR_INFO_2W mi2w;
5461 LPMONITOR_INFO_2A mi2a;
5463 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5464 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5466 /* First pass: calculate the size for all Entries */
5467 mi2w = (LPMONITOR_INFO_2W) bufferW;
5468 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5470 while (index < numentries) {
5472 needed += entrysize; /* MONITOR_INFO_?A */
5473 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5475 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5476 NULL, 0, NULL, NULL);
5478 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5479 NULL, 0, NULL, NULL);
5480 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5481 NULL, 0, NULL, NULL);
5483 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5484 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5485 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5488 /* check for errors and quit on failure */
5489 if (cbBuf < needed) {
5490 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5494 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5495 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5496 cbBuf -= len ; /* free Bytes in the user-Buffer */
5497 mi2w = (LPMONITOR_INFO_2W) bufferW;
5498 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5500 /* Second Pass: Fill the User Buffer (if we have one) */
5501 while ((index < numentries) && pMonitors) {
5503 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5505 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5506 ptr, cbBuf , NULL, NULL);
5510 mi2a->pEnvironment = ptr;
5511 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5512 ptr, cbBuf, NULL, NULL);
5516 mi2a->pDLLName = ptr;
5517 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5518 ptr, cbBuf, NULL, NULL);
5522 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5523 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5524 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5528 if (pcbNeeded) *pcbNeeded = needed;
5529 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5531 HeapFree(GetProcessHeap(), 0, nameW);
5532 HeapFree(GetProcessHeap(), 0, bufferW);
5534 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5535 (res), GetLastError(), needed, numentries);
5541 /*****************************************************************************
5542 * EnumMonitorsW [WINSPOOL.@]
5544 * Enumerate available Port-Monitors
5547 * pName [I] Servername or NULL (local Computer)
5548 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5549 * pMonitors [O] PTR to Buffer that receives the Result
5550 * cbBuf [I] Size of Buffer at pMonitors
5551 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5552 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5556 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5559 * Windows reads the Registry once and cache the Results.
5561 *| Language-Monitors are also installed in the same Registry-Location but
5562 *| they are filtered in Windows (not returned by EnumMonitors).
5563 *| We do no filtering to simplify our Code.
5566 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5567 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5570 DWORD numentries = 0;
5573 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5574 cbBuf, pcbNeeded, pcReturned);
5576 if (pName && (lstrlenW(pName))) {
5577 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5578 SetLastError(ERROR_ACCESS_DENIED);
5582 /* Level is not checked in win9x */
5583 if (!Level || (Level > 2)) {
5584 WARN("level (%ld) is ignored in win9x\n", Level);
5585 SetLastError(ERROR_INVALID_LEVEL);
5589 SetLastError(RPC_X_NULL_REF_POINTER);
5593 /* Scan all Monitor-Keys */
5595 needed = get_local_monitors(Level, NULL, 0, &numentries);
5597 /* we calculated the needed buffersize. now do the error-checks */
5598 if (cbBuf < needed) {
5599 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5602 else if (!pMonitors || !pcReturned) {
5603 SetLastError(RPC_X_NULL_REF_POINTER);
5607 /* fill the Buffer with the Monitor-Keys */
5608 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5612 if (pcbNeeded) *pcbNeeded = needed;
5613 if (pcReturned) *pcReturned = numentries;
5615 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5616 res, GetLastError(), needed, numentries);
5621 /******************************************************************************
5622 * XcvDataW (WINSPOOL.@)
5625 * There doesn't seem to be an A version...
5627 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5628 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5629 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5631 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5632 pInputData, cbInputData, pOutputData,
5633 cbOutputData, pcbOutputNeeded, pdwStatus);
5637 /*****************************************************************************
5638 * EnumPrinterDataA [WINSPOOL.@]
5641 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5642 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5643 DWORD cbData, LPDWORD pcbData )
5645 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5646 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5647 return ERROR_NO_MORE_ITEMS;
5650 /*****************************************************************************
5651 * EnumPrinterDataW [WINSPOOL.@]
5654 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5655 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5656 DWORD cbData, LPDWORD pcbData )
5658 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5659 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5660 return ERROR_NO_MORE_ITEMS;
5663 /*****************************************************************************
5664 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5667 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5668 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5669 LPDWORD pcbNeeded, LPDWORD pcReturned)
5671 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5672 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5673 pcbNeeded, pcReturned);
5677 /*****************************************************************************
5678 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5681 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5682 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5683 LPDWORD pcbNeeded, LPDWORD pcReturned)
5685 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5686 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5687 pcbNeeded, pcReturned);
5691 /*****************************************************************************
5692 * EnumPrintProcessorsA [WINSPOOL.@]
5695 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5696 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5698 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5699 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5703 /*****************************************************************************
5704 * EnumPrintProcessorsW [WINSPOOL.@]
5707 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5708 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5710 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5711 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5712 cbBuf, pcbNeeded, pcbReturned);
5716 /*****************************************************************************
5717 * ExtDeviceMode [WINSPOOL.@]
5720 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5721 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5724 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5725 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5726 debugstr_a(pProfile), fMode);
5730 /*****************************************************************************
5731 * FindClosePrinterChangeNotification [WINSPOOL.@]
5734 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5736 FIXME("Stub: %p\n", hChange);
5740 /*****************************************************************************
5741 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5744 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5745 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5747 FIXME("Stub: %p %lx %lx %p\n",
5748 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5749 return INVALID_HANDLE_VALUE;
5752 /*****************************************************************************
5753 * FindNextPrinterChangeNotification [WINSPOOL.@]
5756 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5757 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5759 FIXME("Stub: %p %p %p %p\n",
5760 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5764 /*****************************************************************************
5765 * FreePrinterNotifyInfo [WINSPOOL.@]
5768 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5770 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5774 /*****************************************************************************
5777 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5778 * ansi depending on the unicode parameter.
5780 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5790 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5793 memcpy(ptr, str, *size);
5800 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5803 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5810 /*****************************************************************************
5813 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5814 LPDWORD pcbNeeded, BOOL unicode)
5816 DWORD size, left = cbBuf;
5817 BOOL space = (cbBuf > 0);
5824 ji1->JobId = job->job_id;
5827 string_to_buf(job->document_title, ptr, left, &size, unicode);
5828 if(space && size <= left)
5830 ji1->pDocument = (LPWSTR)ptr;
5841 /*****************************************************************************
5844 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5845 LPDWORD pcbNeeded, BOOL unicode)
5847 DWORD size, left = cbBuf;
5848 BOOL space = (cbBuf > 0);
5855 ji2->JobId = job->job_id;
5858 string_to_buf(job->document_title, ptr, left, &size, unicode);
5859 if(space && size <= left)
5861 ji2->pDocument = (LPWSTR)ptr;
5872 /*****************************************************************************
5875 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5876 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5879 DWORD needed = 0, size;
5883 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5885 EnterCriticalSection(&printer_handles_cs);
5886 job = get_job(hPrinter, JobId);
5893 size = sizeof(JOB_INFO_1W);
5898 memset(pJob, 0, size);
5902 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5907 size = sizeof(JOB_INFO_2W);
5912 memset(pJob, 0, size);
5916 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5921 size = sizeof(JOB_INFO_3);
5925 memset(pJob, 0, size);
5934 SetLastError(ERROR_INVALID_LEVEL);
5938 *pcbNeeded = needed;
5940 LeaveCriticalSection(&printer_handles_cs);
5944 /*****************************************************************************
5945 * GetJobA [WINSPOOL.@]
5948 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5949 DWORD cbBuf, LPDWORD pcbNeeded)
5951 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5954 /*****************************************************************************
5955 * GetJobW [WINSPOOL.@]
5958 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5959 DWORD cbBuf, LPDWORD pcbNeeded)
5961 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5964 /*****************************************************************************
5967 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5969 char *unixname, *queue, *cmd;
5970 char fmt[] = "lpr -P%s %s";
5973 if(!(unixname = wine_get_unix_file_name(filename)))
5976 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5977 queue = HeapAlloc(GetProcessHeap(), 0, len);
5978 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5980 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5981 sprintf(cmd, fmt, queue, unixname);
5983 TRACE("printing with: %s\n", cmd);
5986 HeapFree(GetProcessHeap(), 0, cmd);
5987 HeapFree(GetProcessHeap(), 0, queue);
5988 HeapFree(GetProcessHeap(), 0, unixname);
5992 /*****************************************************************************
5995 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5997 #if HAVE_CUPS_CUPS_H
6000 char *unixname, *queue, *doc_titleA;
6004 if(!(unixname = wine_get_unix_file_name(filename)))
6007 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
6008 queue = HeapAlloc(GetProcessHeap(), 0, len);
6009 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
6011 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
6012 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
6013 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
6015 TRACE("printing via cups\n");
6016 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
6017 HeapFree(GetProcessHeap(), 0, doc_titleA);
6018 HeapFree(GetProcessHeap(), 0, queue);
6019 HeapFree(GetProcessHeap(), 0, unixname);
6025 return schedule_lpr(printer_name, filename);
6029 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
6036 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
6040 if(HIWORD(wparam) == BN_CLICKED)
6042 if(LOWORD(wparam) == IDOK)
6045 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
6048 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
6049 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
6051 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
6053 WCHAR caption[200], message[200];
6056 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6057 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
6058 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
6059 if(mb_ret == IDCANCEL)
6061 HeapFree(GetProcessHeap(), 0, filename);
6065 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
6066 if(hf == INVALID_HANDLE_VALUE)
6068 WCHAR caption[200], message[200];
6070 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
6071 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
6072 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
6073 HeapFree(GetProcessHeap(), 0, filename);
6077 DeleteFileW(filename);
6078 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
6080 EndDialog(hwnd, IDOK);
6083 if(LOWORD(wparam) == IDCANCEL)
6085 EndDialog(hwnd, IDCANCEL);
6094 /*****************************************************************************
6097 static BOOL get_filename(LPWSTR *filename)
6099 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6100 file_dlg_proc, (LPARAM)filename) == IDOK;
6103 /*****************************************************************************
6106 static BOOL schedule_file(LPCWSTR filename)
6108 LPWSTR output = NULL;
6110 if(get_filename(&output))
6112 TRACE("copy to %s\n", debugstr_w(output));
6113 CopyFileW(filename, output, FALSE);
6114 HeapFree(GetProcessHeap(), 0, output);
6120 /*****************************************************************************
6123 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6126 char *unixname, *cmdA;
6128 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6132 if(!(unixname = wine_get_unix_file_name(filename)))
6135 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6136 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6137 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6139 TRACE("printing with: %s\n", cmdA);
6141 if((file_fd = open(unixname, O_RDONLY)) == -1)
6146 ERR("pipe() failed!\n");
6156 /* reset signals that we previously set to SIG_IGN */
6157 signal(SIGPIPE, SIG_DFL);
6158 signal(SIGCHLD, SIG_DFL);
6164 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6165 write(fds[1], buf, no_read);
6170 if(file_fd != -1) close(file_fd);
6171 if(fds[0] != -1) close(fds[0]);
6172 if(fds[1] != -1) close(fds[1]);
6174 HeapFree(GetProcessHeap(), 0, cmdA);
6175 HeapFree(GetProcessHeap(), 0, unixname);
6182 /*****************************************************************************
6185 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6187 int in_fd, out_fd, no_read;
6190 char *unixname, *outputA;
6193 if(!(unixname = wine_get_unix_file_name(filename)))
6196 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6197 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6198 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6200 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6201 in_fd = open(unixname, O_RDONLY);
6202 if(out_fd == -1 || in_fd == -1)
6205 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6206 write(out_fd, buf, no_read);
6210 if(in_fd != -1) close(in_fd);
6211 if(out_fd != -1) close(out_fd);
6212 HeapFree(GetProcessHeap(), 0, outputA);
6213 HeapFree(GetProcessHeap(), 0, unixname);
6217 /*****************************************************************************
6218 * ScheduleJob [WINSPOOL.@]
6221 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6223 opened_printer_t *printer;
6225 struct list *cursor, *cursor2;
6227 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6228 EnterCriticalSection(&printer_handles_cs);
6229 printer = get_opened_printer(hPrinter);
6233 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6235 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6238 if(job->job_id != dwJobID) continue;
6240 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6241 if(hf != INVALID_HANDLE_VALUE)
6243 PRINTER_INFO_5W *pi5;
6247 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6248 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6250 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6251 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6252 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6253 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6254 debugstr_w(pi5->pPortName));
6258 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6259 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6261 DWORD type, count = sizeof(output);
6262 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6265 if(output[0] == '|')
6267 schedule_pipe(output + 1, job->filename);
6271 schedule_unixfile(output, job->filename);
6273 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6275 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6277 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6279 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6281 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6283 schedule_file(job->filename);
6287 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6289 HeapFree(GetProcessHeap(), 0, pi5);
6291 DeleteFileW(job->filename);
6293 list_remove(cursor);
6294 HeapFree(GetProcessHeap(), 0, job->document_title);
6295 HeapFree(GetProcessHeap(), 0, job->filename);
6296 HeapFree(GetProcessHeap(), 0, job);
6301 LeaveCriticalSection(&printer_handles_cs);
6305 /*****************************************************************************
6306 * StartDocDlgA [WINSPOOL.@]
6308 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6310 UNICODE_STRING usBuffer;
6315 docW.cbSize = sizeof(docW);
6316 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6317 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6318 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6319 docW.fwType = doc->fwType;
6321 retW = StartDocDlgW(hPrinter, &docW);
6325 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6326 ret = HeapAlloc(GetProcessHeap(), 0, len);
6327 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6328 HeapFree(GetProcessHeap(), 0, retW);
6331 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6332 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6333 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6338 /*****************************************************************************
6339 * StartDocDlgW [WINSPOOL.@]
6341 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6342 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6343 * port is "FILE:". Also returns the full path if passed a relative path.
6345 * The caller should free the returned string from the process heap.
6347 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6352 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6354 PRINTER_INFO_5W *pi5;
6355 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6356 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6358 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6359 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6360 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6362 HeapFree(GetProcessHeap(), 0, pi5);
6365 HeapFree(GetProcessHeap(), 0, pi5);
6368 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6371 get_filename(&name);
6374 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6376 HeapFree(GetProcessHeap(), 0, name);
6379 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6380 GetFullPathNameW(name, len, ret, NULL);
6381 HeapFree(GetProcessHeap(), 0, name);
6386 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6389 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6390 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6392 attr = GetFileAttributesW(ret);
6393 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6395 HeapFree(GetProcessHeap(), 0, ret);