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;
99 static opened_printer_t **printer_handles;
100 static int nb_printer_handles;
101 static LONG next_job_id = 1;
103 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
104 WORD fwCapability, LPSTR lpszOutput,
106 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
107 LPSTR lpszDevice, LPSTR lpszPort,
108 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
111 static const char Printers[] =
112 "System\\CurrentControlSet\\control\\Print\\Printers\\";
114 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
115 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
116 'c','o','n','t','r','o','l','\\',
117 'P','r','i','n','t','\\',
118 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
119 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
121 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
122 'M','i','c','r','o','s','o','f','t','\\',
123 'W','i','n','d','o','w','s',' ','N','T','\\',
124 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
125 'W','i','n','d','o','w','s',0};
127 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
128 'M','i','c','r','o','s','o','f','t','\\',
129 'W','i','n','d','o','w','s',' ','N','T','\\',
130 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
131 'D','e','v','i','c','e','s',0};
133 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
135 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
136 'i','o','n',' ','F','i','l','e',0};
137 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
138 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
139 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
141 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
143 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
144 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
145 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
146 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
147 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
148 static const WCHAR NameW[] = {'N','a','m','e',0};
149 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
150 static const WCHAR PortW[] = {'P','o','r','t',0};
151 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
153 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
155 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
156 'v','e','r','D','a','t','a',0};
157 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
159 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
160 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
161 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
162 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
163 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
164 static const WCHAR emptyStringW[] = {0};
166 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
168 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
169 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
170 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
172 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
173 'D','o','c','u','m','e','n','t',0};
175 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
176 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
177 DWORD Level, LPBYTE pDriverInfo,
178 DWORD cbBuf, LPDWORD pcbNeeded,
180 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
182 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
183 if passed a NULL string. This returns NULLs to the result.
185 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
189 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
190 return usBufferPtr->Buffer;
192 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
196 static LPWSTR strdupW(LPCWSTR p)
202 len = (strlenW(p) + 1) * sizeof(WCHAR);
203 ret = HeapAlloc(GetProcessHeap(), 0, len);
209 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
212 /* If forcing, or no profile string entry for device yet, set the entry
214 * The always change entry if not WINEPS yet is discussable.
217 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
219 !strstr(qbuf,"WINEPS.DRV")
221 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
224 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
225 WriteProfileStringA("windows","device",buf);
226 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
227 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
230 HeapFree(GetProcessHeap(),0,buf);
234 #ifdef HAVE_CUPS_CUPS_H
235 static typeof(cupsGetDests) *pcupsGetDests;
236 static typeof(cupsGetPPD) *pcupsGetPPD;
237 static typeof(cupsPrintFile) *pcupsPrintFile;
238 static void *cupshandle;
240 static BOOL CUPS_LoadPrinters(void)
243 BOOL hadprinter = FALSE;
245 PRINTER_INFO_2A pinfo2a;
247 HKEY hkeyPrinter, hkeyPrinters, hkey;
249 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
252 TRACE("loaded %s\n", SONAME_LIBCUPS);
255 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
256 if (!p##x) return FALSE;
259 DYNCUPS(cupsGetDests);
260 DYNCUPS(cupsPrintFile);
263 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
265 ERR("Can't create Printers key\n");
269 nrofdests = pcupsGetDests(&dests);
270 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
271 for (i=0;i<nrofdests;i++) {
272 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
273 sprintf(port,"LPR:%s",dests[i].name);
274 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
275 sprintf(devline,"WINEPS.DRV,%s",port);
276 WriteProfileStringA("devices",dests[i].name,devline);
277 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
278 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
281 HeapFree(GetProcessHeap(),0,devline);
283 TRACE("Printer %d: %s\n", i, dests[i].name);
284 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
285 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
287 TRACE("Printer already exists\n");
288 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
289 RegCloseKey(hkeyPrinter);
291 memset(&pinfo2a,0,sizeof(pinfo2a));
292 pinfo2a.pPrinterName = dests[i].name;
293 pinfo2a.pDatatype = "RAW";
294 pinfo2a.pPrintProcessor = "WinPrint";
295 pinfo2a.pDriverName = "PS Driver";
296 pinfo2a.pComment = "WINEPS Printer using CUPS";
297 pinfo2a.pLocation = "<physical location of printer>";
298 pinfo2a.pPortName = port;
299 pinfo2a.pParameters = "<parameters?>";
300 pinfo2a.pShareName = "<share name?>";
301 pinfo2a.pSepFile = "<sep file?>";
303 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
304 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
305 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
308 HeapFree(GetProcessHeap(),0,port);
311 if (dests[i].is_default)
312 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
314 RegCloseKey(hkeyPrinters);
320 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
321 PRINTER_INFO_2A pinfo2a;
322 char *e,*s,*name,*prettyname,*devname;
323 BOOL ret = FALSE, set_default = FALSE;
324 char *port,*devline,*env_default;
325 HKEY hkeyPrinter, hkeyPrinters, hkey;
327 while (isspace(*pent)) pent++;
328 s = strchr(pent,':');
330 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
338 TRACE("name=%s entry=%s\n",name, pent);
340 if(ispunct(*name)) { /* a tc entry, not a real printer */
341 TRACE("skipping tc entry\n");
345 if(strstr(pent,":server")) { /* server only version so skip */
346 TRACE("skipping server entry\n");
350 /* Determine whether this is a postscript printer. */
353 env_default = getenv("PRINTER");
355 /* Get longest name, usually the one at the right for later display. */
356 while((s=strchr(prettyname,'|'))) {
359 while(isspace(*--e)) *e = '\0';
360 TRACE("\t%s\n", debugstr_a(prettyname));
361 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
362 for(prettyname = s+1; isspace(*prettyname); prettyname++)
365 e = prettyname + strlen(prettyname);
366 while(isspace(*--e)) *e = '\0';
367 TRACE("\t%s\n", debugstr_a(prettyname));
368 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
370 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
371 * if it is too long, we use it as comment below. */
372 devname = prettyname;
373 if (strlen(devname)>=CCHDEVICENAME-1)
375 if (strlen(devname)>=CCHDEVICENAME-1) {
380 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
381 sprintf(port,"LPR:%s",name);
383 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
384 sprintf(devline,"WINEPS.DRV,%s",port);
385 WriteProfileStringA("devices",devname,devline);
386 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
387 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
390 HeapFree(GetProcessHeap(),0,devline);
392 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
394 ERR("Can't create Printers key\n");
398 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
399 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
401 TRACE("Printer already exists\n");
402 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
403 RegCloseKey(hkeyPrinter);
405 memset(&pinfo2a,0,sizeof(pinfo2a));
406 pinfo2a.pPrinterName = devname;
407 pinfo2a.pDatatype = "RAW";
408 pinfo2a.pPrintProcessor = "WinPrint";
409 pinfo2a.pDriverName = "PS Driver";
410 pinfo2a.pComment = "WINEPS Printer using LPR";
411 pinfo2a.pLocation = prettyname;
412 pinfo2a.pPortName = port;
413 pinfo2a.pParameters = "<parameters?>";
414 pinfo2a.pShareName = "<share name?>";
415 pinfo2a.pSepFile = "<sep file?>";
417 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
418 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
419 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
422 RegCloseKey(hkeyPrinters);
424 if (isfirst || set_default)
425 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
427 HeapFree(GetProcessHeap(), 0, port);
429 HeapFree(GetProcessHeap(), 0, name);
434 PRINTCAP_LoadPrinters(void) {
435 BOOL hadprinter = FALSE;
439 BOOL had_bash = FALSE;
441 f = fopen("/etc/printcap","r");
445 while(fgets(buf,sizeof(buf),f)) {
448 end=strchr(buf,'\n');
452 while(isspace(*start)) start++;
453 if(*start == '#' || *start == '\0')
456 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
457 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
458 HeapFree(GetProcessHeap(),0,pent);
462 if (end && *--end == '\\') {
469 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
472 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
478 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
479 HeapFree(GetProcessHeap(),0,pent);
485 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
488 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
489 lstrlenW(value) * sizeof(WCHAR));
491 return ERROR_FILE_NOT_FOUND;
494 void WINSPOOL_LoadSystemPrinters(void)
496 HKEY hkey, hkeyPrinters;
499 DWORD needed, num, i;
500 WCHAR PrinterName[256];
503 di3a.cVersion = 0x400;
504 di3a.pName = "PS Driver";
505 di3a.pEnvironment = NULL; /* NULL means auto */
506 di3a.pDriverPath = "wineps16";
507 di3a.pDataFile = "<datafile?>";
508 di3a.pConfigFile = "wineps16";
509 di3a.pHelpFile = "<helpfile?>";
510 di3a.pDependentFiles = "<dependend files?>";
511 di3a.pMonitorName = "<monitor name?>";
512 di3a.pDefaultDataType = "RAW";
514 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
515 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
519 /* This ensures that all printer entries have a valid Name value. If causes
520 problems later if they don't. If one is found to be missed we create one
521 and set it equal to the name of the key */
522 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
523 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
524 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
525 for(i = 0; i < num; i++) {
526 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
527 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
528 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
529 set_reg_szW(hkey, NameW, PrinterName);
536 RegCloseKey(hkeyPrinters);
539 /* We want to avoid calling AddPrinter on printers as much as
540 possible, because on cups printers this will (eventually) lead
541 to a call to cupsGetPPD which takes forever, even with non-cups
542 printers AddPrinter takes a while. So we'll tag all printers that
543 were automatically added last time around, if they still exist
544 we'll leave them be otherwise we'll delete them. */
545 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
547 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
548 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
549 for(i = 0; i < num; i++) {
550 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
551 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
552 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
554 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
562 HeapFree(GetProcessHeap(), 0, pi);
566 #ifdef HAVE_CUPS_CUPS_H
567 done = CUPS_LoadPrinters();
570 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
571 /* Check for [ppd] section in config file before parsing /etc/printcap */
572 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
573 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
574 &hkey) == ERROR_SUCCESS) {
576 PRINTCAP_LoadPrinters();
580 /* Now enumerate the list again and delete any printers that a still tagged */
581 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
583 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
584 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
585 for(i = 0; i < num; i++) {
586 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
587 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
588 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
589 DWORD dw, type, size = sizeof(dw);
590 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
591 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
601 HeapFree(GetProcessHeap(), 0, pi);
609 /******************************************************************
610 * get_opened_printer_entry
611 * Get the first place empty in the opened printer table
613 static HANDLE get_opened_printer_entry( LPCWSTR name )
615 UINT_PTR handle = nb_printer_handles, i;
616 jobqueue_t *queue = NULL;
617 opened_printer_t *printer;
619 EnterCriticalSection(&printer_handles_cs);
621 for (i = 0; i < nb_printer_handles; i++)
623 if (!printer_handles[i])
625 if(handle == nb_printer_handles)
628 else if(!queue && !strcmpW(name, printer_handles[i]->name))
629 queue = printer_handles[i]->queue;
632 if (handle >= nb_printer_handles)
634 opened_printer_t **new_array;
636 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
637 (nb_printer_handles + 16) * sizeof(*new_array) );
639 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
640 (nb_printer_handles + 16) * sizeof(*new_array) );
647 printer_handles = new_array;
648 nb_printer_handles += 16;
651 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
657 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
658 strcpyW(printer->name, name);
660 printer->queue = queue;
663 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
664 list_init(&printer->queue->jobs);
665 printer->queue->ref = 0;
667 InterlockedIncrement(&printer->queue->ref);
670 printer_handles[handle] = printer;
673 LeaveCriticalSection(&printer_handles_cs);
675 return (HANDLE)handle;
678 /******************************************************************
680 * Get the pointer to the opened printer referred by the handle
682 static opened_printer_t *get_opened_printer(HANDLE hprn)
684 UINT_PTR idx = (UINT_PTR)hprn;
685 opened_printer_t *ret = NULL;
687 EnterCriticalSection(&printer_handles_cs);
689 if ((idx <= 0) || (idx > nb_printer_handles))
692 ret = printer_handles[idx - 1];
694 LeaveCriticalSection(&printer_handles_cs);
698 /******************************************************************
699 * get_opened_printer_name
700 * Get the pointer to the opened printer name referred by the handle
702 static LPCWSTR get_opened_printer_name(HANDLE hprn)
704 opened_printer_t *printer = get_opened_printer(hprn);
705 if(!printer) return NULL;
706 return printer->name;
709 /******************************************************************
710 * WINSPOOL_GetOpenedPrinterRegKey
713 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
715 LPCWSTR name = get_opened_printer_name(hPrinter);
719 if(!name) return ERROR_INVALID_HANDLE;
721 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
725 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
727 ERR("Can't find opened printer %s in registry\n",
729 RegCloseKey(hkeyPrinters);
730 return ERROR_INVALID_PRINTER_NAME; /* ? */
732 RegCloseKey(hkeyPrinters);
733 return ERROR_SUCCESS;
736 /******************************************************************
739 * Get the pointer to the specified job.
740 * Should hold the printer_handles_cs before calling.
742 static job_t *get_job(HANDLE hprn, DWORD JobId)
744 opened_printer_t *printer = get_opened_printer(hprn);
747 if(!printer) return NULL;
748 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
750 if(job->job_id == JobId)
756 /***********************************************************
759 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
762 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
765 Formname = (dmA->dmSize > off_formname);
766 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
767 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
768 dmW->dmDeviceName, CCHDEVICENAME);
770 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
771 dmA->dmSize - CCHDEVICENAME);
773 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
774 off_formname - CCHDEVICENAME);
775 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
776 dmW->dmFormName, CCHFORMNAME);
777 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
778 (off_formname + CCHFORMNAME));
781 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
786 /***********************************************************
788 * Creates an ascii copy of supplied devmode on heap
790 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
795 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
797 if(!dmW) return NULL;
798 Formname = (dmW->dmSize > off_formname);
799 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
800 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
801 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
802 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
804 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
805 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
807 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
808 off_formname - CCHDEVICENAME * sizeof(WCHAR));
809 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
810 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
811 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
812 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
815 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
820 /***********************************************************
822 * Creates a unicode copy of PRINTER_INFO_2A on heap
824 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
826 LPPRINTER_INFO_2W piW;
827 UNICODE_STRING usBuffer;
829 if(!piA) return NULL;
830 piW = HeapAlloc(heap, 0, sizeof(*piW));
831 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
833 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
834 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
835 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
836 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
837 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
838 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
839 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
840 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
841 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
842 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
843 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
844 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
848 /***********************************************************
849 * FREE_PRINTER_INFO_2W
850 * Free PRINTER_INFO_2W and all strings
852 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
856 HeapFree(heap,0,piW->pServerName);
857 HeapFree(heap,0,piW->pPrinterName);
858 HeapFree(heap,0,piW->pShareName);
859 HeapFree(heap,0,piW->pPortName);
860 HeapFree(heap,0,piW->pDriverName);
861 HeapFree(heap,0,piW->pComment);
862 HeapFree(heap,0,piW->pLocation);
863 HeapFree(heap,0,piW->pDevMode);
864 HeapFree(heap,0,piW->pSepFile);
865 HeapFree(heap,0,piW->pPrintProcessor);
866 HeapFree(heap,0,piW->pDatatype);
867 HeapFree(heap,0,piW->pParameters);
868 HeapFree(heap,0,piW);
872 /******************************************************************
873 * DeviceCapabilities [WINSPOOL.@]
874 * DeviceCapabilitiesA [WINSPOOL.@]
877 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
878 LPSTR pOutput, LPDEVMODEA lpdm)
882 if (!GDI_CallDeviceCapabilities16)
884 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
886 if (!GDI_CallDeviceCapabilities16) return -1;
888 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
890 /* If DC_PAPERSIZE map POINT16s to POINTs */
891 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
892 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
893 POINT *pt = (POINT *)pOutput;
895 memcpy(tmp, pOutput, ret * sizeof(POINT16));
896 for(i = 0; i < ret; i++, pt++)
901 HeapFree( GetProcessHeap(), 0, tmp );
907 /*****************************************************************************
908 * DeviceCapabilitiesW [WINSPOOL.@]
910 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
913 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
914 WORD fwCapability, LPWSTR pOutput,
915 const DEVMODEW *pDevMode)
917 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
918 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
919 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
922 if(pOutput && (fwCapability == DC_BINNAMES ||
923 fwCapability == DC_FILEDEPENDENCIES ||
924 fwCapability == DC_PAPERNAMES)) {
925 /* These need A -> W translation */
928 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
932 switch(fwCapability) {
937 case DC_FILEDEPENDENCIES:
941 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
942 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
944 for(i = 0; i < ret; i++)
945 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
946 pOutput + (i * size), size);
947 HeapFree(GetProcessHeap(), 0, pOutputA);
949 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
950 (LPSTR)pOutput, dmA);
952 HeapFree(GetProcessHeap(),0,pPortA);
953 HeapFree(GetProcessHeap(),0,pDeviceA);
954 HeapFree(GetProcessHeap(),0,dmA);
958 /******************************************************************
959 * DocumentPropertiesA [WINSPOOL.@]
961 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
963 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
964 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
965 LPDEVMODEA pDevModeInput,DWORD fMode )
967 LPSTR lpName = pDeviceName;
970 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
971 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
975 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
977 ERR("no name from hPrinter?\n");
978 SetLastError(ERROR_INVALID_HANDLE);
981 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
984 if (!GDI_CallExtDeviceMode16)
986 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
988 if (!GDI_CallExtDeviceMode16) {
989 ERR("No CallExtDeviceMode16?\n");
993 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
994 pDevModeInput, NULL, fMode);
997 HeapFree(GetProcessHeap(),0,lpName);
1002 /*****************************************************************************
1003 * DocumentPropertiesW (WINSPOOL.@)
1005 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1007 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1009 LPDEVMODEW pDevModeOutput,
1010 LPDEVMODEW pDevModeInput, DWORD fMode)
1013 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1014 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1015 LPDEVMODEA pDevModeOutputA = NULL;
1018 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1019 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1021 if(pDevModeOutput) {
1022 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1023 if(ret < 0) return ret;
1024 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1026 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1027 pDevModeInputA, fMode);
1028 if(pDevModeOutput) {
1029 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1030 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1032 if(fMode == 0 && ret > 0)
1033 ret += (CCHDEVICENAME + CCHFORMNAME);
1034 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1035 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1039 /******************************************************************
1040 * OpenPrinterA [WINSPOOL.@]
1043 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1044 LPPRINTER_DEFAULTSA pDefault)
1046 UNICODE_STRING lpPrinterNameW;
1047 UNICODE_STRING usBuffer;
1048 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1049 PWSTR pwstrPrinterNameW;
1052 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1055 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1056 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1057 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1058 pDefaultW = &DefaultW;
1060 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1062 RtlFreeUnicodeString(&usBuffer);
1063 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1065 RtlFreeUnicodeString(&lpPrinterNameW);
1069 /******************************************************************
1070 * OpenPrinterW [WINSPOOL.@]
1073 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1074 LPPRINTER_DEFAULTSW pDefault)
1076 HKEY hkeyPrinters, hkeyPrinter;
1078 if (!lpPrinterName) {
1079 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1080 SetLastError(ERROR_INVALID_PARAMETER);
1084 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1087 /* Check Printer exists */
1088 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1090 ERR("Can't create Printers key\n");
1091 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1095 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1096 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1098 TRACE("Can't find printer %s in registry\n",
1099 debugstr_w(lpPrinterName));
1100 RegCloseKey(hkeyPrinters);
1101 SetLastError(ERROR_INVALID_PRINTER_NAME);
1104 RegCloseKey(hkeyPrinter);
1105 RegCloseKey(hkeyPrinters);
1107 if(!phPrinter) /* This seems to be what win95 does anyway */
1110 /* Get the unique handle of the printer*/
1111 *phPrinter = get_opened_printer_entry( lpPrinterName );
1113 if (pDefault != NULL)
1114 FIXME("Not handling pDefault\n");
1119 /******************************************************************
1120 * AddMonitorA [WINSPOOL.@]
1123 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1125 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1126 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1130 /******************************************************************************
1131 * AddMonitorW [WINSPOOL.@]
1133 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1135 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1136 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1140 /******************************************************************
1141 * DeletePrinterDriverA [WINSPOOL.@]
1145 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1147 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1148 debugstr_a(pDriverName));
1149 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1153 /******************************************************************
1154 * DeletePrinterDriverW [WINSPOOL.@]
1158 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1160 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1161 debugstr_w(pDriverName));
1162 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1166 /******************************************************************
1167 * DeleteMonitorA [WINSPOOL.@]
1171 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1173 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1174 debugstr_a(pMonitorName));
1175 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1179 /******************************************************************
1180 * DeleteMonitorW [WINSPOOL.@]
1184 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1186 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1187 debugstr_w(pMonitorName));
1188 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1192 /******************************************************************
1193 * DeletePortA [WINSPOOL.@]
1197 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1199 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1200 debugstr_a(pPortName));
1201 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1205 /******************************************************************
1206 * DeletePortW [WINSPOOL.@]
1210 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1212 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1213 debugstr_w(pPortName));
1214 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1218 /******************************************************************************
1219 * SetPrinterW [WINSPOOL.@]
1229 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1233 /******************************************************************************
1234 * WritePrinter [WINSPOOL.@]
1236 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1238 opened_printer_t *printer;
1241 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1243 EnterCriticalSection(&printer_handles_cs);
1244 printer = get_opened_printer(hPrinter);
1247 SetLastError(ERROR_INVALID_HANDLE);
1253 SetLastError(ERROR_SPL_NO_STARTDOC);
1257 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1259 LeaveCriticalSection(&printer_handles_cs);
1263 /*****************************************************************************
1264 * AddFormA [WINSPOOL.@]
1266 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1268 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1272 /*****************************************************************************
1273 * AddFormW [WINSPOOL.@]
1275 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1277 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1281 /*****************************************************************************
1282 * AddJobA [WINSPOOL.@]
1284 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1287 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1291 SetLastError(ERROR_INVALID_LEVEL);
1295 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1298 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1299 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1300 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1301 if(*pcbNeeded > cbBuf) {
1302 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1305 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1306 addjobA->JobId = addjobW->JobId;
1307 addjobA->Path = (char *)(addjobA + 1);
1308 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1314 /*****************************************************************************
1315 * AddJobW [WINSPOOL.@]
1317 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1319 opened_printer_t *printer;
1322 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1323 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1324 WCHAR path[MAX_PATH], filename[MAX_PATH];
1326 ADDJOB_INFO_1W *addjob;
1328 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1330 EnterCriticalSection(&printer_handles_cs);
1332 printer = get_opened_printer(hPrinter);
1335 SetLastError(ERROR_INVALID_HANDLE);
1340 SetLastError(ERROR_INVALID_LEVEL);
1344 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1348 job->job_id = InterlockedIncrement(&next_job_id);
1350 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1351 if(path[len - 1] != '\\')
1353 memcpy(path + len, spool_path, sizeof(spool_path));
1354 sprintfW(filename, fmtW, path, job->job_id);
1356 len = strlenW(filename);
1357 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1358 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1359 job->document_title = strdupW(default_doc_title);
1360 list_add_tail(&printer->queue->jobs, &job->entry);
1362 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1363 if(*pcbNeeded <= cbBuf) {
1364 addjob = (ADDJOB_INFO_1W*)pData;
1365 addjob->JobId = job->job_id;
1366 addjob->Path = (WCHAR *)(addjob + 1);
1367 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1370 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1373 LeaveCriticalSection(&printer_handles_cs);
1377 /*****************************************************************************
1378 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1380 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1381 DWORD level, LPBYTE Info,
1382 DWORD cbBuf, LPDWORD needed)
1384 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1385 level, Info, cbBuf);
1389 /*****************************************************************************
1390 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1392 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1393 DWORD level, LPBYTE Info,
1394 DWORD cbBuf, LPDWORD needed)
1396 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1397 level, Info, cbBuf);
1401 /*****************************************************************************
1402 * WINSPOOL_OpenDriverReg [internal]
1404 * opens the registry for the printer drivers depending on the given input
1405 * variable pEnvironment
1408 * the opened hkey on success
1411 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1413 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1414 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1416 LPWSTR lpKey, buffer = NULL;
1420 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1424 pEnvW = pEnvironment;
1426 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1427 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1428 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1433 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1435 if(!GetVersionExW( &ver))
1438 switch (ver.dwPlatformId) {
1439 case VER_PLATFORM_WIN32s:
1440 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1442 case VER_PLATFORM_WIN32_NT:
1449 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1452 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1453 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1454 wsprintfW( lpKey, DriversW, pEnvW);
1456 TRACE("%s\n", debugstr_w(lpKey));
1458 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1461 HeapFree( GetProcessHeap(), 0, buffer);
1462 HeapFree( GetProcessHeap(), 0, lpKey);
1467 /*****************************************************************************
1468 * AddPrinterW [WINSPOOL.@]
1470 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1472 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1476 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1479 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1482 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1483 SetLastError(ERROR_INVALID_PARAMETER);
1487 ERR("Level = %ld, unsupported!\n", Level);
1488 SetLastError(ERROR_INVALID_LEVEL);
1491 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1492 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1493 debugstr_w(pi->pPrinterName)
1495 SetLastError(ERROR_INVALID_LEVEL);
1499 SetLastError(ERROR_INVALID_PARAMETER);
1502 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1504 ERR("Can't create Printers key\n");
1507 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1508 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1509 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1510 RegCloseKey(hkeyPrinter);
1511 RegCloseKey(hkeyPrinters);
1514 RegCloseKey(hkeyPrinter);
1516 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1518 ERR("Can't create Drivers key\n");
1519 RegCloseKey(hkeyPrinters);
1522 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1524 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1525 RegCloseKey(hkeyPrinters);
1526 RegCloseKey(hkeyDrivers);
1527 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1530 RegCloseKey(hkeyDriver);
1531 RegCloseKey(hkeyDrivers);
1533 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1534 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1535 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1536 RegCloseKey(hkeyPrinters);
1540 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1542 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1543 SetLastError(ERROR_INVALID_PRINTER_NAME);
1544 RegCloseKey(hkeyPrinters);
1547 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1548 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1549 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1551 /* See if we can load the driver. We may need the devmode structure anyway
1554 * Note that DocumentPropertiesW will briefly try to open the printer we
1555 * just create to find a DEVMODEA struct (it will use the WINEPS default
1556 * one in case it is not there, so we are ok).
1558 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1561 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1562 size = sizeof(DEVMODEW);
1568 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1569 ZeroMemory(dmW,size);
1571 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1573 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1574 HeapFree(GetProcessHeap(),0,dmW);
1579 /* set devmode to printer name */
1580 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1584 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1585 and we support these drivers. NT writes DEVMODEW so somehow
1586 we'll need to distinguish between these when we support NT
1590 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1591 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1592 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1593 HeapFree(GetProcessHeap(), 0, dmA);
1595 HeapFree(GetProcessHeap(), 0, dmW);
1597 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1598 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1599 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1600 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1602 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1603 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1604 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1605 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1606 (LPBYTE)&pi->Priority, sizeof(DWORD));
1607 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1608 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1609 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1610 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1611 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1612 (LPBYTE)&pi->Status, sizeof(DWORD));
1613 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1614 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1616 RegCloseKey(hkeyPrinter);
1617 RegCloseKey(hkeyPrinters);
1618 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1619 ERR("OpenPrinter failing\n");
1625 /*****************************************************************************
1626 * AddPrinterA [WINSPOOL.@]
1628 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1630 UNICODE_STRING pNameW;
1632 PRINTER_INFO_2W *piW;
1633 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1636 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1638 ERR("Level = %ld, unsupported!\n", Level);
1639 SetLastError(ERROR_INVALID_LEVEL);
1642 pwstrNameW = asciitounicode(&pNameW,pName);
1643 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1645 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1647 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1648 RtlFreeUnicodeString(&pNameW);
1653 /*****************************************************************************
1654 * ClosePrinter [WINSPOOL.@]
1656 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1658 UINT_PTR i = (UINT_PTR)hPrinter;
1659 opened_printer_t *printer = NULL;
1662 TRACE("Handle %p\n", hPrinter);
1664 EnterCriticalSection(&printer_handles_cs);
1666 if ((i > 0) && (i <= nb_printer_handles))
1667 printer = printer_handles[i - 1];
1671 struct list *cursor, *cursor2;
1674 EndDocPrinter(hPrinter);
1676 if(InterlockedDecrement(&printer->queue->ref) == 0)
1678 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
1680 job_t *job = LIST_ENTRY(cursor, job_t, entry);
1681 ScheduleJob(hPrinter, job->job_id);
1683 HeapFree(GetProcessHeap(), 0, printer->queue);
1685 HeapFree(GetProcessHeap(), 0, printer->name);
1686 HeapFree(GetProcessHeap(), 0, printer);
1687 printer_handles[i - 1] = NULL;
1690 LeaveCriticalSection(&printer_handles_cs);
1694 /*****************************************************************************
1695 * DeleteFormA [WINSPOOL.@]
1697 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1699 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1703 /*****************************************************************************
1704 * DeleteFormW [WINSPOOL.@]
1706 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1708 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1712 /*****************************************************************************
1713 * WINSPOOL_SHRegDeleteKey
1715 * Recursively delete subkeys.
1716 * Cut & paste from shlwapi.
1719 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1721 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1722 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1725 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1728 /* Find how many subkeys there are */
1729 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1730 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1734 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1735 /* Name too big: alloc a buffer for it */
1736 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1739 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1742 /* Recursively delete all the subkeys */
1743 for(i = 0; i < dwKeyCount && !dwRet; i++)
1745 dwSize = dwMaxSubkeyLen;
1746 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1748 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1751 if (lpszName != szNameBuf)
1752 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1756 RegCloseKey(hSubKey);
1758 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1763 /*****************************************************************************
1764 * DeletePrinter [WINSPOOL.@]
1766 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1768 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1769 HKEY hkeyPrinters, hkey;
1772 SetLastError(ERROR_INVALID_HANDLE);
1775 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1776 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1777 RegCloseKey(hkeyPrinters);
1779 WriteProfileStringW(devicesW, lpNameW, NULL);
1780 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1781 RegDeleteValueW(hkey, lpNameW);
1787 /*****************************************************************************
1788 * SetPrinterA [WINSPOOL.@]
1790 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1793 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1797 /*****************************************************************************
1798 * SetJobA [WINSPOOL.@]
1800 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1801 LPBYTE pJob, DWORD Command)
1805 UNICODE_STRING usBuffer;
1807 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
1809 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1810 are all ignored by SetJob, so we don't bother copying them */
1818 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
1819 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
1821 JobW = (LPBYTE)info1W;
1822 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
1823 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
1824 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
1825 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
1826 info1W->Status = info1A->Status;
1827 info1W->Priority = info1A->Priority;
1828 info1W->Position = info1A->Position;
1829 info1W->PagesPrinted = info1A->PagesPrinted;
1834 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
1835 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
1837 JobW = (LPBYTE)info2W;
1838 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
1839 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
1840 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
1841 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
1842 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
1843 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
1844 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
1845 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
1846 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
1847 info2W->Status = info2A->Status;
1848 info2W->Priority = info2A->Priority;
1849 info2W->Position = info2A->Position;
1850 info2W->StartTime = info2A->StartTime;
1851 info2W->UntilTime = info2A->UntilTime;
1852 info2W->PagesPrinted = info2A->PagesPrinted;
1856 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
1857 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
1860 SetLastError(ERROR_INVALID_LEVEL);
1864 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
1870 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
1871 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
1872 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
1873 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
1874 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
1879 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
1880 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
1881 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
1882 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
1883 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
1884 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
1885 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
1886 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
1887 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
1891 HeapFree(GetProcessHeap(), 0, JobW);
1896 /*****************************************************************************
1897 * SetJobW [WINSPOOL.@]
1899 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1900 LPBYTE pJob, DWORD Command)
1905 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
1906 FIXME("Ignoring everything other than document title\n");
1908 EnterCriticalSection(&printer_handles_cs);
1909 job = get_job(hPrinter, JobId);
1919 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
1920 HeapFree(GetProcessHeap(), 0, job->document_title);
1921 job->document_title = strdupW(info1->pDocument);
1926 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
1927 HeapFree(GetProcessHeap(), 0, job->document_title);
1928 job->document_title = strdupW(info2->pDocument);
1934 SetLastError(ERROR_INVALID_LEVEL);
1939 LeaveCriticalSection(&printer_handles_cs);
1943 /*****************************************************************************
1944 * EndDocPrinter [WINSPOOL.@]
1946 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
1948 opened_printer_t *printer;
1950 TRACE("(%p)\n", hPrinter);
1952 EnterCriticalSection(&printer_handles_cs);
1954 printer = get_opened_printer(hPrinter);
1957 SetLastError(ERROR_INVALID_HANDLE);
1963 SetLastError(ERROR_SPL_NO_STARTDOC);
1967 CloseHandle(printer->doc->hf);
1968 ScheduleJob(hPrinter, printer->doc->job_id);
1969 HeapFree(GetProcessHeap(), 0, printer->doc);
1970 printer->doc = NULL;
1973 LeaveCriticalSection(&printer_handles_cs);
1977 /*****************************************************************************
1978 * EndPagePrinter [WINSPOOL.@]
1980 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
1982 FIXME("(%p): stub\n", hPrinter);
1986 /*****************************************************************************
1987 * StartDocPrinterA [WINSPOOL.@]
1989 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
1991 UNICODE_STRING usBuffer;
1993 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
1996 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
1997 or one (DOC_INFO_3) extra DWORDs */
2001 doc2W.JobId = doc2->JobId;
2004 doc2W.dwMode = doc2->dwMode;
2007 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2008 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2009 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2013 SetLastError(ERROR_INVALID_LEVEL);
2017 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2019 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2020 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2021 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2026 /*****************************************************************************
2027 * StartDocPrinterW [WINSPOOL.@]
2029 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2031 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2032 opened_printer_t *printer;
2033 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2034 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2035 JOB_INFO_1W job_info;
2036 DWORD needed, ret = 0;
2040 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2041 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2042 debugstr_w(doc->pDatatype));
2044 if(Level < 1 || Level > 3)
2046 SetLastError(ERROR_INVALID_LEVEL);
2050 EnterCriticalSection(&printer_handles_cs);
2051 printer = get_opened_printer(hPrinter);
2054 SetLastError(ERROR_INVALID_HANDLE);
2060 SetLastError(ERROR_INVALID_PRINTER_STATE);
2064 /* Even if we're printing to a file we still add a print job, we'll
2065 just ignore the spool file name */
2067 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2069 ERR("AddJob failed gle %08lx\n", GetLastError());
2073 if(doc->pOutputFile)
2074 filename = doc->pOutputFile;
2076 filename = addjob->Path;
2078 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2079 if(hf == INVALID_HANDLE_VALUE)
2082 memset(&job_info, 0, sizeof(job_info));
2083 job_info.pDocument = doc->pDocName;
2084 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2086 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2087 printer->doc->hf = hf;
2088 ret = printer->doc->job_id = addjob->JobId;
2090 LeaveCriticalSection(&printer_handles_cs);
2095 /*****************************************************************************
2096 * StartPagePrinter [WINSPOOL.@]
2098 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2100 FIXME("(%p): stub\n", hPrinter);
2104 /*****************************************************************************
2105 * GetFormA [WINSPOOL.@]
2107 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2108 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2110 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2111 Level,pForm,cbBuf,pcbNeeded);
2115 /*****************************************************************************
2116 * GetFormW [WINSPOOL.@]
2118 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2119 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2121 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2122 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2126 /*****************************************************************************
2127 * SetFormA [WINSPOOL.@]
2129 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2132 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2136 /*****************************************************************************
2137 * SetFormW [WINSPOOL.@]
2139 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2142 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2146 /*****************************************************************************
2147 * ReadPrinter [WINSPOOL.@]
2149 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2150 LPDWORD pNoBytesRead)
2152 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2156 /*****************************************************************************
2157 * ResetPrinterA [WINSPOOL.@]
2159 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2161 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2165 /*****************************************************************************
2166 * ResetPrinterW [WINSPOOL.@]
2168 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2170 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2174 /*****************************************************************************
2175 * WINSPOOL_GetDWORDFromReg
2177 * Return DWORD associated with ValueName from hkey.
2179 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2181 DWORD sz = sizeof(DWORD), type, value = 0;
2184 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2186 if(ret != ERROR_SUCCESS) {
2187 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2190 if(type != REG_DWORD) {
2191 ERR("Got type %ld\n", type);
2197 /*****************************************************************************
2198 * WINSPOOL_GetStringFromReg
2200 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2201 * String is stored either as unicode or ascii.
2202 * Bit of a hack here to get the ValueName if we want ascii.
2204 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2205 DWORD buflen, DWORD *needed,
2208 DWORD sz = buflen, type;
2212 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2214 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2215 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2216 HeapFree(GetProcessHeap(),0,ValueNameA);
2218 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2219 WARN("Got ret = %ld\n", ret);
2227 /*****************************************************************************
2228 * WINSPOOL_GetDefaultDevMode
2230 * Get a default DevMode values for wineps.
2234 static void WINSPOOL_GetDefaultDevMode(
2236 DWORD buflen, DWORD *needed,
2240 static const char szwps[] = "wineps.drv";
2242 /* fill default DEVMODE - should be read from ppd... */
2243 ZeroMemory( &dm, sizeof(dm) );
2244 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2245 dm.dmSpecVersion = DM_SPECVERSION;
2246 dm.dmDriverVersion = 1;
2247 dm.dmSize = sizeof(DEVMODEA);
2248 dm.dmDriverExtra = 0;
2250 DM_ORIENTATION | DM_PAPERSIZE |
2251 DM_PAPERLENGTH | DM_PAPERWIDTH |
2254 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2255 DM_YRESOLUTION | DM_TTOPTION;
2257 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2258 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2259 dm.u1.s1.dmPaperLength = 2970;
2260 dm.u1.s1.dmPaperWidth = 2100;
2264 dm.dmDefaultSource = DMBIN_AUTO;
2265 dm.dmPrintQuality = DMRES_MEDIUM;
2268 dm.dmYResolution = 300; /* 300dpi */
2269 dm.dmTTOption = DMTT_BITMAP;
2272 /* dm.dmLogPixels */
2273 /* dm.dmBitsPerPel */
2274 /* dm.dmPelsWidth */
2275 /* dm.dmPelsHeight */
2276 /* dm.dmDisplayFlags */
2277 /* dm.dmDisplayFrequency */
2278 /* dm.dmICMMethod */
2279 /* dm.dmICMIntent */
2280 /* dm.dmMediaType */
2281 /* dm.dmDitherType */
2282 /* dm.dmReserved1 */
2283 /* dm.dmReserved2 */
2284 /* dm.dmPanningWidth */
2285 /* dm.dmPanningHeight */
2288 if(buflen >= sizeof(DEVMODEW)) {
2289 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2290 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2291 HeapFree(GetProcessHeap(),0,pdmW);
2293 *needed = sizeof(DEVMODEW);
2297 if(buflen >= sizeof(DEVMODEA)) {
2298 memcpy(ptr, &dm, sizeof(DEVMODEA));
2300 *needed = sizeof(DEVMODEA);
2304 /*****************************************************************************
2305 * WINSPOOL_GetDevModeFromReg
2307 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2308 * DevMode is stored either as unicode or ascii.
2310 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2312 DWORD buflen, DWORD *needed,
2315 DWORD sz = buflen, type;
2318 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2319 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2320 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2321 if (sz < sizeof(DEVMODEA))
2323 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2326 /* ensures that dmSize is not erratically bogus if registry is invalid */
2327 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2328 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2330 sz += (CCHDEVICENAME + CCHFORMNAME);
2332 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2333 memcpy(ptr, dmW, sz);
2334 HeapFree(GetProcessHeap(),0,dmW);
2341 /*********************************************************************
2342 * WINSPOOL_GetPrinter_2
2344 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2345 * The strings are either stored as unicode or ascii.
2347 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2348 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2351 DWORD size, left = cbBuf;
2352 BOOL space = (cbBuf > 0);
2357 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2359 if(space && size <= left) {
2360 pi2->pPrinterName = (LPWSTR)ptr;
2367 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2369 if(space && size <= left) {
2370 pi2->pShareName = (LPWSTR)ptr;
2377 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2379 if(space && size <= left) {
2380 pi2->pPortName = (LPWSTR)ptr;
2387 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2389 if(space && size <= left) {
2390 pi2->pDriverName = (LPWSTR)ptr;
2397 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2399 if(space && size <= left) {
2400 pi2->pComment = (LPWSTR)ptr;
2407 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2409 if(space && size <= left) {
2410 pi2->pLocation = (LPWSTR)ptr;
2417 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2419 if(space && size <= left) {
2420 pi2->pDevMode = (LPDEVMODEW)ptr;
2429 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2430 if(space && size <= left) {
2431 pi2->pDevMode = (LPDEVMODEW)ptr;
2438 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2440 if(space && size <= left) {
2441 pi2->pSepFile = (LPWSTR)ptr;
2448 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2450 if(space && size <= left) {
2451 pi2->pPrintProcessor = (LPWSTR)ptr;
2458 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2460 if(space && size <= left) {
2461 pi2->pDatatype = (LPWSTR)ptr;
2468 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2470 if(space && size <= left) {
2471 pi2->pParameters = (LPWSTR)ptr;
2479 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2480 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2481 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2482 "Default Priority");
2483 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2484 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2487 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2488 memset(pi2, 0, sizeof(*pi2));
2493 /*********************************************************************
2494 * WINSPOOL_GetPrinter_4
2496 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2498 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2499 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2502 DWORD size, left = cbBuf;
2503 BOOL space = (cbBuf > 0);
2508 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2510 if(space && size <= left) {
2511 pi4->pPrinterName = (LPWSTR)ptr;
2519 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2522 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2523 memset(pi4, 0, sizeof(*pi4));
2528 /*********************************************************************
2529 * WINSPOOL_GetPrinter_5
2531 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2533 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2534 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2537 DWORD size, left = cbBuf;
2538 BOOL space = (cbBuf > 0);
2543 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2545 if(space && size <= left) {
2546 pi5->pPrinterName = (LPWSTR)ptr;
2553 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2555 if(space && size <= left) {
2556 pi5->pPortName = (LPWSTR)ptr;
2564 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2565 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2567 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2571 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2572 memset(pi5, 0, sizeof(*pi5));
2577 /*****************************************************************************
2578 * WINSPOOL_GetPrinter
2580 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2581 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2582 * just a collection of pointers to strings.
2584 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2585 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2588 DWORD size, needed = 0;
2590 HKEY hkeyPrinter, hkeyPrinters;
2593 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2595 if (!(name = get_opened_printer_name(hPrinter))) {
2596 SetLastError(ERROR_INVALID_HANDLE);
2600 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2602 ERR("Can't create Printers key\n");
2605 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2607 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2608 RegCloseKey(hkeyPrinters);
2609 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2616 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2618 size = sizeof(PRINTER_INFO_2W);
2620 ptr = pPrinter + size;
2622 memset(pPrinter, 0, size);
2627 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2635 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2637 size = sizeof(PRINTER_INFO_4W);
2639 ptr = pPrinter + size;
2641 memset(pPrinter, 0, size);
2646 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2655 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2657 size = sizeof(PRINTER_INFO_5W);
2659 ptr = pPrinter + size;
2661 memset(pPrinter, 0, size);
2667 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2674 FIXME("Unimplemented level %ld\n", Level);
2675 SetLastError(ERROR_INVALID_LEVEL);
2676 RegCloseKey(hkeyPrinters);
2677 RegCloseKey(hkeyPrinter);
2681 RegCloseKey(hkeyPrinter);
2682 RegCloseKey(hkeyPrinters);
2684 TRACE("returning %d needed = %ld\n", ret, needed);
2685 if(pcbNeeded) *pcbNeeded = needed;
2687 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2691 /*****************************************************************************
2692 * GetPrinterW [WINSPOOL.@]
2694 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2695 DWORD cbBuf, LPDWORD pcbNeeded)
2697 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2701 /*****************************************************************************
2702 * GetPrinterA [WINSPOOL.@]
2704 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2705 DWORD cbBuf, LPDWORD pcbNeeded)
2707 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2711 /*****************************************************************************
2712 * WINSPOOL_EnumPrinters
2714 * Implementation of EnumPrintersA|W
2716 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2717 DWORD dwLevel, LPBYTE lpbPrinters,
2718 DWORD cbBuf, LPDWORD lpdwNeeded,
2719 LPDWORD lpdwReturned, BOOL unicode)
2722 HKEY hkeyPrinters, hkeyPrinter;
2723 WCHAR PrinterName[255];
2724 DWORD needed = 0, number = 0;
2725 DWORD used, i, left;
2729 memset(lpbPrinters, 0, cbBuf);
2735 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2736 if(dwType == PRINTER_ENUM_DEFAULT)
2739 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2740 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2741 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2742 if(!dwType) return TRUE;
2745 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2746 FIXME("dwType = %08lx\n", dwType);
2747 SetLastError(ERROR_INVALID_FLAGS);
2751 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2753 ERR("Can't create Printers key\n");
2757 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2758 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2759 RegCloseKey(hkeyPrinters);
2760 ERR("Can't query Printers key\n");
2763 TRACE("Found %ld printers\n", number);
2767 RegCloseKey(hkeyPrinters);
2769 *lpdwReturned = number;
2773 used = number * sizeof(PRINTER_INFO_2W);
2776 used = number * sizeof(PRINTER_INFO_4W);
2779 used = number * sizeof(PRINTER_INFO_5W);
2783 SetLastError(ERROR_INVALID_LEVEL);
2784 RegCloseKey(hkeyPrinters);
2787 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2789 for(i = 0; i < number; i++) {
2790 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2792 ERR("Can't enum key number %ld\n", i);
2793 RegCloseKey(hkeyPrinters);
2796 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2797 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2799 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2800 RegCloseKey(hkeyPrinters);
2805 buf = lpbPrinters + used;
2806 left = cbBuf - used;
2814 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2815 left, &needed, unicode);
2817 if(pi) pi += sizeof(PRINTER_INFO_2W);
2820 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2821 left, &needed, unicode);
2823 if(pi) pi += sizeof(PRINTER_INFO_4W);
2826 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2827 left, &needed, unicode);
2829 if(pi) pi += sizeof(PRINTER_INFO_5W);
2832 ERR("Shouldn't be here!\n");
2833 RegCloseKey(hkeyPrinter);
2834 RegCloseKey(hkeyPrinters);
2837 RegCloseKey(hkeyPrinter);
2839 RegCloseKey(hkeyPrinters);
2846 memset(lpbPrinters, 0, cbBuf);
2847 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2851 *lpdwReturned = number;
2852 SetLastError(ERROR_SUCCESS);
2857 /******************************************************************
2858 * EnumPrintersW [WINSPOOL.@]
2860 * Enumerates the available printers, print servers and print
2861 * providers, depending on the specified flags, name and level.
2865 * If level is set to 1:
2866 * Not implemented yet!
2867 * Returns TRUE with an empty list.
2869 * If level is set to 2:
2870 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2871 * Returns an array of PRINTER_INFO_2 data structures in the
2872 * lpbPrinters buffer. Note that according to MSDN also an
2873 * OpenPrinter should be performed on every remote printer.
2875 * If level is set to 4 (officially WinNT only):
2876 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2877 * Fast: Only the registry is queried to retrieve printer names,
2878 * no connection to the driver is made.
2879 * Returns an array of PRINTER_INFO_4 data structures in the
2880 * lpbPrinters buffer.
2882 * If level is set to 5 (officially WinNT4/Win9x only):
2883 * Fast: Only the registry is queried to retrieve printer names,
2884 * no connection to the driver is made.
2885 * Returns an array of PRINTER_INFO_5 data structures in the
2886 * lpbPrinters buffer.
2888 * If level set to 3 or 6+:
2889 * returns zero (failure!)
2891 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2895 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2896 * - Only levels 2, 4 and 5 are implemented at the moment.
2897 * - 16-bit printer drivers are not enumerated.
2898 * - Returned amount of bytes used/needed does not match the real Windoze
2899 * implementation (as in this implementation, all strings are part
2900 * of the buffer, whereas Win32 keeps them somewhere else)
2901 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2904 * - In a regular Wine installation, no registry settings for printers
2905 * exist, which makes this function return an empty list.
2907 BOOL WINAPI EnumPrintersW(
2908 DWORD dwType, /* [in] Types of print objects to enumerate */
2909 LPWSTR lpszName, /* [in] name of objects to enumerate */
2910 DWORD dwLevel, /* [in] type of printer info structure */
2911 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2912 DWORD cbBuf, /* [in] max size of buffer in bytes */
2913 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2914 LPDWORD lpdwReturned /* [out] number of entries returned */
2917 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2918 lpdwNeeded, lpdwReturned, TRUE);
2921 /******************************************************************
2922 * EnumPrintersA [WINSPOOL.@]
2925 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2926 DWORD dwLevel, LPBYTE lpbPrinters,
2927 DWORD cbBuf, LPDWORD lpdwNeeded,
2928 LPDWORD lpdwReturned)
2931 UNICODE_STRING lpszNameW;
2934 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2935 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2936 lpdwNeeded, lpdwReturned, FALSE);
2937 RtlFreeUnicodeString(&lpszNameW);
2941 /*****************************************************************************
2942 * WINSPOOL_GetDriverInfoFromReg [internal]
2944 * Enters the information from the registry into the DRIVER_INFO struct
2947 * zero if the printer driver does not exist in the registry
2948 * (only if Level > 1) otherwise nonzero
2950 static BOOL WINSPOOL_GetDriverInfoFromReg(
2953 LPWSTR pEnvironment,
2955 LPBYTE ptr, /* DRIVER_INFO */
2956 LPBYTE pDriverStrings, /* strings buffer */
2957 DWORD cbBuf, /* size of string buffer */
2958 LPDWORD pcbNeeded, /* space needed for str. */
2959 BOOL unicode) /* type of strings */
2960 { DWORD dw, size, tmp, type;
2962 LPBYTE strPtr = pDriverStrings;
2964 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
2965 debugstr_w(DriverName), debugstr_w(pEnvironment),
2966 Level, ptr, pDriverStrings, cbBuf, unicode);
2969 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
2970 if (*pcbNeeded <= cbBuf)
2971 strcpyW((LPWSTR)strPtr, DriverName);
2973 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
2975 if(*pcbNeeded <= cbBuf)
2976 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
2977 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
2981 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
2985 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
2986 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
2989 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
2990 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
2991 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
2996 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
2998 WARN("Can't get Version\n");
3000 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
3003 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3005 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3007 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3010 if(*pcbNeeded <= cbBuf) {
3012 strcpyW((LPWSTR)strPtr, pEnvironment);
3014 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3015 (LPSTR)strPtr, size, NULL, NULL);
3017 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
3018 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3021 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3024 if(*pcbNeeded <= cbBuf)
3025 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3028 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
3029 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3032 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3035 if(*pcbNeeded <= cbBuf)
3036 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3039 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
3040 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3043 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3044 0, &size, unicode)) {
3046 if(*pcbNeeded <= cbBuf)
3047 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3048 size, &tmp, unicode);
3050 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
3051 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3055 RegCloseKey(hkeyDriver);
3056 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3060 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3063 if(*pcbNeeded <= cbBuf)
3064 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3065 size, &tmp, unicode);
3067 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3068 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3071 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3074 if(*pcbNeeded <= cbBuf)
3075 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3076 size, &tmp, unicode);
3078 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3079 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3082 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3085 if(*pcbNeeded <= cbBuf)
3086 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3087 size, &tmp, unicode);
3089 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3090 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3093 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3096 if(*pcbNeeded <= cbBuf)
3097 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3098 size, &tmp, unicode);
3100 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3101 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3104 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3105 RegCloseKey(hkeyDriver);
3109 /*****************************************************************************
3110 * WINSPOOL_GetPrinterDriver
3112 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3113 DWORD Level, LPBYTE pDriverInfo,
3114 DWORD cbBuf, LPDWORD pcbNeeded,
3118 WCHAR DriverName[100];
3119 DWORD ret, type, size, needed = 0;
3121 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3123 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3124 Level,pDriverInfo,cbBuf, pcbNeeded);
3126 ZeroMemory(pDriverInfo, cbBuf);
3128 if (!(name = get_opened_printer_name(hPrinter))) {
3129 SetLastError(ERROR_INVALID_HANDLE);
3132 if(Level < 1 || Level > 3) {
3133 SetLastError(ERROR_INVALID_LEVEL);
3136 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3138 ERR("Can't create Printers key\n");
3141 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3143 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3144 RegCloseKey(hkeyPrinters);
3145 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3148 size = sizeof(DriverName);
3150 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3151 (LPBYTE)DriverName, &size);
3152 RegCloseKey(hkeyPrinter);
3153 RegCloseKey(hkeyPrinters);
3154 if(ret != ERROR_SUCCESS) {
3155 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3159 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3161 ERR("Can't create Drivers key\n");
3167 size = sizeof(DRIVER_INFO_1W);
3170 size = sizeof(DRIVER_INFO_2W);
3173 size = sizeof(DRIVER_INFO_3W);
3176 ERR("Invalid level\n");
3181 ptr = pDriverInfo + size;
3183 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3184 pEnvironment, Level, pDriverInfo,
3185 (cbBuf < size) ? NULL : ptr,
3186 (cbBuf < size) ? 0 : cbBuf - size,
3187 &needed, unicode)) {
3188 RegCloseKey(hkeyDrivers);
3192 RegCloseKey(hkeyDrivers);
3194 if(pcbNeeded) *pcbNeeded = size + needed;
3195 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3196 if(cbBuf >= needed) return TRUE;
3197 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3201 /*****************************************************************************
3202 * GetPrinterDriverA [WINSPOOL.@]
3204 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3205 DWORD Level, LPBYTE pDriverInfo,
3206 DWORD cbBuf, LPDWORD pcbNeeded)
3209 UNICODE_STRING pEnvW;
3212 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3213 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3214 cbBuf, pcbNeeded, FALSE);
3215 RtlFreeUnicodeString(&pEnvW);
3218 /*****************************************************************************
3219 * GetPrinterDriverW [WINSPOOL.@]
3221 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3222 DWORD Level, LPBYTE pDriverInfo,
3223 DWORD cbBuf, LPDWORD pcbNeeded)
3225 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3226 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3229 /*****************************************************************************
3230 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3232 * Return the PATH for the Printer-Drivers (UNICODE)
3235 * pName [I] Servername (NT only) or NULL (local Computer)
3236 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3237 * Level [I] Structure-Level (must be 1)
3238 * pDriverDirectory [O] PTR to Buffer that receives the Result
3239 * cbBuf [I] Size of Buffer at pDriverDirectory
3240 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3241 * required for pDriverDirectory
3244 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3245 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3246 * if cbBuf is to small
3248 * Native Values returned in pDriverDirectory on Success:
3249 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3250 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3251 *| win9x(Windows 4.0): "%winsysdir%"
3253 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3256 *- pName != NULL not supported
3257 *- pEnvironment != NULL not supported
3258 *- Current Implementation returns always "%winsysdir%"
3261 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3262 DWORD Level, LPBYTE pDriverDirectory,
3263 DWORD cbBuf, LPDWORD pcbNeeded)
3267 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3268 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3270 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
3271 SetLastError(ERROR_INVALID_PARAMETER);
3274 if(pEnvironment != NULL) {
3275 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
3276 SetLastError(ERROR_INVALID_ENVIRONMENT);
3279 if(Level != 1) /* win95 ignores this so we just carry on */
3280 WARN("Level = %ld - assuming 1\n", Level);
3282 /* FIXME should read from registry */
3283 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
3284 /* GetSystemDirectoryW returns number of TCHAR without '\0'
3288 needed*=sizeof(WCHAR);
3291 *pcbNeeded = needed;
3292 TRACE("required <%08lx>\n", *pcbNeeded);
3293 if(needed > cbBuf) {
3294 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3301 /*****************************************************************************
3302 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3304 * Return the PATH for the Printer-Drivers (ANSI)
3306 * See GetPrinterDriverDirectoryW.
3309 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3312 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3313 DWORD Level, LPBYTE pDriverDirectory,
3314 DWORD cbBuf, LPDWORD pcbNeeded)
3316 UNICODE_STRING nameW, environmentW;
3319 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3320 WCHAR *driverDirectoryW = NULL;
3322 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3324 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3325 else nameW.Buffer = NULL;
3326 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3327 else environmentW.Buffer = NULL;
3329 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3330 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3333 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3334 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3336 *pcbNeeded = needed;
3337 ret = (needed <= cbBuf) ? TRUE : FALSE;
3339 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3341 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
3343 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3344 RtlFreeUnicodeString(&environmentW);
3345 RtlFreeUnicodeString(&nameW);
3350 /*****************************************************************************
3351 * AddPrinterDriverA [WINSPOOL.@]
3353 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3356 HKEY hkeyDrivers, hkeyName;
3358 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3360 if(level != 2 && level != 3) {
3361 SetLastError(ERROR_INVALID_LEVEL);
3365 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3366 SetLastError(ERROR_INVALID_PARAMETER);
3370 WARN("pDriverInfo == NULL\n");
3371 SetLastError(ERROR_INVALID_PARAMETER);
3376 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3378 memset(&di3, 0, sizeof(di3));
3379 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3382 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3384 SetLastError(ERROR_INVALID_PARAMETER);
3387 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3388 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3389 if(!di3.pHelpFile) di3.pHelpFile = "";
3390 if(!di3.pMonitorName) di3.pMonitorName = "";
3392 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3395 ERR("Can't create Drivers key\n");
3399 if(level == 2) { /* apparently can't overwrite with level2 */
3400 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3401 RegCloseKey(hkeyName);
3402 RegCloseKey(hkeyDrivers);
3403 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3404 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3408 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3409 RegCloseKey(hkeyDrivers);
3410 ERR("Can't create Name key\n");
3413 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3415 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3416 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3417 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3419 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3420 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3421 (LPBYTE) di3.pDependentFiles, 0);
3422 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3423 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3424 RegCloseKey(hkeyName);
3425 RegCloseKey(hkeyDrivers);
3430 /*****************************************************************************
3431 * AddPrinterDriverW [WINSPOOL.@]
3433 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3436 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3441 /*****************************************************************************
3442 * AddPrintProcessorA [WINSPOOL.@]
3444 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3445 LPSTR pPrintProcessorName)
3447 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3448 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3452 /*****************************************************************************
3453 * AddPrintProcessorW [WINSPOOL.@]
3455 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3456 LPWSTR pPrintProcessorName)
3458 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3459 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3463 /*****************************************************************************
3464 * AddPrintProvidorA [WINSPOOL.@]
3466 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3468 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3472 /*****************************************************************************
3473 * AddPrintProvidorW [WINSPOOL.@]
3475 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3477 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3481 /*****************************************************************************
3482 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3484 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3485 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3487 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3488 pDevModeOutput, pDevModeInput);
3492 /*****************************************************************************
3493 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3495 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3496 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3498 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3499 pDevModeOutput, pDevModeInput);
3503 /*****************************************************************************
3504 * PrinterProperties [WINSPOOL.@]
3506 * Displays a dialog to set the properties of the printer.
3509 * nonzero on success or zero on failure
3512 * implemented as stub only
3514 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3515 HANDLE hPrinter /* [in] handle to printer object */
3517 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3518 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3522 /*****************************************************************************
3523 * EnumJobsA [WINSPOOL.@]
3526 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3527 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3530 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3531 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3533 if(pcbNeeded) *pcbNeeded = 0;
3534 if(pcReturned) *pcReturned = 0;
3539 /*****************************************************************************
3540 * EnumJobsW [WINSPOOL.@]
3543 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3544 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3547 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3548 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3550 if(pcbNeeded) *pcbNeeded = 0;
3551 if(pcReturned) *pcReturned = 0;
3555 /*****************************************************************************
3556 * WINSPOOL_EnumPrinterDrivers [internal]
3558 * Delivers information about all printer drivers installed on the
3559 * localhost or a given server
3562 * nonzero on success or zero on failure. If the buffer for the returned
3563 * information is too small the function will return an error
3566 * - only implemented for localhost, foreign hosts will return an error
3568 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3569 DWORD Level, LPBYTE pDriverInfo,
3570 DWORD cbBuf, LPDWORD pcbNeeded,
3571 LPDWORD pcReturned, BOOL unicode)
3574 DWORD i, needed, number = 0, size = 0;
3575 WCHAR DriverNameW[255];
3578 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3579 debugstr_w(pName), debugstr_w(pEnvironment),
3580 Level, pDriverInfo, cbBuf, unicode);
3582 /* check for local drivers */
3584 ERR("remote drivers unsupported! Current remote host is %s\n",
3589 /* check input parameter */
3590 if((Level < 1) || (Level > 3)) {
3591 ERR("unsupported level %ld\n", Level);
3592 SetLastError(ERROR_INVALID_LEVEL);
3596 /* initialize return values */
3598 memset( pDriverInfo, 0, cbBuf);
3602 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3604 ERR("Can't open Drivers key\n");
3608 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3609 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3610 RegCloseKey(hkeyDrivers);
3611 ERR("Can't query Drivers key\n");
3614 TRACE("Found %ld Drivers\n", number);
3616 /* get size of single struct
3617 * unicode and ascii structure have the same size
3621 size = sizeof(DRIVER_INFO_1A);
3624 size = sizeof(DRIVER_INFO_2A);
3627 size = sizeof(DRIVER_INFO_3A);
3631 /* calculate required buffer size */
3632 *pcbNeeded = size * number;
3634 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3636 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3637 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3639 ERR("Can't enum key number %ld\n", i);
3640 RegCloseKey(hkeyDrivers);
3643 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3644 pEnvironment, Level, ptr,
3645 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3646 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3647 &needed, unicode)) {
3648 RegCloseKey(hkeyDrivers);
3651 (*pcbNeeded) += needed;
3654 RegCloseKey(hkeyDrivers);
3656 if(cbBuf < *pcbNeeded){
3657 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3661 *pcReturned = number;
3665 /*****************************************************************************
3666 * EnumPrinterDriversW [WINSPOOL.@]
3668 * see function EnumPrinterDrivers for RETURNS, BUGS
3670 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3671 LPBYTE pDriverInfo, DWORD cbBuf,
3672 LPDWORD pcbNeeded, LPDWORD pcReturned)
3674 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3675 cbBuf, pcbNeeded, pcReturned, TRUE);
3678 /*****************************************************************************
3679 * EnumPrinterDriversA [WINSPOOL.@]
3681 * see function EnumPrinterDrivers for RETURNS, BUGS
3683 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3684 LPBYTE pDriverInfo, DWORD cbBuf,
3685 LPDWORD pcbNeeded, LPDWORD pcReturned)
3687 UNICODE_STRING pNameW, pEnvironmentW;
3688 PWSTR pwstrNameW, pwstrEnvironmentW;
3690 pwstrNameW = asciitounicode(&pNameW, pName);
3691 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3693 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3694 Level, pDriverInfo, cbBuf, pcbNeeded,
3696 RtlFreeUnicodeString(&pNameW);
3697 RtlFreeUnicodeString(&pEnvironmentW);
3702 static CHAR PortMonitor[] = "Wine Port Monitor";
3703 static CHAR PortDescription[] = "Wine Port";
3705 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3709 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3710 NULL, OPEN_EXISTING, 0, NULL );
3711 if (handle == INVALID_HANDLE_VALUE)
3713 TRACE("Checking %s exists\n", name );
3714 CloseHandle( handle );
3718 static DWORD WINSPOOL_CountSerialPorts(void)
3725 strcpy( name, "COMx:" );
3727 if (WINSPOOL_ComPortExists( name ))
3734 /******************************************************************************
3735 * EnumPortsA (WINSPOOL.@)
3737 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3738 LPDWORD bufneeded,LPDWORD bufreturned)
3741 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3742 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3746 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3747 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3752 info_size = sizeof (PORT_INFO_1A);
3755 info_size = sizeof (PORT_INFO_2A);
3758 SetLastError(ERROR_INVALID_LEVEL);
3762 /* see how many exist */
3765 serial_count = WINSPOOL_CountSerialPorts();
3768 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3769 if ( r == ERROR_SUCCESS )
3771 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3772 &printer_count, NULL, NULL, NULL, NULL);
3774 count = serial_count + printer_count;
3776 /* then fill in the structure info structure once
3777 we know the offset to the first string */
3779 memset( buffer, 0, bufsize );
3781 ofs = info_size*count;
3782 for ( i=0; i<count; i++)
3784 DWORD vallen = sizeof(portname) - 1;
3786 /* get the serial port values, then the printer values */
3787 if ( i < serial_count )
3789 strcpy( portname, "COMx:" );
3790 portname[3] = '1' + i;
3791 if (!WINSPOOL_ComPortExists( portname ))
3794 TRACE("Found %s\n", portname );
3795 vallen = strlen( portname );
3799 r = RegEnumValueA( hkey_printer, i-serial_count,
3800 portname, &vallen, NULL, NULL, NULL, 0 );
3805 /* add a colon if necessary, and make it upper case */
3806 CharUpperBuffA(portname,vallen);
3807 if (strcasecmp(portname,"nul")!=0)
3808 if (vallen && (portname[vallen-1] != ':') )
3809 lstrcatA(portname,":");
3811 /* add the port info structure if we can fit it */
3812 if ( info_size*(n+1) < bufsize )
3816 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3817 info->pName = (LPSTR) &buffer[ofs];
3819 else if ( level == 2)
3821 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3822 info->pPortName = (LPSTR) &buffer[ofs];
3823 /* FIXME: fill in more stuff here */
3824 info->pMonitorName = PortMonitor;
3825 info->pDescription = PortDescription;
3826 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3829 /* add the name of the port if we can fit it */
3830 if ( ofs < bufsize )
3831 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
3837 ofs += lstrlenA(portname)+1;
3840 RegCloseKey(hkey_printer);
3851 /******************************************************************************
3852 * EnumPortsW (WINSPOOL.@)
3854 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3855 LPDWORD bufneeded,LPDWORD bufreturned)
3857 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3858 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3862 /******************************************************************************
3863 * GetDefaultPrinterW (WINSPOOL.@)
3866 * This function must read the value from data 'device' of key
3867 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3869 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3873 WCHAR *buffer, *ptr;
3877 SetLastError(ERROR_INVALID_PARAMETER);
3881 /* make the buffer big enough for the stuff from the profile/registry,
3882 * the content must fit into the local buffer to compute the correct
3883 * size even if the extern buffer is too small or not given.
3884 * (20 for ,driver,port) */
3886 len = max(100, (insize + 20));
3887 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3889 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3891 SetLastError (ERROR_FILE_NOT_FOUND);
3895 TRACE("%s\n", debugstr_w(buffer));
3897 if ((ptr = strchrW(buffer, ',')) == NULL)
3899 SetLastError(ERROR_INVALID_NAME);
3905 *namesize = strlenW(buffer) + 1;
3906 if(!name || (*namesize > insize))
3908 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3912 strcpyW(name, buffer);
3915 HeapFree( GetProcessHeap(), 0, buffer);
3920 /******************************************************************************
3921 * GetDefaultPrinterA (WINSPOOL.@)
3923 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
3927 WCHAR *bufferW = NULL;
3931 SetLastError(ERROR_INVALID_PARAMETER);
3935 if(name && *namesize) {
3937 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
3940 if(!GetDefaultPrinterW( bufferW, namesize)) {
3945 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
3949 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
3952 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
3955 HeapFree( GetProcessHeap(), 0, bufferW);
3960 /******************************************************************************
3961 * SetPrinterDataExA (WINSPOOL.@)
3963 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
3964 LPCSTR pValueName, DWORD Type,
3965 LPBYTE pData, DWORD cbData)
3967 HKEY hkeyPrinter, hkeySubkey;
3970 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
3971 debugstr_a(pValueName), Type, pData, cbData);
3973 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
3977 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
3979 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
3980 RegCloseKey(hkeyPrinter);
3983 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
3984 RegCloseKey(hkeySubkey);
3985 RegCloseKey(hkeyPrinter);
3989 /******************************************************************************
3990 * SetPrinterDataExW (WINSPOOL.@)
3992 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
3993 LPCWSTR pValueName, DWORD Type,
3994 LPBYTE pData, DWORD cbData)
3996 HKEY hkeyPrinter, hkeySubkey;
3999 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4000 debugstr_w(pValueName), Type, pData, cbData);
4002 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4006 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4008 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4009 RegCloseKey(hkeyPrinter);
4012 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4013 RegCloseKey(hkeySubkey);
4014 RegCloseKey(hkeyPrinter);
4018 /******************************************************************************
4019 * SetPrinterDataA (WINSPOOL.@)
4021 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4022 LPBYTE pData, DWORD cbData)
4024 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4028 /******************************************************************************
4029 * SetPrinterDataW (WINSPOOL.@)
4031 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4032 LPBYTE pData, DWORD cbData)
4034 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4038 /******************************************************************************
4039 * GetPrinterDataExA (WINSPOOL.@)
4041 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4042 LPCSTR pValueName, LPDWORD pType,
4043 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4045 HKEY hkeyPrinter, hkeySubkey;
4048 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4049 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4052 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4056 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4058 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4059 RegCloseKey(hkeyPrinter);
4063 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4064 RegCloseKey(hkeySubkey);
4065 RegCloseKey(hkeyPrinter);
4069 /******************************************************************************
4070 * GetPrinterDataExW (WINSPOOL.@)
4072 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4073 LPCWSTR pValueName, LPDWORD pType,
4074 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4076 HKEY hkeyPrinter, hkeySubkey;
4079 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4080 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4083 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4087 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4089 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4090 RegCloseKey(hkeyPrinter);
4094 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4095 RegCloseKey(hkeySubkey);
4096 RegCloseKey(hkeyPrinter);
4100 /******************************************************************************
4101 * GetPrinterDataA (WINSPOOL.@)
4103 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4104 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4106 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4107 pData, nSize, pcbNeeded);
4110 /******************************************************************************
4111 * GetPrinterDataW (WINSPOOL.@)
4113 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4114 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4116 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4117 pData, nSize, pcbNeeded);
4120 /*******************************************************************************
4121 * EnumPrinterDataExW [WINSPOOL.@]
4123 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4124 LPBYTE pEnumValues, DWORD cbEnumValues,
4125 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4127 HKEY hkPrinter, hkSubKey;
4128 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4129 cbValueNameLen, cbMaxValueLen, cbValueLen,
4134 PPRINTER_ENUM_VALUESW ppev;
4136 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4138 if (pKeyName == NULL || *pKeyName == 0)
4139 return ERROR_INVALID_PARAMETER;
4141 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4142 if (ret != ERROR_SUCCESS)
4144 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4149 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4150 if (ret != ERROR_SUCCESS)
4152 r = RegCloseKey (hkPrinter);
4153 if (r != ERROR_SUCCESS)
4154 WARN ("RegCloseKey returned %li\n", r);
4155 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4156 debugstr_w (pKeyName), ret);
4160 ret = RegCloseKey (hkPrinter);
4161 if (ret != ERROR_SUCCESS)
4163 ERR ("RegCloseKey returned %li\n", ret);
4164 r = RegCloseKey (hkSubKey);
4165 if (r != ERROR_SUCCESS)
4166 WARN ("RegCloseKey returned %li\n", r);
4170 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4171 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4172 if (ret != ERROR_SUCCESS)
4174 r = RegCloseKey (hkSubKey);
4175 if (r != ERROR_SUCCESS)
4176 WARN ("RegCloseKey returned %li\n", r);
4177 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4181 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4182 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4184 if (cValues == 0) /* empty key */
4186 r = RegCloseKey (hkSubKey);
4187 if (r != ERROR_SUCCESS)
4188 WARN ("RegCloseKey returned %li\n", r);
4189 *pcbEnumValues = *pnEnumValues = 0;
4190 return ERROR_SUCCESS;
4193 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4195 hHeap = GetProcessHeap ();
4198 ERR ("GetProcessHeap failed\n");
4199 r = RegCloseKey (hkSubKey);
4200 if (r != ERROR_SUCCESS)
4201 WARN ("RegCloseKey returned %li\n", r);
4202 return ERROR_OUTOFMEMORY;
4205 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4206 if (lpValueName == NULL)
4208 ERR ("Failed to allocate %li bytes from process heap\n",
4209 cbMaxValueNameLen * sizeof (WCHAR));
4210 r = RegCloseKey (hkSubKey);
4211 if (r != ERROR_SUCCESS)
4212 WARN ("RegCloseKey returned %li\n", r);
4213 return ERROR_OUTOFMEMORY;
4216 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4217 if (lpValue == NULL)
4219 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4220 if (HeapFree (hHeap, 0, lpValueName) == 0)
4221 WARN ("HeapFree failed with code %li\n", GetLastError ());
4222 r = RegCloseKey (hkSubKey);
4223 if (r != ERROR_SUCCESS)
4224 WARN ("RegCloseKey returned %li\n", r);
4225 return ERROR_OUTOFMEMORY;
4228 TRACE ("pass 1: calculating buffer required for all names and values\n");
4230 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4232 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4234 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4236 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4237 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4238 NULL, NULL, lpValue, &cbValueLen);
4239 if (ret != ERROR_SUCCESS)
4241 if (HeapFree (hHeap, 0, lpValue) == 0)
4242 WARN ("HeapFree failed with code %li\n", GetLastError ());
4243 if (HeapFree (hHeap, 0, lpValueName) == 0)
4244 WARN ("HeapFree failed with code %li\n", GetLastError ());
4245 r = RegCloseKey (hkSubKey);
4246 if (r != ERROR_SUCCESS)
4247 WARN ("RegCloseKey returned %li\n", r);
4248 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4252 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4253 debugstr_w (lpValueName), dwIndex,
4254 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4256 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4257 cbBufSize += cbValueLen;
4260 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4262 *pcbEnumValues = cbBufSize;
4263 *pnEnumValues = cValues;
4265 if (cbEnumValues < cbBufSize) /* buffer too small */
4267 if (HeapFree (hHeap, 0, lpValue) == 0)
4268 WARN ("HeapFree failed with code %li\n", GetLastError ());
4269 if (HeapFree (hHeap, 0, lpValueName) == 0)
4270 WARN ("HeapFree failed with code %li\n", GetLastError ());
4271 r = RegCloseKey (hkSubKey);
4272 if (r != ERROR_SUCCESS)
4273 WARN ("RegCloseKey returned %li\n", r);
4274 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4275 return ERROR_MORE_DATA;
4278 TRACE ("pass 2: copying all names and values to buffer\n");
4280 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4281 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4283 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4285 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4286 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4287 NULL, &dwType, lpValue, &cbValueLen);
4288 if (ret != ERROR_SUCCESS)
4290 if (HeapFree (hHeap, 0, lpValue) == 0)
4291 WARN ("HeapFree failed with code %li\n", GetLastError ());
4292 if (HeapFree (hHeap, 0, lpValueName) == 0)
4293 WARN ("HeapFree failed with code %li\n", GetLastError ());
4294 r = RegCloseKey (hkSubKey);
4295 if (r != ERROR_SUCCESS)
4296 WARN ("RegCloseKey returned %li\n", r);
4297 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4301 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4302 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4303 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4304 pEnumValues += cbValueNameLen;
4306 /* return # of *bytes* (including trailing \0), not # of chars */
4307 ppev[dwIndex].cbValueName = cbValueNameLen;
4309 ppev[dwIndex].dwType = dwType;
4311 memcpy (pEnumValues, lpValue, cbValueLen);
4312 ppev[dwIndex].pData = pEnumValues;
4313 pEnumValues += cbValueLen;
4315 ppev[dwIndex].cbData = cbValueLen;
4317 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4318 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4321 if (HeapFree (hHeap, 0, lpValue) == 0)
4323 ret = GetLastError ();
4324 ERR ("HeapFree failed with code %li\n", ret);
4325 if (HeapFree (hHeap, 0, lpValueName) == 0)
4326 WARN ("HeapFree failed with code %li\n", GetLastError ());
4327 r = RegCloseKey (hkSubKey);
4328 if (r != ERROR_SUCCESS)
4329 WARN ("RegCloseKey returned %li\n", r);
4333 if (HeapFree (hHeap, 0, lpValueName) == 0)
4335 ret = GetLastError ();
4336 ERR ("HeapFree failed with code %li\n", ret);
4337 r = RegCloseKey (hkSubKey);
4338 if (r != ERROR_SUCCESS)
4339 WARN ("RegCloseKey returned %li\n", r);
4343 ret = RegCloseKey (hkSubKey);
4344 if (ret != ERROR_SUCCESS)
4346 ERR ("RegCloseKey returned %li\n", ret);
4350 return ERROR_SUCCESS;
4353 /*******************************************************************************
4354 * EnumPrinterDataExA [WINSPOOL.@]
4356 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4357 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4358 * what Windows 2000 SP1 does.
4361 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4362 LPBYTE pEnumValues, DWORD cbEnumValues,
4363 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4367 DWORD ret, dwIndex, dwBufSize;
4371 TRACE ("%p %s\n", hPrinter, pKeyName);
4373 if (pKeyName == NULL || *pKeyName == 0)
4374 return ERROR_INVALID_PARAMETER;
4376 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4379 ret = GetLastError ();
4380 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4384 hHeap = GetProcessHeap ();
4387 ERR ("GetProcessHeap failed\n");
4388 return ERROR_OUTOFMEMORY;
4391 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4392 if (pKeyNameW == NULL)
4394 ERR ("Failed to allocate %li bytes from process heap\n",
4395 (LONG) len * sizeof (WCHAR));
4396 return ERROR_OUTOFMEMORY;
4399 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4401 ret = GetLastError ();
4402 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4403 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4404 WARN ("HeapFree failed with code %li\n", GetLastError ());
4408 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4409 pcbEnumValues, pnEnumValues);
4410 if (ret != ERROR_SUCCESS)
4412 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4413 WARN ("HeapFree failed with code %li\n", GetLastError ());
4414 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4418 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4420 ret = GetLastError ();
4421 ERR ("HeapFree failed with code %li\n", ret);
4425 if (*pnEnumValues == 0) /* empty key */
4426 return ERROR_SUCCESS;
4429 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4431 PPRINTER_ENUM_VALUESW ppev =
4432 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4434 if (dwBufSize < ppev->cbValueName)
4435 dwBufSize = ppev->cbValueName;
4437 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4438 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4439 dwBufSize = ppev->cbData;
4442 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4444 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4445 if (pBuffer == NULL)
4447 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4448 return ERROR_OUTOFMEMORY;
4451 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4453 PPRINTER_ENUM_VALUESW ppev =
4454 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4456 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4457 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4461 ret = GetLastError ();
4462 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4463 if (HeapFree (hHeap, 0, pBuffer) == 0)
4464 WARN ("HeapFree failed with code %li\n", GetLastError ());
4468 memcpy (ppev->pValueName, pBuffer, len);
4470 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4472 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4473 ppev->dwType != REG_MULTI_SZ)
4476 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4477 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4480 ret = GetLastError ();
4481 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4482 if (HeapFree (hHeap, 0, pBuffer) == 0)
4483 WARN ("HeapFree failed with code %li\n", GetLastError ());
4487 memcpy (ppev->pData, pBuffer, len);
4489 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4490 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4493 if (HeapFree (hHeap, 0, pBuffer) == 0)
4495 ret = GetLastError ();
4496 ERR ("HeapFree failed with code %li\n", ret);
4500 return ERROR_SUCCESS;
4503 /******************************************************************************
4504 * AbortPrinter (WINSPOOL.@)
4506 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4508 FIXME("(%p), stub!\n", hPrinter);
4512 /******************************************************************************
4513 * AddPortA (WINSPOOL.@)
4515 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4517 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4521 /******************************************************************************
4522 * AddPortW (WINSPOOL.@)
4524 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4526 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4530 /******************************************************************************
4531 * AddPortExA (WINSPOOL.@)
4533 * Adds a print spooler port without presenting a user interface.
4535 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4537 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4538 lpBuffer, debugstr_a(lpMonitorName));
4542 /******************************************************************************
4543 * AddPortExW (WINSPOOL.@)
4547 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4549 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4550 lpBuffer, debugstr_w(lpMonitorName));
4554 /******************************************************************************
4555 * AddPrinterConnectionA (WINSPOOL.@)
4557 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4559 FIXME("%s\n", debugstr_a(pName));
4563 /******************************************************************************
4564 * AddPrinterConnectionW (WINSPOOL.@)
4566 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4568 FIXME("%s\n", debugstr_w(pName));
4572 /******************************************************************************
4573 * AddPrinterDriverExW (WINSPOOL.@)
4575 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4576 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4578 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4579 Level, pDriverInfo, dwFileCopyFlags);
4580 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4584 /******************************************************************************
4585 * AddPrinterDriverExA (WINSPOOL.@)
4587 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4588 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4590 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4591 Level, pDriverInfo, dwFileCopyFlags);
4592 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4596 /******************************************************************************
4597 * ConfigurePortA (WINSPOOL.@)
4599 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4601 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4605 /******************************************************************************
4606 * ConfigurePortW (WINSPOOL.@)
4608 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4610 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4614 /******************************************************************************
4615 * ConnectToPrinterDlg (WINSPOOL.@)
4617 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4619 FIXME("%p %lx\n", hWnd, Flags);
4623 /******************************************************************************
4624 * DeletePrinterConnectionA (WINSPOOL.@)
4626 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4628 FIXME("%s\n", debugstr_a(pName));
4632 /******************************************************************************
4633 * DeletePrinterConnectionW (WINSPOOL.@)
4635 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4637 FIXME("%s\n", debugstr_w(pName));
4641 /******************************************************************************
4642 * DeletePrinterDriverExW (WINSPOOL.@)
4644 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4645 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4647 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4648 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4652 /******************************************************************************
4653 * DeletePrinterDriverExA (WINSPOOL.@)
4655 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4656 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4658 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4659 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4663 /******************************************************************************
4664 * DeletePrinterDataExW (WINSPOOL.@)
4666 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4669 FIXME("%p %s %s\n", hPrinter,
4670 debugstr_w(pKeyName), debugstr_w(pValueName));
4671 return ERROR_INVALID_PARAMETER;
4674 /******************************************************************************
4675 * DeletePrinterDataExA (WINSPOOL.@)
4677 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4680 FIXME("%p %s %s\n", hPrinter,
4681 debugstr_a(pKeyName), debugstr_a(pValueName));
4682 return ERROR_INVALID_PARAMETER;
4685 /******************************************************************************
4686 * DeletePrintProcessorA (WINSPOOL.@)
4688 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4690 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4691 debugstr_a(pPrintProcessorName));
4695 /******************************************************************************
4696 * DeletePrintProcessorW (WINSPOOL.@)
4698 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4700 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4701 debugstr_w(pPrintProcessorName));
4705 /******************************************************************************
4706 * DeletePrintProvidorA (WINSPOOL.@)
4708 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4710 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4711 debugstr_a(pPrintProviderName));
4715 /******************************************************************************
4716 * DeletePrintProvidorW (WINSPOOL.@)
4718 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4720 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4721 debugstr_w(pPrintProviderName));
4725 /******************************************************************************
4726 * EnumFormsA (WINSPOOL.@)
4728 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4729 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4731 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4735 /******************************************************************************
4736 * EnumFormsW (WINSPOOL.@)
4738 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4739 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4741 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4745 /*****************************************************************************
4746 * EnumMonitorsA [WINSPOOL.@]
4749 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4750 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4752 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4753 cbBuf, pcbNeeded, pcReturned);
4754 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4758 /*****************************************************************************
4759 * EnumMonitorsW [WINSPOOL.@]
4762 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4763 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4765 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4766 cbBuf, pcbNeeded, pcReturned);
4767 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4771 /******************************************************************************
4772 * XcvDataW (WINSPOOL.@)
4775 * There doesn't seem to be an A version...
4777 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4778 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4779 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4781 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4782 pInputData, cbInputData, pOutputData,
4783 cbOutputData, pcbOutputNeeded, pdwStatus);
4787 /*****************************************************************************
4788 * EnumPrinterDataA [WINSPOOL.@]
4791 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4792 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4793 DWORD cbData, LPDWORD pcbData )
4795 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4796 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4797 return ERROR_NO_MORE_ITEMS;
4800 /*****************************************************************************
4801 * EnumPrinterDataW [WINSPOOL.@]
4804 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4805 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4806 DWORD cbData, LPDWORD pcbData )
4808 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4809 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4810 return ERROR_NO_MORE_ITEMS;
4813 /*****************************************************************************
4814 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4817 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4818 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4819 LPDWORD pcbNeeded, LPDWORD pcReturned)
4821 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4822 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4823 pcbNeeded, pcReturned);
4827 /*****************************************************************************
4828 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4831 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4832 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4833 LPDWORD pcbNeeded, LPDWORD pcReturned)
4835 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4836 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4837 pcbNeeded, pcReturned);
4841 /*****************************************************************************
4842 * EnumPrintProcessorsA [WINSPOOL.@]
4845 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4846 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4848 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4849 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
4853 /*****************************************************************************
4854 * EnumPrintProcessorsW [WINSPOOL.@]
4857 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4858 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4860 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4861 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
4862 cbBuf, pcbNeeded, pcbReturned);
4866 /*****************************************************************************
4867 * ExtDeviceMode [WINSPOOL.@]
4870 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
4871 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
4874 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
4875 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
4876 debugstr_a(pProfile), fMode);
4880 /*****************************************************************************
4881 * FindClosePrinterChangeNotification [WINSPOOL.@]
4884 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
4886 FIXME("Stub: %p\n", hChange);
4890 /*****************************************************************************
4891 * FindFirstPrinterChangeNotification [WINSPOOL.@]
4894 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
4895 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
4897 FIXME("Stub: %p %lx %lx %p\n",
4898 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
4899 return INVALID_HANDLE_VALUE;
4902 /*****************************************************************************
4903 * FindNextPrinterChangeNotification [WINSPOOL.@]
4906 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
4907 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
4909 FIXME("Stub: %p %p %p %p\n",
4910 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
4914 /*****************************************************************************
4915 * FreePrinterNotifyInfo [WINSPOOL.@]
4918 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
4920 FIXME("Stub: %p\n", pPrinterNotifyInfo);
4924 /*****************************************************************************
4927 * Copies a unicode string into a buffer. The buffer will either contain unicode or
4928 * ansi depending on the unicode parameter.
4930 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
4940 *size = (strlenW(str) + 1) * sizeof(WCHAR);
4943 memcpy(ptr, str, *size);
4950 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
4953 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
4960 /*****************************************************************************
4963 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
4964 LPDWORD pcbNeeded, BOOL unicode)
4966 DWORD size, left = cbBuf;
4967 BOOL space = (cbBuf > 0);
4974 ji1->JobId = job->job_id;
4977 string_to_buf(job->document_title, ptr, left, &size, unicode);
4978 if(space && size <= left)
4980 ji1->pDocument = (LPWSTR)ptr;
4991 /*****************************************************************************
4994 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
4995 LPDWORD pcbNeeded, BOOL unicode)
4997 DWORD size, left = cbBuf;
4998 BOOL space = (cbBuf > 0);
5005 ji2->JobId = job->job_id;
5008 string_to_buf(job->document_title, ptr, left, &size, unicode);
5009 if(space && size <= left)
5011 ji2->pDocument = (LPWSTR)ptr;
5022 /*****************************************************************************
5025 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5026 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5029 DWORD needed = 0, size;
5033 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5035 EnterCriticalSection(&printer_handles_cs);
5036 job = get_job(hPrinter, JobId);
5043 size = sizeof(JOB_INFO_1W);
5048 memset(pJob, 0, size);
5052 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5057 size = sizeof(JOB_INFO_2W);
5062 memset(pJob, 0, size);
5066 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5071 size = sizeof(JOB_INFO_3);
5075 memset(pJob, 0, size);
5084 SetLastError(ERROR_INVALID_LEVEL);
5088 *pcbNeeded = needed;
5090 LeaveCriticalSection(&printer_handles_cs);
5094 /*****************************************************************************
5095 * GetJobA [WINSPOOL.@]
5098 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5099 DWORD cbBuf, LPDWORD pcbNeeded)
5101 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5104 /*****************************************************************************
5105 * GetJobW [WINSPOOL.@]
5108 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5109 DWORD cbBuf, LPDWORD pcbNeeded)
5111 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5114 /*****************************************************************************
5117 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5119 char *unixname, *queue, *cmd;
5120 char fmt[] = "lpr -P%s %s";
5123 if(!(unixname = wine_get_unix_file_name(filename)))
5126 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5127 queue = HeapAlloc(GetProcessHeap(), 0, len);
5128 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5130 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5131 sprintf(cmd, fmt, queue, unixname);
5133 TRACE("printing with: %s\n", cmd);
5136 HeapFree(GetProcessHeap(), 0, cmd);
5137 HeapFree(GetProcessHeap(), 0, queue);
5138 HeapFree(GetProcessHeap(), 0, unixname);
5142 /*****************************************************************************
5145 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5147 #if HAVE_CUPS_CUPS_H
5150 char *unixname, *queue, *doc_titleA;
5154 if(!(unixname = wine_get_unix_file_name(filename)))
5157 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5158 queue = HeapAlloc(GetProcessHeap(), 0, len);
5159 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5161 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5162 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5163 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5165 TRACE("printing via cups\n");
5166 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5167 HeapFree(GetProcessHeap(), 0, doc_titleA);
5168 HeapFree(GetProcessHeap(), 0, queue);
5169 HeapFree(GetProcessHeap(), 0, unixname);
5175 return schedule_lpr(printer_name, filename);
5179 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5186 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5190 if(HIWORD(wparam) == BN_CLICKED)
5192 if(LOWORD(wparam) == IDOK)
5195 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5198 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5199 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5201 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5203 WCHAR caption[200], message[200];
5206 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5207 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5208 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5209 if(mb_ret == IDCANCEL)
5211 HeapFree(GetProcessHeap(), 0, filename);
5215 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5216 if(hf == INVALID_HANDLE_VALUE)
5218 WCHAR caption[200], message[200];
5220 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5221 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5222 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5223 HeapFree(GetProcessHeap(), 0, filename);
5227 DeleteFileW(filename);
5228 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5230 EndDialog(hwnd, IDOK);
5233 if(LOWORD(wparam) == IDCANCEL)
5235 EndDialog(hwnd, IDCANCEL);
5244 /*****************************************************************************
5247 static BOOL get_filename(LPWSTR *filename)
5249 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5250 file_dlg_proc, (LPARAM)filename) == IDOK;
5253 /*****************************************************************************
5256 static BOOL schedule_file(LPCWSTR filename)
5258 LPWSTR output = NULL;
5260 if(get_filename(&output))
5262 TRACE("copy to %s\n", debugstr_w(output));
5263 CopyFileW(filename, output, FALSE);
5264 HeapFree(GetProcessHeap(), 0, output);
5270 /*****************************************************************************
5273 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5276 char *unixname, *cmdA;
5278 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5282 if(!(unixname = wine_get_unix_file_name(filename)))
5285 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5286 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5287 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5289 TRACE("printing with: %s\n", cmdA);
5291 if((file_fd = open(unixname, O_RDONLY)) == -1)
5296 ERR("pipe() failed!\n");
5306 /* reset signals that we previously set to SIG_IGN */
5307 signal(SIGPIPE, SIG_DFL);
5308 signal(SIGCHLD, SIG_DFL);
5314 while((no_read = read(file_fd, buf, sizeof(buf))))
5315 write(fds[1], buf, no_read);
5320 if(file_fd != -1) close(file_fd);
5321 if(fds[0] != -1) close(fds[0]);
5322 if(fds[1] != -1) close(fds[1]);
5324 HeapFree(GetProcessHeap(), 0, cmdA);
5325 HeapFree(GetProcessHeap(), 0, unixname);
5332 /*****************************************************************************
5335 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
5337 int in_fd, out_fd, no_read;
5340 char *unixname, *outputA;
5343 if(!(unixname = wine_get_unix_file_name(filename)))
5346 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
5347 outputA = HeapAlloc(GetProcessHeap(), 0, len);
5348 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
5350 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5351 in_fd = open(unixname, O_RDONLY);
5352 if(out_fd == -1 || in_fd == -1)
5355 while((no_read = read(in_fd, buf, sizeof(buf))))
5356 write(out_fd, buf, no_read);
5360 if(in_fd != -1) close(in_fd);
5361 if(out_fd != -1) close(out_fd);
5362 HeapFree(GetProcessHeap(), 0, outputA);
5363 HeapFree(GetProcessHeap(), 0, unixname);
5367 /*****************************************************************************
5368 * ScheduleJob [WINSPOOL.@]
5371 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
5373 opened_printer_t *printer;
5375 struct list *cursor, *cursor2;
5377 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
5378 EnterCriticalSection(&printer_handles_cs);
5379 printer = get_opened_printer(hPrinter);
5383 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
5385 job_t *job = LIST_ENTRY(cursor, job_t, entry);
5388 if(job->job_id != dwJobID) continue;
5390 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
5391 if(hf != INVALID_HANDLE_VALUE)
5393 PRINTER_INFO_5W *pi5;
5397 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5398 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5400 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
5401 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
5402 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
5403 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
5404 debugstr_w(pi5->pPortName));
5408 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5409 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
5411 DWORD type, count = sizeof(output);
5412 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
5415 if(output[0] == '|')
5417 schedule_pipe(output + 1, job->filename);
5421 schedule_unixfile(output, job->filename);
5423 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
5425 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
5427 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
5429 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
5431 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
5433 schedule_file(job->filename);
5437 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
5439 HeapFree(GetProcessHeap(), 0, pi5);
5441 DeleteFileW(job->filename);
5443 list_remove(cursor);
5444 HeapFree(GetProcessHeap(), 0, job->document_title);
5445 HeapFree(GetProcessHeap(), 0, job->filename);
5446 HeapFree(GetProcessHeap(), 0, job);
5451 LeaveCriticalSection(&printer_handles_cs);
5455 /*****************************************************************************
5456 * StartDocDlgA [WINSPOOL.@]
5458 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
5460 UNICODE_STRING usBuffer;
5465 docW.cbSize = sizeof(docW);
5466 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
5467 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
5468 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
5469 docW.fwType = doc->fwType;
5471 retW = StartDocDlgW(hPrinter, &docW);
5475 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
5476 ret = HeapAlloc(GetProcessHeap(), 0, len);
5477 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
5478 HeapFree(GetProcessHeap(), 0, retW);
5481 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
5482 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
5483 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
5488 /*****************************************************************************
5489 * StartDocDlgW [WINSPOOL.@]
5491 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5492 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5493 * port is "FILE:". Also returns the full path if passed a relative path.
5495 * The caller should free the returned string from the process heap.
5497 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
5502 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
5504 PRINTER_INFO_5W *pi5;
5505 GetPrinterW(hPrinter, 5, NULL, 0, &len);
5506 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
5508 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
5509 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
5510 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
5512 HeapFree(GetProcessHeap(), 0, pi5);
5515 HeapFree(GetProcessHeap(), 0, pi5);
5518 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
5521 get_filename(&name);
5524 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
5526 HeapFree(GetProcessHeap(), 0, name);
5529 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5530 GetFullPathNameW(name, len, ret, NULL);
5531 HeapFree(GetProcessHeap(), 0, name);
5536 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
5539 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5540 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
5542 attr = GetFileAttributesW(ret);
5543 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
5545 HeapFree(GetProcessHeap(), 0, ret);