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.@]
1125 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1127 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1128 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1132 /******************************************************************************
1133 * AddMonitorW [WINSPOOL.@]
1135 * Install a Printmonitor
1138 * pName [I] Servername or NULL (local Computer)
1139 * Level [I] Structure-Level (Must be 2)
1140 * pMonitors [I] PTR to MONITOR_INFO_2
1147 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1153 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1155 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1156 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1160 /******************************************************************
1161 * DeletePrinterDriverA [WINSPOOL.@]
1165 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1167 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1168 debugstr_a(pDriverName));
1169 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1173 /******************************************************************
1174 * DeletePrinterDriverW [WINSPOOL.@]
1178 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1180 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1181 debugstr_w(pDriverName));
1182 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1186 /******************************************************************
1187 * DeleteMonitorA [WINSPOOL.@]
1189 * See DeleteMonitorW.
1193 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1195 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1196 debugstr_a(pMonitorName));
1197 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1201 /******************************************************************
1202 * DeleteMonitorW [WINSPOOL.@]
1204 * Delete a specific Printmonitor from a Printing-Environment
1207 * pName [I] Servername or NULL (local Computer)
1208 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1209 * pMonitorName [I] Name of the Monitor, that should be deleted
1220 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1222 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1223 debugstr_w(pMonitorName));
1224 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1228 /******************************************************************
1229 * DeletePortA [WINSPOOL.@]
1235 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1237 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1238 debugstr_a(pPortName));
1239 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1243 /******************************************************************
1244 * DeletePortW [WINSPOOL.@]
1246 * Delete a specific Port
1249 * pName [I] Servername or NULL (local Computer)
1250 * hWnd [I] Handle to parent Window for the Dialog-Box
1251 * pPortName [I] Name of the Port, that should be deleted
1262 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1264 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1265 debugstr_w(pPortName));
1266 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1270 /******************************************************************************
1271 * SetPrinterW [WINSPOOL.@]
1281 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1285 /******************************************************************************
1286 * WritePrinter [WINSPOOL.@]
1288 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1290 opened_printer_t *printer;
1293 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1295 EnterCriticalSection(&printer_handles_cs);
1296 printer = get_opened_printer(hPrinter);
1299 SetLastError(ERROR_INVALID_HANDLE);
1305 SetLastError(ERROR_SPL_NO_STARTDOC);
1309 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1311 LeaveCriticalSection(&printer_handles_cs);
1315 /*****************************************************************************
1316 * AddFormA [WINSPOOL.@]
1318 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1320 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1324 /*****************************************************************************
1325 * AddFormW [WINSPOOL.@]
1327 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1329 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1333 /*****************************************************************************
1334 * AddJobA [WINSPOOL.@]
1336 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1339 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1343 SetLastError(ERROR_INVALID_LEVEL);
1347 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1350 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1351 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1352 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1353 if(*pcbNeeded > cbBuf) {
1354 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1357 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1358 addjobA->JobId = addjobW->JobId;
1359 addjobA->Path = (char *)(addjobA + 1);
1360 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1366 /*****************************************************************************
1367 * AddJobW [WINSPOOL.@]
1369 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1371 opened_printer_t *printer;
1374 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1375 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1376 WCHAR path[MAX_PATH], filename[MAX_PATH];
1378 ADDJOB_INFO_1W *addjob;
1380 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1382 EnterCriticalSection(&printer_handles_cs);
1384 printer = get_opened_printer(hPrinter);
1387 SetLastError(ERROR_INVALID_HANDLE);
1392 SetLastError(ERROR_INVALID_LEVEL);
1396 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1400 job->job_id = InterlockedIncrement(&next_job_id);
1402 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1403 if(path[len - 1] != '\\')
1405 memcpy(path + len, spool_path, sizeof(spool_path));
1406 sprintfW(filename, fmtW, path, job->job_id);
1408 len = strlenW(filename);
1409 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1410 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1411 job->document_title = strdupW(default_doc_title);
1412 list_add_tail(&printer->queue->jobs, &job->entry);
1414 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1415 if(*pcbNeeded <= cbBuf) {
1416 addjob = (ADDJOB_INFO_1W*)pData;
1417 addjob->JobId = job->job_id;
1418 addjob->Path = (WCHAR *)(addjob + 1);
1419 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1422 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1425 LeaveCriticalSection(&printer_handles_cs);
1429 /*****************************************************************************
1430 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1432 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1433 DWORD level, LPBYTE Info,
1434 DWORD cbBuf, LPDWORD needed)
1436 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1437 level, Info, cbBuf);
1441 /*****************************************************************************
1442 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1444 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1445 DWORD level, LPBYTE Info,
1446 DWORD cbBuf, LPDWORD needed)
1448 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1449 level, Info, cbBuf);
1453 /*****************************************************************************
1454 * WINSPOOL_OpenDriverReg [internal]
1456 * opens the registry for the printer drivers depending on the given input
1457 * variable pEnvironment
1460 * the opened hkey on success
1463 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1465 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1466 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1468 LPWSTR lpKey, buffer = NULL;
1472 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1476 pEnvW = pEnvironment;
1478 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1479 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1480 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1485 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1487 if(!GetVersionExW( &ver))
1490 switch (ver.dwPlatformId) {
1491 case VER_PLATFORM_WIN32s:
1492 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1494 case VER_PLATFORM_WIN32_NT:
1501 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1504 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1505 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1506 wsprintfW( lpKey, DriversW, pEnvW);
1508 TRACE("%s\n", debugstr_w(lpKey));
1510 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1513 HeapFree( GetProcessHeap(), 0, buffer);
1514 HeapFree( GetProcessHeap(), 0, lpKey);
1519 /*****************************************************************************
1520 * AddPrinterW [WINSPOOL.@]
1522 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1524 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1528 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1531 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1534 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1535 SetLastError(ERROR_INVALID_PARAMETER);
1539 ERR("Level = %ld, unsupported!\n", Level);
1540 SetLastError(ERROR_INVALID_LEVEL);
1543 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1544 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1545 debugstr_w(pi->pPrinterName)
1547 SetLastError(ERROR_INVALID_LEVEL);
1551 SetLastError(ERROR_INVALID_PARAMETER);
1554 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1556 ERR("Can't create Printers key\n");
1559 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1560 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1561 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1562 RegCloseKey(hkeyPrinter);
1563 RegCloseKey(hkeyPrinters);
1566 RegCloseKey(hkeyPrinter);
1568 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1570 ERR("Can't create Drivers key\n");
1571 RegCloseKey(hkeyPrinters);
1574 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1576 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1577 RegCloseKey(hkeyPrinters);
1578 RegCloseKey(hkeyDrivers);
1579 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1582 RegCloseKey(hkeyDriver);
1583 RegCloseKey(hkeyDrivers);
1585 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1586 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1587 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1588 RegCloseKey(hkeyPrinters);
1592 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1594 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1595 SetLastError(ERROR_INVALID_PRINTER_NAME);
1596 RegCloseKey(hkeyPrinters);
1599 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1600 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1601 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1603 /* See if we can load the driver. We may need the devmode structure anyway
1606 * Note that DocumentPropertiesW will briefly try to open the printer we
1607 * just create to find a DEVMODEA struct (it will use the WINEPS default
1608 * one in case it is not there, so we are ok).
1610 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1613 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1614 size = sizeof(DEVMODEW);
1620 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1621 ZeroMemory(dmW,size);
1623 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1625 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1626 HeapFree(GetProcessHeap(),0,dmW);
1631 /* set devmode to printer name */
1632 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1636 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1637 and we support these drivers. NT writes DEVMODEW so somehow
1638 we'll need to distinguish between these when we support NT
1642 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1643 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1644 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1645 HeapFree(GetProcessHeap(), 0, dmA);
1647 HeapFree(GetProcessHeap(), 0, dmW);
1649 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1650 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1651 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1652 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1654 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1655 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1656 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1657 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1658 (LPBYTE)&pi->Priority, sizeof(DWORD));
1659 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1660 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1661 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1662 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1663 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1664 (LPBYTE)&pi->Status, sizeof(DWORD));
1665 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1666 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1668 RegCloseKey(hkeyPrinter);
1669 RegCloseKey(hkeyPrinters);
1670 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1671 ERR("OpenPrinter failing\n");
1677 /*****************************************************************************
1678 * AddPrinterA [WINSPOOL.@]
1680 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1682 UNICODE_STRING pNameW;
1684 PRINTER_INFO_2W *piW;
1685 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1688 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1690 ERR("Level = %ld, unsupported!\n", Level);
1691 SetLastError(ERROR_INVALID_LEVEL);
1694 pwstrNameW = asciitounicode(&pNameW,pName);
1695 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1697 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1699 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1700 RtlFreeUnicodeString(&pNameW);
1705 /*****************************************************************************
1706 * ClosePrinter [WINSPOOL.@]
1708 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1710 UINT_PTR i = (UINT_PTR)hPrinter;
1711 opened_printer_t *printer = NULL;
1714 TRACE("Handle %p\n", hPrinter);
1716 EnterCriticalSection(&printer_handles_cs);
1718 if ((i > 0) && (i <= nb_printer_handles))
1719 printer = printer_handles[i - 1];
1723 struct list *cursor, *cursor2;
1726 EndDocPrinter(hPrinter);
1728 if(InterlockedDecrement(&printer->queue->ref) == 0)
1730 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
1732 job_t *job = LIST_ENTRY(cursor, job_t, entry);
1733 ScheduleJob(hPrinter, job->job_id);
1735 HeapFree(GetProcessHeap(), 0, printer->queue);
1737 HeapFree(GetProcessHeap(), 0, printer->name);
1738 HeapFree(GetProcessHeap(), 0, printer);
1739 printer_handles[i - 1] = NULL;
1742 LeaveCriticalSection(&printer_handles_cs);
1746 /*****************************************************************************
1747 * DeleteFormA [WINSPOOL.@]
1749 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1751 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1755 /*****************************************************************************
1756 * DeleteFormW [WINSPOOL.@]
1758 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1760 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1764 /*****************************************************************************
1765 * WINSPOOL_SHRegDeleteKey
1767 * Recursively delete subkeys.
1768 * Cut & paste from shlwapi.
1771 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1773 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1774 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1777 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1780 /* Find how many subkeys there are */
1781 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1782 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1786 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1787 /* Name too big: alloc a buffer for it */
1788 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1791 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1794 /* Recursively delete all the subkeys */
1795 for(i = 0; i < dwKeyCount && !dwRet; i++)
1797 dwSize = dwMaxSubkeyLen;
1798 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1800 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1803 if (lpszName != szNameBuf)
1804 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1808 RegCloseKey(hSubKey);
1810 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1815 /*****************************************************************************
1816 * DeletePrinter [WINSPOOL.@]
1818 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1820 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1821 HKEY hkeyPrinters, hkey;
1824 SetLastError(ERROR_INVALID_HANDLE);
1827 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1828 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1829 RegCloseKey(hkeyPrinters);
1831 WriteProfileStringW(devicesW, lpNameW, NULL);
1832 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1833 RegDeleteValueW(hkey, lpNameW);
1839 /*****************************************************************************
1840 * SetPrinterA [WINSPOOL.@]
1842 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1845 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1849 /*****************************************************************************
1850 * SetJobA [WINSPOOL.@]
1852 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1853 LPBYTE pJob, DWORD Command)
1857 UNICODE_STRING usBuffer;
1859 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
1861 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1862 are all ignored by SetJob, so we don't bother copying them */
1870 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
1871 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
1873 JobW = (LPBYTE)info1W;
1874 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
1875 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
1876 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
1877 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
1878 info1W->Status = info1A->Status;
1879 info1W->Priority = info1A->Priority;
1880 info1W->Position = info1A->Position;
1881 info1W->PagesPrinted = info1A->PagesPrinted;
1886 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
1887 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
1889 JobW = (LPBYTE)info2W;
1890 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
1891 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
1892 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
1893 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
1894 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
1895 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
1896 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
1897 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
1898 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
1899 info2W->Status = info2A->Status;
1900 info2W->Priority = info2A->Priority;
1901 info2W->Position = info2A->Position;
1902 info2W->StartTime = info2A->StartTime;
1903 info2W->UntilTime = info2A->UntilTime;
1904 info2W->PagesPrinted = info2A->PagesPrinted;
1908 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
1909 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
1912 SetLastError(ERROR_INVALID_LEVEL);
1916 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
1922 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
1923 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
1924 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
1925 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
1926 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
1931 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
1932 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
1933 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
1934 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
1935 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
1936 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
1937 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
1938 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
1939 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
1943 HeapFree(GetProcessHeap(), 0, JobW);
1948 /*****************************************************************************
1949 * SetJobW [WINSPOOL.@]
1951 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
1952 LPBYTE pJob, DWORD Command)
1957 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
1958 FIXME("Ignoring everything other than document title\n");
1960 EnterCriticalSection(&printer_handles_cs);
1961 job = get_job(hPrinter, JobId);
1971 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
1972 HeapFree(GetProcessHeap(), 0, job->document_title);
1973 job->document_title = strdupW(info1->pDocument);
1978 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
1979 HeapFree(GetProcessHeap(), 0, job->document_title);
1980 job->document_title = strdupW(info2->pDocument);
1986 SetLastError(ERROR_INVALID_LEVEL);
1991 LeaveCriticalSection(&printer_handles_cs);
1995 /*****************************************************************************
1996 * EndDocPrinter [WINSPOOL.@]
1998 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2000 opened_printer_t *printer;
2002 TRACE("(%p)\n", hPrinter);
2004 EnterCriticalSection(&printer_handles_cs);
2006 printer = get_opened_printer(hPrinter);
2009 SetLastError(ERROR_INVALID_HANDLE);
2015 SetLastError(ERROR_SPL_NO_STARTDOC);
2019 CloseHandle(printer->doc->hf);
2020 ScheduleJob(hPrinter, printer->doc->job_id);
2021 HeapFree(GetProcessHeap(), 0, printer->doc);
2022 printer->doc = NULL;
2025 LeaveCriticalSection(&printer_handles_cs);
2029 /*****************************************************************************
2030 * EndPagePrinter [WINSPOOL.@]
2032 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2034 FIXME("(%p): stub\n", hPrinter);
2038 /*****************************************************************************
2039 * StartDocPrinterA [WINSPOOL.@]
2041 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2043 UNICODE_STRING usBuffer;
2045 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2048 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2049 or one (DOC_INFO_3) extra DWORDs */
2053 doc2W.JobId = doc2->JobId;
2056 doc2W.dwMode = doc2->dwMode;
2059 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2060 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2061 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2065 SetLastError(ERROR_INVALID_LEVEL);
2069 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2071 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2072 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2073 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2078 /*****************************************************************************
2079 * StartDocPrinterW [WINSPOOL.@]
2081 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2083 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2084 opened_printer_t *printer;
2085 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2086 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2087 JOB_INFO_1W job_info;
2088 DWORD needed, ret = 0;
2092 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2093 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2094 debugstr_w(doc->pDatatype));
2096 if(Level < 1 || Level > 3)
2098 SetLastError(ERROR_INVALID_LEVEL);
2102 EnterCriticalSection(&printer_handles_cs);
2103 printer = get_opened_printer(hPrinter);
2106 SetLastError(ERROR_INVALID_HANDLE);
2112 SetLastError(ERROR_INVALID_PRINTER_STATE);
2116 /* Even if we're printing to a file we still add a print job, we'll
2117 just ignore the spool file name */
2119 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2121 ERR("AddJob failed gle %08lx\n", GetLastError());
2125 if(doc->pOutputFile)
2126 filename = doc->pOutputFile;
2128 filename = addjob->Path;
2130 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2131 if(hf == INVALID_HANDLE_VALUE)
2134 memset(&job_info, 0, sizeof(job_info));
2135 job_info.pDocument = doc->pDocName;
2136 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2138 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2139 printer->doc->hf = hf;
2140 ret = printer->doc->job_id = addjob->JobId;
2142 LeaveCriticalSection(&printer_handles_cs);
2147 /*****************************************************************************
2148 * StartPagePrinter [WINSPOOL.@]
2150 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2152 FIXME("(%p): stub\n", hPrinter);
2156 /*****************************************************************************
2157 * GetFormA [WINSPOOL.@]
2159 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2160 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2162 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2163 Level,pForm,cbBuf,pcbNeeded);
2167 /*****************************************************************************
2168 * GetFormW [WINSPOOL.@]
2170 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2171 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2173 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2174 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2178 /*****************************************************************************
2179 * SetFormA [WINSPOOL.@]
2181 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2184 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2188 /*****************************************************************************
2189 * SetFormW [WINSPOOL.@]
2191 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2194 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2198 /*****************************************************************************
2199 * ReadPrinter [WINSPOOL.@]
2201 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2202 LPDWORD pNoBytesRead)
2204 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2208 /*****************************************************************************
2209 * ResetPrinterA [WINSPOOL.@]
2211 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2213 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2217 /*****************************************************************************
2218 * ResetPrinterW [WINSPOOL.@]
2220 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2222 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2226 /*****************************************************************************
2227 * WINSPOOL_GetDWORDFromReg
2229 * Return DWORD associated with ValueName from hkey.
2231 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2233 DWORD sz = sizeof(DWORD), type, value = 0;
2236 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2238 if(ret != ERROR_SUCCESS) {
2239 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2242 if(type != REG_DWORD) {
2243 ERR("Got type %ld\n", type);
2249 /*****************************************************************************
2250 * WINSPOOL_GetStringFromReg
2252 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2253 * String is stored either as unicode or ascii.
2254 * Bit of a hack here to get the ValueName if we want ascii.
2256 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2257 DWORD buflen, DWORD *needed,
2260 DWORD sz = buflen, type;
2264 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2266 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2267 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2268 HeapFree(GetProcessHeap(),0,ValueNameA);
2270 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2271 WARN("Got ret = %ld\n", ret);
2279 /*****************************************************************************
2280 * WINSPOOL_GetDefaultDevMode
2282 * Get a default DevMode values for wineps.
2286 static void WINSPOOL_GetDefaultDevMode(
2288 DWORD buflen, DWORD *needed,
2292 static const char szwps[] = "wineps.drv";
2294 /* fill default DEVMODE - should be read from ppd... */
2295 ZeroMemory( &dm, sizeof(dm) );
2296 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2297 dm.dmSpecVersion = DM_SPECVERSION;
2298 dm.dmDriverVersion = 1;
2299 dm.dmSize = sizeof(DEVMODEA);
2300 dm.dmDriverExtra = 0;
2302 DM_ORIENTATION | DM_PAPERSIZE |
2303 DM_PAPERLENGTH | DM_PAPERWIDTH |
2306 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2307 DM_YRESOLUTION | DM_TTOPTION;
2309 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2310 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2311 dm.u1.s1.dmPaperLength = 2970;
2312 dm.u1.s1.dmPaperWidth = 2100;
2316 dm.dmDefaultSource = DMBIN_AUTO;
2317 dm.dmPrintQuality = DMRES_MEDIUM;
2320 dm.dmYResolution = 300; /* 300dpi */
2321 dm.dmTTOption = DMTT_BITMAP;
2324 /* dm.dmLogPixels */
2325 /* dm.dmBitsPerPel */
2326 /* dm.dmPelsWidth */
2327 /* dm.dmPelsHeight */
2328 /* dm.dmDisplayFlags */
2329 /* dm.dmDisplayFrequency */
2330 /* dm.dmICMMethod */
2331 /* dm.dmICMIntent */
2332 /* dm.dmMediaType */
2333 /* dm.dmDitherType */
2334 /* dm.dmReserved1 */
2335 /* dm.dmReserved2 */
2336 /* dm.dmPanningWidth */
2337 /* dm.dmPanningHeight */
2340 if(buflen >= sizeof(DEVMODEW)) {
2341 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2342 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2343 HeapFree(GetProcessHeap(),0,pdmW);
2345 *needed = sizeof(DEVMODEW);
2349 if(buflen >= sizeof(DEVMODEA)) {
2350 memcpy(ptr, &dm, sizeof(DEVMODEA));
2352 *needed = sizeof(DEVMODEA);
2356 /*****************************************************************************
2357 * WINSPOOL_GetDevModeFromReg
2359 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2360 * DevMode is stored either as unicode or ascii.
2362 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2364 DWORD buflen, DWORD *needed,
2367 DWORD sz = buflen, type;
2370 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2371 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2372 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2373 if (sz < sizeof(DEVMODEA))
2375 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2378 /* ensures that dmSize is not erratically bogus if registry is invalid */
2379 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2380 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2382 sz += (CCHDEVICENAME + CCHFORMNAME);
2384 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2385 memcpy(ptr, dmW, sz);
2386 HeapFree(GetProcessHeap(),0,dmW);
2393 /*********************************************************************
2394 * WINSPOOL_GetPrinter_2
2396 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2397 * The strings are either stored as unicode or ascii.
2399 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2400 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2403 DWORD size, left = cbBuf;
2404 BOOL space = (cbBuf > 0);
2409 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2411 if(space && size <= left) {
2412 pi2->pPrinterName = (LPWSTR)ptr;
2419 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2421 if(space && size <= left) {
2422 pi2->pShareName = (LPWSTR)ptr;
2429 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2431 if(space && size <= left) {
2432 pi2->pPortName = (LPWSTR)ptr;
2439 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2441 if(space && size <= left) {
2442 pi2->pDriverName = (LPWSTR)ptr;
2449 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2451 if(space && size <= left) {
2452 pi2->pComment = (LPWSTR)ptr;
2459 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2461 if(space && size <= left) {
2462 pi2->pLocation = (LPWSTR)ptr;
2469 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2471 if(space && size <= left) {
2472 pi2->pDevMode = (LPDEVMODEW)ptr;
2481 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2482 if(space && size <= left) {
2483 pi2->pDevMode = (LPDEVMODEW)ptr;
2490 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2492 if(space && size <= left) {
2493 pi2->pSepFile = (LPWSTR)ptr;
2500 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2502 if(space && size <= left) {
2503 pi2->pPrintProcessor = (LPWSTR)ptr;
2510 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2512 if(space && size <= left) {
2513 pi2->pDatatype = (LPWSTR)ptr;
2520 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2522 if(space && size <= left) {
2523 pi2->pParameters = (LPWSTR)ptr;
2531 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2532 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2533 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2534 "Default Priority");
2535 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2536 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2539 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2540 memset(pi2, 0, sizeof(*pi2));
2545 /*********************************************************************
2546 * WINSPOOL_GetPrinter_4
2548 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2550 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2551 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2554 DWORD size, left = cbBuf;
2555 BOOL space = (cbBuf > 0);
2560 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2562 if(space && size <= left) {
2563 pi4->pPrinterName = (LPWSTR)ptr;
2571 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2574 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2575 memset(pi4, 0, sizeof(*pi4));
2580 /*********************************************************************
2581 * WINSPOOL_GetPrinter_5
2583 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2585 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2586 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2589 DWORD size, left = cbBuf;
2590 BOOL space = (cbBuf > 0);
2595 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2597 if(space && size <= left) {
2598 pi5->pPrinterName = (LPWSTR)ptr;
2605 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2607 if(space && size <= left) {
2608 pi5->pPortName = (LPWSTR)ptr;
2616 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2617 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2619 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2623 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2624 memset(pi5, 0, sizeof(*pi5));
2629 /*****************************************************************************
2630 * WINSPOOL_GetPrinter
2632 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2633 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2634 * just a collection of pointers to strings.
2636 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2637 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2640 DWORD size, needed = 0;
2642 HKEY hkeyPrinter, hkeyPrinters;
2645 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2647 if (!(name = get_opened_printer_name(hPrinter))) {
2648 SetLastError(ERROR_INVALID_HANDLE);
2652 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2654 ERR("Can't create Printers key\n");
2657 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2659 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2660 RegCloseKey(hkeyPrinters);
2661 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2668 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2670 size = sizeof(PRINTER_INFO_2W);
2672 ptr = pPrinter + size;
2674 memset(pPrinter, 0, size);
2679 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2687 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2689 size = sizeof(PRINTER_INFO_4W);
2691 ptr = pPrinter + size;
2693 memset(pPrinter, 0, size);
2698 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2707 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2709 size = sizeof(PRINTER_INFO_5W);
2711 ptr = pPrinter + size;
2713 memset(pPrinter, 0, size);
2719 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2726 FIXME("Unimplemented level %ld\n", Level);
2727 SetLastError(ERROR_INVALID_LEVEL);
2728 RegCloseKey(hkeyPrinters);
2729 RegCloseKey(hkeyPrinter);
2733 RegCloseKey(hkeyPrinter);
2734 RegCloseKey(hkeyPrinters);
2736 TRACE("returning %d needed = %ld\n", ret, needed);
2737 if(pcbNeeded) *pcbNeeded = needed;
2739 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2743 /*****************************************************************************
2744 * GetPrinterW [WINSPOOL.@]
2746 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2747 DWORD cbBuf, LPDWORD pcbNeeded)
2749 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2753 /*****************************************************************************
2754 * GetPrinterA [WINSPOOL.@]
2756 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2757 DWORD cbBuf, LPDWORD pcbNeeded)
2759 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2763 /*****************************************************************************
2764 * WINSPOOL_EnumPrinters
2766 * Implementation of EnumPrintersA|W
2768 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2769 DWORD dwLevel, LPBYTE lpbPrinters,
2770 DWORD cbBuf, LPDWORD lpdwNeeded,
2771 LPDWORD lpdwReturned, BOOL unicode)
2774 HKEY hkeyPrinters, hkeyPrinter;
2775 WCHAR PrinterName[255];
2776 DWORD needed = 0, number = 0;
2777 DWORD used, i, left;
2781 memset(lpbPrinters, 0, cbBuf);
2787 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2788 if(dwType == PRINTER_ENUM_DEFAULT)
2791 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2792 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2793 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2794 if(!dwType) return TRUE;
2797 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2798 FIXME("dwType = %08lx\n", dwType);
2799 SetLastError(ERROR_INVALID_FLAGS);
2803 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2805 ERR("Can't create Printers key\n");
2809 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2810 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2811 RegCloseKey(hkeyPrinters);
2812 ERR("Can't query Printers key\n");
2815 TRACE("Found %ld printers\n", number);
2819 RegCloseKey(hkeyPrinters);
2821 *lpdwReturned = number;
2825 used = number * sizeof(PRINTER_INFO_2W);
2828 used = number * sizeof(PRINTER_INFO_4W);
2831 used = number * sizeof(PRINTER_INFO_5W);
2835 SetLastError(ERROR_INVALID_LEVEL);
2836 RegCloseKey(hkeyPrinters);
2839 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2841 for(i = 0; i < number; i++) {
2842 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2844 ERR("Can't enum key number %ld\n", i);
2845 RegCloseKey(hkeyPrinters);
2848 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2849 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2851 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2852 RegCloseKey(hkeyPrinters);
2857 buf = lpbPrinters + used;
2858 left = cbBuf - used;
2866 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2867 left, &needed, unicode);
2869 if(pi) pi += sizeof(PRINTER_INFO_2W);
2872 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2873 left, &needed, unicode);
2875 if(pi) pi += sizeof(PRINTER_INFO_4W);
2878 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2879 left, &needed, unicode);
2881 if(pi) pi += sizeof(PRINTER_INFO_5W);
2884 ERR("Shouldn't be here!\n");
2885 RegCloseKey(hkeyPrinter);
2886 RegCloseKey(hkeyPrinters);
2889 RegCloseKey(hkeyPrinter);
2891 RegCloseKey(hkeyPrinters);
2898 memset(lpbPrinters, 0, cbBuf);
2899 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2903 *lpdwReturned = number;
2904 SetLastError(ERROR_SUCCESS);
2909 /******************************************************************
2910 * EnumPrintersW [WINSPOOL.@]
2912 * Enumerates the available printers, print servers and print
2913 * providers, depending on the specified flags, name and level.
2917 * If level is set to 1:
2918 * Not implemented yet!
2919 * Returns TRUE with an empty list.
2921 * If level is set to 2:
2922 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2923 * Returns an array of PRINTER_INFO_2 data structures in the
2924 * lpbPrinters buffer. Note that according to MSDN also an
2925 * OpenPrinter should be performed on every remote printer.
2927 * If level is set to 4 (officially WinNT only):
2928 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2929 * Fast: Only the registry is queried to retrieve printer names,
2930 * no connection to the driver is made.
2931 * Returns an array of PRINTER_INFO_4 data structures in the
2932 * lpbPrinters buffer.
2934 * If level is set to 5 (officially WinNT4/Win9x only):
2935 * Fast: Only the registry is queried to retrieve printer names,
2936 * no connection to the driver is made.
2937 * Returns an array of PRINTER_INFO_5 data structures in the
2938 * lpbPrinters buffer.
2940 * If level set to 3 or 6+:
2941 * returns zero (failure!)
2943 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2947 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2948 * - Only levels 2, 4 and 5 are implemented at the moment.
2949 * - 16-bit printer drivers are not enumerated.
2950 * - Returned amount of bytes used/needed does not match the real Windoze
2951 * implementation (as in this implementation, all strings are part
2952 * of the buffer, whereas Win32 keeps them somewhere else)
2953 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2956 * - In a regular Wine installation, no registry settings for printers
2957 * exist, which makes this function return an empty list.
2959 BOOL WINAPI EnumPrintersW(
2960 DWORD dwType, /* [in] Types of print objects to enumerate */
2961 LPWSTR lpszName, /* [in] name of objects to enumerate */
2962 DWORD dwLevel, /* [in] type of printer info structure */
2963 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2964 DWORD cbBuf, /* [in] max size of buffer in bytes */
2965 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2966 LPDWORD lpdwReturned /* [out] number of entries returned */
2969 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2970 lpdwNeeded, lpdwReturned, TRUE);
2973 /******************************************************************
2974 * EnumPrintersA [WINSPOOL.@]
2977 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
2978 DWORD dwLevel, LPBYTE lpbPrinters,
2979 DWORD cbBuf, LPDWORD lpdwNeeded,
2980 LPDWORD lpdwReturned)
2983 UNICODE_STRING lpszNameW;
2986 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
2987 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
2988 lpdwNeeded, lpdwReturned, FALSE);
2989 RtlFreeUnicodeString(&lpszNameW);
2993 /*****************************************************************************
2994 * WINSPOOL_GetDriverInfoFromReg [internal]
2996 * Enters the information from the registry into the DRIVER_INFO struct
2999 * zero if the printer driver does not exist in the registry
3000 * (only if Level > 1) otherwise nonzero
3002 static BOOL WINSPOOL_GetDriverInfoFromReg(
3005 LPWSTR pEnvironment,
3007 LPBYTE ptr, /* DRIVER_INFO */
3008 LPBYTE pDriverStrings, /* strings buffer */
3009 DWORD cbBuf, /* size of string buffer */
3010 LPDWORD pcbNeeded, /* space needed for str. */
3011 BOOL unicode) /* type of strings */
3012 { DWORD dw, size, tmp, type;
3014 LPBYTE strPtr = pDriverStrings;
3016 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3017 debugstr_w(DriverName), debugstr_w(pEnvironment),
3018 Level, ptr, pDriverStrings, cbBuf, unicode);
3021 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3022 if (*pcbNeeded <= cbBuf)
3023 strcpyW((LPWSTR)strPtr, DriverName);
3025 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3027 if(*pcbNeeded <= cbBuf)
3028 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3029 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3033 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3037 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
3038 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3041 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3042 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3043 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3048 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
3050 WARN("Can't get Version\n");
3052 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
3055 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3057 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3059 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3062 if(*pcbNeeded <= cbBuf) {
3064 strcpyW((LPWSTR)strPtr, pEnvironment);
3066 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3067 (LPSTR)strPtr, size, NULL, NULL);
3069 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
3070 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3073 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3076 if(*pcbNeeded <= cbBuf)
3077 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3080 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
3081 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3084 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3087 if(*pcbNeeded <= cbBuf)
3088 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3091 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
3092 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3095 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3096 0, &size, unicode)) {
3098 if(*pcbNeeded <= cbBuf)
3099 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3100 size, &tmp, unicode);
3102 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
3103 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3107 RegCloseKey(hkeyDriver);
3108 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3112 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3115 if(*pcbNeeded <= cbBuf)
3116 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3117 size, &tmp, unicode);
3119 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3120 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3123 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3126 if(*pcbNeeded <= cbBuf)
3127 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3128 size, &tmp, unicode);
3130 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3131 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3134 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3137 if(*pcbNeeded <= cbBuf)
3138 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3139 size, &tmp, unicode);
3141 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3142 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3145 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3148 if(*pcbNeeded <= cbBuf)
3149 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3150 size, &tmp, unicode);
3152 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3153 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3156 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3157 RegCloseKey(hkeyDriver);
3161 /*****************************************************************************
3162 * WINSPOOL_GetPrinterDriver
3164 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3165 DWORD Level, LPBYTE pDriverInfo,
3166 DWORD cbBuf, LPDWORD pcbNeeded,
3170 WCHAR DriverName[100];
3171 DWORD ret, type, size, needed = 0;
3173 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3175 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3176 Level,pDriverInfo,cbBuf, pcbNeeded);
3178 ZeroMemory(pDriverInfo, cbBuf);
3180 if (!(name = get_opened_printer_name(hPrinter))) {
3181 SetLastError(ERROR_INVALID_HANDLE);
3184 if(Level < 1 || Level > 3) {
3185 SetLastError(ERROR_INVALID_LEVEL);
3188 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3190 ERR("Can't create Printers key\n");
3193 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3195 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3196 RegCloseKey(hkeyPrinters);
3197 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3200 size = sizeof(DriverName);
3202 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3203 (LPBYTE)DriverName, &size);
3204 RegCloseKey(hkeyPrinter);
3205 RegCloseKey(hkeyPrinters);
3206 if(ret != ERROR_SUCCESS) {
3207 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3211 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3213 ERR("Can't create Drivers key\n");
3219 size = sizeof(DRIVER_INFO_1W);
3222 size = sizeof(DRIVER_INFO_2W);
3225 size = sizeof(DRIVER_INFO_3W);
3228 ERR("Invalid level\n");
3233 ptr = pDriverInfo + size;
3235 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3236 pEnvironment, Level, pDriverInfo,
3237 (cbBuf < size) ? NULL : ptr,
3238 (cbBuf < size) ? 0 : cbBuf - size,
3239 &needed, unicode)) {
3240 RegCloseKey(hkeyDrivers);
3244 RegCloseKey(hkeyDrivers);
3246 if(pcbNeeded) *pcbNeeded = size + needed;
3247 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3248 if(cbBuf >= needed) return TRUE;
3249 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3253 /*****************************************************************************
3254 * GetPrinterDriverA [WINSPOOL.@]
3256 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3257 DWORD Level, LPBYTE pDriverInfo,
3258 DWORD cbBuf, LPDWORD pcbNeeded)
3261 UNICODE_STRING pEnvW;
3264 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3265 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3266 cbBuf, pcbNeeded, FALSE);
3267 RtlFreeUnicodeString(&pEnvW);
3270 /*****************************************************************************
3271 * GetPrinterDriverW [WINSPOOL.@]
3273 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3274 DWORD Level, LPBYTE pDriverInfo,
3275 DWORD cbBuf, LPDWORD pcbNeeded)
3277 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3278 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3281 /*****************************************************************************
3282 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3284 * Return the PATH for the Printer-Drivers (UNICODE)
3287 * pName [I] Servername (NT only) or NULL (local Computer)
3288 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3289 * Level [I] Structure-Level (must be 1)
3290 * pDriverDirectory [O] PTR to Buffer that receives the Result
3291 * cbBuf [I] Size of Buffer at pDriverDirectory
3292 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3293 * required for pDriverDirectory
3296 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3297 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3298 * if cbBuf is too small
3300 * Native Values returned in pDriverDirectory on Success:
3301 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3302 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3303 *| win9x(Windows 4.0): "%winsysdir%"
3305 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3308 *- pName != NULL not supported
3309 *- pEnvironment != NULL not supported
3310 *- Current Implementation returns always "%winsysdir%"
3313 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3314 DWORD Level, LPBYTE pDriverDirectory,
3315 DWORD cbBuf, LPDWORD pcbNeeded)
3319 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3320 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3322 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
3323 SetLastError(ERROR_INVALID_PARAMETER);
3326 if(pEnvironment != NULL) {
3327 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
3328 SetLastError(ERROR_INVALID_ENVIRONMENT);
3331 if(Level != 1) /* win95 ignores this so we just carry on */
3332 WARN("Level = %ld - assuming 1\n", Level);
3334 /* FIXME should read from registry */
3335 needed = GetSystemDirectoryW( (LPWSTR)pDriverDirectory, cbBuf/sizeof(WCHAR));
3336 /* GetSystemDirectoryW returns number of TCHAR without '\0'
3340 needed*=sizeof(WCHAR);
3343 *pcbNeeded = needed;
3344 TRACE("required <%08lx>\n", *pcbNeeded);
3345 if(needed > cbBuf) {
3346 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3353 /*****************************************************************************
3354 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3356 * Return the PATH for the Printer-Drivers (ANSI)
3358 * See GetPrinterDriverDirectoryW.
3361 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3364 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3365 DWORD Level, LPBYTE pDriverDirectory,
3366 DWORD cbBuf, LPDWORD pcbNeeded)
3368 UNICODE_STRING nameW, environmentW;
3371 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3372 WCHAR *driverDirectoryW = NULL;
3374 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3376 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3377 else nameW.Buffer = NULL;
3378 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3379 else environmentW.Buffer = NULL;
3381 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3382 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3385 needed = 1 + WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3386 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3388 *pcbNeeded = needed;
3389 ret = (needed <= cbBuf) ? TRUE : FALSE;
3391 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3393 TRACE("provided<%ld> required <%ld>\n", cbBuf, *pcbNeeded);
3395 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3396 RtlFreeUnicodeString(&environmentW);
3397 RtlFreeUnicodeString(&nameW);
3402 /*****************************************************************************
3403 * AddPrinterDriverA [WINSPOOL.@]
3405 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3408 HKEY hkeyDrivers, hkeyName;
3410 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3412 if(level != 2 && level != 3) {
3413 SetLastError(ERROR_INVALID_LEVEL);
3417 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3418 SetLastError(ERROR_INVALID_PARAMETER);
3422 WARN("pDriverInfo == NULL\n");
3423 SetLastError(ERROR_INVALID_PARAMETER);
3428 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3430 memset(&di3, 0, sizeof(di3));
3431 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3434 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3436 SetLastError(ERROR_INVALID_PARAMETER);
3439 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3440 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3441 if(!di3.pHelpFile) di3.pHelpFile = "";
3442 if(!di3.pMonitorName) di3.pMonitorName = "";
3444 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3447 ERR("Can't create Drivers key\n");
3451 if(level == 2) { /* apparently can't overwrite with level2 */
3452 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3453 RegCloseKey(hkeyName);
3454 RegCloseKey(hkeyDrivers);
3455 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3456 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3460 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3461 RegCloseKey(hkeyDrivers);
3462 ERR("Can't create Name key\n");
3465 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3467 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3468 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3469 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3471 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3472 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3473 (LPBYTE) di3.pDependentFiles, 0);
3474 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3475 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3476 RegCloseKey(hkeyName);
3477 RegCloseKey(hkeyDrivers);
3482 /*****************************************************************************
3483 * AddPrinterDriverW [WINSPOOL.@]
3485 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3488 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3493 /*****************************************************************************
3494 * AddPrintProcessorA [WINSPOOL.@]
3496 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3497 LPSTR pPrintProcessorName)
3499 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3500 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3504 /*****************************************************************************
3505 * AddPrintProcessorW [WINSPOOL.@]
3507 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3508 LPWSTR pPrintProcessorName)
3510 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3511 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3515 /*****************************************************************************
3516 * AddPrintProvidorA [WINSPOOL.@]
3518 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3520 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3524 /*****************************************************************************
3525 * AddPrintProvidorW [WINSPOOL.@]
3527 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3529 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3533 /*****************************************************************************
3534 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3536 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3537 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3539 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3540 pDevModeOutput, pDevModeInput);
3544 /*****************************************************************************
3545 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3547 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3548 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3550 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3551 pDevModeOutput, pDevModeInput);
3555 /*****************************************************************************
3556 * PrinterProperties [WINSPOOL.@]
3558 * Displays a dialog to set the properties of the printer.
3561 * nonzero on success or zero on failure
3564 * implemented as stub only
3566 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3567 HANDLE hPrinter /* [in] handle to printer object */
3569 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3570 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3574 /*****************************************************************************
3575 * EnumJobsA [WINSPOOL.@]
3578 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3579 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3582 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3583 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3585 if(pcbNeeded) *pcbNeeded = 0;
3586 if(pcReturned) *pcReturned = 0;
3591 /*****************************************************************************
3592 * EnumJobsW [WINSPOOL.@]
3595 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3596 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3599 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3600 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3602 if(pcbNeeded) *pcbNeeded = 0;
3603 if(pcReturned) *pcReturned = 0;
3607 /*****************************************************************************
3608 * WINSPOOL_EnumPrinterDrivers [internal]
3610 * Delivers information about all printer drivers installed on the
3611 * localhost or a given server
3614 * nonzero on success or zero on failure. If the buffer for the returned
3615 * information is too small the function will return an error
3618 * - only implemented for localhost, foreign hosts will return an error
3620 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3621 DWORD Level, LPBYTE pDriverInfo,
3622 DWORD cbBuf, LPDWORD pcbNeeded,
3623 LPDWORD pcReturned, BOOL unicode)
3626 DWORD i, needed, number = 0, size = 0;
3627 WCHAR DriverNameW[255];
3630 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3631 debugstr_w(pName), debugstr_w(pEnvironment),
3632 Level, pDriverInfo, cbBuf, unicode);
3634 /* check for local drivers */
3636 ERR("remote drivers unsupported! Current remote host is %s\n",
3641 /* check input parameter */
3642 if((Level < 1) || (Level > 3)) {
3643 ERR("unsupported level %ld\n", Level);
3644 SetLastError(ERROR_INVALID_LEVEL);
3648 /* initialize return values */
3650 memset( pDriverInfo, 0, cbBuf);
3654 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3656 ERR("Can't open Drivers key\n");
3660 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3661 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3662 RegCloseKey(hkeyDrivers);
3663 ERR("Can't query Drivers key\n");
3666 TRACE("Found %ld Drivers\n", number);
3668 /* get size of single struct
3669 * unicode and ascii structure have the same size
3673 size = sizeof(DRIVER_INFO_1A);
3676 size = sizeof(DRIVER_INFO_2A);
3679 size = sizeof(DRIVER_INFO_3A);
3683 /* calculate required buffer size */
3684 *pcbNeeded = size * number;
3686 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3688 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3689 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3691 ERR("Can't enum key number %ld\n", i);
3692 RegCloseKey(hkeyDrivers);
3695 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3696 pEnvironment, Level, ptr,
3697 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3698 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3699 &needed, unicode)) {
3700 RegCloseKey(hkeyDrivers);
3703 (*pcbNeeded) += needed;
3706 RegCloseKey(hkeyDrivers);
3708 if(cbBuf < *pcbNeeded){
3709 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3713 *pcReturned = number;
3717 /*****************************************************************************
3718 * EnumPrinterDriversW [WINSPOOL.@]
3720 * see function EnumPrinterDrivers for RETURNS, BUGS
3722 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3723 LPBYTE pDriverInfo, DWORD cbBuf,
3724 LPDWORD pcbNeeded, LPDWORD pcReturned)
3726 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3727 cbBuf, pcbNeeded, pcReturned, TRUE);
3730 /*****************************************************************************
3731 * EnumPrinterDriversA [WINSPOOL.@]
3733 * see function EnumPrinterDrivers for RETURNS, BUGS
3735 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3736 LPBYTE pDriverInfo, DWORD cbBuf,
3737 LPDWORD pcbNeeded, LPDWORD pcReturned)
3739 UNICODE_STRING pNameW, pEnvironmentW;
3740 PWSTR pwstrNameW, pwstrEnvironmentW;
3742 pwstrNameW = asciitounicode(&pNameW, pName);
3743 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3745 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3746 Level, pDriverInfo, cbBuf, pcbNeeded,
3748 RtlFreeUnicodeString(&pNameW);
3749 RtlFreeUnicodeString(&pEnvironmentW);
3754 static CHAR PortMonitor[] = "Wine Port Monitor";
3755 static CHAR PortDescription[] = "Wine Port";
3757 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3761 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3762 NULL, OPEN_EXISTING, 0, NULL );
3763 if (handle == INVALID_HANDLE_VALUE)
3765 TRACE("Checking %s exists\n", name );
3766 CloseHandle( handle );
3770 static DWORD WINSPOOL_CountSerialPorts(void)
3777 strcpy( name, "COMx:" );
3779 if (WINSPOOL_ComPortExists( name ))
3786 /******************************************************************************
3787 * EnumPortsA (WINSPOOL.@)
3792 * ANSI-Version did not call the UNICODE-Version
3795 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3796 LPDWORD bufneeded,LPDWORD bufreturned)
3799 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3800 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3804 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3805 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3810 info_size = sizeof (PORT_INFO_1A);
3813 info_size = sizeof (PORT_INFO_2A);
3816 SetLastError(ERROR_INVALID_LEVEL);
3820 /* see how many exist */
3823 serial_count = WINSPOOL_CountSerialPorts();
3826 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3827 if ( r == ERROR_SUCCESS )
3829 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3830 &printer_count, NULL, NULL, NULL, NULL);
3832 count = serial_count + printer_count;
3834 /* then fill in the structure info structure once
3835 we know the offset to the first string */
3837 memset( buffer, 0, bufsize );
3839 ofs = info_size*count;
3840 for ( i=0; i<count; i++)
3842 DWORD vallen = sizeof(portname) - 1;
3844 /* get the serial port values, then the printer values */
3845 if ( i < serial_count )
3847 strcpy( portname, "COMx:" );
3848 portname[3] = '1' + i;
3849 if (!WINSPOOL_ComPortExists( portname ))
3852 TRACE("Found %s\n", portname );
3853 vallen = strlen( portname );
3857 r = RegEnumValueA( hkey_printer, i-serial_count,
3858 portname, &vallen, NULL, NULL, NULL, 0 );
3863 /* add a colon if necessary, and make it upper case */
3864 CharUpperBuffA(portname,vallen);
3865 if (strcasecmp(portname,"nul")!=0)
3866 if (vallen && (portname[vallen-1] != ':') )
3867 lstrcatA(portname,":");
3869 /* add the port info structure if we can fit it */
3870 if ( info_size*(n+1) < bufsize )
3874 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3875 info->pName = (LPSTR) &buffer[ofs];
3877 else if ( level == 2)
3879 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3880 info->pPortName = (LPSTR) &buffer[ofs];
3881 /* FIXME: fill in more stuff here */
3882 info->pMonitorName = PortMonitor;
3883 info->pDescription = PortDescription;
3884 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
3887 /* add the name of the port if we can fit it */
3888 if ( ofs < bufsize )
3889 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
3895 ofs += lstrlenA(portname)+1;
3898 RegCloseKey(hkey_printer);
3909 /******************************************************************************
3910 * EnumPortsW (WINSPOOL.@)
3912 * Enumerate available Ports
3915 * name [I] Servername or NULL (local Computer)
3916 * level [I] Structure-Level (1 or 2)
3917 * buffer [O] PTR to Buffer that receives the Result
3918 * bufsize [I] Size of Buffer at buffer
3919 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
3920 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
3924 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
3927 * UNICODE-Version is a stub
3930 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3931 LPDWORD bufneeded,LPDWORD bufreturned)
3933 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
3934 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
3938 /******************************************************************************
3939 * GetDefaultPrinterW (WINSPOOL.@)
3942 * This function must read the value from data 'device' of key
3943 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
3945 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
3949 WCHAR *buffer, *ptr;
3953 SetLastError(ERROR_INVALID_PARAMETER);
3957 /* make the buffer big enough for the stuff from the profile/registry,
3958 * the content must fit into the local buffer to compute the correct
3959 * size even if the extern buffer is too small or not given.
3960 * (20 for ,driver,port) */
3962 len = max(100, (insize + 20));
3963 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
3965 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
3967 SetLastError (ERROR_FILE_NOT_FOUND);
3971 TRACE("%s\n", debugstr_w(buffer));
3973 if ((ptr = strchrW(buffer, ',')) == NULL)
3975 SetLastError(ERROR_INVALID_NAME);
3981 *namesize = strlenW(buffer) + 1;
3982 if(!name || (*namesize > insize))
3984 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3988 strcpyW(name, buffer);
3991 HeapFree( GetProcessHeap(), 0, buffer);
3996 /******************************************************************************
3997 * GetDefaultPrinterA (WINSPOOL.@)
3999 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4003 WCHAR *bufferW = NULL;
4007 SetLastError(ERROR_INVALID_PARAMETER);
4011 if(name && *namesize) {
4013 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4016 if(!GetDefaultPrinterW( bufferW, namesize)) {
4021 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4025 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4028 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4031 HeapFree( GetProcessHeap(), 0, bufferW);
4036 /******************************************************************************
4037 * SetPrinterDataExA (WINSPOOL.@)
4039 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4040 LPCSTR pValueName, DWORD Type,
4041 LPBYTE pData, DWORD cbData)
4043 HKEY hkeyPrinter, hkeySubkey;
4046 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4047 debugstr_a(pValueName), Type, pData, cbData);
4049 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4053 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4055 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4056 RegCloseKey(hkeyPrinter);
4059 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4060 RegCloseKey(hkeySubkey);
4061 RegCloseKey(hkeyPrinter);
4065 /******************************************************************************
4066 * SetPrinterDataExW (WINSPOOL.@)
4068 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4069 LPCWSTR pValueName, DWORD Type,
4070 LPBYTE pData, DWORD cbData)
4072 HKEY hkeyPrinter, hkeySubkey;
4075 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4076 debugstr_w(pValueName), Type, pData, cbData);
4078 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4082 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4084 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4085 RegCloseKey(hkeyPrinter);
4088 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4089 RegCloseKey(hkeySubkey);
4090 RegCloseKey(hkeyPrinter);
4094 /******************************************************************************
4095 * SetPrinterDataA (WINSPOOL.@)
4097 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4098 LPBYTE pData, DWORD cbData)
4100 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4104 /******************************************************************************
4105 * SetPrinterDataW (WINSPOOL.@)
4107 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4108 LPBYTE pData, DWORD cbData)
4110 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4114 /******************************************************************************
4115 * GetPrinterDataExA (WINSPOOL.@)
4117 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4118 LPCSTR pValueName, LPDWORD pType,
4119 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4121 HKEY hkeyPrinter, hkeySubkey;
4124 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4125 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4128 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4132 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4134 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4135 RegCloseKey(hkeyPrinter);
4139 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4140 RegCloseKey(hkeySubkey);
4141 RegCloseKey(hkeyPrinter);
4145 /******************************************************************************
4146 * GetPrinterDataExW (WINSPOOL.@)
4148 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4149 LPCWSTR pValueName, LPDWORD pType,
4150 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4152 HKEY hkeyPrinter, hkeySubkey;
4155 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4156 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4159 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4163 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4165 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4166 RegCloseKey(hkeyPrinter);
4170 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4171 RegCloseKey(hkeySubkey);
4172 RegCloseKey(hkeyPrinter);
4176 /******************************************************************************
4177 * GetPrinterDataA (WINSPOOL.@)
4179 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4180 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4182 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4183 pData, nSize, pcbNeeded);
4186 /******************************************************************************
4187 * GetPrinterDataW (WINSPOOL.@)
4189 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4190 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4192 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4193 pData, nSize, pcbNeeded);
4196 /*******************************************************************************
4197 * EnumPrinterDataExW [WINSPOOL.@]
4199 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4200 LPBYTE pEnumValues, DWORD cbEnumValues,
4201 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4203 HKEY hkPrinter, hkSubKey;
4204 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4205 cbValueNameLen, cbMaxValueLen, cbValueLen,
4210 PPRINTER_ENUM_VALUESW ppev;
4212 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4214 if (pKeyName == NULL || *pKeyName == 0)
4215 return ERROR_INVALID_PARAMETER;
4217 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4218 if (ret != ERROR_SUCCESS)
4220 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4225 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4226 if (ret != ERROR_SUCCESS)
4228 r = RegCloseKey (hkPrinter);
4229 if (r != ERROR_SUCCESS)
4230 WARN ("RegCloseKey returned %li\n", r);
4231 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4232 debugstr_w (pKeyName), ret);
4236 ret = RegCloseKey (hkPrinter);
4237 if (ret != ERROR_SUCCESS)
4239 ERR ("RegCloseKey returned %li\n", ret);
4240 r = RegCloseKey (hkSubKey);
4241 if (r != ERROR_SUCCESS)
4242 WARN ("RegCloseKey returned %li\n", r);
4246 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4247 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4248 if (ret != ERROR_SUCCESS)
4250 r = RegCloseKey (hkSubKey);
4251 if (r != ERROR_SUCCESS)
4252 WARN ("RegCloseKey returned %li\n", r);
4253 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4257 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4258 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4260 if (cValues == 0) /* empty key */
4262 r = RegCloseKey (hkSubKey);
4263 if (r != ERROR_SUCCESS)
4264 WARN ("RegCloseKey returned %li\n", r);
4265 *pcbEnumValues = *pnEnumValues = 0;
4266 return ERROR_SUCCESS;
4269 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4271 hHeap = GetProcessHeap ();
4274 ERR ("GetProcessHeap failed\n");
4275 r = RegCloseKey (hkSubKey);
4276 if (r != ERROR_SUCCESS)
4277 WARN ("RegCloseKey returned %li\n", r);
4278 return ERROR_OUTOFMEMORY;
4281 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4282 if (lpValueName == NULL)
4284 ERR ("Failed to allocate %li bytes from process heap\n",
4285 cbMaxValueNameLen * sizeof (WCHAR));
4286 r = RegCloseKey (hkSubKey);
4287 if (r != ERROR_SUCCESS)
4288 WARN ("RegCloseKey returned %li\n", r);
4289 return ERROR_OUTOFMEMORY;
4292 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4293 if (lpValue == NULL)
4295 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4296 if (HeapFree (hHeap, 0, lpValueName) == 0)
4297 WARN ("HeapFree failed with code %li\n", GetLastError ());
4298 r = RegCloseKey (hkSubKey);
4299 if (r != ERROR_SUCCESS)
4300 WARN ("RegCloseKey returned %li\n", r);
4301 return ERROR_OUTOFMEMORY;
4304 TRACE ("pass 1: calculating buffer required for all names and values\n");
4306 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4308 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4310 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4312 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4313 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4314 NULL, NULL, lpValue, &cbValueLen);
4315 if (ret != ERROR_SUCCESS)
4317 if (HeapFree (hHeap, 0, lpValue) == 0)
4318 WARN ("HeapFree failed with code %li\n", GetLastError ());
4319 if (HeapFree (hHeap, 0, lpValueName) == 0)
4320 WARN ("HeapFree failed with code %li\n", GetLastError ());
4321 r = RegCloseKey (hkSubKey);
4322 if (r != ERROR_SUCCESS)
4323 WARN ("RegCloseKey returned %li\n", r);
4324 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4328 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4329 debugstr_w (lpValueName), dwIndex,
4330 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4332 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4333 cbBufSize += cbValueLen;
4336 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4338 *pcbEnumValues = cbBufSize;
4339 *pnEnumValues = cValues;
4341 if (cbEnumValues < cbBufSize) /* buffer too small */
4343 if (HeapFree (hHeap, 0, lpValue) == 0)
4344 WARN ("HeapFree failed with code %li\n", GetLastError ());
4345 if (HeapFree (hHeap, 0, lpValueName) == 0)
4346 WARN ("HeapFree failed with code %li\n", GetLastError ());
4347 r = RegCloseKey (hkSubKey);
4348 if (r != ERROR_SUCCESS)
4349 WARN ("RegCloseKey returned %li\n", r);
4350 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4351 return ERROR_MORE_DATA;
4354 TRACE ("pass 2: copying all names and values to buffer\n");
4356 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4357 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4359 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4361 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4362 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4363 NULL, &dwType, lpValue, &cbValueLen);
4364 if (ret != ERROR_SUCCESS)
4366 if (HeapFree (hHeap, 0, lpValue) == 0)
4367 WARN ("HeapFree failed with code %li\n", GetLastError ());
4368 if (HeapFree (hHeap, 0, lpValueName) == 0)
4369 WARN ("HeapFree failed with code %li\n", GetLastError ());
4370 r = RegCloseKey (hkSubKey);
4371 if (r != ERROR_SUCCESS)
4372 WARN ("RegCloseKey returned %li\n", r);
4373 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4377 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4378 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4379 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4380 pEnumValues += cbValueNameLen;
4382 /* return # of *bytes* (including trailing \0), not # of chars */
4383 ppev[dwIndex].cbValueName = cbValueNameLen;
4385 ppev[dwIndex].dwType = dwType;
4387 memcpy (pEnumValues, lpValue, cbValueLen);
4388 ppev[dwIndex].pData = pEnumValues;
4389 pEnumValues += cbValueLen;
4391 ppev[dwIndex].cbData = cbValueLen;
4393 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4394 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4397 if (HeapFree (hHeap, 0, lpValue) == 0)
4399 ret = GetLastError ();
4400 ERR ("HeapFree failed with code %li\n", ret);
4401 if (HeapFree (hHeap, 0, lpValueName) == 0)
4402 WARN ("HeapFree failed with code %li\n", GetLastError ());
4403 r = RegCloseKey (hkSubKey);
4404 if (r != ERROR_SUCCESS)
4405 WARN ("RegCloseKey returned %li\n", r);
4409 if (HeapFree (hHeap, 0, lpValueName) == 0)
4411 ret = GetLastError ();
4412 ERR ("HeapFree failed with code %li\n", ret);
4413 r = RegCloseKey (hkSubKey);
4414 if (r != ERROR_SUCCESS)
4415 WARN ("RegCloseKey returned %li\n", r);
4419 ret = RegCloseKey (hkSubKey);
4420 if (ret != ERROR_SUCCESS)
4422 ERR ("RegCloseKey returned %li\n", ret);
4426 return ERROR_SUCCESS;
4429 /*******************************************************************************
4430 * EnumPrinterDataExA [WINSPOOL.@]
4432 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4433 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4434 * what Windows 2000 SP1 does.
4437 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4438 LPBYTE pEnumValues, DWORD cbEnumValues,
4439 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4443 DWORD ret, dwIndex, dwBufSize;
4447 TRACE ("%p %s\n", hPrinter, pKeyName);
4449 if (pKeyName == NULL || *pKeyName == 0)
4450 return ERROR_INVALID_PARAMETER;
4452 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4455 ret = GetLastError ();
4456 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4460 hHeap = GetProcessHeap ();
4463 ERR ("GetProcessHeap failed\n");
4464 return ERROR_OUTOFMEMORY;
4467 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4468 if (pKeyNameW == NULL)
4470 ERR ("Failed to allocate %li bytes from process heap\n",
4471 (LONG) len * sizeof (WCHAR));
4472 return ERROR_OUTOFMEMORY;
4475 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4477 ret = GetLastError ();
4478 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4479 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4480 WARN ("HeapFree failed with code %li\n", GetLastError ());
4484 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4485 pcbEnumValues, pnEnumValues);
4486 if (ret != ERROR_SUCCESS)
4488 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4489 WARN ("HeapFree failed with code %li\n", GetLastError ());
4490 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4494 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4496 ret = GetLastError ();
4497 ERR ("HeapFree failed with code %li\n", ret);
4501 if (*pnEnumValues == 0) /* empty key */
4502 return ERROR_SUCCESS;
4505 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4507 PPRINTER_ENUM_VALUESW ppev =
4508 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4510 if (dwBufSize < ppev->cbValueName)
4511 dwBufSize = ppev->cbValueName;
4513 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4514 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4515 dwBufSize = ppev->cbData;
4518 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4520 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4521 if (pBuffer == NULL)
4523 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4524 return ERROR_OUTOFMEMORY;
4527 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4529 PPRINTER_ENUM_VALUESW ppev =
4530 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4532 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4533 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4537 ret = GetLastError ();
4538 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4539 if (HeapFree (hHeap, 0, pBuffer) == 0)
4540 WARN ("HeapFree failed with code %li\n", GetLastError ());
4544 memcpy (ppev->pValueName, pBuffer, len);
4546 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4548 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4549 ppev->dwType != REG_MULTI_SZ)
4552 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4553 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4556 ret = GetLastError ();
4557 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4558 if (HeapFree (hHeap, 0, pBuffer) == 0)
4559 WARN ("HeapFree failed with code %li\n", GetLastError ());
4563 memcpy (ppev->pData, pBuffer, len);
4565 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4566 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4569 if (HeapFree (hHeap, 0, pBuffer) == 0)
4571 ret = GetLastError ();
4572 ERR ("HeapFree failed with code %li\n", ret);
4576 return ERROR_SUCCESS;
4579 /******************************************************************************
4580 * AbortPrinter (WINSPOOL.@)
4582 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4584 FIXME("(%p), stub!\n", hPrinter);
4588 /******************************************************************************
4589 * AddPortA (WINSPOOL.@)
4594 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4596 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4600 /******************************************************************************
4601 * AddPortW (WINSPOOL.@)
4603 * Add a Port for a specific Monitor
4606 * pName [I] Servername or NULL (local Computer)
4607 * hWnd [I] Handle to parent Window for the Dialog-Box
4608 * pMonitorName [I] Name of the Monitor that manage the Port
4618 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4620 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4624 /******************************************************************************
4625 * AddPortExA (WINSPOOL.@)
4630 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4632 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4633 lpBuffer, debugstr_a(lpMonitorName));
4637 /******************************************************************************
4638 * AddPortExW (WINSPOOL.@)
4640 * Add a Port for a specific Monitor, without presenting a user interface
4643 * hMonitor [I] Handle from InitializePrintMonitor2()
4644 * pName [I] Servername or NULL (local Computer)
4645 * Level [I] Structure-Level (1 or 2) for lpBuffer
4646 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
4647 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
4657 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4659 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4660 lpBuffer, debugstr_w(lpMonitorName));
4664 /******************************************************************************
4665 * AddPrinterConnectionA (WINSPOOL.@)
4667 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4669 FIXME("%s\n", debugstr_a(pName));
4673 /******************************************************************************
4674 * AddPrinterConnectionW (WINSPOOL.@)
4676 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4678 FIXME("%s\n", debugstr_w(pName));
4682 /******************************************************************************
4683 * AddPrinterDriverExW (WINSPOOL.@)
4685 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4686 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4688 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4689 Level, pDriverInfo, dwFileCopyFlags);
4690 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4694 /******************************************************************************
4695 * AddPrinterDriverExA (WINSPOOL.@)
4697 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4698 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4700 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4701 Level, pDriverInfo, dwFileCopyFlags);
4702 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4706 /******************************************************************************
4707 * ConfigurePortA (WINSPOOL.@)
4709 * See ConfigurePortW.
4712 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4714 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4718 /******************************************************************************
4719 * ConfigurePortW (WINSPOOL.@)
4721 * Display the Configuration-Dialog for a specific Port
4724 * pName [I] Servername or NULL (local Computer)
4725 * hWnd [I] Handle to parent Window for the Dialog-Box
4726 * pPortName [I] Name of the Port, that should be configured
4736 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4738 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4742 /******************************************************************************
4743 * ConnectToPrinterDlg (WINSPOOL.@)
4745 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4747 FIXME("%p %lx\n", hWnd, Flags);
4751 /******************************************************************************
4752 * DeletePrinterConnectionA (WINSPOOL.@)
4754 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4756 FIXME("%s\n", debugstr_a(pName));
4760 /******************************************************************************
4761 * DeletePrinterConnectionW (WINSPOOL.@)
4763 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4765 FIXME("%s\n", debugstr_w(pName));
4769 /******************************************************************************
4770 * DeletePrinterDriverExW (WINSPOOL.@)
4772 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4773 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4775 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4776 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4780 /******************************************************************************
4781 * DeletePrinterDriverExA (WINSPOOL.@)
4783 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4784 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4786 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4787 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4791 /******************************************************************************
4792 * DeletePrinterDataExW (WINSPOOL.@)
4794 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4797 FIXME("%p %s %s\n", hPrinter,
4798 debugstr_w(pKeyName), debugstr_w(pValueName));
4799 return ERROR_INVALID_PARAMETER;
4802 /******************************************************************************
4803 * DeletePrinterDataExA (WINSPOOL.@)
4805 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4808 FIXME("%p %s %s\n", hPrinter,
4809 debugstr_a(pKeyName), debugstr_a(pValueName));
4810 return ERROR_INVALID_PARAMETER;
4813 /******************************************************************************
4814 * DeletePrintProcessorA (WINSPOOL.@)
4816 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4818 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4819 debugstr_a(pPrintProcessorName));
4823 /******************************************************************************
4824 * DeletePrintProcessorW (WINSPOOL.@)
4826 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4828 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4829 debugstr_w(pPrintProcessorName));
4833 /******************************************************************************
4834 * DeletePrintProvidorA (WINSPOOL.@)
4836 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4838 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4839 debugstr_a(pPrintProviderName));
4843 /******************************************************************************
4844 * DeletePrintProvidorW (WINSPOOL.@)
4846 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4848 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4849 debugstr_w(pPrintProviderName));
4853 /******************************************************************************
4854 * EnumFormsA (WINSPOOL.@)
4856 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4857 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4859 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4863 /******************************************************************************
4864 * EnumFormsW (WINSPOOL.@)
4866 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4867 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4869 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4873 /*****************************************************************************
4874 * EnumMonitorsA [WINSPOOL.@]
4876 * See EnumMonitorsW.
4879 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4880 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4882 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4883 cbBuf, pcbNeeded, pcReturned);
4884 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4888 /*****************************************************************************
4889 * EnumMonitorsW [WINSPOOL.@]
4891 * Enumerate available Monitors
4894 * pName [I] Servername or NULL (local Computer)
4895 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
4896 * pMonitors [O] PTR to Buffer that receives the Result
4897 * cbBuf [I] Size of Buffer at pMonitors
4898 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
4899 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
4903 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4909 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
4910 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4912 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
4913 cbBuf, pcbNeeded, pcReturned);
4914 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4918 /******************************************************************************
4919 * XcvDataW (WINSPOOL.@)
4922 * There doesn't seem to be an A version...
4924 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
4925 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
4926 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
4928 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
4929 pInputData, cbInputData, pOutputData,
4930 cbOutputData, pcbOutputNeeded, pdwStatus);
4934 /*****************************************************************************
4935 * EnumPrinterDataA [WINSPOOL.@]
4938 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
4939 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4940 DWORD cbData, LPDWORD pcbData )
4942 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4943 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4944 return ERROR_NO_MORE_ITEMS;
4947 /*****************************************************************************
4948 * EnumPrinterDataW [WINSPOOL.@]
4951 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
4952 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
4953 DWORD cbData, LPDWORD pcbData )
4955 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
4956 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
4957 return ERROR_NO_MORE_ITEMS;
4960 /*****************************************************************************
4961 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
4964 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
4965 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4966 LPDWORD pcbNeeded, LPDWORD pcReturned)
4968 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
4969 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
4970 pcbNeeded, pcReturned);
4974 /*****************************************************************************
4975 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
4978 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
4979 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
4980 LPDWORD pcbNeeded, LPDWORD pcReturned)
4982 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
4983 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
4984 pcbNeeded, pcReturned);
4988 /*****************************************************************************
4989 * EnumPrintProcessorsA [WINSPOOL.@]
4992 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4993 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
4995 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
4996 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5000 /*****************************************************************************
5001 * EnumPrintProcessorsW [WINSPOOL.@]
5004 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5005 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5007 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5008 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5009 cbBuf, pcbNeeded, pcbReturned);
5013 /*****************************************************************************
5014 * ExtDeviceMode [WINSPOOL.@]
5017 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5018 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5021 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5022 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5023 debugstr_a(pProfile), fMode);
5027 /*****************************************************************************
5028 * FindClosePrinterChangeNotification [WINSPOOL.@]
5031 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5033 FIXME("Stub: %p\n", hChange);
5037 /*****************************************************************************
5038 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5041 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5042 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5044 FIXME("Stub: %p %lx %lx %p\n",
5045 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5046 return INVALID_HANDLE_VALUE;
5049 /*****************************************************************************
5050 * FindNextPrinterChangeNotification [WINSPOOL.@]
5053 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5054 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5056 FIXME("Stub: %p %p %p %p\n",
5057 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5061 /*****************************************************************************
5062 * FreePrinterNotifyInfo [WINSPOOL.@]
5065 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5067 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5071 /*****************************************************************************
5074 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5075 * ansi depending on the unicode parameter.
5077 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5087 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5090 memcpy(ptr, str, *size);
5097 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5100 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5107 /*****************************************************************************
5110 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5111 LPDWORD pcbNeeded, BOOL unicode)
5113 DWORD size, left = cbBuf;
5114 BOOL space = (cbBuf > 0);
5121 ji1->JobId = job->job_id;
5124 string_to_buf(job->document_title, ptr, left, &size, unicode);
5125 if(space && size <= left)
5127 ji1->pDocument = (LPWSTR)ptr;
5138 /*****************************************************************************
5141 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5142 LPDWORD pcbNeeded, BOOL unicode)
5144 DWORD size, left = cbBuf;
5145 BOOL space = (cbBuf > 0);
5152 ji2->JobId = job->job_id;
5155 string_to_buf(job->document_title, ptr, left, &size, unicode);
5156 if(space && size <= left)
5158 ji2->pDocument = (LPWSTR)ptr;
5169 /*****************************************************************************
5172 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5173 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5176 DWORD needed = 0, size;
5180 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5182 EnterCriticalSection(&printer_handles_cs);
5183 job = get_job(hPrinter, JobId);
5190 size = sizeof(JOB_INFO_1W);
5195 memset(pJob, 0, size);
5199 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5204 size = sizeof(JOB_INFO_2W);
5209 memset(pJob, 0, size);
5213 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5218 size = sizeof(JOB_INFO_3);
5222 memset(pJob, 0, size);
5231 SetLastError(ERROR_INVALID_LEVEL);
5235 *pcbNeeded = needed;
5237 LeaveCriticalSection(&printer_handles_cs);
5241 /*****************************************************************************
5242 * GetJobA [WINSPOOL.@]
5245 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5246 DWORD cbBuf, LPDWORD pcbNeeded)
5248 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5251 /*****************************************************************************
5252 * GetJobW [WINSPOOL.@]
5255 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5256 DWORD cbBuf, LPDWORD pcbNeeded)
5258 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5261 /*****************************************************************************
5264 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5266 char *unixname, *queue, *cmd;
5267 char fmt[] = "lpr -P%s %s";
5270 if(!(unixname = wine_get_unix_file_name(filename)))
5273 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5274 queue = HeapAlloc(GetProcessHeap(), 0, len);
5275 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5277 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5278 sprintf(cmd, fmt, queue, unixname);
5280 TRACE("printing with: %s\n", cmd);
5283 HeapFree(GetProcessHeap(), 0, cmd);
5284 HeapFree(GetProcessHeap(), 0, queue);
5285 HeapFree(GetProcessHeap(), 0, unixname);
5289 /*****************************************************************************
5292 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5294 #if HAVE_CUPS_CUPS_H
5297 char *unixname, *queue, *doc_titleA;
5301 if(!(unixname = wine_get_unix_file_name(filename)))
5304 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5305 queue = HeapAlloc(GetProcessHeap(), 0, len);
5306 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5308 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5309 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5310 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5312 TRACE("printing via cups\n");
5313 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5314 HeapFree(GetProcessHeap(), 0, doc_titleA);
5315 HeapFree(GetProcessHeap(), 0, queue);
5316 HeapFree(GetProcessHeap(), 0, unixname);
5322 return schedule_lpr(printer_name, filename);
5326 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5333 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5337 if(HIWORD(wparam) == BN_CLICKED)
5339 if(LOWORD(wparam) == IDOK)
5342 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5345 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5346 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5348 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5350 WCHAR caption[200], message[200];
5353 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5354 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5355 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5356 if(mb_ret == IDCANCEL)
5358 HeapFree(GetProcessHeap(), 0, filename);
5362 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5363 if(hf == INVALID_HANDLE_VALUE)
5365 WCHAR caption[200], message[200];
5367 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5368 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5369 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5370 HeapFree(GetProcessHeap(), 0, filename);
5374 DeleteFileW(filename);
5375 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5377 EndDialog(hwnd, IDOK);
5380 if(LOWORD(wparam) == IDCANCEL)
5382 EndDialog(hwnd, IDCANCEL);
5391 /*****************************************************************************
5394 static BOOL get_filename(LPWSTR *filename)
5396 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5397 file_dlg_proc, (LPARAM)filename) == IDOK;
5400 /*****************************************************************************
5403 static BOOL schedule_file(LPCWSTR filename)
5405 LPWSTR output = NULL;
5407 if(get_filename(&output))
5409 TRACE("copy to %s\n", debugstr_w(output));
5410 CopyFileW(filename, output, FALSE);
5411 HeapFree(GetProcessHeap(), 0, output);
5417 /*****************************************************************************
5420 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5423 char *unixname, *cmdA;
5425 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5429 if(!(unixname = wine_get_unix_file_name(filename)))
5432 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5433 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5434 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5436 TRACE("printing with: %s\n", cmdA);
5438 if((file_fd = open(unixname, O_RDONLY)) == -1)
5443 ERR("pipe() failed!\n");
5453 /* reset signals that we previously set to SIG_IGN */
5454 signal(SIGPIPE, SIG_DFL);
5455 signal(SIGCHLD, SIG_DFL);
5461 while((no_read = read(file_fd, buf, sizeof(buf))))
5462 write(fds[1], buf, no_read);
5467 if(file_fd != -1) close(file_fd);
5468 if(fds[0] != -1) close(fds[0]);
5469 if(fds[1] != -1) close(fds[1]);
5471 HeapFree(GetProcessHeap(), 0, cmdA);
5472 HeapFree(GetProcessHeap(), 0, unixname);
5479 /*****************************************************************************
5482 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
5484 int in_fd, out_fd, no_read;
5487 char *unixname, *outputA;
5490 if(!(unixname = wine_get_unix_file_name(filename)))
5493 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
5494 outputA = HeapAlloc(GetProcessHeap(), 0, len);
5495 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
5497 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5498 in_fd = open(unixname, O_RDONLY);
5499 if(out_fd == -1 || in_fd == -1)
5502 while((no_read = read(in_fd, buf, sizeof(buf))))
5503 write(out_fd, buf, no_read);
5507 if(in_fd != -1) close(in_fd);
5508 if(out_fd != -1) close(out_fd);
5509 HeapFree(GetProcessHeap(), 0, outputA);
5510 HeapFree(GetProcessHeap(), 0, unixname);
5514 /*****************************************************************************
5515 * ScheduleJob [WINSPOOL.@]
5518 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
5520 opened_printer_t *printer;
5522 struct list *cursor, *cursor2;
5524 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
5525 EnterCriticalSection(&printer_handles_cs);
5526 printer = get_opened_printer(hPrinter);
5530 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
5532 job_t *job = LIST_ENTRY(cursor, job_t, entry);
5535 if(job->job_id != dwJobID) continue;
5537 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
5538 if(hf != INVALID_HANDLE_VALUE)
5540 PRINTER_INFO_5W *pi5;
5544 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5545 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5547 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
5548 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
5549 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
5550 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
5551 debugstr_w(pi5->pPortName));
5555 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5556 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
5558 DWORD type, count = sizeof(output);
5559 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
5562 if(output[0] == '|')
5564 schedule_pipe(output + 1, job->filename);
5568 schedule_unixfile(output, job->filename);
5570 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
5572 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
5574 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
5576 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
5578 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
5580 schedule_file(job->filename);
5584 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
5586 HeapFree(GetProcessHeap(), 0, pi5);
5588 DeleteFileW(job->filename);
5590 list_remove(cursor);
5591 HeapFree(GetProcessHeap(), 0, job->document_title);
5592 HeapFree(GetProcessHeap(), 0, job->filename);
5593 HeapFree(GetProcessHeap(), 0, job);
5598 LeaveCriticalSection(&printer_handles_cs);
5602 /*****************************************************************************
5603 * StartDocDlgA [WINSPOOL.@]
5605 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
5607 UNICODE_STRING usBuffer;
5612 docW.cbSize = sizeof(docW);
5613 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
5614 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
5615 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
5616 docW.fwType = doc->fwType;
5618 retW = StartDocDlgW(hPrinter, &docW);
5622 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
5623 ret = HeapAlloc(GetProcessHeap(), 0, len);
5624 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
5625 HeapFree(GetProcessHeap(), 0, retW);
5628 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
5629 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
5630 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
5635 /*****************************************************************************
5636 * StartDocDlgW [WINSPOOL.@]
5638 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5639 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5640 * port is "FILE:". Also returns the full path if passed a relative path.
5642 * The caller should free the returned string from the process heap.
5644 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
5649 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
5651 PRINTER_INFO_5W *pi5;
5652 GetPrinterW(hPrinter, 5, NULL, 0, &len);
5653 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
5655 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
5656 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
5657 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
5659 HeapFree(GetProcessHeap(), 0, pi5);
5662 HeapFree(GetProcessHeap(), 0, pi5);
5665 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
5668 get_filename(&name);
5671 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
5673 HeapFree(GetProcessHeap(), 0, name);
5676 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5677 GetFullPathNameW(name, len, ret, NULL);
5678 HeapFree(GetProcessHeap(), 0, name);
5683 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
5686 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5687 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
5689 attr = GetFileAttributesW(ret);
5690 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
5692 HeapFree(GetProcessHeap(), 0, ret);