4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006, 2007 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
63 #include "ddk/winsplp.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
68 /* ############################### */
70 static CRITICAL_SECTION monitor_handles_cs;
71 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
73 0, 0, &monitor_handles_cs,
74 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
75 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
77 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
80 static CRITICAL_SECTION printer_handles_cs;
81 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
83 0, 0, &printer_handles_cs,
84 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
85 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
87 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
89 /* ############################### */
125 WCHAR *document_title;
133 LPCWSTR versionregpath;
134 LPCWSTR versionsubdir;
137 /* ############################### */
139 static struct list monitor_handles = LIST_INIT( monitor_handles );
140 static monitor_t * pm_localport;
142 static opened_printer_t **printer_handles;
143 static int nb_printer_handles;
144 static LONG next_job_id = 1;
146 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
147 WORD fwCapability, LPSTR lpszOutput,
149 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
150 LPSTR lpszDevice, LPSTR lpszPort,
151 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
154 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
155 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
156 'c','o','n','t','r','o','l','\\',
157 'P','r','i','n','t','\\',
158 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
159 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
161 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
162 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
163 'C','o','n','t','r','o','l','\\',
164 'P','r','i','n','t','\\',
165 'M','o','n','i','t','o','r','s','\\',0};
167 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
168 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
169 'C','o','n','t','r','o','l','\\',
170 'P','r','i','n','t','\\',
171 'P','r','i','n','t','e','r','s',0};
173 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
175 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
176 'M','i','c','r','o','s','o','f','t','\\',
177 'W','i','n','d','o','w','s',' ','N','T','\\',
178 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
179 'W','i','n','d','o','w','s',0};
181 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
182 'M','i','c','r','o','s','o','f','t','\\',
183 'W','i','n','d','o','w','s',' ','N','T','\\',
184 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
185 'D','e','v','i','c','e','s',0};
187 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
188 'M','i','c','r','o','s','o','f','t','\\',
189 'W','i','n','d','o','w','s',' ','N','T','\\',
190 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
191 'P','o','r','t','s',0};
193 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
194 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
195 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
196 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
197 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
198 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
199 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
201 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
202 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
204 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
210 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
212 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
213 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
214 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
215 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
216 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW[] = {'N','a','m','e',0};
219 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
220 static const WCHAR PortW[] = {'P','o','r','t',0};
221 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
222 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
224 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
226 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
227 'v','e','r','D','a','t','a',0};
228 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
230 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
232 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
233 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
234 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
235 static const WCHAR emptyStringW[] = {0};
236 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
237 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
239 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
241 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
242 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
243 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
245 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
246 'D','o','c','u','m','e','n','t',0};
249 /*****************************************************************************
250 * WINSPOOL_SHRegDeleteKey
252 * Recursively delete subkeys.
253 * Cut & paste from shlwapi.
256 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
258 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
259 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
262 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
265 /* Find how many subkeys there are */
266 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
267 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
271 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
272 /* Name too big: alloc a buffer for it */
273 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
276 dwRet = ERROR_NOT_ENOUGH_MEMORY;
279 /* Recursively delete all the subkeys */
280 for(i = 0; i < dwKeyCount && !dwRet; i++)
282 dwSize = dwMaxSubkeyLen;
283 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
285 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
288 if (lpszName != szNameBuf)
289 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
293 RegCloseKey(hSubKey);
295 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
301 /******************************************************************
302 * validate the user-supplied printing-environment [internal]
305 * env [I] PTR to Environment-String or NULL
309 * Success: PTR to printenv_t
312 * An empty string is handled the same way as NULL.
313 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
317 static const printenv_t * validate_envW(LPCWSTR env)
319 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
320 3, Version3_RegPathW, Version3_SubdirW};
321 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
322 0, emptyStringW, emptyStringW};
323 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
325 const printenv_t *result = NULL;
328 TRACE("testing %s\n", debugstr_w(env));
331 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
333 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
335 result = all_printenv[i];
340 if (result == NULL) {
341 FIXME("unsupported Environment: %s\n", debugstr_w(env));
342 SetLastError(ERROR_INVALID_ENVIRONMENT);
344 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
348 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
350 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
356 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
357 if passed a NULL string. This returns NULLs to the result.
359 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
363 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
364 return usBufferPtr->Buffer;
366 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
370 static LPWSTR strdupW(LPCWSTR p)
376 len = (strlenW(p) + 1) * sizeof(WCHAR);
377 ret = HeapAlloc(GetProcessHeap(), 0, len);
382 static LPSTR strdupWtoA( LPCWSTR str )
387 if (!str) return NULL;
388 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
389 ret = HeapAlloc( GetProcessHeap(), 0, len );
390 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
394 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
395 The result includes all \0s (specifically the last two). */
396 static int multi_sz_lenA(const char *str)
398 const char *ptr = str;
402 ptr += lstrlenA(ptr) + 1;
405 return ptr - str + 1;
409 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
412 /* If forcing, or no profile string entry for device yet, set the entry
414 * The always change entry if not WINEPS yet is discussable.
417 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
419 !strstr(qbuf,"WINEPS.DRV")
421 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
424 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
425 WriteProfileStringA("windows","device",buf);
426 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
427 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
430 HeapFree(GetProcessHeap(),0,buf);
434 static BOOL add_printer_driver(const char *name)
438 static char driver_path[] = "wineps16",
439 data_file[] = "<datafile?>",
440 config_file[] = "wineps16",
441 help_file[] = "<helpfile?>",
442 dep_file[] = "<dependent files?>\0",
443 monitor_name[] = "<monitor name?>",
444 default_data_type[] = "RAW";
446 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
447 di3a.pName = (char *)name;
448 di3a.pEnvironment = NULL; /* NULL means auto */
449 di3a.pDriverPath = driver_path;
450 di3a.pDataFile = data_file;
451 di3a.pConfigFile = config_file;
452 di3a.pHelpFile = help_file;
453 di3a.pDependentFiles = dep_file;
454 di3a.pMonitorName = monitor_name;
455 di3a.pDefaultDataType = default_data_type;
457 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
459 ERR("Failed adding driver (%d)\n", GetLastError());
465 #ifdef HAVE_CUPS_CUPS_H
466 static typeof(cupsGetDests) *pcupsGetDests;
467 static typeof(cupsGetPPD) *pcupsGetPPD;
468 static typeof(cupsPrintFile) *pcupsPrintFile;
469 static void *cupshandle;
471 static BOOL CUPS_LoadPrinters(void)
474 BOOL hadprinter = FALSE;
476 PRINTER_INFO_2A pinfo2a;
478 HKEY hkeyPrinter, hkeyPrinters, hkey;
480 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
483 TRACE("loaded %s\n", SONAME_LIBCUPS);
486 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
487 if (!p##x) return FALSE;
490 DYNCUPS(cupsGetDests);
491 DYNCUPS(cupsPrintFile);
494 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
496 ERR("Can't create Printers key\n");
500 nrofdests = pcupsGetDests(&dests);
501 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
502 for (i=0;i<nrofdests;i++) {
503 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
504 sprintf(port,"LPR:%s",dests[i].name);
505 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
506 sprintf(devline,"WINEPS.DRV,%s",port);
507 WriteProfileStringA("devices",dests[i].name,devline);
508 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
509 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
512 HeapFree(GetProcessHeap(),0,devline);
514 TRACE("Printer %d: %s\n", i, dests[i].name);
515 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
516 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
518 TRACE("Printer already exists\n");
519 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
520 RegCloseKey(hkeyPrinter);
522 static CHAR data_type[] = "RAW",
523 print_proc[] = "WinPrint",
524 comment[] = "WINEPS Printer using CUPS",
525 location[] = "<physical location of printer>",
526 params[] = "<parameters?>",
527 share_name[] = "<share name?>",
528 sep_file[] = "<sep file?>";
530 add_printer_driver(dests[i].name);
532 memset(&pinfo2a,0,sizeof(pinfo2a));
533 pinfo2a.pPrinterName = dests[i].name;
534 pinfo2a.pDatatype = data_type;
535 pinfo2a.pPrintProcessor = print_proc;
536 pinfo2a.pDriverName = dests[i].name;
537 pinfo2a.pComment = comment;
538 pinfo2a.pLocation = location;
539 pinfo2a.pPortName = port;
540 pinfo2a.pParameters = params;
541 pinfo2a.pShareName = share_name;
542 pinfo2a.pSepFile = sep_file;
544 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
545 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
546 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
549 HeapFree(GetProcessHeap(),0,port);
552 if (dests[i].is_default)
553 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
555 RegCloseKey(hkeyPrinters);
561 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
562 PRINTER_INFO_2A pinfo2a;
563 char *e,*s,*name,*prettyname,*devname;
564 BOOL ret = FALSE, set_default = FALSE;
565 char *port,*devline,*env_default;
566 HKEY hkeyPrinter, hkeyPrinters, hkey;
568 while (isspace(*pent)) pent++;
569 s = strchr(pent,':');
571 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
579 TRACE("name=%s entry=%s\n",name, pent);
581 if(ispunct(*name)) { /* a tc entry, not a real printer */
582 TRACE("skipping tc entry\n");
586 if(strstr(pent,":server")) { /* server only version so skip */
587 TRACE("skipping server entry\n");
591 /* Determine whether this is a postscript printer. */
594 env_default = getenv("PRINTER");
596 /* Get longest name, usually the one at the right for later display. */
597 while((s=strchr(prettyname,'|'))) {
600 while(isspace(*--e)) *e = '\0';
601 TRACE("\t%s\n", debugstr_a(prettyname));
602 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
603 for(prettyname = s+1; isspace(*prettyname); prettyname++)
606 e = prettyname + strlen(prettyname);
607 while(isspace(*--e)) *e = '\0';
608 TRACE("\t%s\n", debugstr_a(prettyname));
609 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
611 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
612 * if it is too long, we use it as comment below. */
613 devname = prettyname;
614 if (strlen(devname)>=CCHDEVICENAME-1)
616 if (strlen(devname)>=CCHDEVICENAME-1) {
621 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
622 sprintf(port,"LPR:%s",name);
624 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
625 sprintf(devline,"WINEPS.DRV,%s",port);
626 WriteProfileStringA("devices",devname,devline);
627 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
628 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
631 HeapFree(GetProcessHeap(),0,devline);
633 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
635 ERR("Can't create Printers key\n");
639 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
640 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
642 TRACE("Printer already exists\n");
643 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
644 RegCloseKey(hkeyPrinter);
646 static CHAR data_type[] = "RAW",
647 print_proc[] = "WinPrint",
648 comment[] = "WINEPS Printer using LPR",
649 params[] = "<parameters?>",
650 share_name[] = "<share name?>",
651 sep_file[] = "<sep file?>";
653 add_printer_driver(devname);
655 memset(&pinfo2a,0,sizeof(pinfo2a));
656 pinfo2a.pPrinterName = devname;
657 pinfo2a.pDatatype = data_type;
658 pinfo2a.pPrintProcessor = print_proc;
659 pinfo2a.pDriverName = devname;
660 pinfo2a.pComment = comment;
661 pinfo2a.pLocation = prettyname;
662 pinfo2a.pPortName = port;
663 pinfo2a.pParameters = params;
664 pinfo2a.pShareName = share_name;
665 pinfo2a.pSepFile = sep_file;
667 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
668 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
669 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
672 RegCloseKey(hkeyPrinters);
674 if (isfirst || set_default)
675 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
677 HeapFree(GetProcessHeap(), 0, port);
679 HeapFree(GetProcessHeap(), 0, name);
684 PRINTCAP_LoadPrinters(void) {
685 BOOL hadprinter = FALSE;
689 BOOL had_bash = FALSE;
691 f = fopen("/etc/printcap","r");
695 while(fgets(buf,sizeof(buf),f)) {
698 end=strchr(buf,'\n');
702 while(isspace(*start)) start++;
703 if(*start == '#' || *start == '\0')
706 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
707 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
708 HeapFree(GetProcessHeap(),0,pent);
712 if (end && *--end == '\\') {
719 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
722 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
728 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
729 HeapFree(GetProcessHeap(),0,pent);
735 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
738 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
739 (lstrlenW(value) + 1) * sizeof(WCHAR));
741 return ERROR_FILE_NOT_FOUND;
744 /*****************************************************************************
745 * enumerate the local monitors (INTERNAL)
747 * returns the needed size (in bytes) for pMonitors
748 * and *lpreturned is set to number of entries returned in pMonitors
751 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
756 LPMONITOR_INFO_2W mi;
757 WCHAR buffer[MAX_PATH];
758 WCHAR dllname[MAX_PATH];
766 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
768 numentries = *lpreturned; /* this is 0, when we scan the registry */
769 len = entrysize * numentries;
770 ptr = (LPWSTR) &pMonitors[len];
773 len = sizeof(buffer);
776 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
777 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
778 /* Scan all Monitor-Registry-Keys */
779 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
780 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
781 dllsize = sizeof(dllname);
784 /* The Monitor must have a Driver-DLL */
785 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
786 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
787 /* We found a valid DLL for this Monitor. */
788 TRACE("using Driver: %s\n", debugstr_w(dllname));
793 /* Windows returns only Port-Monitors here, but to simplify our code,
794 we do no filtering for Language-Monitors */
798 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
800 /* we install and return only monitors for "Windows NT x86" */
801 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
805 /* required size is calculated. Now fill the user-buffer */
806 if (pMonitors && (cbBuf >= needed)){
807 mi = (LPMONITOR_INFO_2W) pMonitors;
808 pMonitors += entrysize;
810 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
812 lstrcpyW(ptr, buffer); /* Name of the Monitor */
813 ptr += (len+1); /* len is lstrlenW(monitorname) */
815 mi->pEnvironment = ptr;
816 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
817 ptr += (lstrlenW(envname_x86W)+1);
820 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
821 ptr += (dllsize / sizeof(WCHAR));
826 len = sizeof(buffer);
831 *lpreturned = numentries;
832 TRACE("need %d byte for %d entries\n", needed, numentries);
836 /******************************************************************
837 * monitor_unload [internal]
839 * release a printmonitor and unload it from memory, when needed
842 static void monitor_unload(monitor_t * pm)
844 if (pm == NULL) return;
845 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
847 EnterCriticalSection(&monitor_handles_cs);
849 if (pm->refcount) pm->refcount--;
851 if (pm->refcount == 0) {
852 list_remove(&pm->entry);
853 FreeLibrary(pm->hdll);
854 HeapFree(GetProcessHeap(), 0, pm->name);
855 HeapFree(GetProcessHeap(), 0, pm->dllname);
856 HeapFree(GetProcessHeap(), 0, pm);
858 LeaveCriticalSection(&monitor_handles_cs);
861 /******************************************************************
862 * monitor_unloadall [internal]
864 * release all printmonitors and unload them from memory, when needed
867 static void monitor_unloadall(void)
872 EnterCriticalSection(&monitor_handles_cs);
873 /* iterate through the list, with safety against removal */
874 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
878 LeaveCriticalSection(&monitor_handles_cs);
881 /******************************************************************
882 * monitor_load [internal]
884 * load a printmonitor, get the dllname from the registry, when needed
885 * initialize the monitor and dump found function-pointers
887 * On failure, SetLastError() is called and NULL is returned
890 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
892 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
893 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
894 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
895 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
896 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
898 monitor_t * pm = NULL;
900 LPWSTR regroot = NULL;
901 LPWSTR driver = dllname;
903 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
904 /* Is the Monitor already loaded? */
905 EnterCriticalSection(&monitor_handles_cs);
908 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
910 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
918 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
919 if (pm == NULL) goto cleanup;
920 list_add_tail(&monitor_handles, &pm->entry);
924 if (pm->name == NULL) {
925 /* Load the monitor */
926 LPMONITOREX pmonitorEx;
930 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
931 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
935 lstrcpyW(regroot, MonitorsW);
936 lstrcatW(regroot, name);
937 /* Get the Driver from the Registry */
938 if (driver == NULL) {
941 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
942 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
943 &namesize) == ERROR_SUCCESS) {
944 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
945 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
952 pm->name = strdupW(name);
953 pm->dllname = strdupW(driver);
955 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
957 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
962 pm->hdll = LoadLibraryW(driver);
963 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
965 if (pm->hdll == NULL) {
967 SetLastError(ERROR_MOD_NOT_FOUND);
972 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
973 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
974 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
975 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
976 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
979 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
980 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
981 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
982 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
983 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
985 if (pInitializePrintMonitorUI != NULL) {
986 pm->monitorUI = pInitializePrintMonitorUI();
987 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
989 TRACE( "0x%08x: dwMonitorSize (%d)\n",
990 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
995 if (pInitializePrintMonitor && regroot) {
996 pmonitorEx = pInitializePrintMonitor(regroot);
997 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
998 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1001 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1002 pm->monitor = &(pmonitorEx->Monitor);
1007 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1011 if (!pm->monitor && regroot) {
1012 if (pInitializePrintMonitor2 != NULL) {
1013 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1015 if (pInitializeMonitorEx != NULL) {
1016 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1018 if (pInitializeMonitor != NULL) {
1019 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1022 if (!pm->monitor && !pm->monitorUI) {
1024 SetLastError(ERROR_PROC_NOT_FOUND);
1029 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1033 LeaveCriticalSection(&monitor_handles_cs);
1034 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1035 HeapFree(GetProcessHeap(), 0, regroot);
1036 TRACE("=> %p\n", pm);
1040 /******************************************************************
1041 * monitor_loadall [internal]
1043 * Load all registered monitors
1046 static DWORD monitor_loadall(void)
1049 DWORD registered = 0;
1052 WCHAR buffer[MAX_PATH];
1055 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1056 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
1057 NULL, NULL, NULL, NULL, NULL);
1059 TRACE("%d monitors registered\n", registered);
1061 EnterCriticalSection(&monitor_handles_cs);
1062 while (id < registered) {
1064 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1065 pm = monitor_load(buffer, NULL);
1069 LeaveCriticalSection(&monitor_handles_cs);
1070 RegCloseKey(hmonitors);
1072 TRACE("%d monitors loaded\n", loaded);
1076 /******************************************************************
1077 * monitor_loadui [internal]
1079 * load the userinterface-dll for a given portmonitor
1081 * On failure, NULL is returned
1084 static monitor_t * monitor_loadui(monitor_t * pm)
1086 monitor_t * pui = NULL;
1087 LPWSTR buffer[MAX_PATH];
1092 if (pm == NULL) return NULL;
1093 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1095 /* Try the Portmonitor first; works for many monitors */
1096 if (pm->monitorUI) {
1097 EnterCriticalSection(&monitor_handles_cs);
1099 LeaveCriticalSection(&monitor_handles_cs);
1103 /* query the userinterface-dllname from the Portmonitor */
1104 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1105 /* building (",XcvMonitor %s",pm->name) not needed yet */
1106 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1107 TRACE("got %u with %p\n", res, hXcv);
1109 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1110 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1111 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1112 pm->monitor->pfnXcvClosePort(hXcv);
1119 /******************************************************************
1120 * monitor_load_by_port [internal]
1122 * load a printmonitor for a given port
1124 * On failure, NULL is returned
1127 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1132 monitor_t * pm = NULL;
1133 DWORD registered = 0;
1137 TRACE("(%s)\n", debugstr_w(portname));
1139 /* Try the Local Monitor first */
1140 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1141 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1142 /* found the portname */
1144 return monitor_load(LocalPortW, NULL);
1149 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1150 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1151 if (buffer == NULL) return NULL;
1153 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1154 EnterCriticalSection(&monitor_handles_cs);
1155 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, ®istered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1157 while ((pm == NULL) && (id < registered)) {
1159 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1160 TRACE("testing %s\n", debugstr_w(buffer));
1161 len = lstrlenW(buffer);
1162 lstrcatW(buffer, bs_Ports_bsW);
1163 lstrcatW(buffer, portname);
1164 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1166 buffer[len] = '\0'; /* use only the Monitor-Name */
1167 pm = monitor_load(buffer, NULL);
1171 LeaveCriticalSection(&monitor_handles_cs);
1174 HeapFree(GetProcessHeap(), 0, buffer);
1178 /******************************************************************
1179 * enumerate the local Ports from all loaded monitors (internal)
1181 * returns the needed size (in bytes) for pPorts
1182 * and *lpreturned is set to number of entries returned in pPorts
1185 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1189 LPPORT_INFO_2W cache;
1191 LPBYTE pi_buffer = NULL;
1192 DWORD pi_allocated = 0;
1203 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1204 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1206 numentries = *lpreturned; /* this is 0, when we scan the registry */
1207 needed = entrysize * numentries;
1208 ptr = (LPWSTR) &pPorts[needed];
1213 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1215 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1218 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1219 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1220 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1221 HeapFree(GetProcessHeap(), 0, pi_buffer);
1222 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1223 pi_allocated = (pi_buffer) ? pi_needed : 0;
1224 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1226 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1227 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1229 numentries += pi_returned;
1230 needed += pi_needed;
1232 /* fill the output-buffer (pPorts), if we have one */
1233 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1235 while (pi_returned > pi_index) {
1236 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1237 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1238 out->pPortName = ptr;
1239 lstrcpyW(ptr, cache->pPortName);
1240 ptr += (lstrlenW(ptr)+1);
1242 out->pMonitorName = ptr;
1243 lstrcpyW(ptr, cache->pMonitorName);
1244 ptr += (lstrlenW(ptr)+1);
1246 out->pDescription = ptr;
1247 lstrcpyW(ptr, cache->pDescription);
1248 ptr += (lstrlenW(ptr)+1);
1249 out->fPortType = cache->fPortType;
1250 out->Reserved = cache->Reserved;
1258 /* the temporary portinfo-buffer is no longer needed */
1259 HeapFree(GetProcessHeap(), 0, pi_buffer);
1261 *lpreturned = numentries;
1262 TRACE("need %d byte for %d entries\n", needed, numentries);
1266 /******************************************************************
1267 * get_servername_from_name (internal)
1269 * for an external server, a copy of the serverpart from the full name is returned
1272 static LPWSTR get_servername_from_name(LPCWSTR name)
1276 WCHAR buffer[MAX_PATH];
1279 if (name == NULL) return NULL;
1280 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1282 server = strdupW(&name[2]); /* skip over both backslash */
1283 if (server == NULL) return NULL;
1285 /* strip '\' and the printername */
1286 ptr = strchrW(server, '\\');
1287 if (ptr) ptr[0] = '\0';
1289 TRACE("found %s\n", debugstr_w(server));
1291 len = sizeof(buffer)/sizeof(buffer[0]);
1292 if (GetComputerNameW(buffer, &len)) {
1293 if (lstrcmpW(buffer, server) == 0) {
1294 /* The requested Servername is our computername */
1295 HeapFree(GetProcessHeap(), 0, server);
1302 /******************************************************************
1303 * get_basename_from_name (internal)
1305 * skip over the serverpart from the full name
1308 static LPCWSTR get_basename_from_name(LPCWSTR name)
1310 if (name == NULL) return NULL;
1311 if ((name[0] == '\\') && (name[1] == '\\')) {
1312 /* skip over the servername and search for the following '\' */
1313 name = strchrW(&name[2], '\\');
1314 if ((name) && (name[1])) {
1315 /* found a separator ('\') followed by a name:
1316 skip over the separator and return the rest */
1321 /* no basename present (we found only a servername) */
1328 /******************************************************************
1329 * get_opened_printer_entry
1330 * Get the first place empty in the opened printer table
1333 * - pDefault is ignored
1335 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1337 UINT_PTR handle = nb_printer_handles, i;
1338 jobqueue_t *queue = NULL;
1339 opened_printer_t *printer = NULL;
1341 LPCWSTR printername;
1346 servername = get_servername_from_name(name);
1348 FIXME("server %s not supported\n", debugstr_w(servername));
1349 HeapFree(GetProcessHeap(), 0, servername);
1350 SetLastError(ERROR_INVALID_PRINTER_NAME);
1354 printername = get_basename_from_name(name);
1355 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1357 /* an empty printername is invalid */
1358 if (printername && (!printername[0])) {
1359 SetLastError(ERROR_INVALID_PARAMETER);
1363 EnterCriticalSection(&printer_handles_cs);
1365 for (i = 0; i < nb_printer_handles; i++)
1367 if (!printer_handles[i])
1369 if(handle == nb_printer_handles)
1374 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1375 queue = printer_handles[i]->queue;
1379 if (handle >= nb_printer_handles)
1381 opened_printer_t **new_array;
1382 if (printer_handles)
1383 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1384 (nb_printer_handles + 16) * sizeof(*new_array) );
1386 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1387 (nb_printer_handles + 16) * sizeof(*new_array) );
1394 printer_handles = new_array;
1395 nb_printer_handles += 16;
1398 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1405 /* clone the base name. This is NULL for the printserver */
1406 printer->printername = strdupW(printername);
1408 /* clone the full name */
1409 printer->name = strdupW(name);
1410 if (name && (!printer->name)) {
1416 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1417 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1418 /* OpenPrinter(",XcvMonitor " detected */
1419 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1420 printer->pm = monitor_load(&printername[len], NULL);
1421 if (printer->pm == NULL) {
1422 SetLastError(ERROR_INVALID_PARAMETER);
1429 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1430 if (strncmpW( printername, XcvPortW, len) == 0) {
1431 /* OpenPrinter(",XcvPort " detected */
1432 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1433 printer->pm = monitor_load_by_port(&printername[len]);
1434 if (printer->pm == NULL) {
1435 SetLastError(ERROR_INVALID_PARAMETER);
1443 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1444 printer->pm->monitor->pfnXcvOpenPort(&printername[len], pDefault->DesiredAccess, &printer->hXcv);
1446 if (printer->hXcv == NULL) {
1447 SetLastError(ERROR_INVALID_PARAMETER);
1454 /* Does the Printer exist? */
1455 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1456 ERR("Can't create Printers key\n");
1460 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1461 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1462 RegCloseKey(hkeyPrinters);
1463 SetLastError(ERROR_INVALID_PRINTER_NAME);
1467 RegCloseKey(hkeyPrinter);
1468 RegCloseKey(hkeyPrinters);
1473 TRACE("using the local printserver\n");
1477 printer->queue = queue;
1480 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1481 if (!printer->queue) {
1485 list_init(&printer->queue->jobs);
1486 printer->queue->ref = 0;
1488 InterlockedIncrement(&printer->queue->ref);
1490 printer_handles[handle] = printer;
1493 LeaveCriticalSection(&printer_handles_cs);
1494 if (!handle && printer) {
1495 /* Something failed: Free all resources */
1496 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1497 monitor_unload(printer->pm);
1498 HeapFree(GetProcessHeap(), 0, printer->printername);
1499 HeapFree(GetProcessHeap(), 0, printer->name);
1500 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1501 HeapFree(GetProcessHeap(), 0, printer);
1504 return (HANDLE)handle;
1507 /******************************************************************
1508 * get_opened_printer
1509 * Get the pointer to the opened printer referred by the handle
1511 static opened_printer_t *get_opened_printer(HANDLE hprn)
1513 UINT_PTR idx = (UINT_PTR)hprn;
1514 opened_printer_t *ret = NULL;
1516 EnterCriticalSection(&printer_handles_cs);
1518 if ((idx <= 0) || (idx > nb_printer_handles))
1521 ret = printer_handles[idx - 1];
1523 LeaveCriticalSection(&printer_handles_cs);
1527 /******************************************************************
1528 * get_opened_printer_name
1529 * Get the pointer to the opened printer name referred by the handle
1531 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1533 opened_printer_t *printer = get_opened_printer(hprn);
1534 if(!printer) return NULL;
1535 return printer->name;
1538 /******************************************************************
1539 * WINSPOOL_GetOpenedPrinterRegKey
1542 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1544 LPCWSTR name = get_opened_printer_name(hPrinter);
1548 if(!name) return ERROR_INVALID_HANDLE;
1550 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1554 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1556 ERR("Can't find opened printer %s in registry\n",
1558 RegCloseKey(hkeyPrinters);
1559 return ERROR_INVALID_PRINTER_NAME; /* ? */
1561 RegCloseKey(hkeyPrinters);
1562 return ERROR_SUCCESS;
1565 void WINSPOOL_LoadSystemPrinters(void)
1567 HKEY hkey, hkeyPrinters;
1569 DWORD needed, num, i;
1570 WCHAR PrinterName[256];
1573 /* This ensures that all printer entries have a valid Name value. If causes
1574 problems later if they don't. If one is found to be missed we create one
1575 and set it equal to the name of the key */
1576 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1577 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1578 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1579 for(i = 0; i < num; i++) {
1580 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1581 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1582 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1583 set_reg_szW(hkey, NameW, PrinterName);
1590 RegCloseKey(hkeyPrinters);
1593 /* We want to avoid calling AddPrinter on printers as much as
1594 possible, because on cups printers this will (eventually) lead
1595 to a call to cupsGetPPD which takes forever, even with non-cups
1596 printers AddPrinter takes a while. So we'll tag all printers that
1597 were automatically added last time around, if they still exist
1598 we'll leave them be otherwise we'll delete them. */
1599 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1601 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1602 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1603 for(i = 0; i < num; i++) {
1604 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1605 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1606 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1608 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1616 HeapFree(GetProcessHeap(), 0, pi);
1620 #ifdef HAVE_CUPS_CUPS_H
1621 done = CUPS_LoadPrinters();
1624 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1625 PRINTCAP_LoadPrinters();
1627 /* Now enumerate the list again and delete any printers that a still tagged */
1628 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1630 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1631 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1632 for(i = 0; i < num; i++) {
1633 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1634 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1635 BOOL delete_driver = FALSE;
1636 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1637 DWORD dw, type, size = sizeof(dw);
1638 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1639 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1640 DeletePrinter(hprn);
1641 delete_driver = TRUE;
1647 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1652 HeapFree(GetProcessHeap(), 0, pi);
1659 /******************************************************************
1662 * Get the pointer to the specified job.
1663 * Should hold the printer_handles_cs before calling.
1665 static job_t *get_job(HANDLE hprn, DWORD JobId)
1667 opened_printer_t *printer = get_opened_printer(hprn);
1670 if(!printer) return NULL;
1671 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1673 if(job->job_id == JobId)
1679 /***********************************************************
1682 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1685 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1688 Formname = (dmA->dmSize > off_formname);
1689 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1690 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1691 dmW->dmDeviceName, CCHDEVICENAME);
1693 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1694 dmA->dmSize - CCHDEVICENAME);
1696 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1697 off_formname - CCHDEVICENAME);
1698 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1699 dmW->dmFormName, CCHFORMNAME);
1700 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1701 (off_formname + CCHFORMNAME));
1704 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1705 dmA->dmDriverExtra);
1709 /***********************************************************
1711 * Creates an ascii copy of supplied devmode on heap
1713 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1718 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1720 if(!dmW) return NULL;
1721 Formname = (dmW->dmSize > off_formname);
1722 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1723 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1724 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1725 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1727 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1728 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1730 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1731 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1732 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1733 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1734 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1735 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1738 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1739 dmW->dmDriverExtra);
1743 /***********************************************************
1744 * PRINTER_INFO_2AtoW
1745 * Creates a unicode copy of PRINTER_INFO_2A on heap
1747 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1749 LPPRINTER_INFO_2W piW;
1750 UNICODE_STRING usBuffer;
1752 if(!piA) return NULL;
1753 piW = HeapAlloc(heap, 0, sizeof(*piW));
1754 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1756 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1757 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1758 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1759 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1760 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1761 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1762 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1763 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1764 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1765 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1766 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1767 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1771 /***********************************************************
1772 * FREE_PRINTER_INFO_2W
1773 * Free PRINTER_INFO_2W and all strings
1775 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1779 HeapFree(heap,0,piW->pServerName);
1780 HeapFree(heap,0,piW->pPrinterName);
1781 HeapFree(heap,0,piW->pShareName);
1782 HeapFree(heap,0,piW->pPortName);
1783 HeapFree(heap,0,piW->pDriverName);
1784 HeapFree(heap,0,piW->pComment);
1785 HeapFree(heap,0,piW->pLocation);
1786 HeapFree(heap,0,piW->pDevMode);
1787 HeapFree(heap,0,piW->pSepFile);
1788 HeapFree(heap,0,piW->pPrintProcessor);
1789 HeapFree(heap,0,piW->pDatatype);
1790 HeapFree(heap,0,piW->pParameters);
1791 HeapFree(heap,0,piW);
1795 /******************************************************************
1796 * DeviceCapabilities [WINSPOOL.@]
1797 * DeviceCapabilitiesA [WINSPOOL.@]
1800 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1801 LPSTR pOutput, LPDEVMODEA lpdm)
1805 if (!GDI_CallDeviceCapabilities16)
1807 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1809 if (!GDI_CallDeviceCapabilities16) return -1;
1811 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1813 /* If DC_PAPERSIZE map POINT16s to POINTs */
1814 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1815 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1816 POINT *pt = (POINT *)pOutput;
1818 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1819 for(i = 0; i < ret; i++, pt++)
1824 HeapFree( GetProcessHeap(), 0, tmp );
1830 /*****************************************************************************
1831 * DeviceCapabilitiesW [WINSPOOL.@]
1833 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1836 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1837 WORD fwCapability, LPWSTR pOutput,
1838 const DEVMODEW *pDevMode)
1840 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1841 LPSTR pDeviceA = strdupWtoA(pDevice);
1842 LPSTR pPortA = strdupWtoA(pPort);
1845 if(pOutput && (fwCapability == DC_BINNAMES ||
1846 fwCapability == DC_FILEDEPENDENCIES ||
1847 fwCapability == DC_PAPERNAMES)) {
1848 /* These need A -> W translation */
1851 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1855 switch(fwCapability) {
1860 case DC_FILEDEPENDENCIES:
1864 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1865 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1867 for(i = 0; i < ret; i++)
1868 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1869 pOutput + (i * size), size);
1870 HeapFree(GetProcessHeap(), 0, pOutputA);
1872 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1873 (LPSTR)pOutput, dmA);
1875 HeapFree(GetProcessHeap(),0,pPortA);
1876 HeapFree(GetProcessHeap(),0,pDeviceA);
1877 HeapFree(GetProcessHeap(),0,dmA);
1881 /******************************************************************
1882 * DocumentPropertiesA [WINSPOOL.@]
1884 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1886 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1887 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1888 LPDEVMODEA pDevModeInput,DWORD fMode )
1890 LPSTR lpName = pDeviceName;
1891 static CHAR port[] = "LPT1:";
1894 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1895 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1899 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1901 ERR("no name from hPrinter?\n");
1902 SetLastError(ERROR_INVALID_HANDLE);
1905 lpName = strdupWtoA(lpNameW);
1908 if (!GDI_CallExtDeviceMode16)
1910 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1912 if (!GDI_CallExtDeviceMode16) {
1913 ERR("No CallExtDeviceMode16?\n");
1917 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1918 pDevModeInput, NULL, fMode);
1921 HeapFree(GetProcessHeap(),0,lpName);
1926 /*****************************************************************************
1927 * DocumentPropertiesW (WINSPOOL.@)
1929 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1931 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1933 LPDEVMODEW pDevModeOutput,
1934 LPDEVMODEW pDevModeInput, DWORD fMode)
1937 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1938 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1939 LPDEVMODEA pDevModeOutputA = NULL;
1942 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1943 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1945 if(pDevModeOutput) {
1946 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1947 if(ret < 0) return ret;
1948 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1950 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1951 pDevModeInputA, fMode);
1952 if(pDevModeOutput) {
1953 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1954 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1956 if(fMode == 0 && ret > 0)
1957 ret += (CCHDEVICENAME + CCHFORMNAME);
1958 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1959 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1963 /******************************************************************
1964 * OpenPrinterA [WINSPOOL.@]
1969 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1970 LPPRINTER_DEFAULTSA pDefault)
1972 UNICODE_STRING lpPrinterNameW;
1973 UNICODE_STRING usBuffer;
1974 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1975 PWSTR pwstrPrinterNameW;
1978 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1981 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1982 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1983 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1984 pDefaultW = &DefaultW;
1986 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1988 RtlFreeUnicodeString(&usBuffer);
1989 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1991 RtlFreeUnicodeString(&lpPrinterNameW);
1995 /******************************************************************
1996 * OpenPrinterW [WINSPOOL.@]
1998 * Open a Printer / Printserver or a Printer-Object
2001 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2002 * phPrinter [O] The resulting Handle is stored here
2003 * pDefault [I] PTR to Default Printer Settings or NULL
2010 * lpPrinterName is one of:
2011 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2012 *| Printer: "PrinterName"
2013 *| Printer-Object: "PrinterName,Job xxx"
2014 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2015 *| XcvPort: "Servername,XcvPort PortName"
2018 *| Printer-Object not supported
2019 *| pDefaults is ignored
2022 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2025 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2027 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2028 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2032 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2033 SetLastError(ERROR_INVALID_PARAMETER);
2037 /* Get the unique handle of the printer or Printserver */
2038 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2039 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2040 return (*phPrinter != 0);
2043 /******************************************************************
2044 * AddMonitorA [WINSPOOL.@]
2049 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2051 LPWSTR nameW = NULL;
2054 LPMONITOR_INFO_2A mi2a;
2055 MONITOR_INFO_2W mi2w;
2057 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2058 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2059 mi2a ? debugstr_a(mi2a->pName) : NULL,
2060 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2061 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2064 SetLastError(ERROR_INVALID_LEVEL);
2068 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2074 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2075 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2076 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2079 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2081 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2082 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2083 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2085 if (mi2a->pEnvironment) {
2086 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2087 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2088 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2090 if (mi2a->pDLLName) {
2091 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2092 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2093 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2096 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2098 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2099 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2100 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2102 HeapFree(GetProcessHeap(), 0, nameW);
2106 /******************************************************************************
2107 * AddMonitorW [WINSPOOL.@]
2109 * Install a Printmonitor
2112 * pName [I] Servername or NULL (local Computer)
2113 * Level [I] Structure-Level (Must be 2)
2114 * pMonitors [I] PTR to MONITOR_INFO_2
2121 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2124 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2126 monitor_t * pm = NULL;
2127 LPMONITOR_INFO_2W mi2w;
2133 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2134 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2135 mi2w ? debugstr_w(mi2w->pName) : NULL,
2136 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2137 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2140 SetLastError(ERROR_INVALID_LEVEL);
2144 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2149 if (pName && (pName[0])) {
2150 FIXME("for server %s not implemented\n", debugstr_w(pName));
2151 SetLastError(ERROR_ACCESS_DENIED);
2156 if (!mi2w->pName || (! mi2w->pName[0])) {
2157 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2158 SetLastError(ERROR_INVALID_PARAMETER);
2161 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2162 WARN("Environment %s requested (we support only %s)\n",
2163 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2164 SetLastError(ERROR_INVALID_ENVIRONMENT);
2168 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2169 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2170 SetLastError(ERROR_INVALID_PARAMETER);
2174 /* Load and initialize the monitor. SetLastError() is called on failure */
2175 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2180 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2181 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2185 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2186 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2187 &disposition) == ERROR_SUCCESS) {
2189 /* Some installers set options for the port before calling AddMonitor.
2190 We query the "Driver" entry to verify that the monitor is installed,
2191 before we return an error.
2192 When a user installs two print monitors at the same time with the
2193 same name but with a different driver DLL and a task switch comes
2194 between RegQueryValueExW and RegSetValueExW, a race condition
2195 is possible but silently ignored. */
2199 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2200 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2201 &namesize) == ERROR_SUCCESS)) {
2202 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2203 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2204 9x: ERROR_ALREADY_EXISTS (183) */
2205 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2210 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2211 res = (RegSetValueExW(hentry, DriverW, 0,
2212 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2214 RegCloseKey(hentry);
2221 /******************************************************************
2222 * DeletePrinterDriverA [WINSPOOL.@]
2225 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2227 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2230 /******************************************************************
2231 * DeletePrinterDriverW [WINSPOOL.@]
2234 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2236 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2239 /******************************************************************
2240 * DeleteMonitorA [WINSPOOL.@]
2242 * See DeleteMonitorW.
2245 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2247 LPWSTR nameW = NULL;
2248 LPWSTR EnvironmentW = NULL;
2249 LPWSTR MonitorNameW = NULL;
2254 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2255 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2256 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2260 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2261 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2262 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2265 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2266 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2267 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2270 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2272 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2273 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2274 HeapFree(GetProcessHeap(), 0, nameW);
2278 /******************************************************************
2279 * DeleteMonitorW [WINSPOOL.@]
2281 * Delete a specific Printmonitor from a Printing-Environment
2284 * pName [I] Servername or NULL (local Computer)
2285 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2286 * pMonitorName [I] Name of the Monitor, that should be deleted
2293 * pEnvironment is ignored in Windows for the local Computer.
2297 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2301 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2302 debugstr_w(pMonitorName));
2304 if (pName && (pName[0])) {
2305 FIXME("for server %s not implemented\n", debugstr_w(pName));
2306 SetLastError(ERROR_ACCESS_DENIED);
2310 /* pEnvironment is ignored in Windows for the local Computer */
2312 if (!pMonitorName || !pMonitorName[0]) {
2313 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2314 SetLastError(ERROR_INVALID_PARAMETER);
2318 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2319 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2323 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2324 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2325 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2330 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2333 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2334 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2338 /******************************************************************
2339 * DeletePortA [WINSPOOL.@]
2344 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2346 LPWSTR nameW = NULL;
2347 LPWSTR portW = NULL;
2351 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2353 /* convert servername to unicode */
2355 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2356 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2357 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2360 /* convert portname to unicode */
2362 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2363 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2364 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2367 res = DeletePortW(nameW, hWnd, portW);
2368 HeapFree(GetProcessHeap(), 0, nameW);
2369 HeapFree(GetProcessHeap(), 0, portW);
2373 /******************************************************************
2374 * DeletePortW [WINSPOOL.@]
2376 * Delete a specific Port
2379 * pName [I] Servername or NULL (local Computer)
2380 * hWnd [I] Handle to parent Window for the Dialog-Box
2381 * pPortName [I] Name of the Port, that should be deleted
2388 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2394 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2396 if (pName && pName[0]) {
2397 SetLastError(ERROR_INVALID_PARAMETER);
2402 SetLastError(RPC_X_NULL_REF_POINTER);
2406 /* an empty Portname is Invalid */
2407 if (!pPortName[0]) {
2408 SetLastError(ERROR_NOT_SUPPORTED);
2412 pm = monitor_load_by_port(pPortName);
2413 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2414 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2415 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2416 TRACE("got %d with %u\n", res, GetLastError());
2420 pui = monitor_loadui(pm);
2421 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2422 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2423 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2424 TRACE("got %d with %u\n", res, GetLastError());
2428 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2429 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2431 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2432 SetLastError(ERROR_NOT_SUPPORTED);
2435 monitor_unload(pui);
2439 TRACE("returning %d with %u\n", res, GetLastError());
2443 /******************************************************************************
2444 * SetPrinterW [WINSPOOL.@]
2446 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2448 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2449 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2453 /******************************************************************************
2454 * WritePrinter [WINSPOOL.@]
2456 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2458 opened_printer_t *printer;
2461 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2463 EnterCriticalSection(&printer_handles_cs);
2464 printer = get_opened_printer(hPrinter);
2467 SetLastError(ERROR_INVALID_HANDLE);
2473 SetLastError(ERROR_SPL_NO_STARTDOC);
2477 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2479 LeaveCriticalSection(&printer_handles_cs);
2483 /*****************************************************************************
2484 * AddFormA [WINSPOOL.@]
2486 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2488 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2492 /*****************************************************************************
2493 * AddFormW [WINSPOOL.@]
2495 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2497 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2501 /*****************************************************************************
2502 * AddJobA [WINSPOOL.@]
2504 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2507 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2511 SetLastError(ERROR_INVALID_LEVEL);
2515 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2518 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2519 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2520 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2521 if(*pcbNeeded > cbBuf) {
2522 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2525 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2526 addjobA->JobId = addjobW->JobId;
2527 addjobA->Path = (char *)(addjobA + 1);
2528 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2534 /*****************************************************************************
2535 * AddJobW [WINSPOOL.@]
2537 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2539 opened_printer_t *printer;
2542 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2543 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2544 WCHAR path[MAX_PATH], filename[MAX_PATH];
2546 ADDJOB_INFO_1W *addjob;
2548 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2550 EnterCriticalSection(&printer_handles_cs);
2552 printer = get_opened_printer(hPrinter);
2555 SetLastError(ERROR_INVALID_HANDLE);
2560 SetLastError(ERROR_INVALID_LEVEL);
2564 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2568 job->job_id = InterlockedIncrement(&next_job_id);
2570 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2571 if(path[len - 1] != '\\')
2573 memcpy(path + len, spool_path, sizeof(spool_path));
2574 sprintfW(filename, fmtW, path, job->job_id);
2576 len = strlenW(filename);
2577 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2578 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2579 job->document_title = strdupW(default_doc_title);
2580 list_add_tail(&printer->queue->jobs, &job->entry);
2582 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2583 if(*pcbNeeded <= cbBuf) {
2584 addjob = (ADDJOB_INFO_1W*)pData;
2585 addjob->JobId = job->job_id;
2586 addjob->Path = (WCHAR *)(addjob + 1);
2587 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2590 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2593 LeaveCriticalSection(&printer_handles_cs);
2597 /*****************************************************************************
2598 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2600 * Return the PATH for the Print-Processors
2602 * See GetPrintProcessorDirectoryW.
2606 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2607 DWORD level, LPBYTE Info,
2608 DWORD cbBuf, LPDWORD pcbNeeded)
2610 LPWSTR serverW = NULL;
2615 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2616 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2620 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2621 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2622 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2626 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2627 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2628 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2631 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2632 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2634 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2637 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2638 cbBuf, NULL, NULL) > 0;
2641 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2642 HeapFree(GetProcessHeap(), 0, envW);
2643 HeapFree(GetProcessHeap(), 0, serverW);
2647 /*****************************************************************************
2648 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2650 * Return the PATH for the Print-Processors
2653 * server [I] Servername (NT only) or NULL (local Computer)
2654 * env [I] Printing-Environment (see below) or NULL (Default)
2655 * level [I] Structure-Level (must be 1)
2656 * Info [O] PTR to Buffer that receives the Result
2657 * cbBuf [I] Size of Buffer at "Info"
2658 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2659 * required for the Buffer at "Info"
2662 * Success: TRUE and in pcbNeeded the Bytes used in Info
2663 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2664 * if cbBuf is too small
2666 * Native Values returned in Info on Success:
2667 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2668 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2669 *| win9x(Windows 4.0): "%winsysdir%"
2671 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2674 * Only NULL or "" is supported for server
2677 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2678 DWORD level, LPBYTE Info,
2679 DWORD cbBuf, LPDWORD pcbNeeded)
2682 const printenv_t * env_t;
2684 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2685 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2687 if(server != NULL && server[0]) {
2688 FIXME("server not supported: %s\n", debugstr_w(server));
2689 SetLastError(ERROR_INVALID_PARAMETER);
2693 env_t = validate_envW(env);
2694 if(!env_t) return FALSE; /* environment invalid or unsupported */
2697 WARN("(Level: %d) is ignored in win9x\n", level);
2698 SetLastError(ERROR_INVALID_LEVEL);
2702 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2703 needed = GetSystemDirectoryW(NULL, 0);
2704 /* add the Size for the Subdirectories */
2705 needed += lstrlenW(spoolprtprocsW);
2706 needed += lstrlenW(env_t->subdir);
2707 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2709 if(pcbNeeded) *pcbNeeded = needed;
2710 TRACE ("required: 0x%x/%d\n", needed, needed);
2711 if (needed > cbBuf) {
2712 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2715 if(pcbNeeded == NULL) {
2716 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2717 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2718 SetLastError(RPC_X_NULL_REF_POINTER);
2722 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2723 SetLastError(RPC_X_NULL_REF_POINTER);
2727 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2728 /* add the Subdirectories */
2729 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2730 lstrcatW((LPWSTR) Info, env_t->subdir);
2731 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2735 /*****************************************************************************
2736 * WINSPOOL_OpenDriverReg [internal]
2738 * opens the registry for the printer drivers depending on the given input
2739 * variable pEnvironment
2742 * the opened hkey on success
2745 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2749 const printenv_t * env;
2752 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2754 if (!pEnvironment || unicode) {
2755 /* pEnvironment was NULL or an Unicode-String: use it direct */
2756 env = validate_envW(pEnvironment);
2760 /* pEnvironment was an ANSI-String: convert to unicode first */
2762 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2763 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2764 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2765 env = validate_envW(buffer);
2766 HeapFree(GetProcessHeap(), 0, buffer);
2768 if (!env) return NULL;
2770 buffer = HeapAlloc( GetProcessHeap(), 0,
2771 (strlenW(DriversW) + strlenW(env->envname) +
2772 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2774 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2775 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2776 HeapFree(GetProcessHeap(), 0, buffer);
2781 /*****************************************************************************
2782 * AddPrinterW [WINSPOOL.@]
2784 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2786 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2790 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2792 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2793 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2794 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2795 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2796 statusW[] = {'S','t','a','t','u','s',0},
2797 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2799 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2802 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2803 SetLastError(ERROR_INVALID_PARAMETER);
2807 ERR("Level = %d, unsupported!\n", Level);
2808 SetLastError(ERROR_INVALID_LEVEL);
2812 SetLastError(ERROR_INVALID_PARAMETER);
2815 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2817 ERR("Can't create Printers key\n");
2820 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2821 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2822 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2823 RegCloseKey(hkeyPrinter);
2824 RegCloseKey(hkeyPrinters);
2827 RegCloseKey(hkeyPrinter);
2829 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2831 ERR("Can't create Drivers key\n");
2832 RegCloseKey(hkeyPrinters);
2835 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2837 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2838 RegCloseKey(hkeyPrinters);
2839 RegCloseKey(hkeyDrivers);
2840 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2843 RegCloseKey(hkeyDriver);
2844 RegCloseKey(hkeyDrivers);
2846 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2847 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2848 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2849 RegCloseKey(hkeyPrinters);
2853 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2855 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2856 SetLastError(ERROR_INVALID_PRINTER_NAME);
2857 RegCloseKey(hkeyPrinters);
2860 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2861 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2862 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2864 /* See if we can load the driver. We may need the devmode structure anyway
2867 * Note that DocumentPropertiesW will briefly try to open the printer we
2868 * just create to find a DEVMODEA struct (it will use the WINEPS default
2869 * one in case it is not there, so we are ok).
2871 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2874 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2875 size = sizeof(DEVMODEW);
2881 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2882 ZeroMemory(dmW,size);
2884 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2886 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2887 HeapFree(GetProcessHeap(),0,dmW);
2892 /* set devmode to printer name */
2893 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2897 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2898 and we support these drivers. NT writes DEVMODEW so somehow
2899 we'll need to distinguish between these when we support NT
2903 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2904 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2905 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2906 HeapFree(GetProcessHeap(), 0, dmA);
2908 HeapFree(GetProcessHeap(), 0, dmW);
2910 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2911 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2912 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2913 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2915 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2916 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2917 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2918 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2919 (LPBYTE)&pi->Priority, sizeof(DWORD));
2920 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2921 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2922 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2923 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2924 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2925 (LPBYTE)&pi->Status, sizeof(DWORD));
2926 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2927 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2929 RegCloseKey(hkeyPrinter);
2930 RegCloseKey(hkeyPrinters);
2931 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2932 ERR("OpenPrinter failing\n");
2938 /*****************************************************************************
2939 * AddPrinterA [WINSPOOL.@]
2941 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2943 UNICODE_STRING pNameW;
2945 PRINTER_INFO_2W *piW;
2946 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2949 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2951 ERR("Level = %d, unsupported!\n", Level);
2952 SetLastError(ERROR_INVALID_LEVEL);
2955 pwstrNameW = asciitounicode(&pNameW,pName);
2956 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2958 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2960 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2961 RtlFreeUnicodeString(&pNameW);
2966 /*****************************************************************************
2967 * ClosePrinter [WINSPOOL.@]
2969 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2971 UINT_PTR i = (UINT_PTR)hPrinter;
2972 opened_printer_t *printer = NULL;
2975 TRACE("(%p)\n", hPrinter);
2977 EnterCriticalSection(&printer_handles_cs);
2979 if ((i > 0) && (i <= nb_printer_handles))
2980 printer = printer_handles[i - 1];
2985 struct list *cursor, *cursor2;
2987 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2988 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2989 printer->hXcv, debugstr_w(printer->name), printer->doc );
2992 EndDocPrinter(hPrinter);
2994 if(InterlockedDecrement(&printer->queue->ref) == 0)
2996 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2998 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2999 ScheduleJob(hPrinter, job->job_id);
3001 HeapFree(GetProcessHeap(), 0, printer->queue);
3003 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3004 monitor_unload(printer->pm);
3005 HeapFree(GetProcessHeap(), 0, printer->printername);
3006 HeapFree(GetProcessHeap(), 0, printer->name);
3007 HeapFree(GetProcessHeap(), 0, printer);
3008 printer_handles[i - 1] = NULL;
3011 LeaveCriticalSection(&printer_handles_cs);
3015 /*****************************************************************************
3016 * DeleteFormA [WINSPOOL.@]
3018 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3020 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3024 /*****************************************************************************
3025 * DeleteFormW [WINSPOOL.@]
3027 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3029 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3033 /*****************************************************************************
3034 * DeletePrinter [WINSPOOL.@]
3036 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3038 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3039 HKEY hkeyPrinters, hkey;
3042 SetLastError(ERROR_INVALID_HANDLE);
3045 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3046 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
3047 RegCloseKey(hkeyPrinters);
3049 WriteProfileStringW(devicesW, lpNameW, NULL);
3050 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3051 RegDeleteValueW(hkey, lpNameW);
3057 /*****************************************************************************
3058 * SetPrinterA [WINSPOOL.@]
3060 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3063 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3067 /*****************************************************************************
3068 * SetJobA [WINSPOOL.@]
3070 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3071 LPBYTE pJob, DWORD Command)
3075 UNICODE_STRING usBuffer;
3077 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3079 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3080 are all ignored by SetJob, so we don't bother copying them */
3088 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3089 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3091 JobW = (LPBYTE)info1W;
3092 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3093 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3094 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3095 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3096 info1W->Status = info1A->Status;
3097 info1W->Priority = info1A->Priority;
3098 info1W->Position = info1A->Position;
3099 info1W->PagesPrinted = info1A->PagesPrinted;
3104 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3105 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3107 JobW = (LPBYTE)info2W;
3108 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3109 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3110 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3111 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3112 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3113 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3114 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3115 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3116 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3117 info2W->Status = info2A->Status;
3118 info2W->Priority = info2A->Priority;
3119 info2W->Position = info2A->Position;
3120 info2W->StartTime = info2A->StartTime;
3121 info2W->UntilTime = info2A->UntilTime;
3122 info2W->PagesPrinted = info2A->PagesPrinted;
3126 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3127 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3130 SetLastError(ERROR_INVALID_LEVEL);
3134 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3140 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3141 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3142 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3143 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3144 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3149 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3150 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3151 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3152 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3153 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3154 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3155 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3156 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3157 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3161 HeapFree(GetProcessHeap(), 0, JobW);
3166 /*****************************************************************************
3167 * SetJobW [WINSPOOL.@]
3169 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3170 LPBYTE pJob, DWORD Command)
3175 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3176 FIXME("Ignoring everything other than document title\n");
3178 EnterCriticalSection(&printer_handles_cs);
3179 job = get_job(hPrinter, JobId);
3189 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3190 HeapFree(GetProcessHeap(), 0, job->document_title);
3191 job->document_title = strdupW(info1->pDocument);
3196 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3197 HeapFree(GetProcessHeap(), 0, job->document_title);
3198 job->document_title = strdupW(info2->pDocument);
3204 SetLastError(ERROR_INVALID_LEVEL);
3209 LeaveCriticalSection(&printer_handles_cs);
3213 /*****************************************************************************
3214 * EndDocPrinter [WINSPOOL.@]
3216 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3218 opened_printer_t *printer;
3220 TRACE("(%p)\n", hPrinter);
3222 EnterCriticalSection(&printer_handles_cs);
3224 printer = get_opened_printer(hPrinter);
3227 SetLastError(ERROR_INVALID_HANDLE);
3233 SetLastError(ERROR_SPL_NO_STARTDOC);
3237 CloseHandle(printer->doc->hf);
3238 ScheduleJob(hPrinter, printer->doc->job_id);
3239 HeapFree(GetProcessHeap(), 0, printer->doc);
3240 printer->doc = NULL;
3243 LeaveCriticalSection(&printer_handles_cs);
3247 /*****************************************************************************
3248 * EndPagePrinter [WINSPOOL.@]
3250 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3252 FIXME("(%p): stub\n", hPrinter);
3256 /*****************************************************************************
3257 * StartDocPrinterA [WINSPOOL.@]
3259 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3261 UNICODE_STRING usBuffer;
3263 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3266 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3267 or one (DOC_INFO_3) extra DWORDs */
3271 doc2W.JobId = doc2->JobId;
3274 doc2W.dwMode = doc2->dwMode;
3277 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3278 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3279 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3283 SetLastError(ERROR_INVALID_LEVEL);
3287 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3289 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3290 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3291 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3296 /*****************************************************************************
3297 * StartDocPrinterW [WINSPOOL.@]
3299 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3301 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3302 opened_printer_t *printer;
3303 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3304 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3305 JOB_INFO_1W job_info;
3306 DWORD needed, ret = 0;
3310 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3311 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3312 debugstr_w(doc->pDatatype));
3314 if(Level < 1 || Level > 3)
3316 SetLastError(ERROR_INVALID_LEVEL);
3320 EnterCriticalSection(&printer_handles_cs);
3321 printer = get_opened_printer(hPrinter);
3324 SetLastError(ERROR_INVALID_HANDLE);
3330 SetLastError(ERROR_INVALID_PRINTER_STATE);
3334 /* Even if we're printing to a file we still add a print job, we'll
3335 just ignore the spool file name */
3337 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3339 ERR("AddJob failed gle %u\n", GetLastError());
3343 if(doc->pOutputFile)
3344 filename = doc->pOutputFile;
3346 filename = addjob->Path;
3348 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3349 if(hf == INVALID_HANDLE_VALUE)
3352 memset(&job_info, 0, sizeof(job_info));
3353 job_info.pDocument = doc->pDocName;
3354 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3356 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3357 printer->doc->hf = hf;
3358 ret = printer->doc->job_id = addjob->JobId;
3360 LeaveCriticalSection(&printer_handles_cs);
3365 /*****************************************************************************
3366 * StartPagePrinter [WINSPOOL.@]
3368 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3370 FIXME("(%p): stub\n", hPrinter);
3374 /*****************************************************************************
3375 * GetFormA [WINSPOOL.@]
3377 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3378 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3380 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3381 Level,pForm,cbBuf,pcbNeeded);
3385 /*****************************************************************************
3386 * GetFormW [WINSPOOL.@]
3388 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3389 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3391 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3392 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3396 /*****************************************************************************
3397 * SetFormA [WINSPOOL.@]
3399 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3402 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3406 /*****************************************************************************
3407 * SetFormW [WINSPOOL.@]
3409 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3412 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3416 /*****************************************************************************
3417 * ReadPrinter [WINSPOOL.@]
3419 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3420 LPDWORD pNoBytesRead)
3422 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3426 /*****************************************************************************
3427 * ResetPrinterA [WINSPOOL.@]
3429 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3431 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3435 /*****************************************************************************
3436 * ResetPrinterW [WINSPOOL.@]
3438 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3440 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3444 /*****************************************************************************
3445 * WINSPOOL_GetDWORDFromReg
3447 * Return DWORD associated with ValueName from hkey.
3449 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3451 DWORD sz = sizeof(DWORD), type, value = 0;
3454 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3456 if(ret != ERROR_SUCCESS) {
3457 WARN("Got ret = %d on name %s\n", ret, ValueName);
3460 if(type != REG_DWORD) {
3461 ERR("Got type %d\n", type);
3467 /*****************************************************************************
3468 * WINSPOOL_GetStringFromReg
3470 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3471 * String is stored either as unicode or ascii.
3472 * Bit of a hack here to get the ValueName if we want ascii.
3474 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3475 DWORD buflen, DWORD *needed,
3478 DWORD sz = buflen, type;
3482 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3484 LPSTR ValueNameA = strdupWtoA(ValueName);
3485 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3486 HeapFree(GetProcessHeap(),0,ValueNameA);
3488 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3489 WARN("Got ret = %d\n", ret);
3493 /* add space for terminating '\0' */
3494 sz += unicode ? sizeof(WCHAR) : 1;
3498 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3503 /*****************************************************************************
3504 * WINSPOOL_GetDefaultDevMode
3506 * Get a default DevMode values for wineps.
3510 static void WINSPOOL_GetDefaultDevMode(
3512 DWORD buflen, DWORD *needed,
3516 static const char szwps[] = "wineps.drv";
3518 /* fill default DEVMODE - should be read from ppd... */
3519 ZeroMemory( &dm, sizeof(dm) );
3520 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3521 dm.dmSpecVersion = DM_SPECVERSION;
3522 dm.dmDriverVersion = 1;
3523 dm.dmSize = sizeof(DEVMODEA);
3524 dm.dmDriverExtra = 0;
3526 DM_ORIENTATION | DM_PAPERSIZE |
3527 DM_PAPERLENGTH | DM_PAPERWIDTH |
3530 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3531 DM_YRESOLUTION | DM_TTOPTION;
3533 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3534 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3535 dm.u1.s1.dmPaperLength = 2970;
3536 dm.u1.s1.dmPaperWidth = 2100;
3540 dm.dmDefaultSource = DMBIN_AUTO;
3541 dm.dmPrintQuality = DMRES_MEDIUM;
3544 dm.dmYResolution = 300; /* 300dpi */
3545 dm.dmTTOption = DMTT_BITMAP;
3548 /* dm.dmLogPixels */
3549 /* dm.dmBitsPerPel */
3550 /* dm.dmPelsWidth */
3551 /* dm.dmPelsHeight */
3552 /* dm.dmDisplayFlags */
3553 /* dm.dmDisplayFrequency */
3554 /* dm.dmICMMethod */
3555 /* dm.dmICMIntent */
3556 /* dm.dmMediaType */
3557 /* dm.dmDitherType */
3558 /* dm.dmReserved1 */
3559 /* dm.dmReserved2 */
3560 /* dm.dmPanningWidth */
3561 /* dm.dmPanningHeight */
3564 if(buflen >= sizeof(DEVMODEW)) {
3565 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3566 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3567 HeapFree(GetProcessHeap(),0,pdmW);
3569 *needed = sizeof(DEVMODEW);
3573 if(buflen >= sizeof(DEVMODEA)) {
3574 memcpy(ptr, &dm, sizeof(DEVMODEA));
3576 *needed = sizeof(DEVMODEA);
3580 /*****************************************************************************
3581 * WINSPOOL_GetDevModeFromReg
3583 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3584 * DevMode is stored either as unicode or ascii.
3586 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3588 DWORD buflen, DWORD *needed,
3591 DWORD sz = buflen, type;
3594 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3595 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3596 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3597 if (sz < sizeof(DEVMODEA))
3599 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3602 /* ensures that dmSize is not erratically bogus if registry is invalid */
3603 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3604 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3606 sz += (CCHDEVICENAME + CCHFORMNAME);
3608 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3609 memcpy(ptr, dmW, sz);
3610 HeapFree(GetProcessHeap(),0,dmW);
3617 /*********************************************************************
3618 * WINSPOOL_GetPrinter_2
3620 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3621 * The strings are either stored as unicode or ascii.
3623 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3624 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3627 DWORD size, left = cbBuf;
3628 BOOL space = (cbBuf > 0);
3633 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3635 if(space && size <= left) {
3636 pi2->pPrinterName = (LPWSTR)ptr;
3643 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3645 if(space && size <= left) {
3646 pi2->pShareName = (LPWSTR)ptr;
3653 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3655 if(space && size <= left) {
3656 pi2->pPortName = (LPWSTR)ptr;
3663 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3665 if(space && size <= left) {
3666 pi2->pDriverName = (LPWSTR)ptr;
3673 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3675 if(space && size <= left) {
3676 pi2->pComment = (LPWSTR)ptr;
3683 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3685 if(space && size <= left) {
3686 pi2->pLocation = (LPWSTR)ptr;
3693 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3695 if(space && size <= left) {
3696 pi2->pDevMode = (LPDEVMODEW)ptr;
3705 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3706 if(space && size <= left) {
3707 pi2->pDevMode = (LPDEVMODEW)ptr;
3714 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3716 if(space && size <= left) {
3717 pi2->pSepFile = (LPWSTR)ptr;
3724 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3726 if(space && size <= left) {
3727 pi2->pPrintProcessor = (LPWSTR)ptr;
3734 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3736 if(space && size <= left) {
3737 pi2->pDatatype = (LPWSTR)ptr;
3744 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3746 if(space && size <= left) {
3747 pi2->pParameters = (LPWSTR)ptr;
3755 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3756 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3757 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3758 "Default Priority");
3759 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3760 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3763 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3764 memset(pi2, 0, sizeof(*pi2));
3769 /*********************************************************************
3770 * WINSPOOL_GetPrinter_4
3772 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3774 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3775 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3778 DWORD size, left = cbBuf;
3779 BOOL space = (cbBuf > 0);
3784 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3786 if(space && size <= left) {
3787 pi4->pPrinterName = (LPWSTR)ptr;
3795 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3798 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3799 memset(pi4, 0, sizeof(*pi4));
3804 /*********************************************************************
3805 * WINSPOOL_GetPrinter_5
3807 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3809 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3810 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3813 DWORD size, left = cbBuf;
3814 BOOL space = (cbBuf > 0);
3819 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3821 if(space && size <= left) {
3822 pi5->pPrinterName = (LPWSTR)ptr;
3829 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3831 if(space && size <= left) {
3832 pi5->pPortName = (LPWSTR)ptr;
3840 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3841 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3843 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3847 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3848 memset(pi5, 0, sizeof(*pi5));
3853 /*****************************************************************************
3854 * WINSPOOL_GetPrinter
3856 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3857 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3858 * just a collection of pointers to strings.
3860 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3861 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3864 DWORD size, needed = 0;
3866 HKEY hkeyPrinter, hkeyPrinters;
3869 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3871 if (!(name = get_opened_printer_name(hPrinter))) {
3872 SetLastError(ERROR_INVALID_HANDLE);
3876 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3878 ERR("Can't create Printers key\n");
3881 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3883 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3884 RegCloseKey(hkeyPrinters);
3885 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3892 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3894 size = sizeof(PRINTER_INFO_2W);
3896 ptr = pPrinter + size;
3898 memset(pPrinter, 0, size);
3903 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3911 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3913 size = sizeof(PRINTER_INFO_4W);
3915 ptr = pPrinter + size;
3917 memset(pPrinter, 0, size);
3922 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3931 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3933 size = sizeof(PRINTER_INFO_5W);
3935 ptr = pPrinter + size;
3937 memset(pPrinter, 0, size);
3943 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3950 FIXME("Unimplemented level %d\n", Level);
3951 SetLastError(ERROR_INVALID_LEVEL);
3952 RegCloseKey(hkeyPrinters);
3953 RegCloseKey(hkeyPrinter);
3957 RegCloseKey(hkeyPrinter);
3958 RegCloseKey(hkeyPrinters);
3960 TRACE("returning %d needed = %d\n", ret, needed);
3961 if(pcbNeeded) *pcbNeeded = needed;
3963 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3967 /*****************************************************************************
3968 * GetPrinterW [WINSPOOL.@]
3970 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3971 DWORD cbBuf, LPDWORD pcbNeeded)
3973 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3977 /*****************************************************************************
3978 * GetPrinterA [WINSPOOL.@]
3980 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3981 DWORD cbBuf, LPDWORD pcbNeeded)
3983 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3987 /*****************************************************************************
3988 * WINSPOOL_EnumPrinters
3990 * Implementation of EnumPrintersA|W
3992 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3993 DWORD dwLevel, LPBYTE lpbPrinters,
3994 DWORD cbBuf, LPDWORD lpdwNeeded,
3995 LPDWORD lpdwReturned, BOOL unicode)
3998 HKEY hkeyPrinters, hkeyPrinter;
3999 WCHAR PrinterName[255];
4000 DWORD needed = 0, number = 0;
4001 DWORD used, i, left;
4005 memset(lpbPrinters, 0, cbBuf);
4011 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4012 if(dwType == PRINTER_ENUM_DEFAULT)
4015 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4016 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4017 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4019 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4027 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4028 FIXME("dwType = %08x\n", dwType);
4029 SetLastError(ERROR_INVALID_FLAGS);
4033 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4035 ERR("Can't create Printers key\n");
4039 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4040 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4041 RegCloseKey(hkeyPrinters);
4042 ERR("Can't query Printers key\n");
4045 TRACE("Found %d printers\n", number);
4049 RegCloseKey(hkeyPrinters);
4051 *lpdwReturned = number;
4055 used = number * sizeof(PRINTER_INFO_2W);
4058 used = number * sizeof(PRINTER_INFO_4W);
4061 used = number * sizeof(PRINTER_INFO_5W);
4065 SetLastError(ERROR_INVALID_LEVEL);
4066 RegCloseKey(hkeyPrinters);
4069 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4071 for(i = 0; i < number; i++) {
4072 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4074 ERR("Can't enum key number %d\n", i);
4075 RegCloseKey(hkeyPrinters);
4078 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4079 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4081 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4082 RegCloseKey(hkeyPrinters);
4087 buf = lpbPrinters + used;
4088 left = cbBuf - used;
4096 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4097 left, &needed, unicode);
4099 if(pi) pi += sizeof(PRINTER_INFO_2W);
4102 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4103 left, &needed, unicode);
4105 if(pi) pi += sizeof(PRINTER_INFO_4W);
4108 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4109 left, &needed, unicode);
4111 if(pi) pi += sizeof(PRINTER_INFO_5W);
4114 ERR("Shouldn't be here!\n");
4115 RegCloseKey(hkeyPrinter);
4116 RegCloseKey(hkeyPrinters);
4119 RegCloseKey(hkeyPrinter);
4121 RegCloseKey(hkeyPrinters);
4128 memset(lpbPrinters, 0, cbBuf);
4129 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4133 *lpdwReturned = number;
4134 SetLastError(ERROR_SUCCESS);
4139 /******************************************************************
4140 * EnumPrintersW [WINSPOOL.@]
4142 * Enumerates the available printers, print servers and print
4143 * providers, depending on the specified flags, name and level.
4147 * If level is set to 1:
4148 * Not implemented yet!
4149 * Returns TRUE with an empty list.
4151 * If level is set to 2:
4152 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4153 * Returns an array of PRINTER_INFO_2 data structures in the
4154 * lpbPrinters buffer. Note that according to MSDN also an
4155 * OpenPrinter should be performed on every remote printer.
4157 * If level is set to 4 (officially WinNT only):
4158 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4159 * Fast: Only the registry is queried to retrieve printer names,
4160 * no connection to the driver is made.
4161 * Returns an array of PRINTER_INFO_4 data structures in the
4162 * lpbPrinters buffer.
4164 * If level is set to 5 (officially WinNT4/Win9x only):
4165 * Fast: Only the registry is queried to retrieve printer names,
4166 * no connection to the driver is made.
4167 * Returns an array of PRINTER_INFO_5 data structures in the
4168 * lpbPrinters buffer.
4170 * If level set to 3 or 6+:
4171 * returns zero (failure!)
4173 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4177 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4178 * - Only levels 2, 4 and 5 are implemented at the moment.
4179 * - 16-bit printer drivers are not enumerated.
4180 * - Returned amount of bytes used/needed does not match the real Windoze
4181 * implementation (as in this implementation, all strings are part
4182 * of the buffer, whereas Win32 keeps them somewhere else)
4183 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4186 * - In a regular Wine installation, no registry settings for printers
4187 * exist, which makes this function return an empty list.
4189 BOOL WINAPI EnumPrintersW(
4190 DWORD dwType, /* [in] Types of print objects to enumerate */
4191 LPWSTR lpszName, /* [in] name of objects to enumerate */
4192 DWORD dwLevel, /* [in] type of printer info structure */
4193 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4194 DWORD cbBuf, /* [in] max size of buffer in bytes */
4195 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4196 LPDWORD lpdwReturned /* [out] number of entries returned */
4199 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4200 lpdwNeeded, lpdwReturned, TRUE);
4203 /******************************************************************
4204 * EnumPrintersA [WINSPOOL.@]
4207 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4208 DWORD dwLevel, LPBYTE lpbPrinters,
4209 DWORD cbBuf, LPDWORD lpdwNeeded,
4210 LPDWORD lpdwReturned)
4212 BOOL ret, unicode = FALSE;
4213 UNICODE_STRING lpszNameW;
4216 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4217 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4218 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4219 lpdwNeeded, lpdwReturned, unicode);
4220 RtlFreeUnicodeString(&lpszNameW);
4224 /*****************************************************************************
4225 * WINSPOOL_GetDriverInfoFromReg [internal]
4227 * Enters the information from the registry into the DRIVER_INFO struct
4230 * zero if the printer driver does not exist in the registry
4231 * (only if Level > 1) otherwise nonzero
4233 static BOOL WINSPOOL_GetDriverInfoFromReg(
4236 LPCWSTR pEnvironment,
4238 LPBYTE ptr, /* DRIVER_INFO */
4239 LPBYTE pDriverStrings, /* strings buffer */
4240 DWORD cbBuf, /* size of string buffer */
4241 LPDWORD pcbNeeded, /* space needed for str. */
4242 BOOL unicode) /* type of strings */
4246 LPBYTE strPtr = pDriverStrings;
4248 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4249 debugstr_w(DriverName), debugstr_w(pEnvironment),
4250 Level, ptr, pDriverStrings, cbBuf, unicode);
4253 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4254 if (*pcbNeeded <= cbBuf)
4255 strcpyW((LPWSTR)strPtr, DriverName);
4257 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4259 if(*pcbNeeded <= cbBuf)
4260 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4261 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4265 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4269 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4270 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4273 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4274 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4275 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4280 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4283 pEnvironment = DefaultEnvironmentW;
4285 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4287 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4290 if(*pcbNeeded <= cbBuf) {
4292 strcpyW((LPWSTR)strPtr, pEnvironment);
4294 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4295 (LPSTR)strPtr, size, NULL, NULL);
4297 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4298 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4301 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4304 if(*pcbNeeded <= cbBuf)
4305 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4308 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4309 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4312 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4315 if(*pcbNeeded <= cbBuf)
4316 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4319 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4320 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4323 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4324 0, &size, unicode)) {
4326 if(*pcbNeeded <= cbBuf)
4327 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4328 size, &tmp, unicode);
4330 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4331 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4335 RegCloseKey(hkeyDriver);
4336 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4340 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4343 if(*pcbNeeded <= cbBuf)
4344 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4345 size, &tmp, unicode);
4347 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4348 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4351 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4354 if(*pcbNeeded <= cbBuf)
4355 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4356 size, &tmp, unicode);
4358 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4359 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4362 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4365 if(*pcbNeeded <= cbBuf)
4366 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4367 size, &tmp, unicode);
4369 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4370 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4373 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4376 if(*pcbNeeded <= cbBuf)
4377 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4378 size, &tmp, unicode);
4380 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4381 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4384 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4385 RegCloseKey(hkeyDriver);
4389 /*****************************************************************************
4390 * WINSPOOL_GetPrinterDriver
4392 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4393 DWORD Level, LPBYTE pDriverInfo,
4394 DWORD cbBuf, LPDWORD pcbNeeded,
4398 WCHAR DriverName[100];
4399 DWORD ret, type, size, needed = 0;
4401 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4403 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4404 Level,pDriverInfo,cbBuf, pcbNeeded);
4406 ZeroMemory(pDriverInfo, cbBuf);
4408 if (!(name = get_opened_printer_name(hPrinter))) {
4409 SetLastError(ERROR_INVALID_HANDLE);
4412 if(Level < 1 || Level > 6) {
4413 SetLastError(ERROR_INVALID_LEVEL);
4416 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4418 ERR("Can't create Printers key\n");
4421 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4423 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4424 RegCloseKey(hkeyPrinters);
4425 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4428 size = sizeof(DriverName);
4430 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4431 (LPBYTE)DriverName, &size);
4432 RegCloseKey(hkeyPrinter);
4433 RegCloseKey(hkeyPrinters);
4434 if(ret != ERROR_SUCCESS) {
4435 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4439 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4441 ERR("Can't create Drivers key\n");
4447 size = sizeof(DRIVER_INFO_1W);
4450 size = sizeof(DRIVER_INFO_2W);
4453 size = sizeof(DRIVER_INFO_3W);
4456 size = sizeof(DRIVER_INFO_4W);
4459 size = sizeof(DRIVER_INFO_5W);
4462 size = sizeof(DRIVER_INFO_6W);
4465 ERR("Invalid level\n");
4470 ptr = pDriverInfo + size;
4472 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4473 pEnvironment, Level, pDriverInfo,
4474 (cbBuf < size) ? NULL : ptr,
4475 (cbBuf < size) ? 0 : cbBuf - size,
4476 &needed, unicode)) {
4477 RegCloseKey(hkeyDrivers);
4481 RegCloseKey(hkeyDrivers);
4483 if(pcbNeeded) *pcbNeeded = size + needed;
4484 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4485 if(cbBuf >= needed) return TRUE;
4486 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4490 /*****************************************************************************
4491 * GetPrinterDriverA [WINSPOOL.@]
4493 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4494 DWORD Level, LPBYTE pDriverInfo,
4495 DWORD cbBuf, LPDWORD pcbNeeded)
4498 UNICODE_STRING pEnvW;
4501 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4502 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4503 cbBuf, pcbNeeded, FALSE);
4504 RtlFreeUnicodeString(&pEnvW);
4507 /*****************************************************************************
4508 * GetPrinterDriverW [WINSPOOL.@]
4510 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4511 DWORD Level, LPBYTE pDriverInfo,
4512 DWORD cbBuf, LPDWORD pcbNeeded)
4514 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4515 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4518 /*****************************************************************************
4519 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4521 * Return the PATH for the Printer-Drivers (UNICODE)
4524 * pName [I] Servername (NT only) or NULL (local Computer)
4525 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4526 * Level [I] Structure-Level (must be 1)
4527 * pDriverDirectory [O] PTR to Buffer that receives the Result
4528 * cbBuf [I] Size of Buffer at pDriverDirectory
4529 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4530 * required for pDriverDirectory
4533 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4534 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4535 * if cbBuf is too small
4537 * Native Values returned in pDriverDirectory on Success:
4538 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4539 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4540 *| win9x(Windows 4.0): "%winsysdir%"
4542 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4545 *- Only NULL or "" is supported for pName
4548 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4549 DWORD Level, LPBYTE pDriverDirectory,
4550 DWORD cbBuf, LPDWORD pcbNeeded)
4553 const printenv_t * env;
4555 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4556 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4557 if(pName != NULL && pName[0]) {
4558 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4559 SetLastError(ERROR_INVALID_PARAMETER);
4563 env = validate_envW(pEnvironment);
4564 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4567 WARN("(Level: %d) is ignored in win9x\n", Level);
4568 SetLastError(ERROR_INVALID_LEVEL);
4572 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4573 needed = GetSystemDirectoryW(NULL, 0);
4574 /* add the Size for the Subdirectories */
4575 needed += lstrlenW(spooldriversW);
4576 needed += lstrlenW(env->subdir);
4577 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4580 *pcbNeeded = needed;
4581 TRACE("required: 0x%x/%d\n", needed, needed);
4582 if(needed > cbBuf) {
4583 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4586 if(pcbNeeded == NULL) {
4587 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4588 SetLastError(RPC_X_NULL_REF_POINTER);
4591 if(pDriverDirectory == NULL) {
4592 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4593 SetLastError(ERROR_INVALID_USER_BUFFER);
4597 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4598 /* add the Subdirectories */
4599 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4600 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4601 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4606 /*****************************************************************************
4607 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4609 * Return the PATH for the Printer-Drivers (ANSI)
4611 * See GetPrinterDriverDirectoryW.
4614 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4617 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4618 DWORD Level, LPBYTE pDriverDirectory,
4619 DWORD cbBuf, LPDWORD pcbNeeded)
4621 UNICODE_STRING nameW, environmentW;
4624 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4625 WCHAR *driverDirectoryW = NULL;
4627 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4628 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4630 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4632 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4633 else nameW.Buffer = NULL;
4634 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4635 else environmentW.Buffer = NULL;
4637 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4638 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4641 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4642 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4644 *pcbNeeded = needed;
4645 ret = (needed <= cbBuf) ? TRUE : FALSE;
4647 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4649 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4651 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4652 RtlFreeUnicodeString(&environmentW);
4653 RtlFreeUnicodeString(&nameW);
4658 /*****************************************************************************
4659 * AddPrinterDriverA [WINSPOOL.@]
4661 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4664 HKEY hkeyDrivers, hkeyName;
4665 static CHAR empty[] = "",
4668 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4670 if(level != 2 && level != 3) {
4671 SetLastError(ERROR_INVALID_LEVEL);
4674 if ((pName) && (pName[0])) {
4675 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4676 SetLastError(ERROR_INVALID_PARAMETER);
4680 WARN("pDriverInfo == NULL\n");
4681 SetLastError(ERROR_INVALID_PARAMETER);
4686 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4688 memset(&di3, 0, sizeof(di3));
4689 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4692 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4694 SetLastError(ERROR_INVALID_PARAMETER);
4698 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4699 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4700 if(!di3.pHelpFile) di3.pHelpFile = empty;
4701 if(!di3.pMonitorName) di3.pMonitorName = empty;
4703 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4706 ERR("Can't create Drivers key\n");
4710 if(level == 2) { /* apparently can't overwrite with level2 */
4711 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4712 RegCloseKey(hkeyName);
4713 RegCloseKey(hkeyDrivers);
4714 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4715 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4719 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4720 RegCloseKey(hkeyDrivers);
4721 ERR("Can't create Name key\n");
4724 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4725 lstrlenA(di3.pConfigFile) + 1);
4726 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4727 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4728 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4730 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4731 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4732 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4733 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4734 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4735 RegCloseKey(hkeyName);
4736 RegCloseKey(hkeyDrivers);
4741 /*****************************************************************************
4742 * AddPrinterDriverW [WINSPOOL.@]
4744 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4747 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4752 /*****************************************************************************
4753 * AddPrintProcessorA [WINSPOOL.@]
4755 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4756 LPSTR pPrintProcessorName)
4758 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4759 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4763 /*****************************************************************************
4764 * AddPrintProcessorW [WINSPOOL.@]
4766 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4767 LPWSTR pPrintProcessorName)
4769 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4770 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4774 /*****************************************************************************
4775 * AddPrintProvidorA [WINSPOOL.@]
4777 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4779 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4783 /*****************************************************************************
4784 * AddPrintProvidorW [WINSPOOL.@]
4786 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4788 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4792 /*****************************************************************************
4793 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4795 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4796 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4798 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4799 pDevModeOutput, pDevModeInput);
4803 /*****************************************************************************
4804 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4806 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4807 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4809 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4810 pDevModeOutput, pDevModeInput);
4814 /*****************************************************************************
4815 * PrinterProperties [WINSPOOL.@]
4817 * Displays a dialog to set the properties of the printer.
4820 * nonzero on success or zero on failure
4823 * implemented as stub only
4825 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4826 HANDLE hPrinter /* [in] handle to printer object */
4828 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4829 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4833 /*****************************************************************************
4834 * EnumJobsA [WINSPOOL.@]
4837 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4838 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4841 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4842 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4844 if(pcbNeeded) *pcbNeeded = 0;
4845 if(pcReturned) *pcReturned = 0;
4850 /*****************************************************************************
4851 * EnumJobsW [WINSPOOL.@]
4854 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4855 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4858 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4859 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4861 if(pcbNeeded) *pcbNeeded = 0;
4862 if(pcReturned) *pcReturned = 0;
4866 /*****************************************************************************
4867 * WINSPOOL_EnumPrinterDrivers [internal]
4869 * Delivers information about all printer drivers installed on the
4870 * localhost or a given server
4873 * nonzero on success or zero on failure. If the buffer for the returned
4874 * information is too small the function will return an error
4877 * - only implemented for localhost, foreign hosts will return an error
4879 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4880 DWORD Level, LPBYTE pDriverInfo,
4881 DWORD cbBuf, LPDWORD pcbNeeded,
4882 LPDWORD pcReturned, BOOL unicode)
4885 DWORD i, needed, number = 0, size = 0;
4886 WCHAR DriverNameW[255];
4889 TRACE("%s,%s,%d,%p,%d,%d\n",
4890 debugstr_w(pName), debugstr_w(pEnvironment),
4891 Level, pDriverInfo, cbBuf, unicode);
4893 /* check for local drivers */
4894 if((pName) && (pName[0])) {
4895 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4896 SetLastError(ERROR_ACCESS_DENIED);
4900 /* check input parameter */
4901 if((Level < 1) || (Level > 3)) {
4902 ERR("unsupported level %d\n", Level);
4903 SetLastError(ERROR_INVALID_LEVEL);
4907 /* initialize return values */
4909 memset( pDriverInfo, 0, cbBuf);
4913 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4915 ERR("Can't open Drivers key\n");
4919 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4920 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4921 RegCloseKey(hkeyDrivers);
4922 ERR("Can't query Drivers key\n");
4925 TRACE("Found %d Drivers\n", number);
4927 /* get size of single struct
4928 * unicode and ascii structure have the same size
4932 size = sizeof(DRIVER_INFO_1A);
4935 size = sizeof(DRIVER_INFO_2A);
4938 size = sizeof(DRIVER_INFO_3A);
4942 /* calculate required buffer size */
4943 *pcbNeeded = size * number;
4945 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4947 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4948 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4950 ERR("Can't enum key number %d\n", i);
4951 RegCloseKey(hkeyDrivers);
4954 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4955 pEnvironment, Level, ptr,
4956 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4957 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4958 &needed, unicode)) {
4959 RegCloseKey(hkeyDrivers);
4962 (*pcbNeeded) += needed;
4965 RegCloseKey(hkeyDrivers);
4967 if(cbBuf < *pcbNeeded){
4968 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4972 *pcReturned = number;
4976 /*****************************************************************************
4977 * EnumPrinterDriversW [WINSPOOL.@]
4979 * see function EnumPrinterDrivers for RETURNS, BUGS
4981 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4982 LPBYTE pDriverInfo, DWORD cbBuf,
4983 LPDWORD pcbNeeded, LPDWORD pcReturned)
4985 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4986 cbBuf, pcbNeeded, pcReturned, TRUE);
4989 /*****************************************************************************
4990 * EnumPrinterDriversA [WINSPOOL.@]
4992 * see function EnumPrinterDrivers for RETURNS, BUGS
4994 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4995 LPBYTE pDriverInfo, DWORD cbBuf,
4996 LPDWORD pcbNeeded, LPDWORD pcReturned)
4998 UNICODE_STRING pNameW, pEnvironmentW;
4999 PWSTR pwstrNameW, pwstrEnvironmentW;
5001 pwstrNameW = asciitounicode(&pNameW, pName);
5002 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5004 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5005 Level, pDriverInfo, cbBuf, pcbNeeded,
5007 RtlFreeUnicodeString(&pNameW);
5008 RtlFreeUnicodeString(&pEnvironmentW);
5013 /******************************************************************************
5014 * EnumPortsA (WINSPOOL.@)
5019 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5020 LPDWORD pcbNeeded, LPDWORD pcReturned)
5023 LPBYTE bufferW = NULL;
5024 LPWSTR nameW = NULL;
5026 DWORD numentries = 0;
5029 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5030 cbBuf, pcbNeeded, pcReturned);
5032 /* convert servername to unicode */
5034 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5035 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5036 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5038 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5039 needed = cbBuf * sizeof(WCHAR);
5040 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5041 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5043 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5044 if (pcbNeeded) needed = *pcbNeeded;
5045 /* HeapReAlloc return NULL, when bufferW was NULL */
5046 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5047 HeapAlloc(GetProcessHeap(), 0, needed);
5049 /* Try again with the large Buffer */
5050 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5052 needed = pcbNeeded ? *pcbNeeded : 0;
5053 numentries = pcReturned ? *pcReturned : 0;
5056 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5057 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5060 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5061 DWORD entrysize = 0;
5064 LPPORT_INFO_2W pi2w;
5065 LPPORT_INFO_2A pi2a;
5068 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5070 /* First pass: calculate the size for all Entries */
5071 pi2w = (LPPORT_INFO_2W) bufferW;
5072 pi2a = (LPPORT_INFO_2A) pPorts;
5074 while (index < numentries) {
5076 needed += entrysize; /* PORT_INFO_?A */
5077 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5079 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5080 NULL, 0, NULL, NULL);
5082 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5083 NULL, 0, NULL, NULL);
5084 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5085 NULL, 0, NULL, NULL);
5087 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5088 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5089 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5092 /* check for errors and quit on failure */
5093 if (cbBuf < needed) {
5094 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5098 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5099 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5100 cbBuf -= len ; /* free Bytes in the user-Buffer */
5101 pi2w = (LPPORT_INFO_2W) bufferW;
5102 pi2a = (LPPORT_INFO_2A) pPorts;
5104 /* Second Pass: Fill the User Buffer (if we have one) */
5105 while ((index < numentries) && pPorts) {
5107 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5108 pi2a->pPortName = ptr;
5109 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5110 ptr, cbBuf , NULL, NULL);
5114 pi2a->pMonitorName = ptr;
5115 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5116 ptr, cbBuf, NULL, NULL);
5120 pi2a->pDescription = ptr;
5121 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5122 ptr, cbBuf, NULL, NULL);
5126 pi2a->fPortType = pi2w->fPortType;
5127 pi2a->Reserved = 0; /* documented: "must be zero" */
5130 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5131 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5132 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5137 if (pcbNeeded) *pcbNeeded = needed;
5138 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5140 HeapFree(GetProcessHeap(), 0, nameW);
5141 HeapFree(GetProcessHeap(), 0, bufferW);
5143 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5144 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5150 /******************************************************************************
5151 * EnumPortsW (WINSPOOL.@)
5153 * Enumerate available Ports
5156 * name [I] Servername or NULL (local Computer)
5157 * level [I] Structure-Level (1 or 2)
5158 * buffer [O] PTR to Buffer that receives the Result
5159 * bufsize [I] Size of Buffer at buffer
5160 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5161 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5165 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5169 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5172 DWORD numentries = 0;
5175 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5176 cbBuf, pcbNeeded, pcReturned);
5178 if (pName && (pName[0])) {
5179 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5180 SetLastError(ERROR_ACCESS_DENIED);
5184 /* Level is not checked in win9x */
5185 if (!Level || (Level > 2)) {
5186 WARN("level (%d) is ignored in win9x\n", Level);
5187 SetLastError(ERROR_INVALID_LEVEL);
5191 SetLastError(RPC_X_NULL_REF_POINTER);
5195 EnterCriticalSection(&monitor_handles_cs);
5198 /* Scan all local Ports */
5200 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5202 /* we calculated the needed buffersize. now do the error-checks */
5203 if (cbBuf < needed) {
5204 monitor_unloadall();
5205 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5206 goto emP_cleanup_cs;
5208 else if (!pPorts || !pcReturned) {
5209 monitor_unloadall();
5210 SetLastError(RPC_X_NULL_REF_POINTER);
5211 goto emP_cleanup_cs;
5214 /* Fill the Buffer */
5215 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5217 monitor_unloadall();
5220 LeaveCriticalSection(&monitor_handles_cs);
5223 if (pcbNeeded) *pcbNeeded = needed;
5224 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5226 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5227 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5232 /******************************************************************************
5233 * GetDefaultPrinterW (WINSPOOL.@)
5236 * This function must read the value from data 'device' of key
5237 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5239 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5243 WCHAR *buffer, *ptr;
5247 SetLastError(ERROR_INVALID_PARAMETER);
5251 /* make the buffer big enough for the stuff from the profile/registry,
5252 * the content must fit into the local buffer to compute the correct
5253 * size even if the extern buffer is too small or not given.
5254 * (20 for ,driver,port) */
5256 len = max(100, (insize + 20));
5257 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5259 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5261 SetLastError (ERROR_FILE_NOT_FOUND);
5265 TRACE("%s\n", debugstr_w(buffer));
5267 if ((ptr = strchrW(buffer, ',')) == NULL)
5269 SetLastError(ERROR_INVALID_NAME);
5275 *namesize = strlenW(buffer) + 1;
5276 if(!name || (*namesize > insize))
5278 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5282 strcpyW(name, buffer);
5285 HeapFree( GetProcessHeap(), 0, buffer);
5290 /******************************************************************************
5291 * GetDefaultPrinterA (WINSPOOL.@)
5293 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5297 WCHAR *bufferW = NULL;
5301 SetLastError(ERROR_INVALID_PARAMETER);
5305 if(name && *namesize) {
5307 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5310 if(!GetDefaultPrinterW( bufferW, namesize)) {
5315 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5319 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5322 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5325 HeapFree( GetProcessHeap(), 0, bufferW);
5330 /******************************************************************************
5331 * SetDefaultPrinterW (WINSPOOL.204)
5333 * Set the Name of the Default Printer
5336 * pszPrinter [I] Name of the Printer or NULL
5343 * When the Parameter is NULL or points to an Empty String and
5344 * a Default Printer was already present, then this Function changes nothing.
5345 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5346 * the First enumerated local Printer is used.
5349 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5352 TRACE("(%s)\n", debugstr_w(pszPrinter));
5354 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5358 /******************************************************************************
5359 * SetDefaultPrinterA (WINSPOOL.202)
5361 * See SetDefaultPrinterW.
5364 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5367 TRACE("(%s)\n", debugstr_a(pszPrinter));
5369 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5374 /******************************************************************************
5375 * SetPrinterDataExA (WINSPOOL.@)
5377 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5378 LPCSTR pValueName, DWORD Type,
5379 LPBYTE pData, DWORD cbData)
5381 HKEY hkeyPrinter, hkeySubkey;
5384 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5385 debugstr_a(pValueName), Type, pData, cbData);
5387 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5391 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5393 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5394 RegCloseKey(hkeyPrinter);
5397 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5398 RegCloseKey(hkeySubkey);
5399 RegCloseKey(hkeyPrinter);
5403 /******************************************************************************
5404 * SetPrinterDataExW (WINSPOOL.@)
5406 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5407 LPCWSTR pValueName, DWORD Type,
5408 LPBYTE pData, DWORD cbData)
5410 HKEY hkeyPrinter, hkeySubkey;
5413 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5414 debugstr_w(pValueName), Type, pData, cbData);
5416 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5420 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5422 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5423 RegCloseKey(hkeyPrinter);
5426 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5427 RegCloseKey(hkeySubkey);
5428 RegCloseKey(hkeyPrinter);
5432 /******************************************************************************
5433 * SetPrinterDataA (WINSPOOL.@)
5435 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5436 LPBYTE pData, DWORD cbData)
5438 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5442 /******************************************************************************
5443 * SetPrinterDataW (WINSPOOL.@)
5445 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5446 LPBYTE pData, DWORD cbData)
5448 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5452 /******************************************************************************
5453 * GetPrinterDataExA (WINSPOOL.@)
5455 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5456 LPCSTR pValueName, LPDWORD pType,
5457 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5459 HKEY hkeyPrinter, hkeySubkey;
5462 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5463 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5466 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5470 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5472 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5473 RegCloseKey(hkeyPrinter);
5477 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5478 RegCloseKey(hkeySubkey);
5479 RegCloseKey(hkeyPrinter);
5483 /******************************************************************************
5484 * GetPrinterDataExW (WINSPOOL.@)
5486 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5487 LPCWSTR pValueName, LPDWORD pType,
5488 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5490 HKEY hkeyPrinter, hkeySubkey;
5493 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5494 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5497 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5501 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5503 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5504 RegCloseKey(hkeyPrinter);
5508 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5509 RegCloseKey(hkeySubkey);
5510 RegCloseKey(hkeyPrinter);
5514 /******************************************************************************
5515 * GetPrinterDataA (WINSPOOL.@)
5517 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5518 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5520 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5521 pData, nSize, pcbNeeded);
5524 /******************************************************************************
5525 * GetPrinterDataW (WINSPOOL.@)
5527 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5528 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5530 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5531 pData, nSize, pcbNeeded);
5534 /*******************************************************************************
5535 * EnumPrinterDataExW [WINSPOOL.@]
5537 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5538 LPBYTE pEnumValues, DWORD cbEnumValues,
5539 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5541 HKEY hkPrinter, hkSubKey;
5542 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5543 cbValueNameLen, cbMaxValueLen, cbValueLen,
5548 PPRINTER_ENUM_VALUESW ppev;
5550 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5552 if (pKeyName == NULL || *pKeyName == 0)
5553 return ERROR_INVALID_PARAMETER;
5555 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5556 if (ret != ERROR_SUCCESS)
5558 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5563 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5564 if (ret != ERROR_SUCCESS)
5566 r = RegCloseKey (hkPrinter);
5567 if (r != ERROR_SUCCESS)
5568 WARN ("RegCloseKey returned %i\n", r);
5569 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5570 debugstr_w (pKeyName), ret);
5574 ret = RegCloseKey (hkPrinter);
5575 if (ret != ERROR_SUCCESS)
5577 ERR ("RegCloseKey returned %i\n", ret);
5578 r = RegCloseKey (hkSubKey);
5579 if (r != ERROR_SUCCESS)
5580 WARN ("RegCloseKey returned %i\n", r);
5584 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5585 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5586 if (ret != ERROR_SUCCESS)
5588 r = RegCloseKey (hkSubKey);
5589 if (r != ERROR_SUCCESS)
5590 WARN ("RegCloseKey returned %i\n", r);
5591 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5595 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5596 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5598 if (cValues == 0) /* empty key */
5600 r = RegCloseKey (hkSubKey);
5601 if (r != ERROR_SUCCESS)
5602 WARN ("RegCloseKey returned %i\n", r);
5603 *pcbEnumValues = *pnEnumValues = 0;
5604 return ERROR_SUCCESS;
5607 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5609 hHeap = GetProcessHeap ();
5612 ERR ("GetProcessHeap failed\n");
5613 r = RegCloseKey (hkSubKey);
5614 if (r != ERROR_SUCCESS)
5615 WARN ("RegCloseKey returned %i\n", r);
5616 return ERROR_OUTOFMEMORY;
5619 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5620 if (lpValueName == NULL)
5622 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5623 r = RegCloseKey (hkSubKey);
5624 if (r != ERROR_SUCCESS)
5625 WARN ("RegCloseKey returned %i\n", r);
5626 return ERROR_OUTOFMEMORY;
5629 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5630 if (lpValue == NULL)
5632 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5633 if (HeapFree (hHeap, 0, lpValueName) == 0)
5634 WARN ("HeapFree failed with code %i\n", GetLastError ());
5635 r = RegCloseKey (hkSubKey);
5636 if (r != ERROR_SUCCESS)
5637 WARN ("RegCloseKey returned %i\n", r);
5638 return ERROR_OUTOFMEMORY;
5641 TRACE ("pass 1: calculating buffer required for all names and values\n");
5643 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5645 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5647 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5649 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5650 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5651 NULL, NULL, lpValue, &cbValueLen);
5652 if (ret != ERROR_SUCCESS)
5654 if (HeapFree (hHeap, 0, lpValue) == 0)
5655 WARN ("HeapFree failed with code %i\n", GetLastError ());
5656 if (HeapFree (hHeap, 0, lpValueName) == 0)
5657 WARN ("HeapFree failed with code %i\n", GetLastError ());
5658 r = RegCloseKey (hkSubKey);
5659 if (r != ERROR_SUCCESS)
5660 WARN ("RegCloseKey returned %i\n", r);
5661 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5665 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5666 debugstr_w (lpValueName), dwIndex,
5667 cbValueNameLen + 1, cbValueLen);
5669 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5670 cbBufSize += cbValueLen;
5673 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5675 *pcbEnumValues = cbBufSize;
5676 *pnEnumValues = cValues;
5678 if (cbEnumValues < cbBufSize) /* buffer too small */
5680 if (HeapFree (hHeap, 0, lpValue) == 0)
5681 WARN ("HeapFree failed with code %i\n", GetLastError ());
5682 if (HeapFree (hHeap, 0, lpValueName) == 0)
5683 WARN ("HeapFree failed with code %i\n", GetLastError ());
5684 r = RegCloseKey (hkSubKey);
5685 if (r != ERROR_SUCCESS)
5686 WARN ("RegCloseKey returned %i\n", r);
5687 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5688 return ERROR_MORE_DATA;
5691 TRACE ("pass 2: copying all names and values to buffer\n");
5693 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5694 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5696 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5698 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5699 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5700 NULL, &dwType, lpValue, &cbValueLen);
5701 if (ret != ERROR_SUCCESS)
5703 if (HeapFree (hHeap, 0, lpValue) == 0)
5704 WARN ("HeapFree failed with code %i\n", GetLastError ());
5705 if (HeapFree (hHeap, 0, lpValueName) == 0)
5706 WARN ("HeapFree failed with code %i\n", GetLastError ());
5707 r = RegCloseKey (hkSubKey);
5708 if (r != ERROR_SUCCESS)
5709 WARN ("RegCloseKey returned %i\n", r);
5710 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5714 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5715 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5716 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5717 pEnumValues += cbValueNameLen;
5719 /* return # of *bytes* (including trailing \0), not # of chars */
5720 ppev[dwIndex].cbValueName = cbValueNameLen;
5722 ppev[dwIndex].dwType = dwType;
5724 memcpy (pEnumValues, lpValue, cbValueLen);
5725 ppev[dwIndex].pData = pEnumValues;
5726 pEnumValues += cbValueLen;
5728 ppev[dwIndex].cbData = cbValueLen;
5730 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5731 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5734 if (HeapFree (hHeap, 0, lpValue) == 0)
5736 ret = GetLastError ();
5737 ERR ("HeapFree failed with code %i\n", ret);
5738 if (HeapFree (hHeap, 0, lpValueName) == 0)
5739 WARN ("HeapFree failed with code %i\n", GetLastError ());
5740 r = RegCloseKey (hkSubKey);
5741 if (r != ERROR_SUCCESS)
5742 WARN ("RegCloseKey returned %i\n", r);
5746 if (HeapFree (hHeap, 0, lpValueName) == 0)
5748 ret = GetLastError ();
5749 ERR ("HeapFree failed with code %i\n", ret);
5750 r = RegCloseKey (hkSubKey);
5751 if (r != ERROR_SUCCESS)
5752 WARN ("RegCloseKey returned %i\n", r);
5756 ret = RegCloseKey (hkSubKey);
5757 if (ret != ERROR_SUCCESS)
5759 ERR ("RegCloseKey returned %i\n", ret);
5763 return ERROR_SUCCESS;
5766 /*******************************************************************************
5767 * EnumPrinterDataExA [WINSPOOL.@]
5769 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5770 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5771 * what Windows 2000 SP1 does.
5774 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5775 LPBYTE pEnumValues, DWORD cbEnumValues,
5776 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5780 DWORD ret, dwIndex, dwBufSize;
5784 TRACE ("%p %s\n", hPrinter, pKeyName);
5786 if (pKeyName == NULL || *pKeyName == 0)
5787 return ERROR_INVALID_PARAMETER;
5789 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5792 ret = GetLastError ();
5793 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5797 hHeap = GetProcessHeap ();
5800 ERR ("GetProcessHeap failed\n");
5801 return ERROR_OUTOFMEMORY;
5804 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5805 if (pKeyNameW == NULL)
5807 ERR ("Failed to allocate %i bytes from process heap\n",
5808 (LONG)(len * sizeof (WCHAR)));
5809 return ERROR_OUTOFMEMORY;
5812 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5814 ret = GetLastError ();
5815 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5816 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5817 WARN ("HeapFree failed with code %i\n", GetLastError ());
5821 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5822 pcbEnumValues, pnEnumValues);
5823 if (ret != ERROR_SUCCESS)
5825 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5826 WARN ("HeapFree failed with code %i\n", GetLastError ());
5827 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5831 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5833 ret = GetLastError ();
5834 ERR ("HeapFree failed with code %i\n", ret);
5838 if (*pnEnumValues == 0) /* empty key */
5839 return ERROR_SUCCESS;
5842 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5844 PPRINTER_ENUM_VALUESW ppev =
5845 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5847 if (dwBufSize < ppev->cbValueName)
5848 dwBufSize = ppev->cbValueName;
5850 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5851 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5852 dwBufSize = ppev->cbData;
5855 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5857 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5858 if (pBuffer == NULL)
5860 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5861 return ERROR_OUTOFMEMORY;
5864 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5866 PPRINTER_ENUM_VALUESW ppev =
5867 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5869 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5870 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5874 ret = GetLastError ();
5875 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5876 if (HeapFree (hHeap, 0, pBuffer) == 0)
5877 WARN ("HeapFree failed with code %i\n", GetLastError ());
5881 memcpy (ppev->pValueName, pBuffer, len);
5883 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5885 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5886 ppev->dwType != REG_MULTI_SZ)
5889 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5890 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5893 ret = GetLastError ();
5894 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5895 if (HeapFree (hHeap, 0, pBuffer) == 0)
5896 WARN ("HeapFree failed with code %i\n", GetLastError ());
5900 memcpy (ppev->pData, pBuffer, len);
5902 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5903 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5906 if (HeapFree (hHeap, 0, pBuffer) == 0)
5908 ret = GetLastError ();
5909 ERR ("HeapFree failed with code %i\n", ret);
5913 return ERROR_SUCCESS;
5916 /******************************************************************************
5917 * AbortPrinter (WINSPOOL.@)
5919 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5921 FIXME("(%p), stub!\n", hPrinter);
5925 /******************************************************************************
5926 * AddPortA (WINSPOOL.@)
5931 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5933 LPWSTR nameW = NULL;
5934 LPWSTR monitorW = NULL;
5938 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5941 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5942 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5943 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5947 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5948 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5949 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5951 res = AddPortW(nameW, hWnd, monitorW);
5952 HeapFree(GetProcessHeap(), 0, nameW);
5953 HeapFree(GetProcessHeap(), 0, monitorW);
5957 /******************************************************************************
5958 * AddPortW (WINSPOOL.@)
5960 * Add a Port for a specific Monitor
5963 * pName [I] Servername or NULL (local Computer)
5964 * hWnd [I] Handle to parent Window for the Dialog-Box
5965 * pMonitorName [I] Name of the Monitor that manage the Port
5972 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5978 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5980 if (pName && pName[0]) {
5981 SetLastError(ERROR_INVALID_PARAMETER);
5985 if (!pMonitorName) {
5986 SetLastError(RPC_X_NULL_REF_POINTER);
5990 /* an empty Monitorname is Invalid */
5991 if (!pMonitorName[0]) {
5992 SetLastError(ERROR_NOT_SUPPORTED);
5996 pm = monitor_load(pMonitorName, NULL);
5997 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
5998 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
5999 TRACE("got %d with %u\n", res, GetLastError());
6004 pui = monitor_loadui(pm);
6005 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6006 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6007 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6008 TRACE("got %d with %u\n", res, GetLastError());
6013 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6014 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6016 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6017 SetLastError(ERROR_NOT_SUPPORTED);
6020 monitor_unload(pui);
6023 TRACE("returning %d with %u\n", res, GetLastError());
6027 /******************************************************************************
6028 * AddPortExA (WINSPOOL.@)
6033 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
6035 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
6036 lpBuffer, debugstr_a(lpMonitorName));
6040 /******************************************************************************
6041 * AddPortExW (WINSPOOL.@)
6043 * Add a Port for a specific Monitor, without presenting a user interface
6046 * hMonitor [I] Handle from InitializePrintMonitor2()
6047 * pName [I] Servername or NULL (local Computer)
6048 * Level [I] Structure-Level (1 or 2) for lpBuffer
6049 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6050 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
6060 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
6062 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
6063 lpBuffer, debugstr_w(lpMonitorName));
6067 /******************************************************************************
6068 * AddPrinterConnectionA (WINSPOOL.@)
6070 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6072 FIXME("%s\n", debugstr_a(pName));
6076 /******************************************************************************
6077 * AddPrinterConnectionW (WINSPOOL.@)
6079 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6081 FIXME("%s\n", debugstr_w(pName));
6085 /******************************************************************************
6086 * AddPrinterDriverExW (WINSPOOL.@)
6088 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6089 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6091 FIXME("%s %d %p %d\n", debugstr_w(pName),
6092 Level, pDriverInfo, dwFileCopyFlags);
6093 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6097 /******************************************************************************
6098 * AddPrinterDriverExA (WINSPOOL.@)
6100 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6101 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6103 FIXME("%s %d %p %d\n", debugstr_a(pName),
6104 Level, pDriverInfo, dwFileCopyFlags);
6105 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6109 /******************************************************************************
6110 * ConfigurePortA (WINSPOOL.@)
6112 * See ConfigurePortW.
6115 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6117 LPWSTR nameW = NULL;
6118 LPWSTR portW = NULL;
6122 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6124 /* convert servername to unicode */
6126 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6127 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6128 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6131 /* convert portname to unicode */
6133 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6134 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6135 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6138 res = ConfigurePortW(nameW, hWnd, portW);
6139 HeapFree(GetProcessHeap(), 0, nameW);
6140 HeapFree(GetProcessHeap(), 0, portW);
6144 /******************************************************************************
6145 * ConfigurePortW (WINSPOOL.@)
6147 * Display the Configuration-Dialog for a specific Port
6150 * pName [I] Servername or NULL (local Computer)
6151 * hWnd [I] Handle to parent Window for the Dialog-Box
6152 * pPortName [I] Name of the Port, that should be configured
6159 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6165 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6167 if (pName && pName[0]) {
6168 SetLastError(ERROR_INVALID_PARAMETER);
6173 SetLastError(RPC_X_NULL_REF_POINTER);
6177 /* an empty Portname is Invalid, but can popup a Dialog */
6178 if (!pPortName[0]) {
6179 SetLastError(ERROR_NOT_SUPPORTED);
6183 pm = monitor_load_by_port(pPortName);
6184 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6185 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6186 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6187 TRACE("got %d with %u\n", res, GetLastError());
6191 pui = monitor_loadui(pm);
6192 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6193 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6194 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6195 TRACE("got %d with %u\n", res, GetLastError());
6199 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6200 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6202 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6203 SetLastError(ERROR_NOT_SUPPORTED);
6206 monitor_unload(pui);
6210 TRACE("returning %d with %u\n", res, GetLastError());
6214 /******************************************************************************
6215 * ConnectToPrinterDlg (WINSPOOL.@)
6217 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6219 FIXME("%p %x\n", hWnd, Flags);
6223 /******************************************************************************
6224 * DeletePrinterConnectionA (WINSPOOL.@)
6226 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6228 FIXME("%s\n", debugstr_a(pName));
6232 /******************************************************************************
6233 * DeletePrinterConnectionW (WINSPOOL.@)
6235 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6237 FIXME("%s\n", debugstr_w(pName));
6241 /******************************************************************************
6242 * DeletePrinterDriverExW (WINSPOOL.@)
6244 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6245 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6250 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6251 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6253 if(pName && pName[0])
6255 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6256 SetLastError(ERROR_INVALID_PARAMETER);
6262 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6263 SetLastError(ERROR_INVALID_PARAMETER);
6267 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6271 ERR("Can't open drivers key\n");
6275 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6278 RegCloseKey(hkey_drivers);
6283 /******************************************************************************
6284 * DeletePrinterDriverExA (WINSPOOL.@)
6286 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6287 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6289 UNICODE_STRING NameW, EnvW, DriverW;
6292 asciitounicode(&NameW, pName);
6293 asciitounicode(&EnvW, pEnvironment);
6294 asciitounicode(&DriverW, pDriverName);
6296 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6298 RtlFreeUnicodeString(&DriverW);
6299 RtlFreeUnicodeString(&EnvW);
6300 RtlFreeUnicodeString(&NameW);
6305 /******************************************************************************
6306 * DeletePrinterDataExW (WINSPOOL.@)
6308 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6311 FIXME("%p %s %s\n", hPrinter,
6312 debugstr_w(pKeyName), debugstr_w(pValueName));
6313 return ERROR_INVALID_PARAMETER;
6316 /******************************************************************************
6317 * DeletePrinterDataExA (WINSPOOL.@)
6319 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6322 FIXME("%p %s %s\n", hPrinter,
6323 debugstr_a(pKeyName), debugstr_a(pValueName));
6324 return ERROR_INVALID_PARAMETER;
6327 /******************************************************************************
6328 * DeletePrintProcessorA (WINSPOOL.@)
6330 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6332 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6333 debugstr_a(pPrintProcessorName));
6337 /******************************************************************************
6338 * DeletePrintProcessorW (WINSPOOL.@)
6340 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6342 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6343 debugstr_w(pPrintProcessorName));
6347 /******************************************************************************
6348 * DeletePrintProvidorA (WINSPOOL.@)
6350 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6352 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6353 debugstr_a(pPrintProviderName));
6357 /******************************************************************************
6358 * DeletePrintProvidorW (WINSPOOL.@)
6360 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6362 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6363 debugstr_w(pPrintProviderName));
6367 /******************************************************************************
6368 * EnumFormsA (WINSPOOL.@)
6370 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6371 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6373 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6374 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6378 /******************************************************************************
6379 * EnumFormsW (WINSPOOL.@)
6381 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6382 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6384 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6385 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6389 /*****************************************************************************
6390 * EnumMonitorsA [WINSPOOL.@]
6392 * See EnumMonitorsW.
6395 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6396 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6399 LPBYTE bufferW = NULL;
6400 LPWSTR nameW = NULL;
6402 DWORD numentries = 0;
6405 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6406 cbBuf, pcbNeeded, pcReturned);
6408 /* convert servername to unicode */
6410 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6411 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6412 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6414 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6415 needed = cbBuf * sizeof(WCHAR);
6416 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6417 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6419 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6420 if (pcbNeeded) needed = *pcbNeeded;
6421 /* HeapReAlloc return NULL, when bufferW was NULL */
6422 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6423 HeapAlloc(GetProcessHeap(), 0, needed);
6425 /* Try again with the large Buffer */
6426 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6428 numentries = pcReturned ? *pcReturned : 0;
6431 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6432 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6435 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6436 DWORD entrysize = 0;
6439 LPMONITOR_INFO_2W mi2w;
6440 LPMONITOR_INFO_2A mi2a;
6442 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6443 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6445 /* First pass: calculate the size for all Entries */
6446 mi2w = (LPMONITOR_INFO_2W) bufferW;
6447 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6449 while (index < numentries) {
6451 needed += entrysize; /* MONITOR_INFO_?A */
6452 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6454 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6455 NULL, 0, NULL, NULL);
6457 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6458 NULL, 0, NULL, NULL);
6459 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6460 NULL, 0, NULL, NULL);
6462 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6463 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6464 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6467 /* check for errors and quit on failure */
6468 if (cbBuf < needed) {
6469 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6473 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6474 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6475 cbBuf -= len ; /* free Bytes in the user-Buffer */
6476 mi2w = (LPMONITOR_INFO_2W) bufferW;
6477 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6479 /* Second Pass: Fill the User Buffer (if we have one) */
6480 while ((index < numentries) && pMonitors) {
6482 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6484 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6485 ptr, cbBuf , NULL, NULL);
6489 mi2a->pEnvironment = ptr;
6490 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6491 ptr, cbBuf, NULL, NULL);
6495 mi2a->pDLLName = ptr;
6496 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6497 ptr, cbBuf, NULL, NULL);
6501 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6502 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6503 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6507 if (pcbNeeded) *pcbNeeded = needed;
6508 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6510 HeapFree(GetProcessHeap(), 0, nameW);
6511 HeapFree(GetProcessHeap(), 0, bufferW);
6513 TRACE("returning %d with %d (%d byte for %d entries)\n",
6514 (res), GetLastError(), needed, numentries);
6520 /*****************************************************************************
6521 * EnumMonitorsW [WINSPOOL.@]
6523 * Enumerate available Port-Monitors
6526 * pName [I] Servername or NULL (local Computer)
6527 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6528 * pMonitors [O] PTR to Buffer that receives the Result
6529 * cbBuf [I] Size of Buffer at pMonitors
6530 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6531 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6535 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6538 * Windows reads the Registry once and cache the Results.
6540 *| Language-Monitors are also installed in the same Registry-Location but
6541 *| they are filtered in Windows (not returned by EnumMonitors).
6542 *| We do no filtering to simplify our Code.
6545 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6546 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6549 DWORD numentries = 0;
6552 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6553 cbBuf, pcbNeeded, pcReturned);
6555 if (pName && (lstrlenW(pName))) {
6556 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6557 SetLastError(ERROR_ACCESS_DENIED);
6561 /* Level is not checked in win9x */
6562 if (!Level || (Level > 2)) {
6563 WARN("level (%d) is ignored in win9x\n", Level);
6564 SetLastError(ERROR_INVALID_LEVEL);
6568 SetLastError(RPC_X_NULL_REF_POINTER);
6572 /* Scan all Monitor-Keys */
6574 needed = get_local_monitors(Level, NULL, 0, &numentries);
6576 /* we calculated the needed buffersize. now do the error-checks */
6577 if (cbBuf < needed) {
6578 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6581 else if (!pMonitors || !pcReturned) {
6582 SetLastError(RPC_X_NULL_REF_POINTER);
6586 /* fill the Buffer with the Monitor-Keys */
6587 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6591 if (pcbNeeded) *pcbNeeded = needed;
6592 if (pcReturned) *pcReturned = numentries;
6594 TRACE("returning %d with %d (%d byte for %d entries)\n",
6595 res, GetLastError(), needed, numentries);
6600 /******************************************************************************
6601 * XcvDataW (WINSPOOL.@)
6603 * Execute commands in the Printmonitor DLL
6606 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6607 * pszDataName [i] Name of the command to execute
6608 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6609 * cbInputData [i] Size in Bytes of Buffer at pInputData
6610 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6611 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6612 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6613 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6620 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6621 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6623 * Minimal List of commands, that a Printmonitor DLL should support:
6625 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6626 *| "AddPort" : Add a Port
6627 *| "DeletePort": Delete a Port
6629 * Many Printmonitors support additional commands. Examples for localspl.dll:
6630 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6631 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6634 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6635 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6636 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6638 opened_printer_t *printer;
6640 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6641 pInputData, cbInputData, pOutputData,
6642 cbOutputData, pcbOutputNeeded, pdwStatus);
6644 printer = get_opened_printer(hXcv);
6645 if (!printer || (!printer->hXcv)) {
6646 SetLastError(ERROR_INVALID_HANDLE);
6650 if (!pcbOutputNeeded) {
6651 SetLastError(ERROR_INVALID_PARAMETER);
6655 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6656 SetLastError(RPC_X_NULL_REF_POINTER);
6660 *pcbOutputNeeded = 0;
6662 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6663 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6668 /*****************************************************************************
6669 * EnumPrinterDataA [WINSPOOL.@]
6672 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6673 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6674 DWORD cbData, LPDWORD pcbData )
6676 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6677 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6678 return ERROR_NO_MORE_ITEMS;
6681 /*****************************************************************************
6682 * EnumPrinterDataW [WINSPOOL.@]
6685 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6686 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6687 DWORD cbData, LPDWORD pcbData )
6689 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6690 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6691 return ERROR_NO_MORE_ITEMS;
6694 /*****************************************************************************
6695 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6698 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6699 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6700 LPDWORD pcbNeeded, LPDWORD pcReturned)
6702 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6703 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6704 pcbNeeded, pcReturned);
6708 /*****************************************************************************
6709 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6712 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6713 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6714 LPDWORD pcbNeeded, LPDWORD pcReturned)
6716 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6717 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6718 pcbNeeded, pcReturned);
6722 /*****************************************************************************
6723 * EnumPrintProcessorsA [WINSPOOL.@]
6726 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6727 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6729 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6730 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6734 /*****************************************************************************
6735 * EnumPrintProcessorsW [WINSPOOL.@]
6738 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6739 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6741 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6742 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6743 cbBuf, pcbNeeded, pcbReturned);
6747 /*****************************************************************************
6748 * ExtDeviceMode [WINSPOOL.@]
6751 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6752 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6755 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6756 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6757 debugstr_a(pProfile), fMode);
6761 /*****************************************************************************
6762 * FindClosePrinterChangeNotification [WINSPOOL.@]
6765 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6767 FIXME("Stub: %p\n", hChange);
6771 /*****************************************************************************
6772 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6775 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6776 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6778 FIXME("Stub: %p %x %x %p\n",
6779 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6780 return INVALID_HANDLE_VALUE;
6783 /*****************************************************************************
6784 * FindNextPrinterChangeNotification [WINSPOOL.@]
6787 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6788 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6790 FIXME("Stub: %p %p %p %p\n",
6791 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6795 /*****************************************************************************
6796 * FreePrinterNotifyInfo [WINSPOOL.@]
6799 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6801 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6805 /*****************************************************************************
6808 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6809 * ansi depending on the unicode parameter.
6811 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6821 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6824 memcpy(ptr, str, *size);
6831 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6834 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6841 /*****************************************************************************
6844 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6845 LPDWORD pcbNeeded, BOOL unicode)
6847 DWORD size, left = cbBuf;
6848 BOOL space = (cbBuf > 0);
6855 ji1->JobId = job->job_id;
6858 string_to_buf(job->document_title, ptr, left, &size, unicode);
6859 if(space && size <= left)
6861 ji1->pDocument = (LPWSTR)ptr;
6872 /*****************************************************************************
6875 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6876 LPDWORD pcbNeeded, BOOL unicode)
6878 DWORD size, left = cbBuf;
6879 BOOL space = (cbBuf > 0);
6886 ji2->JobId = job->job_id;
6889 string_to_buf(job->document_title, ptr, left, &size, unicode);
6890 if(space && size <= left)
6892 ji2->pDocument = (LPWSTR)ptr;
6903 /*****************************************************************************
6906 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6907 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6910 DWORD needed = 0, size;
6914 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6916 EnterCriticalSection(&printer_handles_cs);
6917 job = get_job(hPrinter, JobId);
6924 size = sizeof(JOB_INFO_1W);
6929 memset(pJob, 0, size);
6933 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6938 size = sizeof(JOB_INFO_2W);
6943 memset(pJob, 0, size);
6947 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6952 size = sizeof(JOB_INFO_3);
6956 memset(pJob, 0, size);
6965 SetLastError(ERROR_INVALID_LEVEL);
6969 *pcbNeeded = needed;
6971 LeaveCriticalSection(&printer_handles_cs);
6975 /*****************************************************************************
6976 * GetJobA [WINSPOOL.@]
6979 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6980 DWORD cbBuf, LPDWORD pcbNeeded)
6982 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
6985 /*****************************************************************************
6986 * GetJobW [WINSPOOL.@]
6989 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6990 DWORD cbBuf, LPDWORD pcbNeeded)
6992 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
6995 /*****************************************************************************
6998 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7000 char *unixname, *queue, *cmd;
7001 char fmt[] = "lpr -P%s %s";
7004 if(!(unixname = wine_get_unix_file_name(filename)))
7007 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7008 queue = HeapAlloc(GetProcessHeap(), 0, len);
7009 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7011 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7012 sprintf(cmd, fmt, queue, unixname);
7014 TRACE("printing with: %s\n", cmd);
7017 HeapFree(GetProcessHeap(), 0, cmd);
7018 HeapFree(GetProcessHeap(), 0, queue);
7019 HeapFree(GetProcessHeap(), 0, unixname);
7023 /*****************************************************************************
7026 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7028 #if HAVE_CUPS_CUPS_H
7031 char *unixname, *queue, *doc_titleA;
7035 if(!(unixname = wine_get_unix_file_name(filename)))
7038 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7039 queue = HeapAlloc(GetProcessHeap(), 0, len);
7040 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7042 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7043 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7044 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7046 TRACE("printing via cups\n");
7047 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7048 HeapFree(GetProcessHeap(), 0, doc_titleA);
7049 HeapFree(GetProcessHeap(), 0, queue);
7050 HeapFree(GetProcessHeap(), 0, unixname);
7056 return schedule_lpr(printer_name, filename);
7060 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7067 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7071 if(HIWORD(wparam) == BN_CLICKED)
7073 if(LOWORD(wparam) == IDOK)
7076 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7079 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7080 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7082 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7084 WCHAR caption[200], message[200];
7087 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7088 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7089 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7090 if(mb_ret == IDCANCEL)
7092 HeapFree(GetProcessHeap(), 0, filename);
7096 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7097 if(hf == INVALID_HANDLE_VALUE)
7099 WCHAR caption[200], message[200];
7101 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7102 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7103 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7104 HeapFree(GetProcessHeap(), 0, filename);
7108 DeleteFileW(filename);
7109 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7111 EndDialog(hwnd, IDOK);
7114 if(LOWORD(wparam) == IDCANCEL)
7116 EndDialog(hwnd, IDCANCEL);
7125 /*****************************************************************************
7128 static BOOL get_filename(LPWSTR *filename)
7130 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7131 file_dlg_proc, (LPARAM)filename) == IDOK;
7134 /*****************************************************************************
7137 static BOOL schedule_file(LPCWSTR filename)
7139 LPWSTR output = NULL;
7141 if(get_filename(&output))
7143 TRACE("copy to %s\n", debugstr_w(output));
7144 CopyFileW(filename, output, FALSE);
7145 HeapFree(GetProcessHeap(), 0, output);
7151 /*****************************************************************************
7154 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7157 char *unixname, *cmdA;
7159 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7163 if(!(unixname = wine_get_unix_file_name(filename)))
7166 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7167 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7168 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7170 TRACE("printing with: %s\n", cmdA);
7172 if((file_fd = open(unixname, O_RDONLY)) == -1)
7177 ERR("pipe() failed!\n");
7187 /* reset signals that we previously set to SIG_IGN */
7188 signal(SIGPIPE, SIG_DFL);
7189 signal(SIGCHLD, SIG_DFL);
7191 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7195 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7196 write(fds[1], buf, no_read);
7201 if(file_fd != -1) close(file_fd);
7202 if(fds[0] != -1) close(fds[0]);
7203 if(fds[1] != -1) close(fds[1]);
7205 HeapFree(GetProcessHeap(), 0, cmdA);
7206 HeapFree(GetProcessHeap(), 0, unixname);
7213 /*****************************************************************************
7216 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7218 int in_fd, out_fd, no_read;
7221 char *unixname, *outputA;
7224 if(!(unixname = wine_get_unix_file_name(filename)))
7227 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7228 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7229 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7231 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7232 in_fd = open(unixname, O_RDONLY);
7233 if(out_fd == -1 || in_fd == -1)
7236 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7237 write(out_fd, buf, no_read);
7241 if(in_fd != -1) close(in_fd);
7242 if(out_fd != -1) close(out_fd);
7243 HeapFree(GetProcessHeap(), 0, outputA);
7244 HeapFree(GetProcessHeap(), 0, unixname);
7248 /*****************************************************************************
7249 * ScheduleJob [WINSPOOL.@]
7252 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7254 opened_printer_t *printer;
7256 struct list *cursor, *cursor2;
7258 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7259 EnterCriticalSection(&printer_handles_cs);
7260 printer = get_opened_printer(hPrinter);
7264 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7266 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7269 if(job->job_id != dwJobID) continue;
7271 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7272 if(hf != INVALID_HANDLE_VALUE)
7274 PRINTER_INFO_5W *pi5;
7278 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7279 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7281 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7282 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7283 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7284 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7285 debugstr_w(pi5->pPortName));
7289 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7290 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7292 DWORD type, count = sizeof(output);
7293 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7296 if(output[0] == '|')
7298 schedule_pipe(output + 1, job->filename);
7302 schedule_unixfile(output, job->filename);
7304 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7306 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7308 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7310 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7312 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7314 schedule_file(job->filename);
7318 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7320 HeapFree(GetProcessHeap(), 0, pi5);
7322 DeleteFileW(job->filename);
7324 list_remove(cursor);
7325 HeapFree(GetProcessHeap(), 0, job->document_title);
7326 HeapFree(GetProcessHeap(), 0, job->filename);
7327 HeapFree(GetProcessHeap(), 0, job);
7332 LeaveCriticalSection(&printer_handles_cs);
7336 /*****************************************************************************
7337 * StartDocDlgA [WINSPOOL.@]
7339 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7341 UNICODE_STRING usBuffer;
7344 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7347 docW.cbSize = sizeof(docW);
7348 if (doc->lpszDocName)
7350 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7351 if (!(docW.lpszDocName = docnameW)) return NULL;
7353 if (doc->lpszOutput)
7355 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7356 if (!(docW.lpszOutput = outputW)) return NULL;
7358 if (doc->lpszDatatype)
7360 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7361 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7363 docW.fwType = doc->fwType;
7365 retW = StartDocDlgW(hPrinter, &docW);
7369 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7370 ret = HeapAlloc(GetProcessHeap(), 0, len);
7371 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7372 HeapFree(GetProcessHeap(), 0, retW);
7375 HeapFree(GetProcessHeap(), 0, datatypeW);
7376 HeapFree(GetProcessHeap(), 0, outputW);
7377 HeapFree(GetProcessHeap(), 0, docnameW);
7382 /*****************************************************************************
7383 * StartDocDlgW [WINSPOOL.@]
7385 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7386 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7387 * port is "FILE:". Also returns the full path if passed a relative path.
7389 * The caller should free the returned string from the process heap.
7391 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7396 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7398 PRINTER_INFO_5W *pi5;
7399 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7400 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7402 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7403 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7404 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7406 HeapFree(GetProcessHeap(), 0, pi5);
7409 HeapFree(GetProcessHeap(), 0, pi5);
7412 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7416 if (get_filename(&name))
7418 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7420 HeapFree(GetProcessHeap(), 0, name);
7423 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7424 GetFullPathNameW(name, len, ret, NULL);
7425 HeapFree(GetProcessHeap(), 0, name);
7430 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7433 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7434 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7436 attr = GetFileAttributesW(ret);
7437 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7439 HeapFree(GetProcessHeap(), 0, ret);