4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "wine/port.h"
38 #ifdef HAVE_CUPS_CUPS_H
39 # include <cups/cups.h>
40 # ifndef SONAME_LIBCUPS
41 # define SONAME_LIBCUPS "libcups.so"
45 #define NONAMELESSUNION
46 #define NONAMELESSSTRUCT
47 #include "wine/library.h"
56 #include "wine/windef16.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "wine/list.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
96 WCHAR *document_title;
105 /* ############################### */
107 static opened_printer_t **printer_handles;
108 static int nb_printer_handles;
109 static LONG next_job_id = 1;
111 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
112 WORD fwCapability, LPSTR lpszOutput,
114 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
115 LPSTR lpszDevice, LPSTR lpszPort,
116 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
119 static const char Printers[] =
120 "System\\CurrentControlSet\\control\\Print\\Printers\\";
122 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
123 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
124 'c','o','n','t','r','o','l','\\',
125 'P','r','i','n','t','\\',
126 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
127 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
129 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
130 'M','i','c','r','o','s','o','f','t','\\',
131 'W','i','n','d','o','w','s',' ','N','T','\\',
132 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
133 'W','i','n','d','o','w','s',0};
135 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
136 'M','i','c','r','o','s','o','f','t','\\',
137 'W','i','n','d','o','w','s',' ','N','T','\\',
138 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
139 'D','e','v','i','c','e','s',0};
141 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
142 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
143 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
144 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
145 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
147 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
149 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
150 'i','o','n',' ','F','i','l','e',0};
151 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
152 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
153 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
155 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
157 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
158 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
159 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
160 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
161 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
162 static const WCHAR NameW[] = {'N','a','m','e',0};
163 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
164 static const WCHAR PortW[] = {'P','o','r','t',0};
165 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
167 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
169 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
170 'v','e','r','D','a','t','a',0};
171 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
173 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
174 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
175 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
176 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
177 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
178 static const WCHAR emptyStringW[] = {0};
180 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
182 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
183 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
184 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
186 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
187 'D','o','c','u','m','e','n','t',0};
189 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
190 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
191 DWORD Level, LPBYTE pDriverInfo,
192 DWORD cbBuf, LPDWORD pcbNeeded,
194 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
196 /******************************************************************
197 * validate the user-supplied printing-environment [internal]
200 * env [I] PTR to Environment-String or NULL
204 * Success: PTR to printenv_t
207 * An empty string is handled the same way as NULL.
208 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
212 static const printenv_t * validate_envW(LPCWSTR env)
214 static const printenv_t env_x86 = {envname_x86W, subdir_x86W};
215 static const printenv_t env_win40 = {envname_win40W, subdir_win40W};
216 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
218 const printenv_t *result = NULL;
221 TRACE("testing %s\n", debugstr_w(env));
224 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
226 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
228 result = all_printenv[i];
233 if (result == NULL) {
234 FIXME("unsupported Environment: %s\n", debugstr_w(env));
235 SetLastError(ERROR_INVALID_ENVIRONMENT);
237 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
241 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
243 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
249 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
250 if passed a NULL string. This returns NULLs to the result.
252 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
256 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
257 return usBufferPtr->Buffer;
259 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
263 static LPWSTR strdupW(LPCWSTR p)
269 len = (strlenW(p) + 1) * sizeof(WCHAR);
270 ret = HeapAlloc(GetProcessHeap(), 0, len);
276 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
279 /* If forcing, or no profile string entry for device yet, set the entry
281 * The always change entry if not WINEPS yet is discussable.
284 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
286 !strstr(qbuf,"WINEPS.DRV")
288 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
291 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
292 WriteProfileStringA("windows","device",buf);
293 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
294 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
297 HeapFree(GetProcessHeap(),0,buf);
301 #ifdef HAVE_CUPS_CUPS_H
302 static typeof(cupsGetDests) *pcupsGetDests;
303 static typeof(cupsGetPPD) *pcupsGetPPD;
304 static typeof(cupsPrintFile) *pcupsPrintFile;
305 static void *cupshandle;
307 static BOOL CUPS_LoadPrinters(void)
310 BOOL hadprinter = FALSE;
312 PRINTER_INFO_2A pinfo2a;
314 HKEY hkeyPrinter, hkeyPrinters, hkey;
316 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
319 TRACE("loaded %s\n", SONAME_LIBCUPS);
322 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
323 if (!p##x) return FALSE;
326 DYNCUPS(cupsGetDests);
327 DYNCUPS(cupsPrintFile);
330 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
332 ERR("Can't create Printers key\n");
336 nrofdests = pcupsGetDests(&dests);
337 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
338 for (i=0;i<nrofdests;i++) {
339 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
340 sprintf(port,"LPR:%s",dests[i].name);
341 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
342 sprintf(devline,"WINEPS.DRV,%s",port);
343 WriteProfileStringA("devices",dests[i].name,devline);
344 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
345 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
348 HeapFree(GetProcessHeap(),0,devline);
350 TRACE("Printer %d: %s\n", i, dests[i].name);
351 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
352 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
354 TRACE("Printer already exists\n");
355 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
356 RegCloseKey(hkeyPrinter);
358 memset(&pinfo2a,0,sizeof(pinfo2a));
359 pinfo2a.pPrinterName = dests[i].name;
360 pinfo2a.pDatatype = "RAW";
361 pinfo2a.pPrintProcessor = "WinPrint";
362 pinfo2a.pDriverName = "PS Driver";
363 pinfo2a.pComment = "WINEPS Printer using CUPS";
364 pinfo2a.pLocation = "<physical location of printer>";
365 pinfo2a.pPortName = port;
366 pinfo2a.pParameters = "<parameters?>";
367 pinfo2a.pShareName = "<share name?>";
368 pinfo2a.pSepFile = "<sep file?>";
370 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
371 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
372 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
375 HeapFree(GetProcessHeap(),0,port);
378 if (dests[i].is_default)
379 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
381 RegCloseKey(hkeyPrinters);
387 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
388 PRINTER_INFO_2A pinfo2a;
389 char *e,*s,*name,*prettyname,*devname;
390 BOOL ret = FALSE, set_default = FALSE;
391 char *port,*devline,*env_default;
392 HKEY hkeyPrinter, hkeyPrinters, hkey;
394 while (isspace(*pent)) pent++;
395 s = strchr(pent,':');
397 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
405 TRACE("name=%s entry=%s\n",name, pent);
407 if(ispunct(*name)) { /* a tc entry, not a real printer */
408 TRACE("skipping tc entry\n");
412 if(strstr(pent,":server")) { /* server only version so skip */
413 TRACE("skipping server entry\n");
417 /* Determine whether this is a postscript printer. */
420 env_default = getenv("PRINTER");
422 /* Get longest name, usually the one at the right for later display. */
423 while((s=strchr(prettyname,'|'))) {
426 while(isspace(*--e)) *e = '\0';
427 TRACE("\t%s\n", debugstr_a(prettyname));
428 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
429 for(prettyname = s+1; isspace(*prettyname); prettyname++)
432 e = prettyname + strlen(prettyname);
433 while(isspace(*--e)) *e = '\0';
434 TRACE("\t%s\n", debugstr_a(prettyname));
435 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
437 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
438 * if it is too long, we use it as comment below. */
439 devname = prettyname;
440 if (strlen(devname)>=CCHDEVICENAME-1)
442 if (strlen(devname)>=CCHDEVICENAME-1) {
447 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
448 sprintf(port,"LPR:%s",name);
450 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
451 sprintf(devline,"WINEPS.DRV,%s",port);
452 WriteProfileStringA("devices",devname,devline);
453 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
454 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
457 HeapFree(GetProcessHeap(),0,devline);
459 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
461 ERR("Can't create Printers key\n");
465 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
466 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
468 TRACE("Printer already exists\n");
469 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
470 RegCloseKey(hkeyPrinter);
472 memset(&pinfo2a,0,sizeof(pinfo2a));
473 pinfo2a.pPrinterName = devname;
474 pinfo2a.pDatatype = "RAW";
475 pinfo2a.pPrintProcessor = "WinPrint";
476 pinfo2a.pDriverName = "PS Driver";
477 pinfo2a.pComment = "WINEPS Printer using LPR";
478 pinfo2a.pLocation = prettyname;
479 pinfo2a.pPortName = port;
480 pinfo2a.pParameters = "<parameters?>";
481 pinfo2a.pShareName = "<share name?>";
482 pinfo2a.pSepFile = "<sep file?>";
484 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
485 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
486 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
489 RegCloseKey(hkeyPrinters);
491 if (isfirst || set_default)
492 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
494 HeapFree(GetProcessHeap(), 0, port);
496 HeapFree(GetProcessHeap(), 0, name);
501 PRINTCAP_LoadPrinters(void) {
502 BOOL hadprinter = FALSE;
506 BOOL had_bash = FALSE;
508 f = fopen("/etc/printcap","r");
512 while(fgets(buf,sizeof(buf),f)) {
515 end=strchr(buf,'\n');
519 while(isspace(*start)) start++;
520 if(*start == '#' || *start == '\0')
523 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
524 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
525 HeapFree(GetProcessHeap(),0,pent);
529 if (end && *--end == '\\') {
536 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
539 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
545 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
546 HeapFree(GetProcessHeap(),0,pent);
552 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
555 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
556 lstrlenW(value) * sizeof(WCHAR));
558 return ERROR_FILE_NOT_FOUND;
561 void WINSPOOL_LoadSystemPrinters(void)
563 HKEY hkey, hkeyPrinters;
566 DWORD needed, num, i;
567 WCHAR PrinterName[256];
570 di3a.cVersion = 0x400;
571 di3a.pName = "PS Driver";
572 di3a.pEnvironment = NULL; /* NULL means auto */
573 di3a.pDriverPath = "wineps16";
574 di3a.pDataFile = "<datafile?>";
575 di3a.pConfigFile = "wineps16";
576 di3a.pHelpFile = "<helpfile?>";
577 di3a.pDependentFiles = "<dependend files?>";
578 di3a.pMonitorName = "<monitor name?>";
579 di3a.pDefaultDataType = "RAW";
581 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
582 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
586 /* This ensures that all printer entries have a valid Name value. If causes
587 problems later if they don't. If one is found to be missed we create one
588 and set it equal to the name of the key */
589 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
590 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
591 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
592 for(i = 0; i < num; i++) {
593 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
594 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
595 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
596 set_reg_szW(hkey, NameW, PrinterName);
603 RegCloseKey(hkeyPrinters);
606 /* We want to avoid calling AddPrinter on printers as much as
607 possible, because on cups printers this will (eventually) lead
608 to a call to cupsGetPPD which takes forever, even with non-cups
609 printers AddPrinter takes a while. So we'll tag all printers that
610 were automatically added last time around, if they still exist
611 we'll leave them be otherwise we'll delete them. */
612 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
614 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
615 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
616 for(i = 0; i < num; i++) {
617 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
618 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
619 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
621 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
629 HeapFree(GetProcessHeap(), 0, pi);
633 #ifdef HAVE_CUPS_CUPS_H
634 done = CUPS_LoadPrinters();
637 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
638 /* Check for [ppd] section in config file before parsing /etc/printcap */
639 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
640 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
641 &hkey) == ERROR_SUCCESS) {
643 PRINTCAP_LoadPrinters();
647 /* Now enumerate the list again and delete any printers that a still tagged */
648 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
650 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
651 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
652 for(i = 0; i < num; i++) {
653 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
654 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
655 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
656 DWORD dw, type, size = sizeof(dw);
657 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
658 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
668 HeapFree(GetProcessHeap(), 0, pi);
676 /******************************************************************
677 * get_opened_printer_entry
678 * Get the first place empty in the opened printer table
680 static HANDLE get_opened_printer_entry( LPCWSTR name )
682 UINT_PTR handle = nb_printer_handles, i;
683 jobqueue_t *queue = NULL;
684 opened_printer_t *printer;
686 EnterCriticalSection(&printer_handles_cs);
688 for (i = 0; i < nb_printer_handles; i++)
690 if (!printer_handles[i])
692 if(handle == nb_printer_handles)
695 else if(!queue && !strcmpW(name, printer_handles[i]->name))
696 queue = printer_handles[i]->queue;
699 if (handle >= nb_printer_handles)
701 opened_printer_t **new_array;
703 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
704 (nb_printer_handles + 16) * sizeof(*new_array) );
706 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
707 (nb_printer_handles + 16) * sizeof(*new_array) );
714 printer_handles = new_array;
715 nb_printer_handles += 16;
718 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
724 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
725 strcpyW(printer->name, name);
727 printer->queue = queue;
730 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
731 list_init(&printer->queue->jobs);
732 printer->queue->ref = 0;
734 InterlockedIncrement(&printer->queue->ref);
737 printer_handles[handle] = printer;
740 LeaveCriticalSection(&printer_handles_cs);
742 return (HANDLE)handle;
745 /******************************************************************
747 * Get the pointer to the opened printer referred by the handle
749 static opened_printer_t *get_opened_printer(HANDLE hprn)
751 UINT_PTR idx = (UINT_PTR)hprn;
752 opened_printer_t *ret = NULL;
754 EnterCriticalSection(&printer_handles_cs);
756 if ((idx <= 0) || (idx > nb_printer_handles))
759 ret = printer_handles[idx - 1];
761 LeaveCriticalSection(&printer_handles_cs);
765 /******************************************************************
766 * get_opened_printer_name
767 * Get the pointer to the opened printer name referred by the handle
769 static LPCWSTR get_opened_printer_name(HANDLE hprn)
771 opened_printer_t *printer = get_opened_printer(hprn);
772 if(!printer) return NULL;
773 return printer->name;
776 /******************************************************************
777 * WINSPOOL_GetOpenedPrinterRegKey
780 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
782 LPCWSTR name = get_opened_printer_name(hPrinter);
786 if(!name) return ERROR_INVALID_HANDLE;
788 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
792 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
794 ERR("Can't find opened printer %s in registry\n",
796 RegCloseKey(hkeyPrinters);
797 return ERROR_INVALID_PRINTER_NAME; /* ? */
799 RegCloseKey(hkeyPrinters);
800 return ERROR_SUCCESS;
803 /******************************************************************
806 * Get the pointer to the specified job.
807 * Should hold the printer_handles_cs before calling.
809 static job_t *get_job(HANDLE hprn, DWORD JobId)
811 opened_printer_t *printer = get_opened_printer(hprn);
814 if(!printer) return NULL;
815 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
817 if(job->job_id == JobId)
823 /***********************************************************
826 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
829 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
832 Formname = (dmA->dmSize > off_formname);
833 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
834 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
835 dmW->dmDeviceName, CCHDEVICENAME);
837 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
838 dmA->dmSize - CCHDEVICENAME);
840 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
841 off_formname - CCHDEVICENAME);
842 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
843 dmW->dmFormName, CCHFORMNAME);
844 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
845 (off_formname + CCHFORMNAME));
848 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
853 /***********************************************************
855 * Creates an ascii copy of supplied devmode on heap
857 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
862 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
864 if(!dmW) return NULL;
865 Formname = (dmW->dmSize > off_formname);
866 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
867 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
868 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
869 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
871 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
872 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
874 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
875 off_formname - CCHDEVICENAME * sizeof(WCHAR));
876 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
877 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
878 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
879 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
882 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
887 /***********************************************************
889 * Creates a unicode copy of PRINTER_INFO_2A on heap
891 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
893 LPPRINTER_INFO_2W piW;
894 UNICODE_STRING usBuffer;
896 if(!piA) return NULL;
897 piW = HeapAlloc(heap, 0, sizeof(*piW));
898 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
900 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
901 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
902 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
903 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
904 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
905 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
906 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
907 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
908 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
909 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
910 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
911 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
915 /***********************************************************
916 * FREE_PRINTER_INFO_2W
917 * Free PRINTER_INFO_2W and all strings
919 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
923 HeapFree(heap,0,piW->pServerName);
924 HeapFree(heap,0,piW->pPrinterName);
925 HeapFree(heap,0,piW->pShareName);
926 HeapFree(heap,0,piW->pPortName);
927 HeapFree(heap,0,piW->pDriverName);
928 HeapFree(heap,0,piW->pComment);
929 HeapFree(heap,0,piW->pLocation);
930 HeapFree(heap,0,piW->pDevMode);
931 HeapFree(heap,0,piW->pSepFile);
932 HeapFree(heap,0,piW->pPrintProcessor);
933 HeapFree(heap,0,piW->pDatatype);
934 HeapFree(heap,0,piW->pParameters);
935 HeapFree(heap,0,piW);
939 /******************************************************************
940 * DeviceCapabilities [WINSPOOL.@]
941 * DeviceCapabilitiesA [WINSPOOL.@]
944 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
945 LPSTR pOutput, LPDEVMODEA lpdm)
949 if (!GDI_CallDeviceCapabilities16)
951 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
953 if (!GDI_CallDeviceCapabilities16) return -1;
955 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
957 /* If DC_PAPERSIZE map POINT16s to POINTs */
958 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
959 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
960 POINT *pt = (POINT *)pOutput;
962 memcpy(tmp, pOutput, ret * sizeof(POINT16));
963 for(i = 0; i < ret; i++, pt++)
968 HeapFree( GetProcessHeap(), 0, tmp );
974 /*****************************************************************************
975 * DeviceCapabilitiesW [WINSPOOL.@]
977 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
980 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
981 WORD fwCapability, LPWSTR pOutput,
982 const DEVMODEW *pDevMode)
984 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
985 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
986 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
989 if(pOutput && (fwCapability == DC_BINNAMES ||
990 fwCapability == DC_FILEDEPENDENCIES ||
991 fwCapability == DC_PAPERNAMES)) {
992 /* These need A -> W translation */
995 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
999 switch(fwCapability) {
1004 case DC_FILEDEPENDENCIES:
1008 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1009 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1011 for(i = 0; i < ret; i++)
1012 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1013 pOutput + (i * size), size);
1014 HeapFree(GetProcessHeap(), 0, pOutputA);
1016 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1017 (LPSTR)pOutput, dmA);
1019 HeapFree(GetProcessHeap(),0,pPortA);
1020 HeapFree(GetProcessHeap(),0,pDeviceA);
1021 HeapFree(GetProcessHeap(),0,dmA);
1025 /******************************************************************
1026 * DocumentPropertiesA [WINSPOOL.@]
1028 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1030 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1031 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1032 LPDEVMODEA pDevModeInput,DWORD fMode )
1034 LPSTR lpName = pDeviceName;
1037 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1038 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1042 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1044 ERR("no name from hPrinter?\n");
1045 SetLastError(ERROR_INVALID_HANDLE);
1048 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1051 if (!GDI_CallExtDeviceMode16)
1053 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1055 if (!GDI_CallExtDeviceMode16) {
1056 ERR("No CallExtDeviceMode16?\n");
1060 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1061 pDevModeInput, NULL, fMode);
1064 HeapFree(GetProcessHeap(),0,lpName);
1069 /*****************************************************************************
1070 * DocumentPropertiesW (WINSPOOL.@)
1072 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1074 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1076 LPDEVMODEW pDevModeOutput,
1077 LPDEVMODEW pDevModeInput, DWORD fMode)
1080 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1081 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1082 LPDEVMODEA pDevModeOutputA = NULL;
1085 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1086 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1088 if(pDevModeOutput) {
1089 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1090 if(ret < 0) return ret;
1091 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1093 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1094 pDevModeInputA, fMode);
1095 if(pDevModeOutput) {
1096 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1097 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1099 if(fMode == 0 && ret > 0)
1100 ret += (CCHDEVICENAME + CCHFORMNAME);
1101 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1102 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1106 /******************************************************************
1107 * OpenPrinterA [WINSPOOL.@]
1112 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1113 LPPRINTER_DEFAULTSA pDefault)
1115 UNICODE_STRING lpPrinterNameW;
1116 UNICODE_STRING usBuffer;
1117 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1118 PWSTR pwstrPrinterNameW;
1121 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1124 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1125 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1126 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1127 pDefaultW = &DefaultW;
1129 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1131 RtlFreeUnicodeString(&usBuffer);
1132 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1134 RtlFreeUnicodeString(&lpPrinterNameW);
1138 /******************************************************************
1139 * OpenPrinterW [WINSPOOL.@]
1141 * Open a Printer / Printserver or a Printer-Object
1144 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1145 * phPrinter [O] The resulting Handle is stored here
1146 * pDefault [I] PTR to Default Printer Settings or NULL
1153 * lpPrinterName is one of:
1154 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1155 *| Printer: "PrinterName"
1156 *| Printer-Object: "PrinterName,Job xxx"
1157 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1158 *| XcvPort: "Servername,XcvPort PortName"
1161 *| Printserver not supported
1162 *| Printer-Object not supported
1163 *| XcvMonitor not supported
1164 *| XcvPort not supported
1165 *| pDefaults not supported
1168 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1169 LPPRINTER_DEFAULTSW pDefault)
1171 HKEY hkeyPrinters, hkeyPrinter;
1173 if (!lpPrinterName) {
1174 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1175 SetLastError(ERROR_INVALID_PARAMETER);
1179 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1182 /* Check Printer exists */
1183 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1185 ERR("Can't create Printers key\n");
1186 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1190 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1191 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1193 TRACE("Can't find printer %s in registry\n",
1194 debugstr_w(lpPrinterName));
1195 RegCloseKey(hkeyPrinters);
1196 SetLastError(ERROR_INVALID_PRINTER_NAME);
1199 RegCloseKey(hkeyPrinter);
1200 RegCloseKey(hkeyPrinters);
1202 if(!phPrinter) /* This seems to be what win95 does anyway */
1205 /* Get the unique handle of the printer*/
1206 *phPrinter = get_opened_printer_entry( lpPrinterName );
1208 if (pDefault != NULL)
1209 FIXME("Not handling pDefault\n");
1214 /******************************************************************
1215 * AddMonitorA [WINSPOOL.@]
1220 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1222 FIXME("(%s,0x%08lx,%p), stub!\n", debugstr_a(pName), Level, pMonitors);
1223 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1227 /******************************************************************************
1228 * AddMonitorW [WINSPOOL.@]
1230 * Install a Printmonitor
1233 * pName [I] Servername or NULL (local Computer)
1234 * Level [I] Structure-Level (Must be 2)
1235 * pMonitors [I] PTR to MONITOR_INFO_2
1242 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1248 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1250 FIXME("(%s,0x%08lx,%p), stub!\n",debugstr_w(pName), Level, pMonitors);
1251 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1255 /******************************************************************
1256 * DeletePrinterDriverA [WINSPOOL.@]
1260 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1262 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1263 debugstr_a(pDriverName));
1264 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1268 /******************************************************************
1269 * DeletePrinterDriverW [WINSPOOL.@]
1273 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1275 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1276 debugstr_w(pDriverName));
1277 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1281 /******************************************************************
1282 * DeleteMonitorA [WINSPOOL.@]
1284 * See DeleteMonitorW.
1288 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1290 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1291 debugstr_a(pMonitorName));
1292 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1296 /******************************************************************
1297 * DeleteMonitorW [WINSPOOL.@]
1299 * Delete a specific Printmonitor from a Printing-Environment
1302 * pName [I] Servername or NULL (local Computer)
1303 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1304 * pMonitorName [I] Name of the Monitor, that should be deleted
1315 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1317 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1318 debugstr_w(pMonitorName));
1319 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1323 /******************************************************************
1324 * DeletePortA [WINSPOOL.@]
1330 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1332 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1333 debugstr_a(pPortName));
1334 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1338 /******************************************************************
1339 * DeletePortW [WINSPOOL.@]
1341 * Delete a specific Port
1344 * pName [I] Servername or NULL (local Computer)
1345 * hWnd [I] Handle to parent Window for the Dialog-Box
1346 * pPortName [I] Name of the Port, that should be deleted
1357 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1359 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1360 debugstr_w(pPortName));
1361 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1365 /******************************************************************************
1366 * SetPrinterW [WINSPOOL.@]
1376 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1380 /******************************************************************************
1381 * WritePrinter [WINSPOOL.@]
1383 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1385 opened_printer_t *printer;
1388 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1390 EnterCriticalSection(&printer_handles_cs);
1391 printer = get_opened_printer(hPrinter);
1394 SetLastError(ERROR_INVALID_HANDLE);
1400 SetLastError(ERROR_SPL_NO_STARTDOC);
1404 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1406 LeaveCriticalSection(&printer_handles_cs);
1410 /*****************************************************************************
1411 * AddFormA [WINSPOOL.@]
1413 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1415 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1419 /*****************************************************************************
1420 * AddFormW [WINSPOOL.@]
1422 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1424 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1428 /*****************************************************************************
1429 * AddJobA [WINSPOOL.@]
1431 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1434 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1438 SetLastError(ERROR_INVALID_LEVEL);
1442 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1445 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1446 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1447 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1448 if(*pcbNeeded > cbBuf) {
1449 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1452 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1453 addjobA->JobId = addjobW->JobId;
1454 addjobA->Path = (char *)(addjobA + 1);
1455 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1461 /*****************************************************************************
1462 * AddJobW [WINSPOOL.@]
1464 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1466 opened_printer_t *printer;
1469 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1470 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1471 WCHAR path[MAX_PATH], filename[MAX_PATH];
1473 ADDJOB_INFO_1W *addjob;
1475 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1477 EnterCriticalSection(&printer_handles_cs);
1479 printer = get_opened_printer(hPrinter);
1482 SetLastError(ERROR_INVALID_HANDLE);
1487 SetLastError(ERROR_INVALID_LEVEL);
1491 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1495 job->job_id = InterlockedIncrement(&next_job_id);
1497 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1498 if(path[len - 1] != '\\')
1500 memcpy(path + len, spool_path, sizeof(spool_path));
1501 sprintfW(filename, fmtW, path, job->job_id);
1503 len = strlenW(filename);
1504 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1505 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1506 job->document_title = strdupW(default_doc_title);
1507 list_add_tail(&printer->queue->jobs, &job->entry);
1509 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1510 if(*pcbNeeded <= cbBuf) {
1511 addjob = (ADDJOB_INFO_1W*)pData;
1512 addjob->JobId = job->job_id;
1513 addjob->Path = (WCHAR *)(addjob + 1);
1514 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1517 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1520 LeaveCriticalSection(&printer_handles_cs);
1524 /*****************************************************************************
1525 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1527 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1528 DWORD level, LPBYTE Info,
1529 DWORD cbBuf, LPDWORD needed)
1531 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1532 level, Info, cbBuf);
1536 /*****************************************************************************
1537 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1539 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1540 DWORD level, LPBYTE Info,
1541 DWORD cbBuf, LPDWORD needed)
1543 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1544 level, Info, cbBuf);
1548 /*****************************************************************************
1549 * WINSPOOL_OpenDriverReg [internal]
1551 * opens the registry for the printer drivers depending on the given input
1552 * variable pEnvironment
1555 * the opened hkey on success
1558 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1560 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1561 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1563 LPWSTR lpKey, buffer = NULL;
1567 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1571 pEnvW = pEnvironment;
1573 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1574 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1575 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1580 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1582 if(!GetVersionExW( &ver))
1585 switch (ver.dwPlatformId) {
1586 case VER_PLATFORM_WIN32s:
1587 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1589 case VER_PLATFORM_WIN32_NT:
1596 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1599 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1600 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1601 wsprintfW( lpKey, DriversW, pEnvW);
1603 TRACE("%s\n", debugstr_w(lpKey));
1605 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1608 HeapFree( GetProcessHeap(), 0, buffer);
1609 HeapFree( GetProcessHeap(), 0, lpKey);
1614 /*****************************************************************************
1615 * AddPrinterW [WINSPOOL.@]
1617 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1619 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1623 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1626 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1629 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1630 SetLastError(ERROR_INVALID_PARAMETER);
1634 ERR("Level = %ld, unsupported!\n", Level);
1635 SetLastError(ERROR_INVALID_LEVEL);
1638 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1639 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1640 debugstr_w(pi->pPrinterName)
1642 SetLastError(ERROR_INVALID_LEVEL);
1646 SetLastError(ERROR_INVALID_PARAMETER);
1649 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1651 ERR("Can't create Printers key\n");
1654 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1655 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1656 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1657 RegCloseKey(hkeyPrinter);
1658 RegCloseKey(hkeyPrinters);
1661 RegCloseKey(hkeyPrinter);
1663 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1665 ERR("Can't create Drivers key\n");
1666 RegCloseKey(hkeyPrinters);
1669 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1671 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1672 RegCloseKey(hkeyPrinters);
1673 RegCloseKey(hkeyDrivers);
1674 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1677 RegCloseKey(hkeyDriver);
1678 RegCloseKey(hkeyDrivers);
1680 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1681 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1682 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1683 RegCloseKey(hkeyPrinters);
1687 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1689 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1690 SetLastError(ERROR_INVALID_PRINTER_NAME);
1691 RegCloseKey(hkeyPrinters);
1694 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1695 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1696 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1698 /* See if we can load the driver. We may need the devmode structure anyway
1701 * Note that DocumentPropertiesW will briefly try to open the printer we
1702 * just create to find a DEVMODEA struct (it will use the WINEPS default
1703 * one in case it is not there, so we are ok).
1705 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1708 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1709 size = sizeof(DEVMODEW);
1715 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1716 ZeroMemory(dmW,size);
1718 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1720 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1721 HeapFree(GetProcessHeap(),0,dmW);
1726 /* set devmode to printer name */
1727 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1731 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1732 and we support these drivers. NT writes DEVMODEW so somehow
1733 we'll need to distinguish between these when we support NT
1737 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1738 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1739 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1740 HeapFree(GetProcessHeap(), 0, dmA);
1742 HeapFree(GetProcessHeap(), 0, dmW);
1744 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1745 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1746 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1747 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1749 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1750 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1751 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1752 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1753 (LPBYTE)&pi->Priority, sizeof(DWORD));
1754 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1755 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1756 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1757 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1758 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1759 (LPBYTE)&pi->Status, sizeof(DWORD));
1760 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1761 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1763 RegCloseKey(hkeyPrinter);
1764 RegCloseKey(hkeyPrinters);
1765 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1766 ERR("OpenPrinter failing\n");
1772 /*****************************************************************************
1773 * AddPrinterA [WINSPOOL.@]
1775 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1777 UNICODE_STRING pNameW;
1779 PRINTER_INFO_2W *piW;
1780 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1783 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1785 ERR("Level = %ld, unsupported!\n", Level);
1786 SetLastError(ERROR_INVALID_LEVEL);
1789 pwstrNameW = asciitounicode(&pNameW,pName);
1790 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1792 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
1794 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1795 RtlFreeUnicodeString(&pNameW);
1800 /*****************************************************************************
1801 * ClosePrinter [WINSPOOL.@]
1803 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
1805 UINT_PTR i = (UINT_PTR)hPrinter;
1806 opened_printer_t *printer = NULL;
1809 TRACE("Handle %p\n", hPrinter);
1811 EnterCriticalSection(&printer_handles_cs);
1813 if ((i > 0) && (i <= nb_printer_handles))
1814 printer = printer_handles[i - 1];
1818 struct list *cursor, *cursor2;
1821 EndDocPrinter(hPrinter);
1823 if(InterlockedDecrement(&printer->queue->ref) == 0)
1825 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
1827 job_t *job = LIST_ENTRY(cursor, job_t, entry);
1828 ScheduleJob(hPrinter, job->job_id);
1830 HeapFree(GetProcessHeap(), 0, printer->queue);
1832 HeapFree(GetProcessHeap(), 0, printer->name);
1833 HeapFree(GetProcessHeap(), 0, printer);
1834 printer_handles[i - 1] = NULL;
1837 LeaveCriticalSection(&printer_handles_cs);
1841 /*****************************************************************************
1842 * DeleteFormA [WINSPOOL.@]
1844 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
1846 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
1850 /*****************************************************************************
1851 * DeleteFormW [WINSPOOL.@]
1853 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
1855 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
1859 /*****************************************************************************
1860 * WINSPOOL_SHRegDeleteKey
1862 * Recursively delete subkeys.
1863 * Cut & paste from shlwapi.
1866 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
1868 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1869 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1872 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1875 /* Find how many subkeys there are */
1876 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1877 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1881 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1882 /* Name too big: alloc a buffer for it */
1883 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
1886 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1889 /* Recursively delete all the subkeys */
1890 for(i = 0; i < dwKeyCount && !dwRet; i++)
1892 dwSize = dwMaxSubkeyLen;
1893 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
1895 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
1898 if (lpszName != szNameBuf)
1899 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
1903 RegCloseKey(hSubKey);
1905 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1910 /*****************************************************************************
1911 * DeletePrinter [WINSPOOL.@]
1913 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
1915 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1916 HKEY hkeyPrinters, hkey;
1919 SetLastError(ERROR_INVALID_HANDLE);
1922 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
1923 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
1924 RegCloseKey(hkeyPrinters);
1926 WriteProfileStringW(devicesW, lpNameW, NULL);
1927 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
1928 RegDeleteValueW(hkey, lpNameW);
1934 /*****************************************************************************
1935 * SetPrinterA [WINSPOOL.@]
1937 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1940 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
1944 /*****************************************************************************
1945 * SetJobA [WINSPOOL.@]
1947 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
1948 LPBYTE pJob, DWORD Command)
1952 UNICODE_STRING usBuffer;
1954 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
1956 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
1957 are all ignored by SetJob, so we don't bother copying them */
1965 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
1966 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
1968 JobW = (LPBYTE)info1W;
1969 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
1970 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
1971 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
1972 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
1973 info1W->Status = info1A->Status;
1974 info1W->Priority = info1A->Priority;
1975 info1W->Position = info1A->Position;
1976 info1W->PagesPrinted = info1A->PagesPrinted;
1981 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
1982 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
1984 JobW = (LPBYTE)info2W;
1985 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
1986 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
1987 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
1988 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
1989 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
1990 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
1991 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
1992 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
1993 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
1994 info2W->Status = info2A->Status;
1995 info2W->Priority = info2A->Priority;
1996 info2W->Position = info2A->Position;
1997 info2W->StartTime = info2A->StartTime;
1998 info2W->UntilTime = info2A->UntilTime;
1999 info2W->PagesPrinted = info2A->PagesPrinted;
2003 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2004 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2007 SetLastError(ERROR_INVALID_LEVEL);
2011 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2017 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2018 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2019 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2020 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2021 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2026 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2027 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2028 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2029 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2030 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2031 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2032 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2033 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2034 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2038 HeapFree(GetProcessHeap(), 0, JobW);
2043 /*****************************************************************************
2044 * SetJobW [WINSPOOL.@]
2046 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2047 LPBYTE pJob, DWORD Command)
2052 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2053 FIXME("Ignoring everything other than document title\n");
2055 EnterCriticalSection(&printer_handles_cs);
2056 job = get_job(hPrinter, JobId);
2066 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2067 HeapFree(GetProcessHeap(), 0, job->document_title);
2068 job->document_title = strdupW(info1->pDocument);
2073 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2074 HeapFree(GetProcessHeap(), 0, job->document_title);
2075 job->document_title = strdupW(info2->pDocument);
2081 SetLastError(ERROR_INVALID_LEVEL);
2086 LeaveCriticalSection(&printer_handles_cs);
2090 /*****************************************************************************
2091 * EndDocPrinter [WINSPOOL.@]
2093 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2095 opened_printer_t *printer;
2097 TRACE("(%p)\n", hPrinter);
2099 EnterCriticalSection(&printer_handles_cs);
2101 printer = get_opened_printer(hPrinter);
2104 SetLastError(ERROR_INVALID_HANDLE);
2110 SetLastError(ERROR_SPL_NO_STARTDOC);
2114 CloseHandle(printer->doc->hf);
2115 ScheduleJob(hPrinter, printer->doc->job_id);
2116 HeapFree(GetProcessHeap(), 0, printer->doc);
2117 printer->doc = NULL;
2120 LeaveCriticalSection(&printer_handles_cs);
2124 /*****************************************************************************
2125 * EndPagePrinter [WINSPOOL.@]
2127 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2129 FIXME("(%p): stub\n", hPrinter);
2133 /*****************************************************************************
2134 * StartDocPrinterA [WINSPOOL.@]
2136 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2138 UNICODE_STRING usBuffer;
2140 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2143 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2144 or one (DOC_INFO_3) extra DWORDs */
2148 doc2W.JobId = doc2->JobId;
2151 doc2W.dwMode = doc2->dwMode;
2154 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2155 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2156 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2160 SetLastError(ERROR_INVALID_LEVEL);
2164 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2166 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2167 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2168 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2173 /*****************************************************************************
2174 * StartDocPrinterW [WINSPOOL.@]
2176 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2178 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2179 opened_printer_t *printer;
2180 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2181 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2182 JOB_INFO_1W job_info;
2183 DWORD needed, ret = 0;
2187 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2188 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2189 debugstr_w(doc->pDatatype));
2191 if(Level < 1 || Level > 3)
2193 SetLastError(ERROR_INVALID_LEVEL);
2197 EnterCriticalSection(&printer_handles_cs);
2198 printer = get_opened_printer(hPrinter);
2201 SetLastError(ERROR_INVALID_HANDLE);
2207 SetLastError(ERROR_INVALID_PRINTER_STATE);
2211 /* Even if we're printing to a file we still add a print job, we'll
2212 just ignore the spool file name */
2214 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2216 ERR("AddJob failed gle %08lx\n", GetLastError());
2220 if(doc->pOutputFile)
2221 filename = doc->pOutputFile;
2223 filename = addjob->Path;
2225 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2226 if(hf == INVALID_HANDLE_VALUE)
2229 memset(&job_info, 0, sizeof(job_info));
2230 job_info.pDocument = doc->pDocName;
2231 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2233 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2234 printer->doc->hf = hf;
2235 ret = printer->doc->job_id = addjob->JobId;
2237 LeaveCriticalSection(&printer_handles_cs);
2242 /*****************************************************************************
2243 * StartPagePrinter [WINSPOOL.@]
2245 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2247 FIXME("(%p): stub\n", hPrinter);
2251 /*****************************************************************************
2252 * GetFormA [WINSPOOL.@]
2254 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2255 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2257 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2258 Level,pForm,cbBuf,pcbNeeded);
2262 /*****************************************************************************
2263 * GetFormW [WINSPOOL.@]
2265 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2266 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2268 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2269 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2273 /*****************************************************************************
2274 * SetFormA [WINSPOOL.@]
2276 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2279 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2283 /*****************************************************************************
2284 * SetFormW [WINSPOOL.@]
2286 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2289 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2293 /*****************************************************************************
2294 * ReadPrinter [WINSPOOL.@]
2296 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2297 LPDWORD pNoBytesRead)
2299 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2303 /*****************************************************************************
2304 * ResetPrinterA [WINSPOOL.@]
2306 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2308 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2312 /*****************************************************************************
2313 * ResetPrinterW [WINSPOOL.@]
2315 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2317 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2321 /*****************************************************************************
2322 * WINSPOOL_GetDWORDFromReg
2324 * Return DWORD associated with ValueName from hkey.
2326 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2328 DWORD sz = sizeof(DWORD), type, value = 0;
2331 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2333 if(ret != ERROR_SUCCESS) {
2334 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2337 if(type != REG_DWORD) {
2338 ERR("Got type %ld\n", type);
2344 /*****************************************************************************
2345 * WINSPOOL_GetStringFromReg
2347 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2348 * String is stored either as unicode or ascii.
2349 * Bit of a hack here to get the ValueName if we want ascii.
2351 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2352 DWORD buflen, DWORD *needed,
2355 DWORD sz = buflen, type;
2359 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2361 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2362 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2363 HeapFree(GetProcessHeap(),0,ValueNameA);
2365 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2366 WARN("Got ret = %ld\n", ret);
2374 /*****************************************************************************
2375 * WINSPOOL_GetDefaultDevMode
2377 * Get a default DevMode values for wineps.
2381 static void WINSPOOL_GetDefaultDevMode(
2383 DWORD buflen, DWORD *needed,
2387 static const char szwps[] = "wineps.drv";
2389 /* fill default DEVMODE - should be read from ppd... */
2390 ZeroMemory( &dm, sizeof(dm) );
2391 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2392 dm.dmSpecVersion = DM_SPECVERSION;
2393 dm.dmDriverVersion = 1;
2394 dm.dmSize = sizeof(DEVMODEA);
2395 dm.dmDriverExtra = 0;
2397 DM_ORIENTATION | DM_PAPERSIZE |
2398 DM_PAPERLENGTH | DM_PAPERWIDTH |
2401 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2402 DM_YRESOLUTION | DM_TTOPTION;
2404 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2405 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2406 dm.u1.s1.dmPaperLength = 2970;
2407 dm.u1.s1.dmPaperWidth = 2100;
2411 dm.dmDefaultSource = DMBIN_AUTO;
2412 dm.dmPrintQuality = DMRES_MEDIUM;
2415 dm.dmYResolution = 300; /* 300dpi */
2416 dm.dmTTOption = DMTT_BITMAP;
2419 /* dm.dmLogPixels */
2420 /* dm.dmBitsPerPel */
2421 /* dm.dmPelsWidth */
2422 /* dm.dmPelsHeight */
2423 /* dm.dmDisplayFlags */
2424 /* dm.dmDisplayFrequency */
2425 /* dm.dmICMMethod */
2426 /* dm.dmICMIntent */
2427 /* dm.dmMediaType */
2428 /* dm.dmDitherType */
2429 /* dm.dmReserved1 */
2430 /* dm.dmReserved2 */
2431 /* dm.dmPanningWidth */
2432 /* dm.dmPanningHeight */
2435 if(buflen >= sizeof(DEVMODEW)) {
2436 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2437 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2438 HeapFree(GetProcessHeap(),0,pdmW);
2440 *needed = sizeof(DEVMODEW);
2444 if(buflen >= sizeof(DEVMODEA)) {
2445 memcpy(ptr, &dm, sizeof(DEVMODEA));
2447 *needed = sizeof(DEVMODEA);
2451 /*****************************************************************************
2452 * WINSPOOL_GetDevModeFromReg
2454 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2455 * DevMode is stored either as unicode or ascii.
2457 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2459 DWORD buflen, DWORD *needed,
2462 DWORD sz = buflen, type;
2465 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2466 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2467 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2468 if (sz < sizeof(DEVMODEA))
2470 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2473 /* ensures that dmSize is not erratically bogus if registry is invalid */
2474 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2475 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2477 sz += (CCHDEVICENAME + CCHFORMNAME);
2479 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2480 memcpy(ptr, dmW, sz);
2481 HeapFree(GetProcessHeap(),0,dmW);
2488 /*********************************************************************
2489 * WINSPOOL_GetPrinter_2
2491 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2492 * The strings are either stored as unicode or ascii.
2494 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2495 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2498 DWORD size, left = cbBuf;
2499 BOOL space = (cbBuf > 0);
2504 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2506 if(space && size <= left) {
2507 pi2->pPrinterName = (LPWSTR)ptr;
2514 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2516 if(space && size <= left) {
2517 pi2->pShareName = (LPWSTR)ptr;
2524 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2526 if(space && size <= left) {
2527 pi2->pPortName = (LPWSTR)ptr;
2534 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2536 if(space && size <= left) {
2537 pi2->pDriverName = (LPWSTR)ptr;
2544 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2546 if(space && size <= left) {
2547 pi2->pComment = (LPWSTR)ptr;
2554 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2556 if(space && size <= left) {
2557 pi2->pLocation = (LPWSTR)ptr;
2564 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2566 if(space && size <= left) {
2567 pi2->pDevMode = (LPDEVMODEW)ptr;
2576 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2577 if(space && size <= left) {
2578 pi2->pDevMode = (LPDEVMODEW)ptr;
2585 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2587 if(space && size <= left) {
2588 pi2->pSepFile = (LPWSTR)ptr;
2595 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2597 if(space && size <= left) {
2598 pi2->pPrintProcessor = (LPWSTR)ptr;
2605 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2607 if(space && size <= left) {
2608 pi2->pDatatype = (LPWSTR)ptr;
2615 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2617 if(space && size <= left) {
2618 pi2->pParameters = (LPWSTR)ptr;
2626 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2627 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2628 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2629 "Default Priority");
2630 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2631 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2634 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2635 memset(pi2, 0, sizeof(*pi2));
2640 /*********************************************************************
2641 * WINSPOOL_GetPrinter_4
2643 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2645 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2646 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2649 DWORD size, left = cbBuf;
2650 BOOL space = (cbBuf > 0);
2655 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2657 if(space && size <= left) {
2658 pi4->pPrinterName = (LPWSTR)ptr;
2666 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2669 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2670 memset(pi4, 0, sizeof(*pi4));
2675 /*********************************************************************
2676 * WINSPOOL_GetPrinter_5
2678 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2680 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2681 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2684 DWORD size, left = cbBuf;
2685 BOOL space = (cbBuf > 0);
2690 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2692 if(space && size <= left) {
2693 pi5->pPrinterName = (LPWSTR)ptr;
2700 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2702 if(space && size <= left) {
2703 pi5->pPortName = (LPWSTR)ptr;
2711 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2712 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2714 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2718 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2719 memset(pi5, 0, sizeof(*pi5));
2724 /*****************************************************************************
2725 * WINSPOOL_GetPrinter
2727 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2728 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2729 * just a collection of pointers to strings.
2731 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2732 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2735 DWORD size, needed = 0;
2737 HKEY hkeyPrinter, hkeyPrinters;
2740 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2742 if (!(name = get_opened_printer_name(hPrinter))) {
2743 SetLastError(ERROR_INVALID_HANDLE);
2747 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2749 ERR("Can't create Printers key\n");
2752 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2754 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2755 RegCloseKey(hkeyPrinters);
2756 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2763 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2765 size = sizeof(PRINTER_INFO_2W);
2767 ptr = pPrinter + size;
2769 memset(pPrinter, 0, size);
2774 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2782 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
2784 size = sizeof(PRINTER_INFO_4W);
2786 ptr = pPrinter + size;
2788 memset(pPrinter, 0, size);
2793 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
2802 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
2804 size = sizeof(PRINTER_INFO_5W);
2806 ptr = pPrinter + size;
2808 memset(pPrinter, 0, size);
2814 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
2821 FIXME("Unimplemented level %ld\n", Level);
2822 SetLastError(ERROR_INVALID_LEVEL);
2823 RegCloseKey(hkeyPrinters);
2824 RegCloseKey(hkeyPrinter);
2828 RegCloseKey(hkeyPrinter);
2829 RegCloseKey(hkeyPrinters);
2831 TRACE("returning %d needed = %ld\n", ret, needed);
2832 if(pcbNeeded) *pcbNeeded = needed;
2834 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2838 /*****************************************************************************
2839 * GetPrinterW [WINSPOOL.@]
2841 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2842 DWORD cbBuf, LPDWORD pcbNeeded)
2844 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2848 /*****************************************************************************
2849 * GetPrinterA [WINSPOOL.@]
2851 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2852 DWORD cbBuf, LPDWORD pcbNeeded)
2854 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2858 /*****************************************************************************
2859 * WINSPOOL_EnumPrinters
2861 * Implementation of EnumPrintersA|W
2863 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
2864 DWORD dwLevel, LPBYTE lpbPrinters,
2865 DWORD cbBuf, LPDWORD lpdwNeeded,
2866 LPDWORD lpdwReturned, BOOL unicode)
2869 HKEY hkeyPrinters, hkeyPrinter;
2870 WCHAR PrinterName[255];
2871 DWORD needed = 0, number = 0;
2872 DWORD used, i, left;
2876 memset(lpbPrinters, 0, cbBuf);
2882 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
2883 if(dwType == PRINTER_ENUM_DEFAULT)
2886 if (dwType & PRINTER_ENUM_CONNECTIONS) {
2887 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
2888 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
2889 if(!dwType) return TRUE;
2892 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
2893 FIXME("dwType = %08lx\n", dwType);
2894 SetLastError(ERROR_INVALID_FLAGS);
2898 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2900 ERR("Can't create Printers key\n");
2904 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
2905 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
2906 RegCloseKey(hkeyPrinters);
2907 ERR("Can't query Printers key\n");
2910 TRACE("Found %ld printers\n", number);
2914 RegCloseKey(hkeyPrinters);
2916 *lpdwReturned = number;
2920 used = number * sizeof(PRINTER_INFO_2W);
2923 used = number * sizeof(PRINTER_INFO_4W);
2926 used = number * sizeof(PRINTER_INFO_5W);
2930 SetLastError(ERROR_INVALID_LEVEL);
2931 RegCloseKey(hkeyPrinters);
2934 pi = (used <= cbBuf) ? lpbPrinters : NULL;
2936 for(i = 0; i < number; i++) {
2937 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
2939 ERR("Can't enum key number %ld\n", i);
2940 RegCloseKey(hkeyPrinters);
2943 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
2944 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
2946 ERR("Can't open key %s\n", debugstr_w(PrinterName));
2947 RegCloseKey(hkeyPrinters);
2952 buf = lpbPrinters + used;
2953 left = cbBuf - used;
2961 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
2962 left, &needed, unicode);
2964 if(pi) pi += sizeof(PRINTER_INFO_2W);
2967 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
2968 left, &needed, unicode);
2970 if(pi) pi += sizeof(PRINTER_INFO_4W);
2973 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
2974 left, &needed, unicode);
2976 if(pi) pi += sizeof(PRINTER_INFO_5W);
2979 ERR("Shouldn't be here!\n");
2980 RegCloseKey(hkeyPrinter);
2981 RegCloseKey(hkeyPrinters);
2984 RegCloseKey(hkeyPrinter);
2986 RegCloseKey(hkeyPrinters);
2993 memset(lpbPrinters, 0, cbBuf);
2994 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2998 *lpdwReturned = number;
2999 SetLastError(ERROR_SUCCESS);
3004 /******************************************************************
3005 * EnumPrintersW [WINSPOOL.@]
3007 * Enumerates the available printers, print servers and print
3008 * providers, depending on the specified flags, name and level.
3012 * If level is set to 1:
3013 * Not implemented yet!
3014 * Returns TRUE with an empty list.
3016 * If level is set to 2:
3017 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3018 * Returns an array of PRINTER_INFO_2 data structures in the
3019 * lpbPrinters buffer. Note that according to MSDN also an
3020 * OpenPrinter should be performed on every remote printer.
3022 * If level is set to 4 (officially WinNT only):
3023 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3024 * Fast: Only the registry is queried to retrieve printer names,
3025 * no connection to the driver is made.
3026 * Returns an array of PRINTER_INFO_4 data structures in the
3027 * lpbPrinters buffer.
3029 * If level is set to 5 (officially WinNT4/Win9x only):
3030 * Fast: Only the registry is queried to retrieve printer names,
3031 * no connection to the driver is made.
3032 * Returns an array of PRINTER_INFO_5 data structures in the
3033 * lpbPrinters buffer.
3035 * If level set to 3 or 6+:
3036 * returns zero (failure!)
3038 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3042 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3043 * - Only levels 2, 4 and 5 are implemented at the moment.
3044 * - 16-bit printer drivers are not enumerated.
3045 * - Returned amount of bytes used/needed does not match the real Windoze
3046 * implementation (as in this implementation, all strings are part
3047 * of the buffer, whereas Win32 keeps them somewhere else)
3048 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3051 * - In a regular Wine installation, no registry settings for printers
3052 * exist, which makes this function return an empty list.
3054 BOOL WINAPI EnumPrintersW(
3055 DWORD dwType, /* [in] Types of print objects to enumerate */
3056 LPWSTR lpszName, /* [in] name of objects to enumerate */
3057 DWORD dwLevel, /* [in] type of printer info structure */
3058 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3059 DWORD cbBuf, /* [in] max size of buffer in bytes */
3060 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3061 LPDWORD lpdwReturned /* [out] number of entries returned */
3064 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3065 lpdwNeeded, lpdwReturned, TRUE);
3068 /******************************************************************
3069 * EnumPrintersA [WINSPOOL.@]
3072 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3073 DWORD dwLevel, LPBYTE lpbPrinters,
3074 DWORD cbBuf, LPDWORD lpdwNeeded,
3075 LPDWORD lpdwReturned)
3078 UNICODE_STRING lpszNameW;
3081 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3082 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3083 lpdwNeeded, lpdwReturned, FALSE);
3084 RtlFreeUnicodeString(&lpszNameW);
3088 /*****************************************************************************
3089 * WINSPOOL_GetDriverInfoFromReg [internal]
3091 * Enters the information from the registry into the DRIVER_INFO struct
3094 * zero if the printer driver does not exist in the registry
3095 * (only if Level > 1) otherwise nonzero
3097 static BOOL WINSPOOL_GetDriverInfoFromReg(
3100 LPWSTR pEnvironment,
3102 LPBYTE ptr, /* DRIVER_INFO */
3103 LPBYTE pDriverStrings, /* strings buffer */
3104 DWORD cbBuf, /* size of string buffer */
3105 LPDWORD pcbNeeded, /* space needed for str. */
3106 BOOL unicode) /* type of strings */
3107 { DWORD dw, size, tmp, type;
3109 LPBYTE strPtr = pDriverStrings;
3111 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3112 debugstr_w(DriverName), debugstr_w(pEnvironment),
3113 Level, ptr, pDriverStrings, cbBuf, unicode);
3116 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3117 if (*pcbNeeded <= cbBuf)
3118 strcpyW((LPWSTR)strPtr, DriverName);
3120 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3122 if(*pcbNeeded <= cbBuf)
3123 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3124 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3128 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3132 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
3133 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3136 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3137 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3138 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3143 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
3145 WARN("Can't get Version\n");
3147 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
3150 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3152 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3154 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3157 if(*pcbNeeded <= cbBuf) {
3159 strcpyW((LPWSTR)strPtr, pEnvironment);
3161 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3162 (LPSTR)strPtr, size, NULL, NULL);
3164 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
3165 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3168 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3171 if(*pcbNeeded <= cbBuf)
3172 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3175 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
3176 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3179 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3182 if(*pcbNeeded <= cbBuf)
3183 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3186 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
3187 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3190 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3191 0, &size, unicode)) {
3193 if(*pcbNeeded <= cbBuf)
3194 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3195 size, &tmp, unicode);
3197 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
3198 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3202 RegCloseKey(hkeyDriver);
3203 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3207 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3210 if(*pcbNeeded <= cbBuf)
3211 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3212 size, &tmp, unicode);
3214 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3215 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3218 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3221 if(*pcbNeeded <= cbBuf)
3222 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3223 size, &tmp, unicode);
3225 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3226 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3229 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3232 if(*pcbNeeded <= cbBuf)
3233 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3234 size, &tmp, unicode);
3236 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3237 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3240 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3243 if(*pcbNeeded <= cbBuf)
3244 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3245 size, &tmp, unicode);
3247 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3248 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3251 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3252 RegCloseKey(hkeyDriver);
3256 /*****************************************************************************
3257 * WINSPOOL_GetPrinterDriver
3259 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3260 DWORD Level, LPBYTE pDriverInfo,
3261 DWORD cbBuf, LPDWORD pcbNeeded,
3265 WCHAR DriverName[100];
3266 DWORD ret, type, size, needed = 0;
3268 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3270 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3271 Level,pDriverInfo,cbBuf, pcbNeeded);
3273 ZeroMemory(pDriverInfo, cbBuf);
3275 if (!(name = get_opened_printer_name(hPrinter))) {
3276 SetLastError(ERROR_INVALID_HANDLE);
3279 if(Level < 1 || Level > 3) {
3280 SetLastError(ERROR_INVALID_LEVEL);
3283 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3285 ERR("Can't create Printers key\n");
3288 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3290 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3291 RegCloseKey(hkeyPrinters);
3292 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3295 size = sizeof(DriverName);
3297 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3298 (LPBYTE)DriverName, &size);
3299 RegCloseKey(hkeyPrinter);
3300 RegCloseKey(hkeyPrinters);
3301 if(ret != ERROR_SUCCESS) {
3302 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3306 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3308 ERR("Can't create Drivers key\n");
3314 size = sizeof(DRIVER_INFO_1W);
3317 size = sizeof(DRIVER_INFO_2W);
3320 size = sizeof(DRIVER_INFO_3W);
3323 ERR("Invalid level\n");
3328 ptr = pDriverInfo + size;
3330 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3331 pEnvironment, Level, pDriverInfo,
3332 (cbBuf < size) ? NULL : ptr,
3333 (cbBuf < size) ? 0 : cbBuf - size,
3334 &needed, unicode)) {
3335 RegCloseKey(hkeyDrivers);
3339 RegCloseKey(hkeyDrivers);
3341 if(pcbNeeded) *pcbNeeded = size + needed;
3342 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3343 if(cbBuf >= needed) return TRUE;
3344 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3348 /*****************************************************************************
3349 * GetPrinterDriverA [WINSPOOL.@]
3351 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3352 DWORD Level, LPBYTE pDriverInfo,
3353 DWORD cbBuf, LPDWORD pcbNeeded)
3356 UNICODE_STRING pEnvW;
3359 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3360 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3361 cbBuf, pcbNeeded, FALSE);
3362 RtlFreeUnicodeString(&pEnvW);
3365 /*****************************************************************************
3366 * GetPrinterDriverW [WINSPOOL.@]
3368 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3369 DWORD Level, LPBYTE pDriverInfo,
3370 DWORD cbBuf, LPDWORD pcbNeeded)
3372 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3373 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3376 /*****************************************************************************
3377 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3379 * Return the PATH for the Printer-Drivers (UNICODE)
3382 * pName [I] Servername (NT only) or NULL (local Computer)
3383 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3384 * Level [I] Structure-Level (must be 1)
3385 * pDriverDirectory [O] PTR to Buffer that receives the Result
3386 * cbBuf [I] Size of Buffer at pDriverDirectory
3387 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3388 * required for pDriverDirectory
3391 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3392 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3393 * if cbBuf is too small
3395 * Native Values returned in pDriverDirectory on Success:
3396 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3397 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3398 *| win9x(Windows 4.0): "%winsysdir%"
3400 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3403 *- Only NULL or "" is supported for pName
3406 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3407 DWORD Level, LPBYTE pDriverDirectory,
3408 DWORD cbBuf, LPDWORD pcbNeeded)
3411 const printenv_t * env;
3413 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3414 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3415 if(pName != NULL && pName[0]) {
3416 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3417 SetLastError(ERROR_INVALID_PARAMETER);
3421 env = validate_envW(pEnvironment);
3422 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3425 WARN("(Level: %ld) is ignored in win9x\n", Level);
3426 SetLastError(ERROR_INVALID_LEVEL);
3430 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3431 needed = GetSystemDirectoryW(NULL, 0);
3432 /* add the Size for the Subdirectories */
3433 needed += lstrlenW(spooldriversW);
3434 needed += lstrlenW(env->subdir);
3435 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3438 *pcbNeeded = needed;
3439 TRACE("required: 0x%lx/%ld\n", needed, needed);
3440 if(needed > cbBuf) {
3441 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3444 if(pcbNeeded == NULL) {
3445 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3446 SetLastError(RPC_X_NULL_REF_POINTER);
3449 if(pDriverDirectory == NULL) {
3450 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3451 SetLastError(ERROR_INVALID_USER_BUFFER);
3455 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3456 /* add the Subdirectories */
3457 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3458 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3459 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3464 /*****************************************************************************
3465 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3467 * Return the PATH for the Printer-Drivers (ANSI)
3469 * See GetPrinterDriverDirectoryW.
3472 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3475 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3476 DWORD Level, LPBYTE pDriverDirectory,
3477 DWORD cbBuf, LPDWORD pcbNeeded)
3479 UNICODE_STRING nameW, environmentW;
3482 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3483 WCHAR *driverDirectoryW = NULL;
3485 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3486 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3488 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3490 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3491 else nameW.Buffer = NULL;
3492 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3493 else environmentW.Buffer = NULL;
3495 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3496 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3499 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3500 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3502 *pcbNeeded = needed;
3503 ret = (needed <= cbBuf) ? TRUE : FALSE;
3505 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3507 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3509 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3510 RtlFreeUnicodeString(&environmentW);
3511 RtlFreeUnicodeString(&nameW);
3516 /*****************************************************************************
3517 * AddPrinterDriverA [WINSPOOL.@]
3519 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3522 HKEY hkeyDrivers, hkeyName;
3524 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3526 if(level != 2 && level != 3) {
3527 SetLastError(ERROR_INVALID_LEVEL);
3531 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3532 SetLastError(ERROR_INVALID_PARAMETER);
3536 WARN("pDriverInfo == NULL\n");
3537 SetLastError(ERROR_INVALID_PARAMETER);
3542 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3544 memset(&di3, 0, sizeof(di3));
3545 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3548 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3550 SetLastError(ERROR_INVALID_PARAMETER);
3553 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3554 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3555 if(!di3.pHelpFile) di3.pHelpFile = "";
3556 if(!di3.pMonitorName) di3.pMonitorName = "";
3558 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3561 ERR("Can't create Drivers key\n");
3565 if(level == 2) { /* apparently can't overwrite with level2 */
3566 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3567 RegCloseKey(hkeyName);
3568 RegCloseKey(hkeyDrivers);
3569 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3570 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3574 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3575 RegCloseKey(hkeyDrivers);
3576 ERR("Can't create Name key\n");
3579 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3581 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3582 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3583 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3585 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3586 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3587 (LPBYTE) di3.pDependentFiles, 0);
3588 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3589 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3590 RegCloseKey(hkeyName);
3591 RegCloseKey(hkeyDrivers);
3596 /*****************************************************************************
3597 * AddPrinterDriverW [WINSPOOL.@]
3599 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3602 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3607 /*****************************************************************************
3608 * AddPrintProcessorA [WINSPOOL.@]
3610 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3611 LPSTR pPrintProcessorName)
3613 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3614 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3618 /*****************************************************************************
3619 * AddPrintProcessorW [WINSPOOL.@]
3621 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3622 LPWSTR pPrintProcessorName)
3624 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3625 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3629 /*****************************************************************************
3630 * AddPrintProvidorA [WINSPOOL.@]
3632 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3634 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3638 /*****************************************************************************
3639 * AddPrintProvidorW [WINSPOOL.@]
3641 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3643 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3647 /*****************************************************************************
3648 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3650 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3651 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3653 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3654 pDevModeOutput, pDevModeInput);
3658 /*****************************************************************************
3659 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3661 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3662 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3664 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3665 pDevModeOutput, pDevModeInput);
3669 /*****************************************************************************
3670 * PrinterProperties [WINSPOOL.@]
3672 * Displays a dialog to set the properties of the printer.
3675 * nonzero on success or zero on failure
3678 * implemented as stub only
3680 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3681 HANDLE hPrinter /* [in] handle to printer object */
3683 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3684 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3688 /*****************************************************************************
3689 * EnumJobsA [WINSPOOL.@]
3692 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3693 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3696 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3697 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3699 if(pcbNeeded) *pcbNeeded = 0;
3700 if(pcReturned) *pcReturned = 0;
3705 /*****************************************************************************
3706 * EnumJobsW [WINSPOOL.@]
3709 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3710 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3713 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3714 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3716 if(pcbNeeded) *pcbNeeded = 0;
3717 if(pcReturned) *pcReturned = 0;
3721 /*****************************************************************************
3722 * WINSPOOL_EnumPrinterDrivers [internal]
3724 * Delivers information about all printer drivers installed on the
3725 * localhost or a given server
3728 * nonzero on success or zero on failure. If the buffer for the returned
3729 * information is too small the function will return an error
3732 * - only implemented for localhost, foreign hosts will return an error
3734 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3735 DWORD Level, LPBYTE pDriverInfo,
3736 DWORD cbBuf, LPDWORD pcbNeeded,
3737 LPDWORD pcReturned, BOOL unicode)
3740 DWORD i, needed, number = 0, size = 0;
3741 WCHAR DriverNameW[255];
3744 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3745 debugstr_w(pName), debugstr_w(pEnvironment),
3746 Level, pDriverInfo, cbBuf, unicode);
3748 /* check for local drivers */
3750 ERR("remote drivers unsupported! Current remote host is %s\n",
3755 /* check input parameter */
3756 if((Level < 1) || (Level > 3)) {
3757 ERR("unsupported level %ld\n", Level);
3758 SetLastError(ERROR_INVALID_LEVEL);
3762 /* initialize return values */
3764 memset( pDriverInfo, 0, cbBuf);
3768 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3770 ERR("Can't open Drivers key\n");
3774 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3775 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3776 RegCloseKey(hkeyDrivers);
3777 ERR("Can't query Drivers key\n");
3780 TRACE("Found %ld Drivers\n", number);
3782 /* get size of single struct
3783 * unicode and ascii structure have the same size
3787 size = sizeof(DRIVER_INFO_1A);
3790 size = sizeof(DRIVER_INFO_2A);
3793 size = sizeof(DRIVER_INFO_3A);
3797 /* calculate required buffer size */
3798 *pcbNeeded = size * number;
3800 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
3802 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
3803 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
3805 ERR("Can't enum key number %ld\n", i);
3806 RegCloseKey(hkeyDrivers);
3809 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
3810 pEnvironment, Level, ptr,
3811 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
3812 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
3813 &needed, unicode)) {
3814 RegCloseKey(hkeyDrivers);
3817 (*pcbNeeded) += needed;
3820 RegCloseKey(hkeyDrivers);
3822 if(cbBuf < *pcbNeeded){
3823 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3827 *pcReturned = number;
3831 /*****************************************************************************
3832 * EnumPrinterDriversW [WINSPOOL.@]
3834 * see function EnumPrinterDrivers for RETURNS, BUGS
3836 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
3837 LPBYTE pDriverInfo, DWORD cbBuf,
3838 LPDWORD pcbNeeded, LPDWORD pcReturned)
3840 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
3841 cbBuf, pcbNeeded, pcReturned, TRUE);
3844 /*****************************************************************************
3845 * EnumPrinterDriversA [WINSPOOL.@]
3847 * see function EnumPrinterDrivers for RETURNS, BUGS
3849 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
3850 LPBYTE pDriverInfo, DWORD cbBuf,
3851 LPDWORD pcbNeeded, LPDWORD pcReturned)
3853 UNICODE_STRING pNameW, pEnvironmentW;
3854 PWSTR pwstrNameW, pwstrEnvironmentW;
3856 pwstrNameW = asciitounicode(&pNameW, pName);
3857 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
3859 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
3860 Level, pDriverInfo, cbBuf, pcbNeeded,
3862 RtlFreeUnicodeString(&pNameW);
3863 RtlFreeUnicodeString(&pEnvironmentW);
3868 static CHAR PortMonitor[] = "Wine Port Monitor";
3869 static CHAR PortDescription[] = "Wine Port";
3871 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
3875 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
3876 NULL, OPEN_EXISTING, 0, NULL );
3877 if (handle == INVALID_HANDLE_VALUE)
3879 TRACE("Checking %s exists\n", name );
3880 CloseHandle( handle );
3884 static DWORD WINSPOOL_CountSerialPorts(void)
3891 strcpy( name, "COMx:" );
3893 if (WINSPOOL_ComPortExists( name ))
3900 /******************************************************************************
3901 * EnumPortsA (WINSPOOL.@)
3906 * ANSI-Version did not call the UNICODE-Version
3909 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
3910 LPDWORD bufneeded,LPDWORD bufreturned)
3913 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
3914 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
3918 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
3919 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
3924 info_size = sizeof (PORT_INFO_1A);
3927 info_size = sizeof (PORT_INFO_2A);
3930 SetLastError(ERROR_INVALID_LEVEL);
3934 /* see how many exist */
3937 serial_count = WINSPOOL_CountSerialPorts();
3940 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
3941 if ( r == ERROR_SUCCESS )
3943 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
3944 &printer_count, NULL, NULL, NULL, NULL);
3946 count = serial_count + printer_count;
3948 /* then fill in the structure info structure once
3949 we know the offset to the first string */
3951 memset( buffer, 0, bufsize );
3953 ofs = info_size*count;
3954 for ( i=0; i<count; i++)
3956 DWORD vallen = sizeof(portname) - 1;
3958 /* get the serial port values, then the printer values */
3959 if ( i < serial_count )
3961 strcpy( portname, "COMx:" );
3962 portname[3] = '1' + i;
3963 if (!WINSPOOL_ComPortExists( portname ))
3966 TRACE("Found %s\n", portname );
3967 vallen = strlen( portname );
3971 r = RegEnumValueA( hkey_printer, i-serial_count,
3972 portname, &vallen, NULL, NULL, NULL, 0 );
3977 /* add a colon if necessary, and make it upper case */
3978 CharUpperBuffA(portname,vallen);
3979 if (strcasecmp(portname,"nul")!=0)
3980 if (vallen && (portname[vallen-1] != ':') )
3981 lstrcatA(portname,":");
3983 /* add the port info structure if we can fit it */
3984 if ( info_size*(n+1) < bufsize )
3988 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
3989 info->pName = (LPSTR) &buffer[ofs];
3991 else if ( level == 2)
3993 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
3994 info->pPortName = (LPSTR) &buffer[ofs];
3995 /* FIXME: fill in more stuff here */
3996 info->pMonitorName = PortMonitor;
3997 info->pDescription = PortDescription;
3998 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4001 /* add the name of the port if we can fit it */
4002 if ( ofs < bufsize )
4003 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4009 ofs += lstrlenA(portname)+1;
4012 RegCloseKey(hkey_printer);
4023 /******************************************************************************
4024 * EnumPortsW (WINSPOOL.@)
4026 * Enumerate available Ports
4029 * name [I] Servername or NULL (local Computer)
4030 * level [I] Structure-Level (1 or 2)
4031 * buffer [O] PTR to Buffer that receives the Result
4032 * bufsize [I] Size of Buffer at buffer
4033 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4034 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4038 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4041 * UNICODE-Version is a stub
4044 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4045 LPDWORD bufneeded,LPDWORD bufreturned)
4047 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4048 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4052 /******************************************************************************
4053 * GetDefaultPrinterW (WINSPOOL.@)
4056 * This function must read the value from data 'device' of key
4057 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4059 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4063 WCHAR *buffer, *ptr;
4067 SetLastError(ERROR_INVALID_PARAMETER);
4071 /* make the buffer big enough for the stuff from the profile/registry,
4072 * the content must fit into the local buffer to compute the correct
4073 * size even if the extern buffer is too small or not given.
4074 * (20 for ,driver,port) */
4076 len = max(100, (insize + 20));
4077 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4079 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4081 SetLastError (ERROR_FILE_NOT_FOUND);
4085 TRACE("%s\n", debugstr_w(buffer));
4087 if ((ptr = strchrW(buffer, ',')) == NULL)
4089 SetLastError(ERROR_INVALID_NAME);
4095 *namesize = strlenW(buffer) + 1;
4096 if(!name || (*namesize > insize))
4098 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4102 strcpyW(name, buffer);
4105 HeapFree( GetProcessHeap(), 0, buffer);
4110 /******************************************************************************
4111 * GetDefaultPrinterA (WINSPOOL.@)
4113 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4117 WCHAR *bufferW = NULL;
4121 SetLastError(ERROR_INVALID_PARAMETER);
4125 if(name && *namesize) {
4127 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4130 if(!GetDefaultPrinterW( bufferW, namesize)) {
4135 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4139 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4142 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4145 HeapFree( GetProcessHeap(), 0, bufferW);
4150 /******************************************************************************
4151 * SetPrinterDataExA (WINSPOOL.@)
4153 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4154 LPCSTR pValueName, DWORD Type,
4155 LPBYTE pData, DWORD cbData)
4157 HKEY hkeyPrinter, hkeySubkey;
4160 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4161 debugstr_a(pValueName), Type, pData, cbData);
4163 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4167 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4169 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4170 RegCloseKey(hkeyPrinter);
4173 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4174 RegCloseKey(hkeySubkey);
4175 RegCloseKey(hkeyPrinter);
4179 /******************************************************************************
4180 * SetPrinterDataExW (WINSPOOL.@)
4182 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4183 LPCWSTR pValueName, DWORD Type,
4184 LPBYTE pData, DWORD cbData)
4186 HKEY hkeyPrinter, hkeySubkey;
4189 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4190 debugstr_w(pValueName), Type, pData, cbData);
4192 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4196 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4198 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4199 RegCloseKey(hkeyPrinter);
4202 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4203 RegCloseKey(hkeySubkey);
4204 RegCloseKey(hkeyPrinter);
4208 /******************************************************************************
4209 * SetPrinterDataA (WINSPOOL.@)
4211 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4212 LPBYTE pData, DWORD cbData)
4214 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4218 /******************************************************************************
4219 * SetPrinterDataW (WINSPOOL.@)
4221 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4222 LPBYTE pData, DWORD cbData)
4224 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4228 /******************************************************************************
4229 * GetPrinterDataExA (WINSPOOL.@)
4231 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4232 LPCSTR pValueName, LPDWORD pType,
4233 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4235 HKEY hkeyPrinter, hkeySubkey;
4238 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4239 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4242 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4246 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4248 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4249 RegCloseKey(hkeyPrinter);
4253 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4254 RegCloseKey(hkeySubkey);
4255 RegCloseKey(hkeyPrinter);
4259 /******************************************************************************
4260 * GetPrinterDataExW (WINSPOOL.@)
4262 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4263 LPCWSTR pValueName, LPDWORD pType,
4264 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4266 HKEY hkeyPrinter, hkeySubkey;
4269 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4270 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4273 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4277 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4279 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4280 RegCloseKey(hkeyPrinter);
4284 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4285 RegCloseKey(hkeySubkey);
4286 RegCloseKey(hkeyPrinter);
4290 /******************************************************************************
4291 * GetPrinterDataA (WINSPOOL.@)
4293 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4294 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4296 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4297 pData, nSize, pcbNeeded);
4300 /******************************************************************************
4301 * GetPrinterDataW (WINSPOOL.@)
4303 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4304 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4306 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4307 pData, nSize, pcbNeeded);
4310 /*******************************************************************************
4311 * EnumPrinterDataExW [WINSPOOL.@]
4313 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4314 LPBYTE pEnumValues, DWORD cbEnumValues,
4315 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4317 HKEY hkPrinter, hkSubKey;
4318 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4319 cbValueNameLen, cbMaxValueLen, cbValueLen,
4324 PPRINTER_ENUM_VALUESW ppev;
4326 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4328 if (pKeyName == NULL || *pKeyName == 0)
4329 return ERROR_INVALID_PARAMETER;
4331 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4332 if (ret != ERROR_SUCCESS)
4334 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4339 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4340 if (ret != ERROR_SUCCESS)
4342 r = RegCloseKey (hkPrinter);
4343 if (r != ERROR_SUCCESS)
4344 WARN ("RegCloseKey returned %li\n", r);
4345 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4346 debugstr_w (pKeyName), ret);
4350 ret = RegCloseKey (hkPrinter);
4351 if (ret != ERROR_SUCCESS)
4353 ERR ("RegCloseKey returned %li\n", ret);
4354 r = RegCloseKey (hkSubKey);
4355 if (r != ERROR_SUCCESS)
4356 WARN ("RegCloseKey returned %li\n", r);
4360 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4361 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4362 if (ret != ERROR_SUCCESS)
4364 r = RegCloseKey (hkSubKey);
4365 if (r != ERROR_SUCCESS)
4366 WARN ("RegCloseKey returned %li\n", r);
4367 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4371 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4372 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4374 if (cValues == 0) /* empty key */
4376 r = RegCloseKey (hkSubKey);
4377 if (r != ERROR_SUCCESS)
4378 WARN ("RegCloseKey returned %li\n", r);
4379 *pcbEnumValues = *pnEnumValues = 0;
4380 return ERROR_SUCCESS;
4383 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4385 hHeap = GetProcessHeap ();
4388 ERR ("GetProcessHeap failed\n");
4389 r = RegCloseKey (hkSubKey);
4390 if (r != ERROR_SUCCESS)
4391 WARN ("RegCloseKey returned %li\n", r);
4392 return ERROR_OUTOFMEMORY;
4395 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4396 if (lpValueName == NULL)
4398 ERR ("Failed to allocate %li bytes from process heap\n",
4399 cbMaxValueNameLen * sizeof (WCHAR));
4400 r = RegCloseKey (hkSubKey);
4401 if (r != ERROR_SUCCESS)
4402 WARN ("RegCloseKey returned %li\n", r);
4403 return ERROR_OUTOFMEMORY;
4406 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4407 if (lpValue == NULL)
4409 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4410 if (HeapFree (hHeap, 0, lpValueName) == 0)
4411 WARN ("HeapFree failed with code %li\n", GetLastError ());
4412 r = RegCloseKey (hkSubKey);
4413 if (r != ERROR_SUCCESS)
4414 WARN ("RegCloseKey returned %li\n", r);
4415 return ERROR_OUTOFMEMORY;
4418 TRACE ("pass 1: calculating buffer required for all names and values\n");
4420 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4422 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4424 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4426 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4427 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4428 NULL, NULL, lpValue, &cbValueLen);
4429 if (ret != ERROR_SUCCESS)
4431 if (HeapFree (hHeap, 0, lpValue) == 0)
4432 WARN ("HeapFree failed with code %li\n", GetLastError ());
4433 if (HeapFree (hHeap, 0, lpValueName) == 0)
4434 WARN ("HeapFree failed with code %li\n", GetLastError ());
4435 r = RegCloseKey (hkSubKey);
4436 if (r != ERROR_SUCCESS)
4437 WARN ("RegCloseKey returned %li\n", r);
4438 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4442 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4443 debugstr_w (lpValueName), dwIndex,
4444 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4446 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4447 cbBufSize += cbValueLen;
4450 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4452 *pcbEnumValues = cbBufSize;
4453 *pnEnumValues = cValues;
4455 if (cbEnumValues < cbBufSize) /* buffer too small */
4457 if (HeapFree (hHeap, 0, lpValue) == 0)
4458 WARN ("HeapFree failed with code %li\n", GetLastError ());
4459 if (HeapFree (hHeap, 0, lpValueName) == 0)
4460 WARN ("HeapFree failed with code %li\n", GetLastError ());
4461 r = RegCloseKey (hkSubKey);
4462 if (r != ERROR_SUCCESS)
4463 WARN ("RegCloseKey returned %li\n", r);
4464 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4465 return ERROR_MORE_DATA;
4468 TRACE ("pass 2: copying all names and values to buffer\n");
4470 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4471 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4473 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4475 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4476 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4477 NULL, &dwType, lpValue, &cbValueLen);
4478 if (ret != ERROR_SUCCESS)
4480 if (HeapFree (hHeap, 0, lpValue) == 0)
4481 WARN ("HeapFree failed with code %li\n", GetLastError ());
4482 if (HeapFree (hHeap, 0, lpValueName) == 0)
4483 WARN ("HeapFree failed with code %li\n", GetLastError ());
4484 r = RegCloseKey (hkSubKey);
4485 if (r != ERROR_SUCCESS)
4486 WARN ("RegCloseKey returned %li\n", r);
4487 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4491 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4492 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4493 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4494 pEnumValues += cbValueNameLen;
4496 /* return # of *bytes* (including trailing \0), not # of chars */
4497 ppev[dwIndex].cbValueName = cbValueNameLen;
4499 ppev[dwIndex].dwType = dwType;
4501 memcpy (pEnumValues, lpValue, cbValueLen);
4502 ppev[dwIndex].pData = pEnumValues;
4503 pEnumValues += cbValueLen;
4505 ppev[dwIndex].cbData = cbValueLen;
4507 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4508 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4511 if (HeapFree (hHeap, 0, lpValue) == 0)
4513 ret = GetLastError ();
4514 ERR ("HeapFree failed with code %li\n", ret);
4515 if (HeapFree (hHeap, 0, lpValueName) == 0)
4516 WARN ("HeapFree failed with code %li\n", GetLastError ());
4517 r = RegCloseKey (hkSubKey);
4518 if (r != ERROR_SUCCESS)
4519 WARN ("RegCloseKey returned %li\n", r);
4523 if (HeapFree (hHeap, 0, lpValueName) == 0)
4525 ret = GetLastError ();
4526 ERR ("HeapFree failed with code %li\n", ret);
4527 r = RegCloseKey (hkSubKey);
4528 if (r != ERROR_SUCCESS)
4529 WARN ("RegCloseKey returned %li\n", r);
4533 ret = RegCloseKey (hkSubKey);
4534 if (ret != ERROR_SUCCESS)
4536 ERR ("RegCloseKey returned %li\n", ret);
4540 return ERROR_SUCCESS;
4543 /*******************************************************************************
4544 * EnumPrinterDataExA [WINSPOOL.@]
4546 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4547 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4548 * what Windows 2000 SP1 does.
4551 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4552 LPBYTE pEnumValues, DWORD cbEnumValues,
4553 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4557 DWORD ret, dwIndex, dwBufSize;
4561 TRACE ("%p %s\n", hPrinter, pKeyName);
4563 if (pKeyName == NULL || *pKeyName == 0)
4564 return ERROR_INVALID_PARAMETER;
4566 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4569 ret = GetLastError ();
4570 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4574 hHeap = GetProcessHeap ();
4577 ERR ("GetProcessHeap failed\n");
4578 return ERROR_OUTOFMEMORY;
4581 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4582 if (pKeyNameW == NULL)
4584 ERR ("Failed to allocate %li bytes from process heap\n",
4585 (LONG) len * sizeof (WCHAR));
4586 return ERROR_OUTOFMEMORY;
4589 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4591 ret = GetLastError ();
4592 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4593 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4594 WARN ("HeapFree failed with code %li\n", GetLastError ());
4598 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4599 pcbEnumValues, pnEnumValues);
4600 if (ret != ERROR_SUCCESS)
4602 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4603 WARN ("HeapFree failed with code %li\n", GetLastError ());
4604 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4608 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4610 ret = GetLastError ();
4611 ERR ("HeapFree failed with code %li\n", ret);
4615 if (*pnEnumValues == 0) /* empty key */
4616 return ERROR_SUCCESS;
4619 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4621 PPRINTER_ENUM_VALUESW ppev =
4622 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4624 if (dwBufSize < ppev->cbValueName)
4625 dwBufSize = ppev->cbValueName;
4627 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4628 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4629 dwBufSize = ppev->cbData;
4632 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4634 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4635 if (pBuffer == NULL)
4637 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4638 return ERROR_OUTOFMEMORY;
4641 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4643 PPRINTER_ENUM_VALUESW ppev =
4644 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4646 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4647 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4651 ret = GetLastError ();
4652 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4653 if (HeapFree (hHeap, 0, pBuffer) == 0)
4654 WARN ("HeapFree failed with code %li\n", GetLastError ());
4658 memcpy (ppev->pValueName, pBuffer, len);
4660 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4662 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4663 ppev->dwType != REG_MULTI_SZ)
4666 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4667 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4670 ret = GetLastError ();
4671 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4672 if (HeapFree (hHeap, 0, pBuffer) == 0)
4673 WARN ("HeapFree failed with code %li\n", GetLastError ());
4677 memcpy (ppev->pData, pBuffer, len);
4679 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4680 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4683 if (HeapFree (hHeap, 0, pBuffer) == 0)
4685 ret = GetLastError ();
4686 ERR ("HeapFree failed with code %li\n", ret);
4690 return ERROR_SUCCESS;
4693 /******************************************************************************
4694 * AbortPrinter (WINSPOOL.@)
4696 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4698 FIXME("(%p), stub!\n", hPrinter);
4702 /******************************************************************************
4703 * AddPortA (WINSPOOL.@)
4708 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4710 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4714 /******************************************************************************
4715 * AddPortW (WINSPOOL.@)
4717 * Add a Port for a specific Monitor
4720 * pName [I] Servername or NULL (local Computer)
4721 * hWnd [I] Handle to parent Window for the Dialog-Box
4722 * pMonitorName [I] Name of the Monitor that manage the Port
4732 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
4734 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
4738 /******************************************************************************
4739 * AddPortExA (WINSPOOL.@)
4744 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
4746 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
4747 lpBuffer, debugstr_a(lpMonitorName));
4751 /******************************************************************************
4752 * AddPortExW (WINSPOOL.@)
4754 * Add a Port for a specific Monitor, without presenting a user interface
4757 * hMonitor [I] Handle from InitializePrintMonitor2()
4758 * pName [I] Servername or NULL (local Computer)
4759 * Level [I] Structure-Level (1 or 2) for lpBuffer
4760 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
4761 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
4771 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
4773 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
4774 lpBuffer, debugstr_w(lpMonitorName));
4778 /******************************************************************************
4779 * AddPrinterConnectionA (WINSPOOL.@)
4781 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
4783 FIXME("%s\n", debugstr_a(pName));
4787 /******************************************************************************
4788 * AddPrinterConnectionW (WINSPOOL.@)
4790 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
4792 FIXME("%s\n", debugstr_w(pName));
4796 /******************************************************************************
4797 * AddPrinterDriverExW (WINSPOOL.@)
4799 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
4800 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4802 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
4803 Level, pDriverInfo, dwFileCopyFlags);
4804 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4808 /******************************************************************************
4809 * AddPrinterDriverExA (WINSPOOL.@)
4811 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
4812 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
4814 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
4815 Level, pDriverInfo, dwFileCopyFlags);
4816 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
4820 /******************************************************************************
4821 * ConfigurePortA (WINSPOOL.@)
4823 * See ConfigurePortW.
4826 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
4828 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
4832 /******************************************************************************
4833 * ConfigurePortW (WINSPOOL.@)
4835 * Display the Configuration-Dialog for a specific Port
4838 * pName [I] Servername or NULL (local Computer)
4839 * hWnd [I] Handle to parent Window for the Dialog-Box
4840 * pPortName [I] Name of the Port, that should be configured
4850 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
4852 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
4856 /******************************************************************************
4857 * ConnectToPrinterDlg (WINSPOOL.@)
4859 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
4861 FIXME("%p %lx\n", hWnd, Flags);
4865 /******************************************************************************
4866 * DeletePrinterConnectionA (WINSPOOL.@)
4868 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
4870 FIXME("%s\n", debugstr_a(pName));
4874 /******************************************************************************
4875 * DeletePrinterConnectionW (WINSPOOL.@)
4877 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
4879 FIXME("%s\n", debugstr_w(pName));
4883 /******************************************************************************
4884 * DeletePrinterDriverExW (WINSPOOL.@)
4886 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
4887 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4889 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
4890 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
4894 /******************************************************************************
4895 * DeletePrinterDriverExA (WINSPOOL.@)
4897 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
4898 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
4900 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
4901 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
4905 /******************************************************************************
4906 * DeletePrinterDataExW (WINSPOOL.@)
4908 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
4911 FIXME("%p %s %s\n", hPrinter,
4912 debugstr_w(pKeyName), debugstr_w(pValueName));
4913 return ERROR_INVALID_PARAMETER;
4916 /******************************************************************************
4917 * DeletePrinterDataExA (WINSPOOL.@)
4919 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
4922 FIXME("%p %s %s\n", hPrinter,
4923 debugstr_a(pKeyName), debugstr_a(pValueName));
4924 return ERROR_INVALID_PARAMETER;
4927 /******************************************************************************
4928 * DeletePrintProcessorA (WINSPOOL.@)
4930 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
4932 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4933 debugstr_a(pPrintProcessorName));
4937 /******************************************************************************
4938 * DeletePrintProcessorW (WINSPOOL.@)
4940 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
4942 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4943 debugstr_w(pPrintProcessorName));
4947 /******************************************************************************
4948 * DeletePrintProvidorA (WINSPOOL.@)
4950 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
4952 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
4953 debugstr_a(pPrintProviderName));
4957 /******************************************************************************
4958 * DeletePrintProvidorW (WINSPOOL.@)
4960 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
4962 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
4963 debugstr_w(pPrintProviderName));
4967 /******************************************************************************
4968 * EnumFormsA (WINSPOOL.@)
4970 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4971 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4973 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4977 /******************************************************************************
4978 * EnumFormsW (WINSPOOL.@)
4980 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
4981 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
4983 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
4987 /*****************************************************************************
4988 * EnumMonitorsA [WINSPOOL.@]
4990 * See EnumMonitorsW.
4993 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
4994 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4996 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_a(pName), Level, pMonitors,
4997 cbBuf, pcbNeeded, pcReturned);
4998 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5002 /*****************************************************************************
5003 * EnumMonitorsW [WINSPOOL.@]
5005 * Enumerate available Monitors
5008 * pName [I] Servername or NULL (local Computer)
5009 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5010 * pMonitors [O] PTR to Buffer that receives the Result
5011 * cbBuf [I] Size of Buffer at pMonitors
5012 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5013 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5017 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5023 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5024 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5026 FIXME("%s,%ld,%p,%ld,%p,%p\n", debugstr_w(pName), Level, pMonitors,
5027 cbBuf, pcbNeeded, pcReturned);
5028 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5032 /******************************************************************************
5033 * XcvDataW (WINSPOOL.@)
5036 * There doesn't seem to be an A version...
5038 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5039 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5040 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5042 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5043 pInputData, cbInputData, pOutputData,
5044 cbOutputData, pcbOutputNeeded, pdwStatus);
5048 /*****************************************************************************
5049 * EnumPrinterDataA [WINSPOOL.@]
5052 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5053 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5054 DWORD cbData, LPDWORD pcbData )
5056 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5057 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5058 return ERROR_NO_MORE_ITEMS;
5061 /*****************************************************************************
5062 * EnumPrinterDataW [WINSPOOL.@]
5065 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5066 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5067 DWORD cbData, LPDWORD pcbData )
5069 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5070 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5071 return ERROR_NO_MORE_ITEMS;
5074 /*****************************************************************************
5075 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5078 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5079 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5080 LPDWORD pcbNeeded, LPDWORD pcReturned)
5082 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5083 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5084 pcbNeeded, pcReturned);
5088 /*****************************************************************************
5089 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5092 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5093 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5094 LPDWORD pcbNeeded, LPDWORD pcReturned)
5096 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5097 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5098 pcbNeeded, pcReturned);
5102 /*****************************************************************************
5103 * EnumPrintProcessorsA [WINSPOOL.@]
5106 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5107 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5109 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5110 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5114 /*****************************************************************************
5115 * EnumPrintProcessorsW [WINSPOOL.@]
5118 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5119 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5121 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5122 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5123 cbBuf, pcbNeeded, pcbReturned);
5127 /*****************************************************************************
5128 * ExtDeviceMode [WINSPOOL.@]
5131 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5132 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5135 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5136 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5137 debugstr_a(pProfile), fMode);
5141 /*****************************************************************************
5142 * FindClosePrinterChangeNotification [WINSPOOL.@]
5145 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5147 FIXME("Stub: %p\n", hChange);
5151 /*****************************************************************************
5152 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5155 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5156 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5158 FIXME("Stub: %p %lx %lx %p\n",
5159 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5160 return INVALID_HANDLE_VALUE;
5163 /*****************************************************************************
5164 * FindNextPrinterChangeNotification [WINSPOOL.@]
5167 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5168 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5170 FIXME("Stub: %p %p %p %p\n",
5171 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5175 /*****************************************************************************
5176 * FreePrinterNotifyInfo [WINSPOOL.@]
5179 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5181 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5185 /*****************************************************************************
5188 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5189 * ansi depending on the unicode parameter.
5191 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5201 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5204 memcpy(ptr, str, *size);
5211 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5214 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5221 /*****************************************************************************
5224 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5225 LPDWORD pcbNeeded, BOOL unicode)
5227 DWORD size, left = cbBuf;
5228 BOOL space = (cbBuf > 0);
5235 ji1->JobId = job->job_id;
5238 string_to_buf(job->document_title, ptr, left, &size, unicode);
5239 if(space && size <= left)
5241 ji1->pDocument = (LPWSTR)ptr;
5252 /*****************************************************************************
5255 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5256 LPDWORD pcbNeeded, BOOL unicode)
5258 DWORD size, left = cbBuf;
5259 BOOL space = (cbBuf > 0);
5266 ji2->JobId = job->job_id;
5269 string_to_buf(job->document_title, ptr, left, &size, unicode);
5270 if(space && size <= left)
5272 ji2->pDocument = (LPWSTR)ptr;
5283 /*****************************************************************************
5286 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5287 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5290 DWORD needed = 0, size;
5294 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5296 EnterCriticalSection(&printer_handles_cs);
5297 job = get_job(hPrinter, JobId);
5304 size = sizeof(JOB_INFO_1W);
5309 memset(pJob, 0, size);
5313 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5318 size = sizeof(JOB_INFO_2W);
5323 memset(pJob, 0, size);
5327 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5332 size = sizeof(JOB_INFO_3);
5336 memset(pJob, 0, size);
5345 SetLastError(ERROR_INVALID_LEVEL);
5349 *pcbNeeded = needed;
5351 LeaveCriticalSection(&printer_handles_cs);
5355 /*****************************************************************************
5356 * GetJobA [WINSPOOL.@]
5359 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5360 DWORD cbBuf, LPDWORD pcbNeeded)
5362 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5365 /*****************************************************************************
5366 * GetJobW [WINSPOOL.@]
5369 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5370 DWORD cbBuf, LPDWORD pcbNeeded)
5372 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5375 /*****************************************************************************
5378 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5380 char *unixname, *queue, *cmd;
5381 char fmt[] = "lpr -P%s %s";
5384 if(!(unixname = wine_get_unix_file_name(filename)))
5387 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5388 queue = HeapAlloc(GetProcessHeap(), 0, len);
5389 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5391 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5392 sprintf(cmd, fmt, queue, unixname);
5394 TRACE("printing with: %s\n", cmd);
5397 HeapFree(GetProcessHeap(), 0, cmd);
5398 HeapFree(GetProcessHeap(), 0, queue);
5399 HeapFree(GetProcessHeap(), 0, unixname);
5403 /*****************************************************************************
5406 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5408 #if HAVE_CUPS_CUPS_H
5411 char *unixname, *queue, *doc_titleA;
5415 if(!(unixname = wine_get_unix_file_name(filename)))
5418 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5419 queue = HeapAlloc(GetProcessHeap(), 0, len);
5420 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5422 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5423 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5424 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5426 TRACE("printing via cups\n");
5427 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5428 HeapFree(GetProcessHeap(), 0, doc_titleA);
5429 HeapFree(GetProcessHeap(), 0, queue);
5430 HeapFree(GetProcessHeap(), 0, unixname);
5436 return schedule_lpr(printer_name, filename);
5440 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5447 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5451 if(HIWORD(wparam) == BN_CLICKED)
5453 if(LOWORD(wparam) == IDOK)
5456 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5459 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5460 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5462 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5464 WCHAR caption[200], message[200];
5467 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5468 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5469 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5470 if(mb_ret == IDCANCEL)
5472 HeapFree(GetProcessHeap(), 0, filename);
5476 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5477 if(hf == INVALID_HANDLE_VALUE)
5479 WCHAR caption[200], message[200];
5481 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5482 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5483 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5484 HeapFree(GetProcessHeap(), 0, filename);
5488 DeleteFileW(filename);
5489 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5491 EndDialog(hwnd, IDOK);
5494 if(LOWORD(wparam) == IDCANCEL)
5496 EndDialog(hwnd, IDCANCEL);
5505 /*****************************************************************************
5508 static BOOL get_filename(LPWSTR *filename)
5510 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5511 file_dlg_proc, (LPARAM)filename) == IDOK;
5514 /*****************************************************************************
5517 static BOOL schedule_file(LPCWSTR filename)
5519 LPWSTR output = NULL;
5521 if(get_filename(&output))
5523 TRACE("copy to %s\n", debugstr_w(output));
5524 CopyFileW(filename, output, FALSE);
5525 HeapFree(GetProcessHeap(), 0, output);
5531 /*****************************************************************************
5534 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5537 char *unixname, *cmdA;
5539 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5543 if(!(unixname = wine_get_unix_file_name(filename)))
5546 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5547 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5548 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5550 TRACE("printing with: %s\n", cmdA);
5552 if((file_fd = open(unixname, O_RDONLY)) == -1)
5557 ERR("pipe() failed!\n");
5567 /* reset signals that we previously set to SIG_IGN */
5568 signal(SIGPIPE, SIG_DFL);
5569 signal(SIGCHLD, SIG_DFL);
5575 while((no_read = read(file_fd, buf, sizeof(buf))))
5576 write(fds[1], buf, no_read);
5581 if(file_fd != -1) close(file_fd);
5582 if(fds[0] != -1) close(fds[0]);
5583 if(fds[1] != -1) close(fds[1]);
5585 HeapFree(GetProcessHeap(), 0, cmdA);
5586 HeapFree(GetProcessHeap(), 0, unixname);
5593 /*****************************************************************************
5596 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
5598 int in_fd, out_fd, no_read;
5601 char *unixname, *outputA;
5604 if(!(unixname = wine_get_unix_file_name(filename)))
5607 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
5608 outputA = HeapAlloc(GetProcessHeap(), 0, len);
5609 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
5611 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5612 in_fd = open(unixname, O_RDONLY);
5613 if(out_fd == -1 || in_fd == -1)
5616 while((no_read = read(in_fd, buf, sizeof(buf))))
5617 write(out_fd, buf, no_read);
5621 if(in_fd != -1) close(in_fd);
5622 if(out_fd != -1) close(out_fd);
5623 HeapFree(GetProcessHeap(), 0, outputA);
5624 HeapFree(GetProcessHeap(), 0, unixname);
5628 /*****************************************************************************
5629 * ScheduleJob [WINSPOOL.@]
5632 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
5634 opened_printer_t *printer;
5636 struct list *cursor, *cursor2;
5638 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
5639 EnterCriticalSection(&printer_handles_cs);
5640 printer = get_opened_printer(hPrinter);
5644 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
5646 job_t *job = LIST_ENTRY(cursor, job_t, entry);
5649 if(job->job_id != dwJobID) continue;
5651 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
5652 if(hf != INVALID_HANDLE_VALUE)
5654 PRINTER_INFO_5W *pi5;
5658 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
5659 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
5661 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
5662 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
5663 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
5664 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
5665 debugstr_w(pi5->pPortName));
5669 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
5670 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
5672 DWORD type, count = sizeof(output);
5673 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
5676 if(output[0] == '|')
5678 schedule_pipe(output + 1, job->filename);
5682 schedule_unixfile(output, job->filename);
5684 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
5686 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
5688 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
5690 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
5692 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
5694 schedule_file(job->filename);
5698 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
5700 HeapFree(GetProcessHeap(), 0, pi5);
5702 DeleteFileW(job->filename);
5704 list_remove(cursor);
5705 HeapFree(GetProcessHeap(), 0, job->document_title);
5706 HeapFree(GetProcessHeap(), 0, job->filename);
5707 HeapFree(GetProcessHeap(), 0, job);
5712 LeaveCriticalSection(&printer_handles_cs);
5716 /*****************************************************************************
5717 * StartDocDlgA [WINSPOOL.@]
5719 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
5721 UNICODE_STRING usBuffer;
5726 docW.cbSize = sizeof(docW);
5727 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
5728 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
5729 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
5730 docW.fwType = doc->fwType;
5732 retW = StartDocDlgW(hPrinter, &docW);
5736 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
5737 ret = HeapAlloc(GetProcessHeap(), 0, len);
5738 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
5739 HeapFree(GetProcessHeap(), 0, retW);
5742 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
5743 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
5744 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
5749 /*****************************************************************************
5750 * StartDocDlgW [WINSPOOL.@]
5752 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
5753 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
5754 * port is "FILE:". Also returns the full path if passed a relative path.
5756 * The caller should free the returned string from the process heap.
5758 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
5763 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
5765 PRINTER_INFO_5W *pi5;
5766 GetPrinterW(hPrinter, 5, NULL, 0, &len);
5767 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
5769 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
5770 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
5771 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
5773 HeapFree(GetProcessHeap(), 0, pi5);
5776 HeapFree(GetProcessHeap(), 0, pi5);
5779 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
5782 get_filename(&name);
5785 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
5787 HeapFree(GetProcessHeap(), 0, name);
5790 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5791 GetFullPathNameW(name, len, ret, NULL);
5792 HeapFree(GetProcessHeap(), 0, name);
5797 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
5800 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5801 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
5803 attr = GetFileAttributesW(ret);
5804 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
5806 HeapFree(GetProcessHeap(), 0, ret);