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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "wine/port.h"
38 #ifdef HAVE_CUPS_CUPS_H
39 # include <cups/cups.h>
40 # ifndef SONAME_LIBCUPS
41 # define SONAME_LIBCUPS "libcups.so"
45 #define NONAMELESSUNION
46 #define NONAMELESSSTRUCT
47 #include "wine/library.h"
56 #include "wine/windef16.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "wine/list.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
96 WCHAR *document_title;
105 /* ############################### */
107 static opened_printer_t **printer_handles;
108 static int nb_printer_handles;
109 static LONG next_job_id = 1;
111 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
112 WORD fwCapability, LPSTR lpszOutput,
114 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
115 LPSTR lpszDevice, LPSTR lpszPort,
116 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
119 static const char Printers[] =
120 "System\\CurrentControlSet\\control\\Print\\Printers\\";
122 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
123 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
124 'c','o','n','t','r','o','l','\\',
125 'P','r','i','n','t','\\',
126 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
127 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
129 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
130 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'C','o','n','t','r','o','l','\\',
132 'P','r','i','n','t','\\',
133 'M','o','n','i','t','o','r','s',0};
135 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
137 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
138 'M','i','c','r','o','s','o','f','t','\\',
139 'W','i','n','d','o','w','s',' ','N','T','\\',
140 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
141 'W','i','n','d','o','w','s',0};
143 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'D','e','v','i','c','e','s',0};
149 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
150 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
151 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
152 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
153 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
155 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
157 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
158 'i','o','n',' ','F','i','l','e',0};
159 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
160 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
161 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
163 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
165 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
166 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
167 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
168 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
169 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
170 static const WCHAR NameW[] = {'N','a','m','e',0};
171 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
172 static const WCHAR PortW[] = {'P','o','r','t',0};
173 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
175 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
177 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
178 'v','e','r','D','a','t','a',0};
179 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
181 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
182 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
183 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
184 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
185 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
186 static const WCHAR emptyStringW[] = {0};
188 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
190 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
191 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
192 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
194 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
195 'D','o','c','u','m','e','n','t',0};
197 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
198 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
199 DWORD Level, LPBYTE pDriverInfo,
200 DWORD cbBuf, LPDWORD pcbNeeded,
202 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
203 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
205 /******************************************************************
206 * validate the user-supplied printing-environment [internal]
209 * env [I] PTR to Environment-String or NULL
213 * Success: PTR to printenv_t
216 * An empty string is handled the same way as NULL.
217 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
221 static const printenv_t * validate_envW(LPCWSTR env)
223 static const printenv_t env_x86 = {envname_x86W, subdir_x86W};
224 static const printenv_t env_win40 = {envname_win40W, subdir_win40W};
225 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
227 const printenv_t *result = NULL;
230 TRACE("testing %s\n", debugstr_w(env));
233 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
235 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
237 result = all_printenv[i];
242 if (result == NULL) {
243 FIXME("unsupported Environment: %s\n", debugstr_w(env));
244 SetLastError(ERROR_INVALID_ENVIRONMENT);
246 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
250 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
252 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
258 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
259 if passed a NULL string. This returns NULLs to the result.
261 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
265 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
266 return usBufferPtr->Buffer;
268 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
272 static LPWSTR strdupW(LPCWSTR p)
278 len = (strlenW(p) + 1) * sizeof(WCHAR);
279 ret = HeapAlloc(GetProcessHeap(), 0, len);
285 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
288 /* If forcing, or no profile string entry for device yet, set the entry
290 * The always change entry if not WINEPS yet is discussable.
293 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
295 !strstr(qbuf,"WINEPS.DRV")
297 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
300 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
301 WriteProfileStringA("windows","device",buf);
302 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
303 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
306 HeapFree(GetProcessHeap(),0,buf);
310 #ifdef HAVE_CUPS_CUPS_H
311 static typeof(cupsGetDests) *pcupsGetDests;
312 static typeof(cupsGetPPD) *pcupsGetPPD;
313 static typeof(cupsPrintFile) *pcupsPrintFile;
314 static void *cupshandle;
316 static BOOL CUPS_LoadPrinters(void)
319 BOOL hadprinter = FALSE;
321 PRINTER_INFO_2A pinfo2a;
323 HKEY hkeyPrinter, hkeyPrinters, hkey;
325 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
328 TRACE("loaded %s\n", SONAME_LIBCUPS);
331 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
332 if (!p##x) return FALSE;
335 DYNCUPS(cupsGetDests);
336 DYNCUPS(cupsPrintFile);
339 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
341 ERR("Can't create Printers key\n");
345 nrofdests = pcupsGetDests(&dests);
346 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
347 for (i=0;i<nrofdests;i++) {
348 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
349 sprintf(port,"LPR:%s",dests[i].name);
350 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
351 sprintf(devline,"WINEPS.DRV,%s",port);
352 WriteProfileStringA("devices",dests[i].name,devline);
353 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
354 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
357 HeapFree(GetProcessHeap(),0,devline);
359 TRACE("Printer %d: %s\n", i, dests[i].name);
360 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
361 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
363 TRACE("Printer already exists\n");
364 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
365 RegCloseKey(hkeyPrinter);
367 memset(&pinfo2a,0,sizeof(pinfo2a));
368 pinfo2a.pPrinterName = dests[i].name;
369 pinfo2a.pDatatype = "RAW";
370 pinfo2a.pPrintProcessor = "WinPrint";
371 pinfo2a.pDriverName = "PS Driver";
372 pinfo2a.pComment = "WINEPS Printer using CUPS";
373 pinfo2a.pLocation = "<physical location of printer>";
374 pinfo2a.pPortName = port;
375 pinfo2a.pParameters = "<parameters?>";
376 pinfo2a.pShareName = "<share name?>";
377 pinfo2a.pSepFile = "<sep file?>";
379 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
380 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
381 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
384 HeapFree(GetProcessHeap(),0,port);
387 if (dests[i].is_default)
388 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
390 RegCloseKey(hkeyPrinters);
396 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
397 PRINTER_INFO_2A pinfo2a;
398 char *e,*s,*name,*prettyname,*devname;
399 BOOL ret = FALSE, set_default = FALSE;
400 char *port,*devline,*env_default;
401 HKEY hkeyPrinter, hkeyPrinters, hkey;
403 while (isspace(*pent)) pent++;
404 s = strchr(pent,':');
406 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
414 TRACE("name=%s entry=%s\n",name, pent);
416 if(ispunct(*name)) { /* a tc entry, not a real printer */
417 TRACE("skipping tc entry\n");
421 if(strstr(pent,":server")) { /* server only version so skip */
422 TRACE("skipping server entry\n");
426 /* Determine whether this is a postscript printer. */
429 env_default = getenv("PRINTER");
431 /* Get longest name, usually the one at the right for later display. */
432 while((s=strchr(prettyname,'|'))) {
435 while(isspace(*--e)) *e = '\0';
436 TRACE("\t%s\n", debugstr_a(prettyname));
437 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
438 for(prettyname = s+1; isspace(*prettyname); prettyname++)
441 e = prettyname + strlen(prettyname);
442 while(isspace(*--e)) *e = '\0';
443 TRACE("\t%s\n", debugstr_a(prettyname));
444 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
446 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
447 * if it is too long, we use it as comment below. */
448 devname = prettyname;
449 if (strlen(devname)>=CCHDEVICENAME-1)
451 if (strlen(devname)>=CCHDEVICENAME-1) {
456 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
457 sprintf(port,"LPR:%s",name);
459 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
460 sprintf(devline,"WINEPS.DRV,%s",port);
461 WriteProfileStringA("devices",devname,devline);
462 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
463 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
466 HeapFree(GetProcessHeap(),0,devline);
468 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
470 ERR("Can't create Printers key\n");
474 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
475 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
477 TRACE("Printer already exists\n");
478 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
479 RegCloseKey(hkeyPrinter);
481 memset(&pinfo2a,0,sizeof(pinfo2a));
482 pinfo2a.pPrinterName = devname;
483 pinfo2a.pDatatype = "RAW";
484 pinfo2a.pPrintProcessor = "WinPrint";
485 pinfo2a.pDriverName = "PS Driver";
486 pinfo2a.pComment = "WINEPS Printer using LPR";
487 pinfo2a.pLocation = prettyname;
488 pinfo2a.pPortName = port;
489 pinfo2a.pParameters = "<parameters?>";
490 pinfo2a.pShareName = "<share name?>";
491 pinfo2a.pSepFile = "<sep file?>";
493 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
494 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
495 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
498 RegCloseKey(hkeyPrinters);
500 if (isfirst || set_default)
501 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
503 HeapFree(GetProcessHeap(), 0, port);
505 HeapFree(GetProcessHeap(), 0, name);
510 PRINTCAP_LoadPrinters(void) {
511 BOOL hadprinter = FALSE;
515 BOOL had_bash = FALSE;
517 f = fopen("/etc/printcap","r");
521 while(fgets(buf,sizeof(buf),f)) {
524 end=strchr(buf,'\n');
528 while(isspace(*start)) start++;
529 if(*start == '#' || *start == '\0')
532 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
533 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
534 HeapFree(GetProcessHeap(),0,pent);
538 if (end && *--end == '\\') {
545 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
548 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
554 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
555 HeapFree(GetProcessHeap(),0,pent);
561 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
564 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
565 lstrlenW(value) * sizeof(WCHAR));
567 return ERROR_FILE_NOT_FOUND;
570 void WINSPOOL_LoadSystemPrinters(void)
572 HKEY hkey, hkeyPrinters;
575 DWORD needed, num, i;
576 WCHAR PrinterName[256];
579 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
580 di3a.pName = "PS Driver";
581 di3a.pEnvironment = NULL; /* NULL means auto */
582 di3a.pDriverPath = "wineps16";
583 di3a.pDataFile = "<datafile?>";
584 di3a.pConfigFile = "wineps16";
585 di3a.pHelpFile = "<helpfile?>";
586 di3a.pDependentFiles = "<dependend files?>";
587 di3a.pMonitorName = "<monitor name?>";
588 di3a.pDefaultDataType = "RAW";
590 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
591 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
595 /* This ensures that all printer entries have a valid Name value. If causes
596 problems later if they don't. If one is found to be missed we create one
597 and set it equal to the name of the key */
598 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
599 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
600 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
601 for(i = 0; i < num; i++) {
602 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
603 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
604 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
605 set_reg_szW(hkey, NameW, PrinterName);
612 RegCloseKey(hkeyPrinters);
615 /* We want to avoid calling AddPrinter on printers as much as
616 possible, because on cups printers this will (eventually) lead
617 to a call to cupsGetPPD which takes forever, even with non-cups
618 printers AddPrinter takes a while. So we'll tag all printers that
619 were automatically added last time around, if they still exist
620 we'll leave them be otherwise we'll delete them. */
621 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
623 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
624 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
625 for(i = 0; i < num; i++) {
626 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
627 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
628 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
630 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
638 HeapFree(GetProcessHeap(), 0, pi);
642 #ifdef HAVE_CUPS_CUPS_H
643 done = CUPS_LoadPrinters();
646 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
647 /* Check for [ppd] section in config file before parsing /etc/printcap */
648 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
649 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
650 &hkey) == ERROR_SUCCESS) {
652 PRINTCAP_LoadPrinters();
656 /* Now enumerate the list again and delete any printers that a still tagged */
657 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
659 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
660 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
661 for(i = 0; i < num; i++) {
662 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
663 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
664 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
665 DWORD dw, type, size = sizeof(dw);
666 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
667 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
677 HeapFree(GetProcessHeap(), 0, pi);
684 /*****************************************************************************
685 * enumerate the local monitors (INTERNAL)
687 * returns the needed size (in bytes) for pMonitors
688 * and *lpreturned is set to number of entries returned in pMonitors
691 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
696 LPMONITOR_INFO_2W mi;
697 WCHAR buffer[MAX_PATH];
698 WCHAR dllname[MAX_PATH];
706 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
708 numentries = *lpreturned; /* this is 0, when we scan the registry */
709 len = entrysize * numentries;
710 ptr = (LPWSTR) &pMonitors[len];
713 len = sizeof(buffer);
716 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
717 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
718 /* Scan all Monitor-Registry-Keys */
719 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
720 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
721 dllsize = sizeof(dllname);
724 /* The Monitor must have a Driver-DLL */
725 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
726 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
727 /* We found a valid DLL for this Monitor. */
728 TRACE("using Driver: %s\n", debugstr_w(dllname));
733 /* Windows returns only Port-Monitors here, but to simplify our code,
734 we do no filtering for Language-Monitors */
738 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
740 /* we install and return only monitors for "Windows NT x86" */
741 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
745 /* required size is calculated. Now fill the user-buffer */
746 if (pMonitors && (cbBuf >= needed)){
747 mi = (LPMONITOR_INFO_2W) pMonitors;
748 pMonitors += entrysize;
750 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
752 lstrcpyW(ptr, buffer); /* Name of the Monitor */
753 ptr += (len+1); /* len is lstrlenW(monitorname) */
755 mi->pEnvironment = ptr;
756 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
757 ptr += (lstrlenW(envname_x86W)+1);
760 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
761 ptr += (dllsize / sizeof(WCHAR));
766 len = sizeof(buffer);
771 *lpreturned = numentries;
772 TRACE("need %ld byte for %ld entries\n", needed, numentries);
776 /******************************************************************
777 * get_opened_printer_entry
778 * Get the first place empty in the opened printer table
780 static HANDLE get_opened_printer_entry( LPCWSTR name )
782 UINT_PTR handle = nb_printer_handles, i;
783 jobqueue_t *queue = NULL;
784 opened_printer_t *printer;
786 EnterCriticalSection(&printer_handles_cs);
788 for (i = 0; i < nb_printer_handles; i++)
790 if (!printer_handles[i])
792 if(handle == nb_printer_handles)
795 else if(!queue && !strcmpW(name, printer_handles[i]->name))
796 queue = printer_handles[i]->queue;
799 if (handle >= nb_printer_handles)
801 opened_printer_t **new_array;
803 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
804 (nb_printer_handles + 16) * sizeof(*new_array) );
806 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
807 (nb_printer_handles + 16) * sizeof(*new_array) );
814 printer_handles = new_array;
815 nb_printer_handles += 16;
818 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
824 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
825 strcpyW(printer->name, name);
827 printer->queue = queue;
830 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
831 list_init(&printer->queue->jobs);
832 printer->queue->ref = 0;
834 InterlockedIncrement(&printer->queue->ref);
837 printer_handles[handle] = printer;
840 LeaveCriticalSection(&printer_handles_cs);
842 return (HANDLE)handle;
845 /******************************************************************
847 * Get the pointer to the opened printer referred by the handle
849 static opened_printer_t *get_opened_printer(HANDLE hprn)
851 UINT_PTR idx = (UINT_PTR)hprn;
852 opened_printer_t *ret = NULL;
854 EnterCriticalSection(&printer_handles_cs);
856 if ((idx <= 0) || (idx > nb_printer_handles))
859 ret = printer_handles[idx - 1];
861 LeaveCriticalSection(&printer_handles_cs);
865 /******************************************************************
866 * get_opened_printer_name
867 * Get the pointer to the opened printer name referred by the handle
869 static LPCWSTR get_opened_printer_name(HANDLE hprn)
871 opened_printer_t *printer = get_opened_printer(hprn);
872 if(!printer) return NULL;
873 return printer->name;
876 /******************************************************************
877 * WINSPOOL_GetOpenedPrinterRegKey
880 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
882 LPCWSTR name = get_opened_printer_name(hPrinter);
886 if(!name) return ERROR_INVALID_HANDLE;
888 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
892 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
894 ERR("Can't find opened printer %s in registry\n",
896 RegCloseKey(hkeyPrinters);
897 return ERROR_INVALID_PRINTER_NAME; /* ? */
899 RegCloseKey(hkeyPrinters);
900 return ERROR_SUCCESS;
903 /******************************************************************
906 * Get the pointer to the specified job.
907 * Should hold the printer_handles_cs before calling.
909 static job_t *get_job(HANDLE hprn, DWORD JobId)
911 opened_printer_t *printer = get_opened_printer(hprn);
914 if(!printer) return NULL;
915 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
917 if(job->job_id == JobId)
923 /***********************************************************
926 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
929 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
932 Formname = (dmA->dmSize > off_formname);
933 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
934 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
935 dmW->dmDeviceName, CCHDEVICENAME);
937 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
938 dmA->dmSize - CCHDEVICENAME);
940 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
941 off_formname - CCHDEVICENAME);
942 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
943 dmW->dmFormName, CCHFORMNAME);
944 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
945 (off_formname + CCHFORMNAME));
948 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
953 /***********************************************************
955 * Creates an ascii copy of supplied devmode on heap
957 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
962 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
964 if(!dmW) return NULL;
965 Formname = (dmW->dmSize > off_formname);
966 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
967 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
968 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
969 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
971 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
972 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
974 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
975 off_formname - CCHDEVICENAME * sizeof(WCHAR));
976 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
977 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
978 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
979 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
982 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
987 /***********************************************************
989 * Creates a unicode copy of PRINTER_INFO_2A on heap
991 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
993 LPPRINTER_INFO_2W piW;
994 UNICODE_STRING usBuffer;
996 if(!piA) return NULL;
997 piW = HeapAlloc(heap, 0, sizeof(*piW));
998 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1000 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1001 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1002 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1003 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1004 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1005 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1006 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1007 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1008 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1009 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1010 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1011 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1015 /***********************************************************
1016 * FREE_PRINTER_INFO_2W
1017 * Free PRINTER_INFO_2W and all strings
1019 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1023 HeapFree(heap,0,piW->pServerName);
1024 HeapFree(heap,0,piW->pPrinterName);
1025 HeapFree(heap,0,piW->pShareName);
1026 HeapFree(heap,0,piW->pPortName);
1027 HeapFree(heap,0,piW->pDriverName);
1028 HeapFree(heap,0,piW->pComment);
1029 HeapFree(heap,0,piW->pLocation);
1030 HeapFree(heap,0,piW->pDevMode);
1031 HeapFree(heap,0,piW->pSepFile);
1032 HeapFree(heap,0,piW->pPrintProcessor);
1033 HeapFree(heap,0,piW->pDatatype);
1034 HeapFree(heap,0,piW->pParameters);
1035 HeapFree(heap,0,piW);
1039 /******************************************************************
1040 * DeviceCapabilities [WINSPOOL.@]
1041 * DeviceCapabilitiesA [WINSPOOL.@]
1044 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1045 LPSTR pOutput, LPDEVMODEA lpdm)
1049 if (!GDI_CallDeviceCapabilities16)
1051 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1053 if (!GDI_CallDeviceCapabilities16) return -1;
1055 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1057 /* If DC_PAPERSIZE map POINT16s to POINTs */
1058 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1059 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1060 POINT *pt = (POINT *)pOutput;
1062 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1063 for(i = 0; i < ret; i++, pt++)
1068 HeapFree( GetProcessHeap(), 0, tmp );
1074 /*****************************************************************************
1075 * DeviceCapabilitiesW [WINSPOOL.@]
1077 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1080 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1081 WORD fwCapability, LPWSTR pOutput,
1082 const DEVMODEW *pDevMode)
1084 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1085 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1086 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1089 if(pOutput && (fwCapability == DC_BINNAMES ||
1090 fwCapability == DC_FILEDEPENDENCIES ||
1091 fwCapability == DC_PAPERNAMES)) {
1092 /* These need A -> W translation */
1095 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1099 switch(fwCapability) {
1104 case DC_FILEDEPENDENCIES:
1108 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1109 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1111 for(i = 0; i < ret; i++)
1112 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1113 pOutput + (i * size), size);
1114 HeapFree(GetProcessHeap(), 0, pOutputA);
1116 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1117 (LPSTR)pOutput, dmA);
1119 HeapFree(GetProcessHeap(),0,pPortA);
1120 HeapFree(GetProcessHeap(),0,pDeviceA);
1121 HeapFree(GetProcessHeap(),0,dmA);
1125 /******************************************************************
1126 * DocumentPropertiesA [WINSPOOL.@]
1128 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1130 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1131 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1132 LPDEVMODEA pDevModeInput,DWORD fMode )
1134 LPSTR lpName = pDeviceName;
1137 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1138 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1142 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1144 ERR("no name from hPrinter?\n");
1145 SetLastError(ERROR_INVALID_HANDLE);
1148 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1151 if (!GDI_CallExtDeviceMode16)
1153 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1155 if (!GDI_CallExtDeviceMode16) {
1156 ERR("No CallExtDeviceMode16?\n");
1160 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1161 pDevModeInput, NULL, fMode);
1164 HeapFree(GetProcessHeap(),0,lpName);
1169 /*****************************************************************************
1170 * DocumentPropertiesW (WINSPOOL.@)
1172 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1174 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1176 LPDEVMODEW pDevModeOutput,
1177 LPDEVMODEW pDevModeInput, DWORD fMode)
1180 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1181 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1182 LPDEVMODEA pDevModeOutputA = NULL;
1185 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1186 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1188 if(pDevModeOutput) {
1189 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1190 if(ret < 0) return ret;
1191 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1193 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1194 pDevModeInputA, fMode);
1195 if(pDevModeOutput) {
1196 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1197 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1199 if(fMode == 0 && ret > 0)
1200 ret += (CCHDEVICENAME + CCHFORMNAME);
1201 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1202 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1206 /******************************************************************
1207 * OpenPrinterA [WINSPOOL.@]
1212 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1213 LPPRINTER_DEFAULTSA pDefault)
1215 UNICODE_STRING lpPrinterNameW;
1216 UNICODE_STRING usBuffer;
1217 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1218 PWSTR pwstrPrinterNameW;
1221 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1224 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1225 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1226 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1227 pDefaultW = &DefaultW;
1229 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1231 RtlFreeUnicodeString(&usBuffer);
1232 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1234 RtlFreeUnicodeString(&lpPrinterNameW);
1238 /******************************************************************
1239 * OpenPrinterW [WINSPOOL.@]
1241 * Open a Printer / Printserver or a Printer-Object
1244 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1245 * phPrinter [O] The resulting Handle is stored here
1246 * pDefault [I] PTR to Default Printer Settings or NULL
1253 * lpPrinterName is one of:
1254 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1255 *| Printer: "PrinterName"
1256 *| Printer-Object: "PrinterName,Job xxx"
1257 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1258 *| XcvPort: "Servername,XcvPort PortName"
1261 *| Printserver not supported
1262 *| Printer-Object not supported
1263 *| XcvMonitor not supported
1264 *| XcvPort not supported
1265 *| pDefaults not supported
1268 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1269 LPPRINTER_DEFAULTSW pDefault)
1271 HKEY hkeyPrinters, hkeyPrinter;
1273 if (!lpPrinterName) {
1274 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1275 SetLastError(ERROR_INVALID_PARAMETER);
1279 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1282 /* Check Printer exists */
1283 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1285 ERR("Can't create Printers key\n");
1286 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1290 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1291 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1293 TRACE("Can't find printer %s in registry\n",
1294 debugstr_w(lpPrinterName));
1295 RegCloseKey(hkeyPrinters);
1296 SetLastError(ERROR_INVALID_PRINTER_NAME);
1299 RegCloseKey(hkeyPrinter);
1300 RegCloseKey(hkeyPrinters);
1302 if(!phPrinter) /* This seems to be what win95 does anyway */
1305 /* Get the unique handle of the printer*/
1306 *phPrinter = get_opened_printer_entry( lpPrinterName );
1308 if (pDefault != NULL)
1309 FIXME("Not handling pDefault\n");
1314 /******************************************************************
1315 * AddMonitorA [WINSPOOL.@]
1320 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1322 LPWSTR nameW = NULL;
1325 LPMONITOR_INFO_2A mi2a;
1326 MONITOR_INFO_2W mi2w;
1328 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1329 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1330 mi2a ? debugstr_a(mi2a->pName) : NULL,
1331 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1332 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1335 SetLastError(ERROR_INVALID_LEVEL);
1339 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1345 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1346 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1347 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1350 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1352 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1353 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1354 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1356 if (mi2a->pEnvironment) {
1357 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1358 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1359 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1361 if (mi2a->pDLLName) {
1362 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1363 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1364 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1367 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1369 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1370 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1371 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1373 HeapFree(GetProcessHeap(), 0, nameW);
1377 /******************************************************************************
1378 * AddMonitorW [WINSPOOL.@]
1380 * Install a Printmonitor
1383 * pName [I] Servername or NULL (local Computer)
1384 * Level [I] Structure-Level (Must be 2)
1385 * pMonitors [I] PTR to MONITOR_INFO_2
1392 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1395 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1397 LPMONITOR_INFO_2W mi2w;
1400 HMODULE hdll = NULL;
1404 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1405 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1406 mi2w ? debugstr_w(mi2w->pName) : NULL,
1407 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1408 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1411 SetLastError(ERROR_INVALID_LEVEL);
1415 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1420 if (pName && (pName[0])) {
1421 FIXME("for server %s not implemented\n", debugstr_w(pName));
1422 SetLastError(ERROR_ACCESS_DENIED);
1427 if (!mi2w->pName || (! mi2w->pName[0])) {
1428 WARN("pName not valid : %s \n", debugstr_w(mi2w->pName));
1429 SetLastError(ERROR_INVALID_PARAMETER);
1432 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1433 WARN("Environment %s requested (we support only %s)\n",
1434 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1435 SetLastError(ERROR_INVALID_ENVIRONMENT);
1439 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1440 WARN("pDLLName not valid : %s \n", debugstr_w(mi2w->pDLLName));
1441 SetLastError(ERROR_INVALID_PARAMETER);
1445 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1450 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1451 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1455 if(RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1456 KEY_WRITE, NULL, &hentry, &disposition) == ERROR_SUCCESS) {
1458 if (disposition == REG_OPENED_EXISTING_KEY) {
1459 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1460 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1461 9x: ERROR_ALREADY_EXISTS (183) */
1462 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1467 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1468 res = (RegSetValueExW(hentry, DriverW, 0,
1469 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1471 RegCloseKey(hentry);
1478 /******************************************************************
1479 * DeletePrinterDriverA [WINSPOOL.@]
1483 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1485 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1486 debugstr_a(pDriverName));
1487 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1491 /******************************************************************
1492 * DeletePrinterDriverW [WINSPOOL.@]
1496 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1498 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1499 debugstr_w(pDriverName));
1500 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1504 /******************************************************************
1505 * DeleteMonitorA [WINSPOOL.@]
1507 * See DeleteMonitorW.
1510 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1512 LPWSTR nameW = NULL;
1513 LPWSTR EnvironmentW = NULL;
1514 LPWSTR MonitorNameW = NULL;
1519 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1520 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1521 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1525 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
1526 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1527 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
1530 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
1531 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1532 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
1535 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
1537 HeapFree(GetProcessHeap(), 0, MonitorNameW);
1538 HeapFree(GetProcessHeap(), 0, EnvironmentW);
1539 HeapFree(GetProcessHeap(), 0, nameW);
1543 /******************************************************************
1544 * DeleteMonitorW [WINSPOOL.@]
1546 * Delete a specific Printmonitor from a Printing-Environment
1549 * pName [I] Servername or NULL (local Computer)
1550 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1551 * pMonitorName [I] Name of the Monitor, that should be deleted
1558 * pEnvironment is ignored in Windows for the local Computer.
1562 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1566 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1567 debugstr_w(pMonitorName));
1569 if (pName && (pName[0])) {
1570 FIXME("for server %s not implemented\n", debugstr_w(pName));
1571 SetLastError(ERROR_ACCESS_DENIED);
1575 /* pEnvironment is ignored in Windows for the local Computer */
1577 if (!pMonitorName || !pMonitorName[0]) {
1578 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1579 SetLastError(ERROR_INVALID_PARAMETER);
1583 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1584 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1588 /* change this, when advapi32.dll/RegDeleteTree is implemented */
1589 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
1590 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
1595 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
1598 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1599 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1603 /******************************************************************
1604 * DeletePortA [WINSPOOL.@]
1610 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1612 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1613 debugstr_a(pPortName));
1614 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1618 /******************************************************************
1619 * DeletePortW [WINSPOOL.@]
1621 * Delete a specific Port
1624 * pName [I] Servername or NULL (local Computer)
1625 * hWnd [I] Handle to parent Window for the Dialog-Box
1626 * pPortName [I] Name of the Port, that should be deleted
1637 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1639 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1640 debugstr_w(pPortName));
1641 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1645 /******************************************************************************
1646 * SetPrinterW [WINSPOOL.@]
1656 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1660 /******************************************************************************
1661 * WritePrinter [WINSPOOL.@]
1663 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1665 opened_printer_t *printer;
1668 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1670 EnterCriticalSection(&printer_handles_cs);
1671 printer = get_opened_printer(hPrinter);
1674 SetLastError(ERROR_INVALID_HANDLE);
1680 SetLastError(ERROR_SPL_NO_STARTDOC);
1684 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1686 LeaveCriticalSection(&printer_handles_cs);
1690 /*****************************************************************************
1691 * AddFormA [WINSPOOL.@]
1693 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1695 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1699 /*****************************************************************************
1700 * AddFormW [WINSPOOL.@]
1702 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1704 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1708 /*****************************************************************************
1709 * AddJobA [WINSPOOL.@]
1711 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1714 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1718 SetLastError(ERROR_INVALID_LEVEL);
1722 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1725 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1726 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1727 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1728 if(*pcbNeeded > cbBuf) {
1729 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1732 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1733 addjobA->JobId = addjobW->JobId;
1734 addjobA->Path = (char *)(addjobA + 1);
1735 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1741 /*****************************************************************************
1742 * AddJobW [WINSPOOL.@]
1744 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1746 opened_printer_t *printer;
1749 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1750 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1751 WCHAR path[MAX_PATH], filename[MAX_PATH];
1753 ADDJOB_INFO_1W *addjob;
1755 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1757 EnterCriticalSection(&printer_handles_cs);
1759 printer = get_opened_printer(hPrinter);
1762 SetLastError(ERROR_INVALID_HANDLE);
1767 SetLastError(ERROR_INVALID_LEVEL);
1771 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1775 job->job_id = InterlockedIncrement(&next_job_id);
1777 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1778 if(path[len - 1] != '\\')
1780 memcpy(path + len, spool_path, sizeof(spool_path));
1781 sprintfW(filename, fmtW, path, job->job_id);
1783 len = strlenW(filename);
1784 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1785 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1786 job->document_title = strdupW(default_doc_title);
1787 list_add_tail(&printer->queue->jobs, &job->entry);
1789 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1790 if(*pcbNeeded <= cbBuf) {
1791 addjob = (ADDJOB_INFO_1W*)pData;
1792 addjob->JobId = job->job_id;
1793 addjob->Path = (WCHAR *)(addjob + 1);
1794 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1797 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1800 LeaveCriticalSection(&printer_handles_cs);
1804 /*****************************************************************************
1805 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1807 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1808 DWORD level, LPBYTE Info,
1809 DWORD cbBuf, LPDWORD needed)
1811 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1812 level, Info, cbBuf);
1816 /*****************************************************************************
1817 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1819 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1820 DWORD level, LPBYTE Info,
1821 DWORD cbBuf, LPDWORD needed)
1823 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1824 level, Info, cbBuf);
1828 /*****************************************************************************
1829 * WINSPOOL_OpenDriverReg [internal]
1831 * opens the registry for the printer drivers depending on the given input
1832 * variable pEnvironment
1835 * the opened hkey on success
1838 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1840 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1841 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1843 LPWSTR lpKey, buffer = NULL;
1847 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1851 pEnvW = pEnvironment;
1853 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1854 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1855 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1860 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1862 if(!GetVersionExW( &ver))
1865 switch (ver.dwPlatformId) {
1866 case VER_PLATFORM_WIN32s:
1867 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1869 case VER_PLATFORM_WIN32_NT:
1876 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1879 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1880 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1881 wsprintfW( lpKey, DriversW, pEnvW);
1883 TRACE("%s\n", debugstr_w(lpKey));
1885 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1888 HeapFree( GetProcessHeap(), 0, buffer);
1889 HeapFree( GetProcessHeap(), 0, lpKey);
1894 /*****************************************************************************
1895 * AddPrinterW [WINSPOOL.@]
1897 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1899 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1903 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1906 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1909 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1910 SetLastError(ERROR_INVALID_PARAMETER);
1914 ERR("Level = %ld, unsupported!\n", Level);
1915 SetLastError(ERROR_INVALID_LEVEL);
1918 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1919 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1920 debugstr_w(pi->pPrinterName)
1922 SetLastError(ERROR_INVALID_LEVEL);
1926 SetLastError(ERROR_INVALID_PARAMETER);
1929 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1931 ERR("Can't create Printers key\n");
1934 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1935 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1936 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1937 RegCloseKey(hkeyPrinter);
1938 RegCloseKey(hkeyPrinters);
1941 RegCloseKey(hkeyPrinter);
1943 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1945 ERR("Can't create Drivers key\n");
1946 RegCloseKey(hkeyPrinters);
1949 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1951 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1952 RegCloseKey(hkeyPrinters);
1953 RegCloseKey(hkeyDrivers);
1954 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1957 RegCloseKey(hkeyDriver);
1958 RegCloseKey(hkeyDrivers);
1960 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1961 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1962 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1963 RegCloseKey(hkeyPrinters);
1967 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1969 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1970 SetLastError(ERROR_INVALID_PRINTER_NAME);
1971 RegCloseKey(hkeyPrinters);
1974 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1975 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1976 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1978 /* See if we can load the driver. We may need the devmode structure anyway
1981 * Note that DocumentPropertiesW will briefly try to open the printer we
1982 * just create to find a DEVMODEA struct (it will use the WINEPS default
1983 * one in case it is not there, so we are ok).
1985 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1988 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1989 size = sizeof(DEVMODEW);
1995 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1996 ZeroMemory(dmW,size);
1998 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2000 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2001 HeapFree(GetProcessHeap(),0,dmW);
2006 /* set devmode to printer name */
2007 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
2011 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2012 and we support these drivers. NT writes DEVMODEW so somehow
2013 we'll need to distinguish between these when we support NT
2017 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2018 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2019 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2020 HeapFree(GetProcessHeap(), 0, dmA);
2022 HeapFree(GetProcessHeap(), 0, dmW);
2024 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2025 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2026 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2027 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2029 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2030 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2031 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2032 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2033 (LPBYTE)&pi->Priority, sizeof(DWORD));
2034 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2035 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2036 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2037 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2038 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2039 (LPBYTE)&pi->Status, sizeof(DWORD));
2040 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2041 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2043 RegCloseKey(hkeyPrinter);
2044 RegCloseKey(hkeyPrinters);
2045 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2046 ERR("OpenPrinter failing\n");
2052 /*****************************************************************************
2053 * AddPrinterA [WINSPOOL.@]
2055 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2057 UNICODE_STRING pNameW;
2059 PRINTER_INFO_2W *piW;
2060 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2063 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2065 ERR("Level = %ld, unsupported!\n", Level);
2066 SetLastError(ERROR_INVALID_LEVEL);
2069 pwstrNameW = asciitounicode(&pNameW,pName);
2070 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2072 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2074 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2075 RtlFreeUnicodeString(&pNameW);
2080 /*****************************************************************************
2081 * ClosePrinter [WINSPOOL.@]
2083 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2085 UINT_PTR i = (UINT_PTR)hPrinter;
2086 opened_printer_t *printer = NULL;
2089 TRACE("Handle %p\n", hPrinter);
2091 EnterCriticalSection(&printer_handles_cs);
2093 if ((i > 0) && (i <= nb_printer_handles))
2094 printer = printer_handles[i - 1];
2098 struct list *cursor, *cursor2;
2101 EndDocPrinter(hPrinter);
2103 if(InterlockedDecrement(&printer->queue->ref) == 0)
2105 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2107 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2108 ScheduleJob(hPrinter, job->job_id);
2110 HeapFree(GetProcessHeap(), 0, printer->queue);
2112 HeapFree(GetProcessHeap(), 0, printer->name);
2113 HeapFree(GetProcessHeap(), 0, printer);
2114 printer_handles[i - 1] = NULL;
2117 LeaveCriticalSection(&printer_handles_cs);
2121 /*****************************************************************************
2122 * DeleteFormA [WINSPOOL.@]
2124 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2126 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2130 /*****************************************************************************
2131 * DeleteFormW [WINSPOOL.@]
2133 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2135 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2139 /*****************************************************************************
2140 * WINSPOOL_SHRegDeleteKey
2142 * Recursively delete subkeys.
2143 * Cut & paste from shlwapi.
2146 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2148 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2149 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2152 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2155 /* Find how many subkeys there are */
2156 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2157 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2161 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2162 /* Name too big: alloc a buffer for it */
2163 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2166 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2169 /* Recursively delete all the subkeys */
2170 for(i = 0; i < dwKeyCount && !dwRet; i++)
2172 dwSize = dwMaxSubkeyLen;
2173 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2175 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2178 if (lpszName != szNameBuf)
2179 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2183 RegCloseKey(hSubKey);
2185 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2190 /*****************************************************************************
2191 * DeletePrinter [WINSPOOL.@]
2193 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2195 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2196 HKEY hkeyPrinters, hkey;
2199 SetLastError(ERROR_INVALID_HANDLE);
2202 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
2203 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2204 RegCloseKey(hkeyPrinters);
2206 WriteProfileStringW(devicesW, lpNameW, NULL);
2207 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2208 RegDeleteValueW(hkey, lpNameW);
2214 /*****************************************************************************
2215 * SetPrinterA [WINSPOOL.@]
2217 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2220 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2224 /*****************************************************************************
2225 * SetJobA [WINSPOOL.@]
2227 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2228 LPBYTE pJob, DWORD Command)
2232 UNICODE_STRING usBuffer;
2234 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2236 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2237 are all ignored by SetJob, so we don't bother copying them */
2245 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2246 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2248 JobW = (LPBYTE)info1W;
2249 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2250 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2251 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2252 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2253 info1W->Status = info1A->Status;
2254 info1W->Priority = info1A->Priority;
2255 info1W->Position = info1A->Position;
2256 info1W->PagesPrinted = info1A->PagesPrinted;
2261 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2262 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2264 JobW = (LPBYTE)info2W;
2265 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2266 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2267 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2268 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2269 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2270 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2271 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2272 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2273 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2274 info2W->Status = info2A->Status;
2275 info2W->Priority = info2A->Priority;
2276 info2W->Position = info2A->Position;
2277 info2W->StartTime = info2A->StartTime;
2278 info2W->UntilTime = info2A->UntilTime;
2279 info2W->PagesPrinted = info2A->PagesPrinted;
2283 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2284 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2287 SetLastError(ERROR_INVALID_LEVEL);
2291 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2297 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2298 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2299 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2300 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2301 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2306 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2307 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2308 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2309 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2310 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2311 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2312 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2313 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2314 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2318 HeapFree(GetProcessHeap(), 0, JobW);
2323 /*****************************************************************************
2324 * SetJobW [WINSPOOL.@]
2326 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2327 LPBYTE pJob, DWORD Command)
2332 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2333 FIXME("Ignoring everything other than document title\n");
2335 EnterCriticalSection(&printer_handles_cs);
2336 job = get_job(hPrinter, JobId);
2346 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2347 HeapFree(GetProcessHeap(), 0, job->document_title);
2348 job->document_title = strdupW(info1->pDocument);
2353 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2354 HeapFree(GetProcessHeap(), 0, job->document_title);
2355 job->document_title = strdupW(info2->pDocument);
2361 SetLastError(ERROR_INVALID_LEVEL);
2366 LeaveCriticalSection(&printer_handles_cs);
2370 /*****************************************************************************
2371 * EndDocPrinter [WINSPOOL.@]
2373 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2375 opened_printer_t *printer;
2377 TRACE("(%p)\n", hPrinter);
2379 EnterCriticalSection(&printer_handles_cs);
2381 printer = get_opened_printer(hPrinter);
2384 SetLastError(ERROR_INVALID_HANDLE);
2390 SetLastError(ERROR_SPL_NO_STARTDOC);
2394 CloseHandle(printer->doc->hf);
2395 ScheduleJob(hPrinter, printer->doc->job_id);
2396 HeapFree(GetProcessHeap(), 0, printer->doc);
2397 printer->doc = NULL;
2400 LeaveCriticalSection(&printer_handles_cs);
2404 /*****************************************************************************
2405 * EndPagePrinter [WINSPOOL.@]
2407 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2409 FIXME("(%p): stub\n", hPrinter);
2413 /*****************************************************************************
2414 * StartDocPrinterA [WINSPOOL.@]
2416 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2418 UNICODE_STRING usBuffer;
2420 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2423 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2424 or one (DOC_INFO_3) extra DWORDs */
2428 doc2W.JobId = doc2->JobId;
2431 doc2W.dwMode = doc2->dwMode;
2434 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2435 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2436 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2440 SetLastError(ERROR_INVALID_LEVEL);
2444 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2446 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2447 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2448 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2453 /*****************************************************************************
2454 * StartDocPrinterW [WINSPOOL.@]
2456 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2458 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2459 opened_printer_t *printer;
2460 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2461 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2462 JOB_INFO_1W job_info;
2463 DWORD needed, ret = 0;
2467 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2468 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2469 debugstr_w(doc->pDatatype));
2471 if(Level < 1 || Level > 3)
2473 SetLastError(ERROR_INVALID_LEVEL);
2477 EnterCriticalSection(&printer_handles_cs);
2478 printer = get_opened_printer(hPrinter);
2481 SetLastError(ERROR_INVALID_HANDLE);
2487 SetLastError(ERROR_INVALID_PRINTER_STATE);
2491 /* Even if we're printing to a file we still add a print job, we'll
2492 just ignore the spool file name */
2494 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2496 ERR("AddJob failed gle %08lx\n", GetLastError());
2500 if(doc->pOutputFile)
2501 filename = doc->pOutputFile;
2503 filename = addjob->Path;
2505 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2506 if(hf == INVALID_HANDLE_VALUE)
2509 memset(&job_info, 0, sizeof(job_info));
2510 job_info.pDocument = doc->pDocName;
2511 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2513 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2514 printer->doc->hf = hf;
2515 ret = printer->doc->job_id = addjob->JobId;
2517 LeaveCriticalSection(&printer_handles_cs);
2522 /*****************************************************************************
2523 * StartPagePrinter [WINSPOOL.@]
2525 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2527 FIXME("(%p): stub\n", hPrinter);
2531 /*****************************************************************************
2532 * GetFormA [WINSPOOL.@]
2534 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2535 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2537 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2538 Level,pForm,cbBuf,pcbNeeded);
2542 /*****************************************************************************
2543 * GetFormW [WINSPOOL.@]
2545 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2546 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2548 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2549 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2553 /*****************************************************************************
2554 * SetFormA [WINSPOOL.@]
2556 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2559 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2563 /*****************************************************************************
2564 * SetFormW [WINSPOOL.@]
2566 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2569 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2573 /*****************************************************************************
2574 * ReadPrinter [WINSPOOL.@]
2576 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2577 LPDWORD pNoBytesRead)
2579 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2583 /*****************************************************************************
2584 * ResetPrinterA [WINSPOOL.@]
2586 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2588 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2592 /*****************************************************************************
2593 * ResetPrinterW [WINSPOOL.@]
2595 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2597 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2601 /*****************************************************************************
2602 * WINSPOOL_GetDWORDFromReg
2604 * Return DWORD associated with ValueName from hkey.
2606 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2608 DWORD sz = sizeof(DWORD), type, value = 0;
2611 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2613 if(ret != ERROR_SUCCESS) {
2614 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2617 if(type != REG_DWORD) {
2618 ERR("Got type %ld\n", type);
2624 /*****************************************************************************
2625 * WINSPOOL_GetStringFromReg
2627 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2628 * String is stored either as unicode or ascii.
2629 * Bit of a hack here to get the ValueName if we want ascii.
2631 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2632 DWORD buflen, DWORD *needed,
2635 DWORD sz = buflen, type;
2639 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2641 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2642 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2643 HeapFree(GetProcessHeap(),0,ValueNameA);
2645 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2646 WARN("Got ret = %ld\n", ret);
2650 /* add space for terminating '\0' */
2651 sz += unicode ? sizeof(WCHAR) : 1;
2655 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
2660 /*****************************************************************************
2661 * WINSPOOL_GetDefaultDevMode
2663 * Get a default DevMode values for wineps.
2667 static void WINSPOOL_GetDefaultDevMode(
2669 DWORD buflen, DWORD *needed,
2673 static const char szwps[] = "wineps.drv";
2675 /* fill default DEVMODE - should be read from ppd... */
2676 ZeroMemory( &dm, sizeof(dm) );
2677 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2678 dm.dmSpecVersion = DM_SPECVERSION;
2679 dm.dmDriverVersion = 1;
2680 dm.dmSize = sizeof(DEVMODEA);
2681 dm.dmDriverExtra = 0;
2683 DM_ORIENTATION | DM_PAPERSIZE |
2684 DM_PAPERLENGTH | DM_PAPERWIDTH |
2687 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2688 DM_YRESOLUTION | DM_TTOPTION;
2690 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2691 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2692 dm.u1.s1.dmPaperLength = 2970;
2693 dm.u1.s1.dmPaperWidth = 2100;
2697 dm.dmDefaultSource = DMBIN_AUTO;
2698 dm.dmPrintQuality = DMRES_MEDIUM;
2701 dm.dmYResolution = 300; /* 300dpi */
2702 dm.dmTTOption = DMTT_BITMAP;
2705 /* dm.dmLogPixels */
2706 /* dm.dmBitsPerPel */
2707 /* dm.dmPelsWidth */
2708 /* dm.dmPelsHeight */
2709 /* dm.dmDisplayFlags */
2710 /* dm.dmDisplayFrequency */
2711 /* dm.dmICMMethod */
2712 /* dm.dmICMIntent */
2713 /* dm.dmMediaType */
2714 /* dm.dmDitherType */
2715 /* dm.dmReserved1 */
2716 /* dm.dmReserved2 */
2717 /* dm.dmPanningWidth */
2718 /* dm.dmPanningHeight */
2721 if(buflen >= sizeof(DEVMODEW)) {
2722 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2723 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2724 HeapFree(GetProcessHeap(),0,pdmW);
2726 *needed = sizeof(DEVMODEW);
2730 if(buflen >= sizeof(DEVMODEA)) {
2731 memcpy(ptr, &dm, sizeof(DEVMODEA));
2733 *needed = sizeof(DEVMODEA);
2737 /*****************************************************************************
2738 * WINSPOOL_GetDevModeFromReg
2740 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2741 * DevMode is stored either as unicode or ascii.
2743 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2745 DWORD buflen, DWORD *needed,
2748 DWORD sz = buflen, type;
2751 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2752 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2753 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2754 if (sz < sizeof(DEVMODEA))
2756 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2759 /* ensures that dmSize is not erratically bogus if registry is invalid */
2760 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2761 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2763 sz += (CCHDEVICENAME + CCHFORMNAME);
2765 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2766 memcpy(ptr, dmW, sz);
2767 HeapFree(GetProcessHeap(),0,dmW);
2774 /*********************************************************************
2775 * WINSPOOL_GetPrinter_2
2777 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2778 * The strings are either stored as unicode or ascii.
2780 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2781 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2784 DWORD size, left = cbBuf;
2785 BOOL space = (cbBuf > 0);
2790 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2792 if(space && size <= left) {
2793 pi2->pPrinterName = (LPWSTR)ptr;
2800 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2802 if(space && size <= left) {
2803 pi2->pShareName = (LPWSTR)ptr;
2810 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2812 if(space && size <= left) {
2813 pi2->pPortName = (LPWSTR)ptr;
2820 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2822 if(space && size <= left) {
2823 pi2->pDriverName = (LPWSTR)ptr;
2830 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2832 if(space && size <= left) {
2833 pi2->pComment = (LPWSTR)ptr;
2840 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2842 if(space && size <= left) {
2843 pi2->pLocation = (LPWSTR)ptr;
2850 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2852 if(space && size <= left) {
2853 pi2->pDevMode = (LPDEVMODEW)ptr;
2862 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2863 if(space && size <= left) {
2864 pi2->pDevMode = (LPDEVMODEW)ptr;
2871 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2873 if(space && size <= left) {
2874 pi2->pSepFile = (LPWSTR)ptr;
2881 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2883 if(space && size <= left) {
2884 pi2->pPrintProcessor = (LPWSTR)ptr;
2891 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2893 if(space && size <= left) {
2894 pi2->pDatatype = (LPWSTR)ptr;
2901 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2903 if(space && size <= left) {
2904 pi2->pParameters = (LPWSTR)ptr;
2912 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2913 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2914 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2915 "Default Priority");
2916 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2917 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2920 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2921 memset(pi2, 0, sizeof(*pi2));
2926 /*********************************************************************
2927 * WINSPOOL_GetPrinter_4
2929 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2931 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2932 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2935 DWORD size, left = cbBuf;
2936 BOOL space = (cbBuf > 0);
2941 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2943 if(space && size <= left) {
2944 pi4->pPrinterName = (LPWSTR)ptr;
2952 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2955 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2956 memset(pi4, 0, sizeof(*pi4));
2961 /*********************************************************************
2962 * WINSPOOL_GetPrinter_5
2964 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2966 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2967 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2970 DWORD size, left = cbBuf;
2971 BOOL space = (cbBuf > 0);
2976 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2978 if(space && size <= left) {
2979 pi5->pPrinterName = (LPWSTR)ptr;
2986 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2988 if(space && size <= left) {
2989 pi5->pPortName = (LPWSTR)ptr;
2997 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2998 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3000 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3004 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3005 memset(pi5, 0, sizeof(*pi5));
3010 /*****************************************************************************
3011 * WINSPOOL_GetPrinter
3013 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3014 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3015 * just a collection of pointers to strings.
3017 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3018 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3021 DWORD size, needed = 0;
3023 HKEY hkeyPrinter, hkeyPrinters;
3026 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3028 if (!(name = get_opened_printer_name(hPrinter))) {
3029 SetLastError(ERROR_INVALID_HANDLE);
3033 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3035 ERR("Can't create Printers key\n");
3038 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3040 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3041 RegCloseKey(hkeyPrinters);
3042 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3049 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3051 size = sizeof(PRINTER_INFO_2W);
3053 ptr = pPrinter + size;
3055 memset(pPrinter, 0, size);
3060 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3068 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3070 size = sizeof(PRINTER_INFO_4W);
3072 ptr = pPrinter + size;
3074 memset(pPrinter, 0, size);
3079 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3088 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3090 size = sizeof(PRINTER_INFO_5W);
3092 ptr = pPrinter + size;
3094 memset(pPrinter, 0, size);
3100 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3107 FIXME("Unimplemented level %ld\n", Level);
3108 SetLastError(ERROR_INVALID_LEVEL);
3109 RegCloseKey(hkeyPrinters);
3110 RegCloseKey(hkeyPrinter);
3114 RegCloseKey(hkeyPrinter);
3115 RegCloseKey(hkeyPrinters);
3117 TRACE("returning %d needed = %ld\n", ret, needed);
3118 if(pcbNeeded) *pcbNeeded = needed;
3120 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3124 /*****************************************************************************
3125 * GetPrinterW [WINSPOOL.@]
3127 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3128 DWORD cbBuf, LPDWORD pcbNeeded)
3130 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3134 /*****************************************************************************
3135 * GetPrinterA [WINSPOOL.@]
3137 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3138 DWORD cbBuf, LPDWORD pcbNeeded)
3140 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3144 /*****************************************************************************
3145 * WINSPOOL_EnumPrinters
3147 * Implementation of EnumPrintersA|W
3149 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3150 DWORD dwLevel, LPBYTE lpbPrinters,
3151 DWORD cbBuf, LPDWORD lpdwNeeded,
3152 LPDWORD lpdwReturned, BOOL unicode)
3155 HKEY hkeyPrinters, hkeyPrinter;
3156 WCHAR PrinterName[255];
3157 DWORD needed = 0, number = 0;
3158 DWORD used, i, left;
3162 memset(lpbPrinters, 0, cbBuf);
3168 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3169 if(dwType == PRINTER_ENUM_DEFAULT)
3172 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3173 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3174 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3175 if(!dwType) return TRUE;
3178 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3179 FIXME("dwType = %08lx\n", dwType);
3180 SetLastError(ERROR_INVALID_FLAGS);
3184 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3186 ERR("Can't create Printers key\n");
3190 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3191 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3192 RegCloseKey(hkeyPrinters);
3193 ERR("Can't query Printers key\n");
3196 TRACE("Found %ld printers\n", number);
3200 RegCloseKey(hkeyPrinters);
3202 *lpdwReturned = number;
3206 used = number * sizeof(PRINTER_INFO_2W);
3209 used = number * sizeof(PRINTER_INFO_4W);
3212 used = number * sizeof(PRINTER_INFO_5W);
3216 SetLastError(ERROR_INVALID_LEVEL);
3217 RegCloseKey(hkeyPrinters);
3220 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3222 for(i = 0; i < number; i++) {
3223 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3225 ERR("Can't enum key number %ld\n", i);
3226 RegCloseKey(hkeyPrinters);
3229 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3230 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3232 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3233 RegCloseKey(hkeyPrinters);
3238 buf = lpbPrinters + used;
3239 left = cbBuf - used;
3247 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3248 left, &needed, unicode);
3250 if(pi) pi += sizeof(PRINTER_INFO_2W);
3253 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3254 left, &needed, unicode);
3256 if(pi) pi += sizeof(PRINTER_INFO_4W);
3259 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3260 left, &needed, unicode);
3262 if(pi) pi += sizeof(PRINTER_INFO_5W);
3265 ERR("Shouldn't be here!\n");
3266 RegCloseKey(hkeyPrinter);
3267 RegCloseKey(hkeyPrinters);
3270 RegCloseKey(hkeyPrinter);
3272 RegCloseKey(hkeyPrinters);
3279 memset(lpbPrinters, 0, cbBuf);
3280 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3284 *lpdwReturned = number;
3285 SetLastError(ERROR_SUCCESS);
3290 /******************************************************************
3291 * EnumPrintersW [WINSPOOL.@]
3293 * Enumerates the available printers, print servers and print
3294 * providers, depending on the specified flags, name and level.
3298 * If level is set to 1:
3299 * Not implemented yet!
3300 * Returns TRUE with an empty list.
3302 * If level is set to 2:
3303 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3304 * Returns an array of PRINTER_INFO_2 data structures in the
3305 * lpbPrinters buffer. Note that according to MSDN also an
3306 * OpenPrinter should be performed on every remote printer.
3308 * If level is set to 4 (officially WinNT only):
3309 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3310 * Fast: Only the registry is queried to retrieve printer names,
3311 * no connection to the driver is made.
3312 * Returns an array of PRINTER_INFO_4 data structures in the
3313 * lpbPrinters buffer.
3315 * If level is set to 5 (officially WinNT4/Win9x only):
3316 * Fast: Only the registry is queried to retrieve printer names,
3317 * no connection to the driver is made.
3318 * Returns an array of PRINTER_INFO_5 data structures in the
3319 * lpbPrinters buffer.
3321 * If level set to 3 or 6+:
3322 * returns zero (failure!)
3324 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3328 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3329 * - Only levels 2, 4 and 5 are implemented at the moment.
3330 * - 16-bit printer drivers are not enumerated.
3331 * - Returned amount of bytes used/needed does not match the real Windoze
3332 * implementation (as in this implementation, all strings are part
3333 * of the buffer, whereas Win32 keeps them somewhere else)
3334 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3337 * - In a regular Wine installation, no registry settings for printers
3338 * exist, which makes this function return an empty list.
3340 BOOL WINAPI EnumPrintersW(
3341 DWORD dwType, /* [in] Types of print objects to enumerate */
3342 LPWSTR lpszName, /* [in] name of objects to enumerate */
3343 DWORD dwLevel, /* [in] type of printer info structure */
3344 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3345 DWORD cbBuf, /* [in] max size of buffer in bytes */
3346 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3347 LPDWORD lpdwReturned /* [out] number of entries returned */
3350 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3351 lpdwNeeded, lpdwReturned, TRUE);
3354 /******************************************************************
3355 * EnumPrintersA [WINSPOOL.@]
3358 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3359 DWORD dwLevel, LPBYTE lpbPrinters,
3360 DWORD cbBuf, LPDWORD lpdwNeeded,
3361 LPDWORD lpdwReturned)
3364 UNICODE_STRING lpszNameW;
3367 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3368 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3369 lpdwNeeded, lpdwReturned, FALSE);
3370 RtlFreeUnicodeString(&lpszNameW);
3374 /*****************************************************************************
3375 * WINSPOOL_GetDriverInfoFromReg [internal]
3377 * Enters the information from the registry into the DRIVER_INFO struct
3380 * zero if the printer driver does not exist in the registry
3381 * (only if Level > 1) otherwise nonzero
3383 static BOOL WINSPOOL_GetDriverInfoFromReg(
3386 LPWSTR pEnvironment,
3388 LPBYTE ptr, /* DRIVER_INFO */
3389 LPBYTE pDriverStrings, /* strings buffer */
3390 DWORD cbBuf, /* size of string buffer */
3391 LPDWORD pcbNeeded, /* space needed for str. */
3392 BOOL unicode) /* type of strings */
3396 LPBYTE strPtr = pDriverStrings;
3398 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3399 debugstr_w(DriverName), debugstr_w(pEnvironment),
3400 Level, ptr, pDriverStrings, cbBuf, unicode);
3403 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3404 if (*pcbNeeded <= cbBuf)
3405 strcpyW((LPWSTR)strPtr, DriverName);
3407 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3409 if(*pcbNeeded <= cbBuf)
3410 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3411 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3415 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3419 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
3420 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3423 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3424 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3425 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3430 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
3433 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3435 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3437 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3440 if(*pcbNeeded <= cbBuf) {
3442 strcpyW((LPWSTR)strPtr, pEnvironment);
3444 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3445 (LPSTR)strPtr, size, NULL, NULL);
3447 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
3448 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3451 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3454 if(*pcbNeeded <= cbBuf)
3455 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3458 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
3459 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3462 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3465 if(*pcbNeeded <= cbBuf)
3466 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3469 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
3470 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3473 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3474 0, &size, unicode)) {
3476 if(*pcbNeeded <= cbBuf)
3477 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3478 size, &tmp, unicode);
3480 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
3481 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3485 RegCloseKey(hkeyDriver);
3486 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3490 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3493 if(*pcbNeeded <= cbBuf)
3494 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3495 size, &tmp, unicode);
3497 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3498 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3501 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3504 if(*pcbNeeded <= cbBuf)
3505 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3506 size, &tmp, unicode);
3508 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3509 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3512 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3515 if(*pcbNeeded <= cbBuf)
3516 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3517 size, &tmp, unicode);
3519 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3520 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3523 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3526 if(*pcbNeeded <= cbBuf)
3527 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3528 size, &tmp, unicode);
3530 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3531 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3534 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3535 RegCloseKey(hkeyDriver);
3539 /*****************************************************************************
3540 * WINSPOOL_GetPrinterDriver
3542 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3543 DWORD Level, LPBYTE pDriverInfo,
3544 DWORD cbBuf, LPDWORD pcbNeeded,
3548 WCHAR DriverName[100];
3549 DWORD ret, type, size, needed = 0;
3551 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3553 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3554 Level,pDriverInfo,cbBuf, pcbNeeded);
3556 ZeroMemory(pDriverInfo, cbBuf);
3558 if (!(name = get_opened_printer_name(hPrinter))) {
3559 SetLastError(ERROR_INVALID_HANDLE);
3562 if(Level < 1 || Level > 6) {
3563 SetLastError(ERROR_INVALID_LEVEL);
3566 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3568 ERR("Can't create Printers key\n");
3571 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3573 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3574 RegCloseKey(hkeyPrinters);
3575 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3578 size = sizeof(DriverName);
3580 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3581 (LPBYTE)DriverName, &size);
3582 RegCloseKey(hkeyPrinter);
3583 RegCloseKey(hkeyPrinters);
3584 if(ret != ERROR_SUCCESS) {
3585 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3589 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3591 ERR("Can't create Drivers key\n");
3597 size = sizeof(DRIVER_INFO_1W);
3600 size = sizeof(DRIVER_INFO_2W);
3603 size = sizeof(DRIVER_INFO_3W);
3606 size = sizeof(DRIVER_INFO_4W);
3609 size = sizeof(DRIVER_INFO_5W);
3612 size = sizeof(DRIVER_INFO_6W);
3615 ERR("Invalid level\n");
3620 ptr = pDriverInfo + size;
3622 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3623 pEnvironment, Level, pDriverInfo,
3624 (cbBuf < size) ? NULL : ptr,
3625 (cbBuf < size) ? 0 : cbBuf - size,
3626 &needed, unicode)) {
3627 RegCloseKey(hkeyDrivers);
3631 RegCloseKey(hkeyDrivers);
3633 if(pcbNeeded) *pcbNeeded = size + needed;
3634 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3635 if(cbBuf >= needed) return TRUE;
3636 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3640 /*****************************************************************************
3641 * GetPrinterDriverA [WINSPOOL.@]
3643 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3644 DWORD Level, LPBYTE pDriverInfo,
3645 DWORD cbBuf, LPDWORD pcbNeeded)
3648 UNICODE_STRING pEnvW;
3651 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3652 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3653 cbBuf, pcbNeeded, FALSE);
3654 RtlFreeUnicodeString(&pEnvW);
3657 /*****************************************************************************
3658 * GetPrinterDriverW [WINSPOOL.@]
3660 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3661 DWORD Level, LPBYTE pDriverInfo,
3662 DWORD cbBuf, LPDWORD pcbNeeded)
3664 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3665 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3668 /*****************************************************************************
3669 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3671 * Return the PATH for the Printer-Drivers (UNICODE)
3674 * pName [I] Servername (NT only) or NULL (local Computer)
3675 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3676 * Level [I] Structure-Level (must be 1)
3677 * pDriverDirectory [O] PTR to Buffer that receives the Result
3678 * cbBuf [I] Size of Buffer at pDriverDirectory
3679 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3680 * required for pDriverDirectory
3683 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3684 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3685 * if cbBuf is too small
3687 * Native Values returned in pDriverDirectory on Success:
3688 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3689 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3690 *| win9x(Windows 4.0): "%winsysdir%"
3692 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3695 *- Only NULL or "" is supported for pName
3698 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3699 DWORD Level, LPBYTE pDriverDirectory,
3700 DWORD cbBuf, LPDWORD pcbNeeded)
3703 const printenv_t * env;
3705 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3706 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3707 if(pName != NULL && pName[0]) {
3708 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3709 SetLastError(ERROR_INVALID_PARAMETER);
3713 env = validate_envW(pEnvironment);
3714 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3717 WARN("(Level: %ld) is ignored in win9x\n", Level);
3718 SetLastError(ERROR_INVALID_LEVEL);
3722 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3723 needed = GetSystemDirectoryW(NULL, 0);
3724 /* add the Size for the Subdirectories */
3725 needed += lstrlenW(spooldriversW);
3726 needed += lstrlenW(env->subdir);
3727 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3730 *pcbNeeded = needed;
3731 TRACE("required: 0x%lx/%ld\n", needed, needed);
3732 if(needed > cbBuf) {
3733 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3736 if(pcbNeeded == NULL) {
3737 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3738 SetLastError(RPC_X_NULL_REF_POINTER);
3741 if(pDriverDirectory == NULL) {
3742 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3743 SetLastError(ERROR_INVALID_USER_BUFFER);
3747 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3748 /* add the Subdirectories */
3749 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3750 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3751 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3756 /*****************************************************************************
3757 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3759 * Return the PATH for the Printer-Drivers (ANSI)
3761 * See GetPrinterDriverDirectoryW.
3764 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3767 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3768 DWORD Level, LPBYTE pDriverDirectory,
3769 DWORD cbBuf, LPDWORD pcbNeeded)
3771 UNICODE_STRING nameW, environmentW;
3774 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3775 WCHAR *driverDirectoryW = NULL;
3777 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3778 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3780 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3782 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3783 else nameW.Buffer = NULL;
3784 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3785 else environmentW.Buffer = NULL;
3787 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3788 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3791 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3792 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3794 *pcbNeeded = needed;
3795 ret = (needed <= cbBuf) ? TRUE : FALSE;
3797 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3799 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3801 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3802 RtlFreeUnicodeString(&environmentW);
3803 RtlFreeUnicodeString(&nameW);
3808 /*****************************************************************************
3809 * AddPrinterDriverA [WINSPOOL.@]
3811 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3814 HKEY hkeyDrivers, hkeyName;
3816 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3818 if(level != 2 && level != 3) {
3819 SetLastError(ERROR_INVALID_LEVEL);
3823 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3824 SetLastError(ERROR_INVALID_PARAMETER);
3828 WARN("pDriverInfo == NULL\n");
3829 SetLastError(ERROR_INVALID_PARAMETER);
3834 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3836 memset(&di3, 0, sizeof(di3));
3837 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3840 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3842 SetLastError(ERROR_INVALID_PARAMETER);
3845 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3846 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3847 if(!di3.pHelpFile) di3.pHelpFile = "";
3848 if(!di3.pMonitorName) di3.pMonitorName = "";
3850 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3853 ERR("Can't create Drivers key\n");
3857 if(level == 2) { /* apparently can't overwrite with level2 */
3858 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3859 RegCloseKey(hkeyName);
3860 RegCloseKey(hkeyDrivers);
3861 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3862 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3866 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3867 RegCloseKey(hkeyDrivers);
3868 ERR("Can't create Name key\n");
3871 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3873 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3874 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3875 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3877 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3878 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3879 (LPBYTE) di3.pDependentFiles, 0);
3880 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3881 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3882 RegCloseKey(hkeyName);
3883 RegCloseKey(hkeyDrivers);
3888 /*****************************************************************************
3889 * AddPrinterDriverW [WINSPOOL.@]
3891 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3894 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3899 /*****************************************************************************
3900 * AddPrintProcessorA [WINSPOOL.@]
3902 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3903 LPSTR pPrintProcessorName)
3905 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3906 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3910 /*****************************************************************************
3911 * AddPrintProcessorW [WINSPOOL.@]
3913 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3914 LPWSTR pPrintProcessorName)
3916 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3917 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3921 /*****************************************************************************
3922 * AddPrintProvidorA [WINSPOOL.@]
3924 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3926 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3930 /*****************************************************************************
3931 * AddPrintProvidorW [WINSPOOL.@]
3933 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3935 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3939 /*****************************************************************************
3940 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3942 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3943 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3945 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3946 pDevModeOutput, pDevModeInput);
3950 /*****************************************************************************
3951 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3953 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3954 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3956 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3957 pDevModeOutput, pDevModeInput);
3961 /*****************************************************************************
3962 * PrinterProperties [WINSPOOL.@]
3964 * Displays a dialog to set the properties of the printer.
3967 * nonzero on success or zero on failure
3970 * implemented as stub only
3972 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3973 HANDLE hPrinter /* [in] handle to printer object */
3975 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3976 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3980 /*****************************************************************************
3981 * EnumJobsA [WINSPOOL.@]
3984 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3985 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3988 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3989 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3991 if(pcbNeeded) *pcbNeeded = 0;
3992 if(pcReturned) *pcReturned = 0;
3997 /*****************************************************************************
3998 * EnumJobsW [WINSPOOL.@]
4001 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4002 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4005 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
4006 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4008 if(pcbNeeded) *pcbNeeded = 0;
4009 if(pcReturned) *pcReturned = 0;
4013 /*****************************************************************************
4014 * WINSPOOL_EnumPrinterDrivers [internal]
4016 * Delivers information about all printer drivers installed on the
4017 * localhost or a given server
4020 * nonzero on success or zero on failure. If the buffer for the returned
4021 * information is too small the function will return an error
4024 * - only implemented for localhost, foreign hosts will return an error
4026 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4027 DWORD Level, LPBYTE pDriverInfo,
4028 DWORD cbBuf, LPDWORD pcbNeeded,
4029 LPDWORD pcReturned, BOOL unicode)
4032 DWORD i, needed, number = 0, size = 0;
4033 WCHAR DriverNameW[255];
4036 TRACE("%s,%s,%ld,%p,%ld,%d\n",
4037 debugstr_w(pName), debugstr_w(pEnvironment),
4038 Level, pDriverInfo, cbBuf, unicode);
4040 /* check for local drivers */
4042 ERR("remote drivers unsupported! Current remote host is %s\n",
4047 /* check input parameter */
4048 if((Level < 1) || (Level > 3)) {
4049 ERR("unsupported level %ld\n", Level);
4050 SetLastError(ERROR_INVALID_LEVEL);
4054 /* initialize return values */
4056 memset( pDriverInfo, 0, cbBuf);
4060 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4062 ERR("Can't open Drivers key\n");
4066 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4067 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4068 RegCloseKey(hkeyDrivers);
4069 ERR("Can't query Drivers key\n");
4072 TRACE("Found %ld Drivers\n", number);
4074 /* get size of single struct
4075 * unicode and ascii structure have the same size
4079 size = sizeof(DRIVER_INFO_1A);
4082 size = sizeof(DRIVER_INFO_2A);
4085 size = sizeof(DRIVER_INFO_3A);
4089 /* calculate required buffer size */
4090 *pcbNeeded = size * number;
4092 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4094 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4095 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4097 ERR("Can't enum key number %ld\n", i);
4098 RegCloseKey(hkeyDrivers);
4101 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4102 pEnvironment, Level, ptr,
4103 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4104 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4105 &needed, unicode)) {
4106 RegCloseKey(hkeyDrivers);
4109 (*pcbNeeded) += needed;
4112 RegCloseKey(hkeyDrivers);
4114 if(cbBuf < *pcbNeeded){
4115 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4119 *pcReturned = number;
4123 /*****************************************************************************
4124 * EnumPrinterDriversW [WINSPOOL.@]
4126 * see function EnumPrinterDrivers for RETURNS, BUGS
4128 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4129 LPBYTE pDriverInfo, DWORD cbBuf,
4130 LPDWORD pcbNeeded, LPDWORD pcReturned)
4132 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4133 cbBuf, pcbNeeded, pcReturned, TRUE);
4136 /*****************************************************************************
4137 * EnumPrinterDriversA [WINSPOOL.@]
4139 * see function EnumPrinterDrivers for RETURNS, BUGS
4141 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4142 LPBYTE pDriverInfo, DWORD cbBuf,
4143 LPDWORD pcbNeeded, LPDWORD pcReturned)
4145 UNICODE_STRING pNameW, pEnvironmentW;
4146 PWSTR pwstrNameW, pwstrEnvironmentW;
4148 pwstrNameW = asciitounicode(&pNameW, pName);
4149 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4151 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4152 Level, pDriverInfo, cbBuf, pcbNeeded,
4154 RtlFreeUnicodeString(&pNameW);
4155 RtlFreeUnicodeString(&pEnvironmentW);
4160 static CHAR PortMonitor[] = "Wine Port Monitor";
4161 static CHAR PortDescription[] = "Wine Port";
4163 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4167 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4168 NULL, OPEN_EXISTING, 0, NULL );
4169 if (handle == INVALID_HANDLE_VALUE)
4171 TRACE("Checking %s exists\n", name );
4172 CloseHandle( handle );
4176 static DWORD WINSPOOL_CountSerialPorts(void)
4183 strcpy( name, "COMx:" );
4185 if (WINSPOOL_ComPortExists( name ))
4192 /******************************************************************************
4193 * EnumPortsA (WINSPOOL.@)
4198 * ANSI-Version did not call the UNICODE-Version
4201 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4202 LPDWORD bufneeded,LPDWORD bufreturned)
4205 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4206 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4210 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4211 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4216 info_size = sizeof (PORT_INFO_1A);
4219 info_size = sizeof (PORT_INFO_2A);
4222 SetLastError(ERROR_INVALID_LEVEL);
4226 /* see how many exist */
4229 serial_count = WINSPOOL_CountSerialPorts();
4232 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4233 if ( r == ERROR_SUCCESS )
4235 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4236 &printer_count, NULL, NULL, NULL, NULL);
4238 count = serial_count + printer_count;
4240 /* then fill in the structure info structure once
4241 we know the offset to the first string */
4243 memset( buffer, 0, bufsize );
4245 ofs = info_size*count;
4246 for ( i=0; i<count; i++)
4248 DWORD vallen = sizeof(portname) - 1;
4250 /* get the serial port values, then the printer values */
4251 if ( i < serial_count )
4253 strcpy( portname, "COMx:" );
4254 portname[3] = '1' + i;
4255 if (!WINSPOOL_ComPortExists( portname ))
4258 TRACE("Found %s\n", portname );
4259 vallen = strlen( portname );
4263 r = RegEnumValueA( hkey_printer, i-serial_count,
4264 portname, &vallen, NULL, NULL, NULL, 0 );
4269 /* add a colon if necessary, and make it upper case */
4270 CharUpperBuffA(portname,vallen);
4271 if (strcasecmp(portname,"nul")!=0)
4272 if (vallen && (portname[vallen-1] != ':') )
4273 lstrcatA(portname,":");
4275 /* add the port info structure if we can fit it */
4276 if ( info_size*(n+1) < bufsize )
4280 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4281 info->pName = (LPSTR) &buffer[ofs];
4283 else if ( level == 2)
4285 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4286 info->pPortName = (LPSTR) &buffer[ofs];
4287 /* FIXME: fill in more stuff here */
4288 info->pMonitorName = PortMonitor;
4289 info->pDescription = PortDescription;
4290 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4293 /* add the name of the port if we can fit it */
4294 if ( ofs < bufsize )
4295 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4301 ofs += lstrlenA(portname)+1;
4304 RegCloseKey(hkey_printer);
4315 /******************************************************************************
4316 * EnumPortsW (WINSPOOL.@)
4318 * Enumerate available Ports
4321 * name [I] Servername or NULL (local Computer)
4322 * level [I] Structure-Level (1 or 2)
4323 * buffer [O] PTR to Buffer that receives the Result
4324 * bufsize [I] Size of Buffer at buffer
4325 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4326 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4330 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4333 * UNICODE-Version is a stub
4336 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4337 LPDWORD bufneeded,LPDWORD bufreturned)
4339 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4340 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4344 /******************************************************************************
4345 * GetDefaultPrinterW (WINSPOOL.@)
4348 * This function must read the value from data 'device' of key
4349 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4351 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4355 WCHAR *buffer, *ptr;
4359 SetLastError(ERROR_INVALID_PARAMETER);
4363 /* make the buffer big enough for the stuff from the profile/registry,
4364 * the content must fit into the local buffer to compute the correct
4365 * size even if the extern buffer is too small or not given.
4366 * (20 for ,driver,port) */
4368 len = max(100, (insize + 20));
4369 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4371 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4373 SetLastError (ERROR_FILE_NOT_FOUND);
4377 TRACE("%s\n", debugstr_w(buffer));
4379 if ((ptr = strchrW(buffer, ',')) == NULL)
4381 SetLastError(ERROR_INVALID_NAME);
4387 *namesize = strlenW(buffer) + 1;
4388 if(!name || (*namesize > insize))
4390 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4394 strcpyW(name, buffer);
4397 HeapFree( GetProcessHeap(), 0, buffer);
4402 /******************************************************************************
4403 * GetDefaultPrinterA (WINSPOOL.@)
4405 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4409 WCHAR *bufferW = NULL;
4413 SetLastError(ERROR_INVALID_PARAMETER);
4417 if(name && *namesize) {
4419 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4422 if(!GetDefaultPrinterW( bufferW, namesize)) {
4427 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4431 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4434 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4437 HeapFree( GetProcessHeap(), 0, bufferW);
4442 /******************************************************************************
4443 * SetDefaultPrinterW (WINSPOOL.204)
4445 * Set the Name of the Default Printer
4448 * pszPrinter [I] Name of the Printer or NULL
4455 * When the Parameter is NULL or points to an Empty String and
4456 * a Default Printer was already present, then this Function changes nothing.
4457 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4458 * the First enumerated local Printer is used.
4461 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4464 TRACE("(%s)\n", debugstr_w(pszPrinter));
4466 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4470 /******************************************************************************
4471 * SetDefaultPrinterA (WINSPOOL.202)
4473 * See SetDefaultPrinterW.
4476 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4479 TRACE("(%s)\n", debugstr_a(pszPrinter));
4481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4486 /******************************************************************************
4487 * SetPrinterDataExA (WINSPOOL.@)
4489 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4490 LPCSTR pValueName, DWORD Type,
4491 LPBYTE pData, DWORD cbData)
4493 HKEY hkeyPrinter, hkeySubkey;
4496 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4497 debugstr_a(pValueName), Type, pData, cbData);
4499 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4503 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4505 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4506 RegCloseKey(hkeyPrinter);
4509 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4510 RegCloseKey(hkeySubkey);
4511 RegCloseKey(hkeyPrinter);
4515 /******************************************************************************
4516 * SetPrinterDataExW (WINSPOOL.@)
4518 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4519 LPCWSTR pValueName, DWORD Type,
4520 LPBYTE pData, DWORD cbData)
4522 HKEY hkeyPrinter, hkeySubkey;
4525 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4526 debugstr_w(pValueName), Type, pData, cbData);
4528 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4532 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4534 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4535 RegCloseKey(hkeyPrinter);
4538 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4539 RegCloseKey(hkeySubkey);
4540 RegCloseKey(hkeyPrinter);
4544 /******************************************************************************
4545 * SetPrinterDataA (WINSPOOL.@)
4547 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4548 LPBYTE pData, DWORD cbData)
4550 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4554 /******************************************************************************
4555 * SetPrinterDataW (WINSPOOL.@)
4557 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4558 LPBYTE pData, DWORD cbData)
4560 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4564 /******************************************************************************
4565 * GetPrinterDataExA (WINSPOOL.@)
4567 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4568 LPCSTR pValueName, LPDWORD pType,
4569 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4571 HKEY hkeyPrinter, hkeySubkey;
4574 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4575 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4578 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4582 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4584 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4585 RegCloseKey(hkeyPrinter);
4589 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4590 RegCloseKey(hkeySubkey);
4591 RegCloseKey(hkeyPrinter);
4595 /******************************************************************************
4596 * GetPrinterDataExW (WINSPOOL.@)
4598 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4599 LPCWSTR pValueName, LPDWORD pType,
4600 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4602 HKEY hkeyPrinter, hkeySubkey;
4605 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4606 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4609 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4613 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4615 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4616 RegCloseKey(hkeyPrinter);
4620 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4621 RegCloseKey(hkeySubkey);
4622 RegCloseKey(hkeyPrinter);
4626 /******************************************************************************
4627 * GetPrinterDataA (WINSPOOL.@)
4629 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4630 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4632 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4633 pData, nSize, pcbNeeded);
4636 /******************************************************************************
4637 * GetPrinterDataW (WINSPOOL.@)
4639 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4640 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4642 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4643 pData, nSize, pcbNeeded);
4646 /*******************************************************************************
4647 * EnumPrinterDataExW [WINSPOOL.@]
4649 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4650 LPBYTE pEnumValues, DWORD cbEnumValues,
4651 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4653 HKEY hkPrinter, hkSubKey;
4654 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4655 cbValueNameLen, cbMaxValueLen, cbValueLen,
4660 PPRINTER_ENUM_VALUESW ppev;
4662 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4664 if (pKeyName == NULL || *pKeyName == 0)
4665 return ERROR_INVALID_PARAMETER;
4667 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4668 if (ret != ERROR_SUCCESS)
4670 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4675 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4676 if (ret != ERROR_SUCCESS)
4678 r = RegCloseKey (hkPrinter);
4679 if (r != ERROR_SUCCESS)
4680 WARN ("RegCloseKey returned %li\n", r);
4681 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4682 debugstr_w (pKeyName), ret);
4686 ret = RegCloseKey (hkPrinter);
4687 if (ret != ERROR_SUCCESS)
4689 ERR ("RegCloseKey returned %li\n", ret);
4690 r = RegCloseKey (hkSubKey);
4691 if (r != ERROR_SUCCESS)
4692 WARN ("RegCloseKey returned %li\n", r);
4696 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4697 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4698 if (ret != ERROR_SUCCESS)
4700 r = RegCloseKey (hkSubKey);
4701 if (r != ERROR_SUCCESS)
4702 WARN ("RegCloseKey returned %li\n", r);
4703 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4707 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4708 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4710 if (cValues == 0) /* empty key */
4712 r = RegCloseKey (hkSubKey);
4713 if (r != ERROR_SUCCESS)
4714 WARN ("RegCloseKey returned %li\n", r);
4715 *pcbEnumValues = *pnEnumValues = 0;
4716 return ERROR_SUCCESS;
4719 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4721 hHeap = GetProcessHeap ();
4724 ERR ("GetProcessHeap failed\n");
4725 r = RegCloseKey (hkSubKey);
4726 if (r != ERROR_SUCCESS)
4727 WARN ("RegCloseKey returned %li\n", r);
4728 return ERROR_OUTOFMEMORY;
4731 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4732 if (lpValueName == NULL)
4734 ERR ("Failed to allocate %li bytes from process heap\n",
4735 cbMaxValueNameLen * sizeof (WCHAR));
4736 r = RegCloseKey (hkSubKey);
4737 if (r != ERROR_SUCCESS)
4738 WARN ("RegCloseKey returned %li\n", r);
4739 return ERROR_OUTOFMEMORY;
4742 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4743 if (lpValue == NULL)
4745 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4746 if (HeapFree (hHeap, 0, lpValueName) == 0)
4747 WARN ("HeapFree failed with code %li\n", GetLastError ());
4748 r = RegCloseKey (hkSubKey);
4749 if (r != ERROR_SUCCESS)
4750 WARN ("RegCloseKey returned %li\n", r);
4751 return ERROR_OUTOFMEMORY;
4754 TRACE ("pass 1: calculating buffer required for all names and values\n");
4756 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4758 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4760 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4762 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4763 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4764 NULL, NULL, lpValue, &cbValueLen);
4765 if (ret != ERROR_SUCCESS)
4767 if (HeapFree (hHeap, 0, lpValue) == 0)
4768 WARN ("HeapFree failed with code %li\n", GetLastError ());
4769 if (HeapFree (hHeap, 0, lpValueName) == 0)
4770 WARN ("HeapFree failed with code %li\n", GetLastError ());
4771 r = RegCloseKey (hkSubKey);
4772 if (r != ERROR_SUCCESS)
4773 WARN ("RegCloseKey returned %li\n", r);
4774 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4778 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4779 debugstr_w (lpValueName), dwIndex,
4780 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4782 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4783 cbBufSize += cbValueLen;
4786 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4788 *pcbEnumValues = cbBufSize;
4789 *pnEnumValues = cValues;
4791 if (cbEnumValues < cbBufSize) /* buffer too small */
4793 if (HeapFree (hHeap, 0, lpValue) == 0)
4794 WARN ("HeapFree failed with code %li\n", GetLastError ());
4795 if (HeapFree (hHeap, 0, lpValueName) == 0)
4796 WARN ("HeapFree failed with code %li\n", GetLastError ());
4797 r = RegCloseKey (hkSubKey);
4798 if (r != ERROR_SUCCESS)
4799 WARN ("RegCloseKey returned %li\n", r);
4800 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4801 return ERROR_MORE_DATA;
4804 TRACE ("pass 2: copying all names and values to buffer\n");
4806 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4807 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4809 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4811 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4812 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4813 NULL, &dwType, lpValue, &cbValueLen);
4814 if (ret != ERROR_SUCCESS)
4816 if (HeapFree (hHeap, 0, lpValue) == 0)
4817 WARN ("HeapFree failed with code %li\n", GetLastError ());
4818 if (HeapFree (hHeap, 0, lpValueName) == 0)
4819 WARN ("HeapFree failed with code %li\n", GetLastError ());
4820 r = RegCloseKey (hkSubKey);
4821 if (r != ERROR_SUCCESS)
4822 WARN ("RegCloseKey returned %li\n", r);
4823 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4827 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4828 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4829 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4830 pEnumValues += cbValueNameLen;
4832 /* return # of *bytes* (including trailing \0), not # of chars */
4833 ppev[dwIndex].cbValueName = cbValueNameLen;
4835 ppev[dwIndex].dwType = dwType;
4837 memcpy (pEnumValues, lpValue, cbValueLen);
4838 ppev[dwIndex].pData = pEnumValues;
4839 pEnumValues += cbValueLen;
4841 ppev[dwIndex].cbData = cbValueLen;
4843 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4844 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4847 if (HeapFree (hHeap, 0, lpValue) == 0)
4849 ret = GetLastError ();
4850 ERR ("HeapFree failed with code %li\n", ret);
4851 if (HeapFree (hHeap, 0, lpValueName) == 0)
4852 WARN ("HeapFree failed with code %li\n", GetLastError ());
4853 r = RegCloseKey (hkSubKey);
4854 if (r != ERROR_SUCCESS)
4855 WARN ("RegCloseKey returned %li\n", r);
4859 if (HeapFree (hHeap, 0, lpValueName) == 0)
4861 ret = GetLastError ();
4862 ERR ("HeapFree failed with code %li\n", ret);
4863 r = RegCloseKey (hkSubKey);
4864 if (r != ERROR_SUCCESS)
4865 WARN ("RegCloseKey returned %li\n", r);
4869 ret = RegCloseKey (hkSubKey);
4870 if (ret != ERROR_SUCCESS)
4872 ERR ("RegCloseKey returned %li\n", ret);
4876 return ERROR_SUCCESS;
4879 /*******************************************************************************
4880 * EnumPrinterDataExA [WINSPOOL.@]
4882 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4883 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4884 * what Windows 2000 SP1 does.
4887 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4888 LPBYTE pEnumValues, DWORD cbEnumValues,
4889 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4893 DWORD ret, dwIndex, dwBufSize;
4897 TRACE ("%p %s\n", hPrinter, pKeyName);
4899 if (pKeyName == NULL || *pKeyName == 0)
4900 return ERROR_INVALID_PARAMETER;
4902 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4905 ret = GetLastError ();
4906 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4910 hHeap = GetProcessHeap ();
4913 ERR ("GetProcessHeap failed\n");
4914 return ERROR_OUTOFMEMORY;
4917 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4918 if (pKeyNameW == NULL)
4920 ERR ("Failed to allocate %li bytes from process heap\n",
4921 (LONG) len * sizeof (WCHAR));
4922 return ERROR_OUTOFMEMORY;
4925 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4927 ret = GetLastError ();
4928 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4929 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4930 WARN ("HeapFree failed with code %li\n", GetLastError ());
4934 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4935 pcbEnumValues, pnEnumValues);
4936 if (ret != ERROR_SUCCESS)
4938 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4939 WARN ("HeapFree failed with code %li\n", GetLastError ());
4940 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4944 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4946 ret = GetLastError ();
4947 ERR ("HeapFree failed with code %li\n", ret);
4951 if (*pnEnumValues == 0) /* empty key */
4952 return ERROR_SUCCESS;
4955 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4957 PPRINTER_ENUM_VALUESW ppev =
4958 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4960 if (dwBufSize < ppev->cbValueName)
4961 dwBufSize = ppev->cbValueName;
4963 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4964 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4965 dwBufSize = ppev->cbData;
4968 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4970 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4971 if (pBuffer == NULL)
4973 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4974 return ERROR_OUTOFMEMORY;
4977 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4979 PPRINTER_ENUM_VALUESW ppev =
4980 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4982 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4983 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4987 ret = GetLastError ();
4988 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4989 if (HeapFree (hHeap, 0, pBuffer) == 0)
4990 WARN ("HeapFree failed with code %li\n", GetLastError ());
4994 memcpy (ppev->pValueName, pBuffer, len);
4996 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4998 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4999 ppev->dwType != REG_MULTI_SZ)
5002 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5003 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5006 ret = GetLastError ();
5007 ERR ("WideCharToMultiByte failed with code %li\n", ret);
5008 if (HeapFree (hHeap, 0, pBuffer) == 0)
5009 WARN ("HeapFree failed with code %li\n", GetLastError ());
5013 memcpy (ppev->pData, pBuffer, len);
5015 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5016 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5019 if (HeapFree (hHeap, 0, pBuffer) == 0)
5021 ret = GetLastError ();
5022 ERR ("HeapFree failed with code %li\n", ret);
5026 return ERROR_SUCCESS;
5029 /******************************************************************************
5030 * AbortPrinter (WINSPOOL.@)
5032 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5034 FIXME("(%p), stub!\n", hPrinter);
5038 /******************************************************************************
5039 * AddPortA (WINSPOOL.@)
5044 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5046 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
5050 /******************************************************************************
5051 * AddPortW (WINSPOOL.@)
5053 * Add a Port for a specific Monitor
5056 * pName [I] Servername or NULL (local Computer)
5057 * hWnd [I] Handle to parent Window for the Dialog-Box
5058 * pMonitorName [I] Name of the Monitor that manage the Port
5068 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5070 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5074 /******************************************************************************
5075 * AddPortExA (WINSPOOL.@)
5080 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5082 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5083 lpBuffer, debugstr_a(lpMonitorName));
5087 /******************************************************************************
5088 * AddPortExW (WINSPOOL.@)
5090 * Add a Port for a specific Monitor, without presenting a user interface
5093 * hMonitor [I] Handle from InitializePrintMonitor2()
5094 * pName [I] Servername or NULL (local Computer)
5095 * Level [I] Structure-Level (1 or 2) for lpBuffer
5096 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5097 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5107 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5109 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5110 lpBuffer, debugstr_w(lpMonitorName));
5114 /******************************************************************************
5115 * AddPrinterConnectionA (WINSPOOL.@)
5117 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5119 FIXME("%s\n", debugstr_a(pName));
5123 /******************************************************************************
5124 * AddPrinterConnectionW (WINSPOOL.@)
5126 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5128 FIXME("%s\n", debugstr_w(pName));
5132 /******************************************************************************
5133 * AddPrinterDriverExW (WINSPOOL.@)
5135 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5136 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5138 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5139 Level, pDriverInfo, dwFileCopyFlags);
5140 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5144 /******************************************************************************
5145 * AddPrinterDriverExA (WINSPOOL.@)
5147 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5148 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5150 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5151 Level, pDriverInfo, dwFileCopyFlags);
5152 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5156 /******************************************************************************
5157 * ConfigurePortA (WINSPOOL.@)
5159 * See ConfigurePortW.
5162 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5164 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5168 /******************************************************************************
5169 * ConfigurePortW (WINSPOOL.@)
5171 * Display the Configuration-Dialog for a specific Port
5174 * pName [I] Servername or NULL (local Computer)
5175 * hWnd [I] Handle to parent Window for the Dialog-Box
5176 * pPortName [I] Name of the Port, that should be configured
5186 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5188 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5192 /******************************************************************************
5193 * ConnectToPrinterDlg (WINSPOOL.@)
5195 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5197 FIXME("%p %lx\n", hWnd, Flags);
5201 /******************************************************************************
5202 * DeletePrinterConnectionA (WINSPOOL.@)
5204 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5206 FIXME("%s\n", debugstr_a(pName));
5210 /******************************************************************************
5211 * DeletePrinterConnectionW (WINSPOOL.@)
5213 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5215 FIXME("%s\n", debugstr_w(pName));
5219 /******************************************************************************
5220 * DeletePrinterDriverExW (WINSPOOL.@)
5222 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5223 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5225 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5226 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5230 /******************************************************************************
5231 * DeletePrinterDriverExA (WINSPOOL.@)
5233 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5234 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5236 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5237 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5241 /******************************************************************************
5242 * DeletePrinterDataExW (WINSPOOL.@)
5244 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5247 FIXME("%p %s %s\n", hPrinter,
5248 debugstr_w(pKeyName), debugstr_w(pValueName));
5249 return ERROR_INVALID_PARAMETER;
5252 /******************************************************************************
5253 * DeletePrinterDataExA (WINSPOOL.@)
5255 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5258 FIXME("%p %s %s\n", hPrinter,
5259 debugstr_a(pKeyName), debugstr_a(pValueName));
5260 return ERROR_INVALID_PARAMETER;
5263 /******************************************************************************
5264 * DeletePrintProcessorA (WINSPOOL.@)
5266 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5268 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5269 debugstr_a(pPrintProcessorName));
5273 /******************************************************************************
5274 * DeletePrintProcessorW (WINSPOOL.@)
5276 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5278 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5279 debugstr_w(pPrintProcessorName));
5283 /******************************************************************************
5284 * DeletePrintProvidorA (WINSPOOL.@)
5286 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5288 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5289 debugstr_a(pPrintProviderName));
5293 /******************************************************************************
5294 * DeletePrintProvidorW (WINSPOOL.@)
5296 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5298 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5299 debugstr_w(pPrintProviderName));
5303 /******************************************************************************
5304 * EnumFormsA (WINSPOOL.@)
5306 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5307 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5309 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5313 /******************************************************************************
5314 * EnumFormsW (WINSPOOL.@)
5316 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5317 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5319 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5323 /*****************************************************************************
5324 * EnumMonitorsA [WINSPOOL.@]
5326 * See EnumMonitorsW.
5329 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5330 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5333 LPBYTE bufferW = NULL;
5334 LPWSTR nameW = NULL;
5336 DWORD numentries = 0;
5339 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5340 cbBuf, pcbNeeded, pcReturned);
5342 /* convert servername to unicode */
5344 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5345 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5346 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5348 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5349 needed = cbBuf * sizeof(WCHAR);
5350 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5351 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5353 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5354 if (pcbNeeded) needed = *pcbNeeded;
5355 /* HeapReAlloc return NULL, when bufferW was NULL */
5356 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5357 HeapAlloc(GetProcessHeap(), 0, needed);
5359 /* Try again with the large Buffer */
5360 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5362 numentries = pcReturned ? *pcReturned : 0;
5365 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5366 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5369 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5370 DWORD entrysize = 0;
5373 LPMONITOR_INFO_2W mi2w;
5374 LPMONITOR_INFO_2A mi2a;
5376 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5377 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5379 /* First pass: calculate the size for all Entries */
5380 mi2w = (LPMONITOR_INFO_2W) bufferW;
5381 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5383 while (index < numentries) {
5385 needed += entrysize; /* MONITOR_INFO_?A */
5386 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5388 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5389 NULL, 0, NULL, NULL);
5391 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5392 NULL, 0, NULL, NULL);
5393 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5394 NULL, 0, NULL, NULL);
5396 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5397 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5398 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5401 /* check for errors and quit on failure */
5402 if (cbBuf < needed) {
5403 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5407 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5408 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5409 cbBuf -= len ; /* free Bytes in the user-Buffer */
5410 mi2w = (LPMONITOR_INFO_2W) bufferW;
5411 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5413 /* Second Pass: Fill the User Buffer (if we have one) */
5414 while ((index < numentries) && pMonitors) {
5416 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5418 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5419 ptr, cbBuf , NULL, NULL);
5423 mi2a->pEnvironment = ptr;
5424 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5425 ptr, cbBuf, NULL, NULL);
5429 mi2a->pDLLName = ptr;
5430 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5431 ptr, cbBuf, NULL, NULL);
5435 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5436 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5437 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5441 if (pcbNeeded) *pcbNeeded = needed;
5442 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5444 HeapFree(GetProcessHeap(), 0, nameW);
5445 HeapFree(GetProcessHeap(), 0, bufferW);
5447 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5448 (res), GetLastError(), needed, numentries);
5454 /*****************************************************************************
5455 * EnumMonitorsW [WINSPOOL.@]
5457 * Enumerate available Port-Monitors
5460 * pName [I] Servername or NULL (local Computer)
5461 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5462 * pMonitors [O] PTR to Buffer that receives the Result
5463 * cbBuf [I] Size of Buffer at pMonitors
5464 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5465 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5469 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5472 * Windows reads the Registry once and cache the Results.
5474 *| Language-Monitors are also installed in the same Registry-Location but
5475 *| they are filtered in Windows (not returned by EnumMonitors).
5476 *| We do no filtering to simplify our Code.
5479 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5480 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5483 DWORD numentries = 0;
5486 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5487 cbBuf, pcbNeeded, pcReturned);
5489 if (pName && (lstrlenW(pName))) {
5490 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5491 SetLastError(ERROR_ACCESS_DENIED);
5495 /* Level is not checked in win9x */
5496 if (!Level || (Level > 2)) {
5497 WARN("level (%ld) is ignored in win9x\n", Level);
5498 SetLastError(ERROR_INVALID_LEVEL);
5502 SetLastError(RPC_X_NULL_REF_POINTER);
5506 /* Scan all Monitor-Keys */
5508 needed = get_local_monitors(Level, NULL, 0, &numentries);
5510 /* we calculated the needed buffersize. now do the error-checks */
5511 if (cbBuf < needed) {
5512 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5515 else if (!pMonitors || !pcReturned) {
5516 SetLastError(RPC_X_NULL_REF_POINTER);
5520 /* fill the Buffer with the Monitor-Keys */
5521 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5525 if (pcbNeeded) *pcbNeeded = needed;
5526 if (pcReturned) *pcReturned = numentries;
5528 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5529 res, GetLastError(), needed, numentries);
5534 /******************************************************************************
5535 * XcvDataW (WINSPOOL.@)
5538 * There doesn't seem to be an A version...
5540 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5541 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5542 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5544 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5545 pInputData, cbInputData, pOutputData,
5546 cbOutputData, pcbOutputNeeded, pdwStatus);
5550 /*****************************************************************************
5551 * EnumPrinterDataA [WINSPOOL.@]
5554 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5555 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5556 DWORD cbData, LPDWORD pcbData )
5558 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5559 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5560 return ERROR_NO_MORE_ITEMS;
5563 /*****************************************************************************
5564 * EnumPrinterDataW [WINSPOOL.@]
5567 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5568 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5569 DWORD cbData, LPDWORD pcbData )
5571 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5572 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5573 return ERROR_NO_MORE_ITEMS;
5576 /*****************************************************************************
5577 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5580 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5581 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5582 LPDWORD pcbNeeded, LPDWORD pcReturned)
5584 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5585 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5586 pcbNeeded, pcReturned);
5590 /*****************************************************************************
5591 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5594 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5595 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5596 LPDWORD pcbNeeded, LPDWORD pcReturned)
5598 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5599 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5600 pcbNeeded, pcReturned);
5604 /*****************************************************************************
5605 * EnumPrintProcessorsA [WINSPOOL.@]
5608 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5609 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5611 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5612 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5616 /*****************************************************************************
5617 * EnumPrintProcessorsW [WINSPOOL.@]
5620 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5621 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5623 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5624 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5625 cbBuf, pcbNeeded, pcbReturned);
5629 /*****************************************************************************
5630 * ExtDeviceMode [WINSPOOL.@]
5633 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5634 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5637 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5638 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5639 debugstr_a(pProfile), fMode);
5643 /*****************************************************************************
5644 * FindClosePrinterChangeNotification [WINSPOOL.@]
5647 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5649 FIXME("Stub: %p\n", hChange);
5653 /*****************************************************************************
5654 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5657 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5658 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5660 FIXME("Stub: %p %lx %lx %p\n",
5661 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5662 return INVALID_HANDLE_VALUE;
5665 /*****************************************************************************
5666 * FindNextPrinterChangeNotification [WINSPOOL.@]
5669 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5670 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5672 FIXME("Stub: %p %p %p %p\n",
5673 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5677 /*****************************************************************************
5678 * FreePrinterNotifyInfo [WINSPOOL.@]
5681 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5683 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5687 /*****************************************************************************
5690 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5691 * ansi depending on the unicode parameter.
5693 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5703 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5706 memcpy(ptr, str, *size);
5713 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5716 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5723 /*****************************************************************************
5726 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5727 LPDWORD pcbNeeded, BOOL unicode)
5729 DWORD size, left = cbBuf;
5730 BOOL space = (cbBuf > 0);
5737 ji1->JobId = job->job_id;
5740 string_to_buf(job->document_title, ptr, left, &size, unicode);
5741 if(space && size <= left)
5743 ji1->pDocument = (LPWSTR)ptr;
5754 /*****************************************************************************
5757 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5758 LPDWORD pcbNeeded, BOOL unicode)
5760 DWORD size, left = cbBuf;
5761 BOOL space = (cbBuf > 0);
5768 ji2->JobId = job->job_id;
5771 string_to_buf(job->document_title, ptr, left, &size, unicode);
5772 if(space && size <= left)
5774 ji2->pDocument = (LPWSTR)ptr;
5785 /*****************************************************************************
5788 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5789 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5792 DWORD needed = 0, size;
5796 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5798 EnterCriticalSection(&printer_handles_cs);
5799 job = get_job(hPrinter, JobId);
5806 size = sizeof(JOB_INFO_1W);
5811 memset(pJob, 0, size);
5815 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5820 size = sizeof(JOB_INFO_2W);
5825 memset(pJob, 0, size);
5829 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5834 size = sizeof(JOB_INFO_3);
5838 memset(pJob, 0, size);
5847 SetLastError(ERROR_INVALID_LEVEL);
5851 *pcbNeeded = needed;
5853 LeaveCriticalSection(&printer_handles_cs);
5857 /*****************************************************************************
5858 * GetJobA [WINSPOOL.@]
5861 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5862 DWORD cbBuf, LPDWORD pcbNeeded)
5864 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5867 /*****************************************************************************
5868 * GetJobW [WINSPOOL.@]
5871 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5872 DWORD cbBuf, LPDWORD pcbNeeded)
5874 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5877 /*****************************************************************************
5880 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5882 char *unixname, *queue, *cmd;
5883 char fmt[] = "lpr -P%s %s";
5886 if(!(unixname = wine_get_unix_file_name(filename)))
5889 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5890 queue = HeapAlloc(GetProcessHeap(), 0, len);
5891 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5893 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5894 sprintf(cmd, fmt, queue, unixname);
5896 TRACE("printing with: %s\n", cmd);
5899 HeapFree(GetProcessHeap(), 0, cmd);
5900 HeapFree(GetProcessHeap(), 0, queue);
5901 HeapFree(GetProcessHeap(), 0, unixname);
5905 /*****************************************************************************
5908 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5910 #if HAVE_CUPS_CUPS_H
5913 char *unixname, *queue, *doc_titleA;
5917 if(!(unixname = wine_get_unix_file_name(filename)))
5920 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5921 queue = HeapAlloc(GetProcessHeap(), 0, len);
5922 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5924 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5925 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5926 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5928 TRACE("printing via cups\n");
5929 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5930 HeapFree(GetProcessHeap(), 0, doc_titleA);
5931 HeapFree(GetProcessHeap(), 0, queue);
5932 HeapFree(GetProcessHeap(), 0, unixname);
5938 return schedule_lpr(printer_name, filename);
5942 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5949 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5953 if(HIWORD(wparam) == BN_CLICKED)
5955 if(LOWORD(wparam) == IDOK)
5958 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5961 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5962 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5964 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5966 WCHAR caption[200], message[200];
5969 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5970 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5971 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5972 if(mb_ret == IDCANCEL)
5974 HeapFree(GetProcessHeap(), 0, filename);
5978 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5979 if(hf == INVALID_HANDLE_VALUE)
5981 WCHAR caption[200], message[200];
5983 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5984 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5985 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5986 HeapFree(GetProcessHeap(), 0, filename);
5990 DeleteFileW(filename);
5991 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5993 EndDialog(hwnd, IDOK);
5996 if(LOWORD(wparam) == IDCANCEL)
5998 EndDialog(hwnd, IDCANCEL);
6007 /*****************************************************************************
6010 static BOOL get_filename(LPWSTR *filename)
6012 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
6013 file_dlg_proc, (LPARAM)filename) == IDOK;
6016 /*****************************************************************************
6019 static BOOL schedule_file(LPCWSTR filename)
6021 LPWSTR output = NULL;
6023 if(get_filename(&output))
6025 TRACE("copy to %s\n", debugstr_w(output));
6026 CopyFileW(filename, output, FALSE);
6027 HeapFree(GetProcessHeap(), 0, output);
6033 /*****************************************************************************
6036 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
6039 char *unixname, *cmdA;
6041 int fds[2] = {-1, -1}, file_fd = -1, no_read;
6045 if(!(unixname = wine_get_unix_file_name(filename)))
6048 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
6049 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
6050 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
6052 TRACE("printing with: %s\n", cmdA);
6054 if((file_fd = open(unixname, O_RDONLY)) == -1)
6059 ERR("pipe() failed!\n");
6069 /* reset signals that we previously set to SIG_IGN */
6070 signal(SIGPIPE, SIG_DFL);
6071 signal(SIGCHLD, SIG_DFL);
6077 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6078 write(fds[1], buf, no_read);
6083 if(file_fd != -1) close(file_fd);
6084 if(fds[0] != -1) close(fds[0]);
6085 if(fds[1] != -1) close(fds[1]);
6087 HeapFree(GetProcessHeap(), 0, cmdA);
6088 HeapFree(GetProcessHeap(), 0, unixname);
6095 /*****************************************************************************
6098 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6100 int in_fd, out_fd, no_read;
6103 char *unixname, *outputA;
6106 if(!(unixname = wine_get_unix_file_name(filename)))
6109 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6110 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6111 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6113 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6114 in_fd = open(unixname, O_RDONLY);
6115 if(out_fd == -1 || in_fd == -1)
6118 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6119 write(out_fd, buf, no_read);
6123 if(in_fd != -1) close(in_fd);
6124 if(out_fd != -1) close(out_fd);
6125 HeapFree(GetProcessHeap(), 0, outputA);
6126 HeapFree(GetProcessHeap(), 0, unixname);
6130 /*****************************************************************************
6131 * ScheduleJob [WINSPOOL.@]
6134 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6136 opened_printer_t *printer;
6138 struct list *cursor, *cursor2;
6140 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6141 EnterCriticalSection(&printer_handles_cs);
6142 printer = get_opened_printer(hPrinter);
6146 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6148 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6151 if(job->job_id != dwJobID) continue;
6153 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6154 if(hf != INVALID_HANDLE_VALUE)
6156 PRINTER_INFO_5W *pi5;
6160 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6161 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6163 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6164 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6165 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6166 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6167 debugstr_w(pi5->pPortName));
6171 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6172 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6174 DWORD type, count = sizeof(output);
6175 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6178 if(output[0] == '|')
6180 schedule_pipe(output + 1, job->filename);
6184 schedule_unixfile(output, job->filename);
6186 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6188 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6190 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6192 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6194 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6196 schedule_file(job->filename);
6200 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6202 HeapFree(GetProcessHeap(), 0, pi5);
6204 DeleteFileW(job->filename);
6206 list_remove(cursor);
6207 HeapFree(GetProcessHeap(), 0, job->document_title);
6208 HeapFree(GetProcessHeap(), 0, job->filename);
6209 HeapFree(GetProcessHeap(), 0, job);
6214 LeaveCriticalSection(&printer_handles_cs);
6218 /*****************************************************************************
6219 * StartDocDlgA [WINSPOOL.@]
6221 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6223 UNICODE_STRING usBuffer;
6228 docW.cbSize = sizeof(docW);
6229 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6230 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6231 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6232 docW.fwType = doc->fwType;
6234 retW = StartDocDlgW(hPrinter, &docW);
6238 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6239 ret = HeapAlloc(GetProcessHeap(), 0, len);
6240 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6241 HeapFree(GetProcessHeap(), 0, retW);
6244 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6245 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6246 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6251 /*****************************************************************************
6252 * StartDocDlgW [WINSPOOL.@]
6254 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6255 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6256 * port is "FILE:". Also returns the full path if passed a relative path.
6258 * The caller should free the returned string from the process heap.
6260 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6265 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6267 PRINTER_INFO_5W *pi5;
6268 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6269 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6271 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6272 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6273 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6275 HeapFree(GetProcessHeap(), 0, pi5);
6278 HeapFree(GetProcessHeap(), 0, pi5);
6281 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6284 get_filename(&name);
6287 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6289 HeapFree(GetProcessHeap(), 0, name);
6292 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6293 GetFullPathNameW(name, len, ret, NULL);
6294 HeapFree(GetProcessHeap(), 0, name);
6299 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6302 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6303 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6305 attr = GetFileAttributesW(ret);
6306 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6308 HeapFree(GetProcessHeap(), 0, ret);