Release 0.9.39.
[wine/gsoc-2012-control.git] / dlls / winspool.drv / info.c
blobd78964b4117157d2065e05d1c469af1674e711ab
1 /*
2 * WINSPOOL functions
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
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
43 # endif
44 #endif
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winuser.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "wingdi.h"
55 #include "winspool.h"
56 #include "winternl.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
61 #include "winnls.h"
63 #include "ddk/winsplp.h"
64 #include "wspool.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 /* ############################### */
91 typedef struct {
92 struct list entry;
93 LPWSTR name;
94 LPWSTR dllname;
95 PMONITORUI monitorUI;
96 LPMONITOR monitor;
97 HMODULE hdll;
98 DWORD refcount;
99 DWORD dwMonitorSize;
100 } monitor_t;
102 typedef struct {
103 DWORD job_id;
104 HANDLE hf;
105 } started_doc_t;
107 typedef struct {
108 struct list jobs;
109 LONG ref;
110 } jobqueue_t;
112 typedef struct {
113 LPWSTR name;
114 LPWSTR printername;
115 monitor_t *pm;
116 HANDLE hXcv;
117 jobqueue_t *queue;
118 started_doc_t *doc;
119 } opened_printer_t;
121 typedef struct {
122 struct list entry;
123 DWORD job_id;
124 WCHAR *filename;
125 WCHAR *document_title;
126 } job_t;
129 typedef struct {
130 LPCWSTR envname;
131 LPCWSTR subdir;
132 DWORD driverversion;
133 LPCWSTR versionregpath;
134 LPCWSTR versionsubdir;
135 } printenv_t;
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,
148 LPDEVMODEA lpdm );
149 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
150 LPSTR lpszDevice, LPSTR lpszPort,
151 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
152 DWORD fwMode );
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',
209 'M','o','d','e',0};
210 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
211 'i','l','e','s',0};
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',
223 's','s','o','r',0};
224 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
225 'v','e','r',0};
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',
229 'i','l','e',0};
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 * validate the user-supplied printing-environment [internal]
252 * PARAMS
253 * env [I] PTR to Environment-String or NULL
255 * RETURNS
256 * Failure: NULL
257 * Success: PTR to printenv_t
259 * NOTES
260 * An empty string is handled the same way as NULL.
261 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
265 static const printenv_t * validate_envW(LPCWSTR env)
267 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
268 3, Version3_RegPathW, Version3_SubdirW};
269 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
270 0, emptyStringW, emptyStringW};
271 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
273 const printenv_t *result = NULL;
274 unsigned int i;
276 TRACE("testing %s\n", debugstr_w(env));
277 if (env && env[0])
279 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
281 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
283 result = all_printenv[i];
284 break;
288 if (result == NULL) {
289 FIXME("unsupported Environment: %s\n", debugstr_w(env));
290 SetLastError(ERROR_INVALID_ENVIRONMENT);
292 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
294 else
296 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
298 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
300 return result;
304 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
305 if passed a NULL string. This returns NULLs to the result.
307 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
309 if ( (src) )
311 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
312 return usBufferPtr->Buffer;
314 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
315 return NULL;
318 static LPWSTR strdupW(LPCWSTR p)
320 LPWSTR ret;
321 DWORD len;
323 if(!p) return NULL;
324 len = (strlenW(p) + 1) * sizeof(WCHAR);
325 ret = HeapAlloc(GetProcessHeap(), 0, len);
326 memcpy(ret, p, len);
327 return ret;
330 static LPSTR strdupWtoA( LPCWSTR str )
332 LPSTR ret;
333 INT len;
335 if (!str) return NULL;
336 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
337 ret = HeapAlloc( GetProcessHeap(), 0, len );
338 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
339 return ret;
342 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
343 The result includes all \0s (specifically the last two). */
344 static int multi_sz_lenA(const char *str)
346 const char *ptr = str;
347 if(!str) return 0;
350 ptr += lstrlenA(ptr) + 1;
351 } while(*ptr);
353 return ptr - str + 1;
356 static void
357 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
358 char qbuf[200];
360 /* If forcing, or no profile string entry for device yet, set the entry
362 * The always change entry if not WINEPS yet is discussable.
364 if (force ||
365 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
366 !strcmp(qbuf,"*") ||
367 !strstr(qbuf,"WINEPS.DRV")
369 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
370 HKEY hkey;
372 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
373 WriteProfileStringA("windows","device",buf);
374 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
375 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
376 RegCloseKey(hkey);
378 HeapFree(GetProcessHeap(),0,buf);
382 static BOOL add_printer_driver(const char *name)
384 DRIVER_INFO_3A di3a;
386 static char driver_path[] = "wineps16",
387 data_file[] = "<datafile?>",
388 config_file[] = "wineps16",
389 help_file[] = "<helpfile?>",
390 dep_file[] = "<dependent files?>\0",
391 monitor_name[] = "<monitor name?>",
392 default_data_type[] = "RAW";
394 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
395 di3a.pName = (char *)name;
396 di3a.pEnvironment = NULL; /* NULL means auto */
397 di3a.pDriverPath = driver_path;
398 di3a.pDataFile = data_file;
399 di3a.pConfigFile = config_file;
400 di3a.pHelpFile = help_file;
401 di3a.pDependentFiles = dep_file;
402 di3a.pMonitorName = monitor_name;
403 di3a.pDefaultDataType = default_data_type;
405 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
407 ERR("Failed adding driver (%d)\n", GetLastError());
408 return FALSE;
410 return TRUE;
413 #ifdef HAVE_CUPS_CUPS_H
414 static typeof(cupsGetDests) *pcupsGetDests;
415 static typeof(cupsGetPPD) *pcupsGetPPD;
416 static typeof(cupsPrintFile) *pcupsPrintFile;
417 static void *cupshandle;
419 static BOOL CUPS_LoadPrinters(void)
421 int i, nrofdests;
422 BOOL hadprinter = FALSE;
423 cups_dest_t *dests;
424 PRINTER_INFO_2A pinfo2a;
425 char *port,*devline;
426 HKEY hkeyPrinter, hkeyPrinters, hkey;
428 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
429 if (!cupshandle)
430 return FALSE;
431 TRACE("loaded %s\n", SONAME_LIBCUPS);
433 #define DYNCUPS(x) \
434 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
435 if (!p##x) return FALSE;
437 DYNCUPS(cupsGetPPD);
438 DYNCUPS(cupsGetDests);
439 DYNCUPS(cupsPrintFile);
440 #undef DYNCUPS
442 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
443 ERROR_SUCCESS) {
444 ERR("Can't create Printers key\n");
445 return FALSE;
448 nrofdests = pcupsGetDests(&dests);
449 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
450 for (i=0;i<nrofdests;i++) {
451 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
452 sprintf(port,"LPR:%s",dests[i].name);
453 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
454 sprintf(devline,"WINEPS.DRV,%s",port);
455 WriteProfileStringA("devices",dests[i].name,devline);
456 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
457 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
458 RegCloseKey(hkey);
460 HeapFree(GetProcessHeap(),0,devline);
462 TRACE("Printer %d: %s\n", i, dests[i].name);
463 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
464 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
465 and continue */
466 TRACE("Printer already exists\n");
467 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
468 RegCloseKey(hkeyPrinter);
469 } else {
470 static CHAR data_type[] = "RAW",
471 print_proc[] = "WinPrint",
472 comment[] = "WINEPS Printer using CUPS",
473 location[] = "<physical location of printer>",
474 params[] = "<parameters?>",
475 share_name[] = "<share name?>",
476 sep_file[] = "<sep file?>";
478 add_printer_driver(dests[i].name);
480 memset(&pinfo2a,0,sizeof(pinfo2a));
481 pinfo2a.pPrinterName = dests[i].name;
482 pinfo2a.pDatatype = data_type;
483 pinfo2a.pPrintProcessor = print_proc;
484 pinfo2a.pDriverName = dests[i].name;
485 pinfo2a.pComment = comment;
486 pinfo2a.pLocation = location;
487 pinfo2a.pPortName = port;
488 pinfo2a.pParameters = params;
489 pinfo2a.pShareName = share_name;
490 pinfo2a.pSepFile = sep_file;
492 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
493 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
494 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
497 HeapFree(GetProcessHeap(),0,port);
499 hadprinter = TRUE;
500 if (dests[i].is_default)
501 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
503 RegCloseKey(hkeyPrinters);
504 return hadprinter;
506 #endif
508 static BOOL
509 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
510 PRINTER_INFO_2A pinfo2a;
511 char *e,*s,*name,*prettyname,*devname;
512 BOOL ret = FALSE, set_default = FALSE;
513 char *port,*devline,*env_default;
514 HKEY hkeyPrinter, hkeyPrinters, hkey;
516 while (isspace(*pent)) pent++;
517 s = strchr(pent,':');
518 if(s) *s='\0';
519 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
520 strcpy(name,pent);
521 if(s) {
522 *s=':';
523 pent = s;
524 } else
525 pent = "";
527 TRACE("name=%s entry=%s\n",name, pent);
529 if(ispunct(*name)) { /* a tc entry, not a real printer */
530 TRACE("skipping tc entry\n");
531 goto end;
534 if(strstr(pent,":server")) { /* server only version so skip */
535 TRACE("skipping server entry\n");
536 goto end;
539 /* Determine whether this is a postscript printer. */
541 ret = TRUE;
542 env_default = getenv("PRINTER");
543 prettyname = name;
544 /* Get longest name, usually the one at the right for later display. */
545 while((s=strchr(prettyname,'|'))) {
546 *s = '\0';
547 e = s;
548 while(isspace(*--e)) *e = '\0';
549 TRACE("\t%s\n", debugstr_a(prettyname));
550 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
551 for(prettyname = s+1; isspace(*prettyname); prettyname++)
554 e = prettyname + strlen(prettyname);
555 while(isspace(*--e)) *e = '\0';
556 TRACE("\t%s\n", debugstr_a(prettyname));
557 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
559 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
560 * if it is too long, we use it as comment below. */
561 devname = prettyname;
562 if (strlen(devname)>=CCHDEVICENAME-1)
563 devname = name;
564 if (strlen(devname)>=CCHDEVICENAME-1) {
565 ret = FALSE;
566 goto end;
569 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
570 sprintf(port,"LPR:%s",name);
572 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
573 sprintf(devline,"WINEPS.DRV,%s",port);
574 WriteProfileStringA("devices",devname,devline);
575 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
576 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
577 RegCloseKey(hkey);
579 HeapFree(GetProcessHeap(),0,devline);
581 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
582 ERROR_SUCCESS) {
583 ERR("Can't create Printers key\n");
584 ret = FALSE;
585 goto end;
587 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
588 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
589 and continue */
590 TRACE("Printer already exists\n");
591 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
592 RegCloseKey(hkeyPrinter);
593 } else {
594 static CHAR data_type[] = "RAW",
595 print_proc[] = "WinPrint",
596 comment[] = "WINEPS Printer using LPR",
597 params[] = "<parameters?>",
598 share_name[] = "<share name?>",
599 sep_file[] = "<sep file?>";
601 add_printer_driver(devname);
603 memset(&pinfo2a,0,sizeof(pinfo2a));
604 pinfo2a.pPrinterName = devname;
605 pinfo2a.pDatatype = data_type;
606 pinfo2a.pPrintProcessor = print_proc;
607 pinfo2a.pDriverName = devname;
608 pinfo2a.pComment = comment;
609 pinfo2a.pLocation = prettyname;
610 pinfo2a.pPortName = port;
611 pinfo2a.pParameters = params;
612 pinfo2a.pShareName = share_name;
613 pinfo2a.pSepFile = sep_file;
615 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
616 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
617 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
620 RegCloseKey(hkeyPrinters);
622 if (isfirst || set_default)
623 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
625 HeapFree(GetProcessHeap(), 0, port);
626 end:
627 HeapFree(GetProcessHeap(), 0, name);
628 return ret;
631 static BOOL
632 PRINTCAP_LoadPrinters(void) {
633 BOOL hadprinter = FALSE;
634 char buf[200];
635 FILE *f;
636 char *pent = NULL;
637 BOOL had_bash = FALSE;
639 f = fopen("/etc/printcap","r");
640 if (!f)
641 return FALSE;
643 while(fgets(buf,sizeof(buf),f)) {
644 char *start, *end;
646 end=strchr(buf,'\n');
647 if (end) *end='\0';
649 start = buf;
650 while(isspace(*start)) start++;
651 if(*start == '#' || *start == '\0')
652 continue;
654 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
655 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
656 HeapFree(GetProcessHeap(),0,pent);
657 pent = NULL;
660 if (end && *--end == '\\') {
661 *end = '\0';
662 had_bash = TRUE;
663 } else
664 had_bash = FALSE;
666 if (pent) {
667 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
668 strcat(pent,start);
669 } else {
670 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
671 strcpy(pent,start);
675 if(pent) {
676 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
677 HeapFree(GetProcessHeap(),0,pent);
679 fclose(f);
680 return hadprinter;
683 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
685 if (value)
686 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
687 (lstrlenW(value) + 1) * sizeof(WCHAR));
688 else
689 return ERROR_FILE_NOT_FOUND;
692 /*****************************************************************************
693 * enumerate the local monitors (INTERNAL)
695 * returns the needed size (in bytes) for pMonitors
696 * and *lpreturned is set to number of entries returned in pMonitors
699 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
701 HKEY hroot = NULL;
702 HKEY hentry = NULL;
703 LPWSTR ptr;
704 LPMONITOR_INFO_2W mi;
705 WCHAR buffer[MAX_PATH];
706 WCHAR dllname[MAX_PATH];
707 DWORD dllsize;
708 DWORD len;
709 DWORD index = 0;
710 DWORD needed = 0;
711 DWORD numentries;
712 DWORD entrysize;
714 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
716 numentries = *lpreturned; /* this is 0, when we scan the registry */
717 len = entrysize * numentries;
718 ptr = (LPWSTR) &pMonitors[len];
720 numentries = 0;
721 len = sizeof(buffer);
722 buffer[0] = '\0';
724 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
725 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
726 /* Scan all Monitor-Registry-Keys */
727 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
728 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
729 dllsize = sizeof(dllname);
730 dllname[0] = '\0';
732 /* The Monitor must have a Driver-DLL */
733 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
734 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
735 /* We found a valid DLL for this Monitor. */
736 TRACE("using Driver: %s\n", debugstr_w(dllname));
738 RegCloseKey(hentry);
741 /* Windows returns only Port-Monitors here, but to simplify our code,
742 we do no filtering for Language-Monitors */
743 if (dllname[0]) {
744 numentries++;
745 needed += entrysize;
746 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
747 if (level > 1) {
748 /* we install and return only monitors for "Windows NT x86" */
749 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
750 needed += dllsize;
753 /* required size is calculated. Now fill the user-buffer */
754 if (pMonitors && (cbBuf >= needed)){
755 mi = (LPMONITOR_INFO_2W) pMonitors;
756 pMonitors += entrysize;
758 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
759 mi->pName = ptr;
760 lstrcpyW(ptr, buffer); /* Name of the Monitor */
761 ptr += (len+1); /* len is lstrlenW(monitorname) */
762 if (level > 1) {
763 mi->pEnvironment = ptr;
764 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
765 ptr += (lstrlenW(envname_x86W)+1);
767 mi->pDLLName = ptr;
768 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
769 ptr += (dllsize / sizeof(WCHAR));
773 index++;
774 len = sizeof(buffer);
775 buffer[0] = '\0';
777 RegCloseKey(hroot);
779 *lpreturned = numentries;
780 TRACE("need %d byte for %d entries\n", needed, numentries);
781 return needed;
784 /******************************************************************
785 * monitor_unload [internal]
787 * release a printmonitor and unload it from memory, when needed
790 static void monitor_unload(monitor_t * pm)
792 if (pm == NULL) return;
793 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
795 EnterCriticalSection(&monitor_handles_cs);
797 if (pm->refcount) pm->refcount--;
799 if (pm->refcount == 0) {
800 list_remove(&pm->entry);
801 FreeLibrary(pm->hdll);
802 HeapFree(GetProcessHeap(), 0, pm->name);
803 HeapFree(GetProcessHeap(), 0, pm->dllname);
804 HeapFree(GetProcessHeap(), 0, pm);
806 LeaveCriticalSection(&monitor_handles_cs);
809 /******************************************************************
810 * monitor_unloadall [internal]
812 * release all printmonitors and unload them from memory, when needed
815 static void monitor_unloadall(void)
817 monitor_t * pm;
818 monitor_t * next;
820 EnterCriticalSection(&monitor_handles_cs);
821 /* iterate through the list, with safety against removal */
822 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
824 monitor_unload(pm);
826 LeaveCriticalSection(&monitor_handles_cs);
829 /******************************************************************
830 * monitor_load [internal]
832 * load a printmonitor, get the dllname from the registry, when needed
833 * initialize the monitor and dump found function-pointers
835 * On failure, SetLastError() is called and NULL is returned
838 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
840 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
841 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
842 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
843 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
844 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
846 monitor_t * pm = NULL;
847 monitor_t * cursor;
848 LPWSTR regroot = NULL;
849 LPWSTR driver = dllname;
851 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
852 /* Is the Monitor already loaded? */
853 EnterCriticalSection(&monitor_handles_cs);
855 if (name) {
856 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
858 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
859 pm = cursor;
860 break;
865 if (pm == NULL) {
866 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
867 if (pm == NULL) goto cleanup;
868 list_add_tail(&monitor_handles, &pm->entry);
870 pm->refcount++;
872 if (pm->name == NULL) {
873 /* Load the monitor */
874 LPMONITOREX pmonitorEx;
875 DWORD len;
877 if (name) {
878 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
879 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
882 if (regroot) {
883 lstrcpyW(regroot, MonitorsW);
884 lstrcatW(regroot, name);
885 /* Get the Driver from the Registry */
886 if (driver == NULL) {
887 HKEY hroot;
888 DWORD namesize;
889 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
890 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
891 &namesize) == ERROR_SUCCESS) {
892 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
893 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
895 RegCloseKey(hroot);
900 pm->name = strdupW(name);
901 pm->dllname = strdupW(driver);
903 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
904 monitor_unload(pm);
905 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
906 pm = NULL;
907 goto cleanup;
910 pm->hdll = LoadLibraryW(driver);
911 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
913 if (pm->hdll == NULL) {
914 monitor_unload(pm);
915 SetLastError(ERROR_MOD_NOT_FOUND);
916 pm = NULL;
917 goto cleanup;
920 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
921 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
922 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
923 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
924 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
927 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
928 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
929 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
930 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
931 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
933 if (pInitializePrintMonitorUI != NULL) {
934 pm->monitorUI = pInitializePrintMonitorUI();
935 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
936 if (pm->monitorUI) {
937 TRACE( "0x%08x: dwMonitorSize (%d)\n",
938 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
943 if (pInitializePrintMonitor && regroot) {
944 pmonitorEx = pInitializePrintMonitor(regroot);
945 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
946 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
948 if (pmonitorEx) {
949 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
950 pm->monitor = &(pmonitorEx->Monitor);
954 if (pm->monitor) {
955 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
959 if (!pm->monitor && regroot) {
960 if (pInitializePrintMonitor2 != NULL) {
961 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
963 if (pInitializeMonitorEx != NULL) {
964 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
966 if (pInitializeMonitor != NULL) {
967 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
970 if (!pm->monitor && !pm->monitorUI) {
971 monitor_unload(pm);
972 SetLastError(ERROR_PROC_NOT_FOUND);
973 pm = NULL;
976 cleanup:
977 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
978 pm->refcount++;
979 pm_localport = pm;
981 LeaveCriticalSection(&monitor_handles_cs);
982 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
983 HeapFree(GetProcessHeap(), 0, regroot);
984 TRACE("=> %p\n", pm);
985 return pm;
988 /******************************************************************
989 * monitor_loadall [internal]
991 * Load all registered monitors
994 static DWORD monitor_loadall(void)
996 monitor_t * pm;
997 DWORD registered = 0;
998 DWORD loaded = 0;
999 HKEY hmonitors;
1000 WCHAR buffer[MAX_PATH];
1001 DWORD id = 0;
1003 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1004 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1005 NULL, NULL, NULL, NULL, NULL);
1007 TRACE("%d monitors registered\n", registered);
1009 EnterCriticalSection(&monitor_handles_cs);
1010 while (id < registered) {
1011 buffer[0] = '\0';
1012 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1013 pm = monitor_load(buffer, NULL);
1014 if (pm) loaded++;
1015 id++;
1017 LeaveCriticalSection(&monitor_handles_cs);
1018 RegCloseKey(hmonitors);
1020 TRACE("%d monitors loaded\n", loaded);
1021 return loaded;
1024 /******************************************************************
1025 * monitor_loadui [internal]
1027 * load the userinterface-dll for a given portmonitor
1029 * On failure, NULL is returned
1032 static monitor_t * monitor_loadui(monitor_t * pm)
1034 monitor_t * pui = NULL;
1035 LPWSTR buffer[MAX_PATH];
1036 HANDLE hXcv;
1037 DWORD len;
1038 DWORD res;
1040 if (pm == NULL) return NULL;
1041 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1043 /* Try the Portmonitor first; works for many monitors */
1044 if (pm->monitorUI) {
1045 EnterCriticalSection(&monitor_handles_cs);
1046 pm->refcount++;
1047 LeaveCriticalSection(&monitor_handles_cs);
1048 return pm;
1051 /* query the userinterface-dllname from the Portmonitor */
1052 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1053 /* building (",XcvMonitor %s",pm->name) not needed yet */
1054 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1055 TRACE("got %u with %p\n", res, hXcv);
1056 if (res) {
1057 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1058 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1059 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1060 pm->monitor->pfnXcvClosePort(hXcv);
1063 return pui;
1067 /******************************************************************
1068 * monitor_load_by_port [internal]
1070 * load a printmonitor for a given port
1072 * On failure, NULL is returned
1075 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1077 HKEY hroot;
1078 HKEY hport;
1079 LPWSTR buffer;
1080 monitor_t * pm = NULL;
1081 DWORD registered = 0;
1082 DWORD id = 0;
1083 DWORD len;
1085 TRACE("(%s)\n", debugstr_w(portname));
1087 /* Try the Local Monitor first */
1088 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1089 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1090 /* found the portname */
1091 RegCloseKey(hroot);
1092 return monitor_load(LocalPortW, NULL);
1094 RegCloseKey(hroot);
1097 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1098 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1099 if (buffer == NULL) return NULL;
1101 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1102 EnterCriticalSection(&monitor_handles_cs);
1103 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1105 while ((pm == NULL) && (id < registered)) {
1106 buffer[0] = '\0';
1107 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1108 TRACE("testing %s\n", debugstr_w(buffer));
1109 len = lstrlenW(buffer);
1110 lstrcatW(buffer, bs_Ports_bsW);
1111 lstrcatW(buffer, portname);
1112 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1113 RegCloseKey(hport);
1114 buffer[len] = '\0'; /* use only the Monitor-Name */
1115 pm = monitor_load(buffer, NULL);
1117 id++;
1119 LeaveCriticalSection(&monitor_handles_cs);
1120 RegCloseKey(hroot);
1122 HeapFree(GetProcessHeap(), 0, buffer);
1123 return pm;
1126 /******************************************************************
1127 * enumerate the local Ports from all loaded monitors (internal)
1129 * returns the needed size (in bytes) for pPorts
1130 * and *lpreturned is set to number of entries returned in pPorts
1133 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1135 monitor_t * pm;
1136 LPWSTR ptr;
1137 LPPORT_INFO_2W cache;
1138 LPPORT_INFO_2W out;
1139 LPBYTE pi_buffer = NULL;
1140 DWORD pi_allocated = 0;
1141 DWORD pi_needed;
1142 DWORD pi_index;
1143 DWORD pi_returned;
1144 DWORD res;
1145 DWORD outindex = 0;
1146 DWORD needed;
1147 DWORD numentries;
1148 DWORD entrysize;
1151 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1152 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1154 numentries = *lpreturned; /* this is 0, when we scan the registry */
1155 needed = entrysize * numentries;
1156 ptr = (LPWSTR) &pPorts[needed];
1158 numentries = 0;
1159 needed = 0;
1161 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1163 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1164 pi_needed = 0;
1165 pi_returned = 0;
1166 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1167 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1168 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1169 HeapFree(GetProcessHeap(), 0, pi_buffer);
1170 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1171 pi_allocated = (pi_buffer) ? pi_needed : 0;
1172 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1174 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1175 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1177 numentries += pi_returned;
1178 needed += pi_needed;
1180 /* fill the output-buffer (pPorts), if we have one */
1181 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1182 pi_index = 0;
1183 while (pi_returned > pi_index) {
1184 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1185 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1186 out->pPortName = ptr;
1187 lstrcpyW(ptr, cache->pPortName);
1188 ptr += (lstrlenW(ptr)+1);
1189 if (level > 1) {
1190 out->pMonitorName = ptr;
1191 lstrcpyW(ptr, cache->pMonitorName);
1192 ptr += (lstrlenW(ptr)+1);
1194 out->pDescription = ptr;
1195 lstrcpyW(ptr, cache->pDescription);
1196 ptr += (lstrlenW(ptr)+1);
1197 out->fPortType = cache->fPortType;
1198 out->Reserved = cache->Reserved;
1200 pi_index++;
1201 outindex++;
1206 /* the temporary portinfo-buffer is no longer needed */
1207 HeapFree(GetProcessHeap(), 0, pi_buffer);
1209 *lpreturned = numentries;
1210 TRACE("need %d byte for %d entries\n", needed, numentries);
1211 return needed;
1214 /******************************************************************
1215 * get_servername_from_name (internal)
1217 * for an external server, a copy of the serverpart from the full name is returned
1220 static LPWSTR get_servername_from_name(LPCWSTR name)
1222 LPWSTR server;
1223 LPWSTR ptr;
1224 WCHAR buffer[MAX_PATH];
1225 DWORD len;
1227 if (name == NULL) return NULL;
1228 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1230 server = strdupW(&name[2]); /* skip over both backslash */
1231 if (server == NULL) return NULL;
1233 /* strip '\' and the printername */
1234 ptr = strchrW(server, '\\');
1235 if (ptr) ptr[0] = '\0';
1237 TRACE("found %s\n", debugstr_w(server));
1239 len = sizeof(buffer)/sizeof(buffer[0]);
1240 if (GetComputerNameW(buffer, &len)) {
1241 if (lstrcmpW(buffer, server) == 0) {
1242 /* The requested Servername is our computername */
1243 HeapFree(GetProcessHeap(), 0, server);
1244 return NULL;
1247 return server;
1250 /******************************************************************
1251 * get_basename_from_name (internal)
1253 * skip over the serverpart from the full name
1256 static LPCWSTR get_basename_from_name(LPCWSTR name)
1258 if (name == NULL) return NULL;
1259 if ((name[0] == '\\') && (name[1] == '\\')) {
1260 /* skip over the servername and search for the following '\' */
1261 name = strchrW(&name[2], '\\');
1262 if ((name) && (name[1])) {
1263 /* found a separator ('\') followed by a name:
1264 skip over the separator and return the rest */
1265 name++;
1267 else
1269 /* no basename present (we found only a servername) */
1270 return NULL;
1273 return name;
1276 /******************************************************************
1277 * get_opened_printer_entry
1278 * Get the first place empty in the opened printer table
1280 * ToDo:
1281 * - pDefault is ignored
1283 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1285 UINT_PTR handle = nb_printer_handles, i;
1286 jobqueue_t *queue = NULL;
1287 opened_printer_t *printer = NULL;
1288 LPWSTR servername;
1289 LPCWSTR printername;
1290 HKEY hkeyPrinters;
1291 HKEY hkeyPrinter;
1292 DWORD len;
1294 servername = get_servername_from_name(name);
1295 if (servername) {
1296 FIXME("server %s not supported\n", debugstr_w(servername));
1297 HeapFree(GetProcessHeap(), 0, servername);
1298 SetLastError(ERROR_INVALID_PRINTER_NAME);
1299 return NULL;
1302 printername = get_basename_from_name(name);
1303 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1305 /* an empty printername is invalid */
1306 if (printername && (!printername[0])) {
1307 SetLastError(ERROR_INVALID_PARAMETER);
1308 return NULL;
1311 EnterCriticalSection(&printer_handles_cs);
1313 for (i = 0; i < nb_printer_handles; i++)
1315 if (!printer_handles[i])
1317 if(handle == nb_printer_handles)
1318 handle = i;
1320 else
1322 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1323 queue = printer_handles[i]->queue;
1327 if (handle >= nb_printer_handles)
1329 opened_printer_t **new_array;
1330 if (printer_handles)
1331 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1332 (nb_printer_handles + 16) * sizeof(*new_array) );
1333 else
1334 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1335 (nb_printer_handles + 16) * sizeof(*new_array) );
1337 if (!new_array)
1339 handle = 0;
1340 goto end;
1342 printer_handles = new_array;
1343 nb_printer_handles += 16;
1346 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1348 handle = 0;
1349 goto end;
1353 /* clone the base name. This is NULL for the printserver */
1354 printer->printername = strdupW(printername);
1356 /* clone the full name */
1357 printer->name = strdupW(name);
1358 if (name && (!printer->name)) {
1359 handle = 0;
1360 goto end;
1363 if (printername) {
1364 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1365 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1366 /* OpenPrinter(",XcvMonitor " detected */
1367 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1368 printer->pm = monitor_load(&printername[len], NULL);
1369 if (printer->pm == NULL) {
1370 SetLastError(ERROR_UNKNOWN_PORT);
1371 handle = 0;
1372 goto end;
1375 else
1377 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1378 if (strncmpW( printername, XcvPortW, len) == 0) {
1379 /* OpenPrinter(",XcvPort " detected */
1380 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1381 printer->pm = monitor_load_by_port(&printername[len]);
1382 if (printer->pm == NULL) {
1383 SetLastError(ERROR_UNKNOWN_PORT);
1384 handle = 0;
1385 goto end;
1390 if (printer->pm) {
1391 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1392 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1393 pDefault ? pDefault->DesiredAccess : 0,
1394 &printer->hXcv);
1396 if (printer->hXcv == NULL) {
1397 SetLastError(ERROR_INVALID_PARAMETER);
1398 handle = 0;
1399 goto end;
1402 else
1404 /* Does the Printer exist? */
1405 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1406 ERR("Can't create Printers key\n");
1407 handle = 0;
1408 goto end;
1410 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1411 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1412 RegCloseKey(hkeyPrinters);
1413 SetLastError(ERROR_INVALID_PRINTER_NAME);
1414 handle = 0;
1415 goto end;
1417 RegCloseKey(hkeyPrinter);
1418 RegCloseKey(hkeyPrinters);
1421 else
1423 TRACE("using the local printserver\n");
1426 if(queue)
1427 printer->queue = queue;
1428 else
1430 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1431 if (!printer->queue) {
1432 handle = 0;
1433 goto end;
1435 list_init(&printer->queue->jobs);
1436 printer->queue->ref = 0;
1438 InterlockedIncrement(&printer->queue->ref);
1440 printer_handles[handle] = printer;
1441 handle++;
1442 end:
1443 LeaveCriticalSection(&printer_handles_cs);
1444 if (!handle && printer) {
1445 /* Something failed: Free all resources */
1446 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1447 monitor_unload(printer->pm);
1448 HeapFree(GetProcessHeap(), 0, printer->printername);
1449 HeapFree(GetProcessHeap(), 0, printer->name);
1450 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1451 HeapFree(GetProcessHeap(), 0, printer);
1454 return (HANDLE)handle;
1457 /******************************************************************
1458 * get_opened_printer
1459 * Get the pointer to the opened printer referred by the handle
1461 static opened_printer_t *get_opened_printer(HANDLE hprn)
1463 UINT_PTR idx = (UINT_PTR)hprn;
1464 opened_printer_t *ret = NULL;
1466 EnterCriticalSection(&printer_handles_cs);
1468 if ((idx <= 0) || (idx > nb_printer_handles))
1469 goto end;
1471 ret = printer_handles[idx - 1];
1472 end:
1473 LeaveCriticalSection(&printer_handles_cs);
1474 return ret;
1477 /******************************************************************
1478 * get_opened_printer_name
1479 * Get the pointer to the opened printer name referred by the handle
1481 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1483 opened_printer_t *printer = get_opened_printer(hprn);
1484 if(!printer) return NULL;
1485 return printer->name;
1488 /******************************************************************
1489 * WINSPOOL_GetOpenedPrinterRegKey
1492 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1494 LPCWSTR name = get_opened_printer_name(hPrinter);
1495 DWORD ret;
1496 HKEY hkeyPrinters;
1498 if(!name) return ERROR_INVALID_HANDLE;
1500 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1501 ERROR_SUCCESS)
1502 return ret;
1504 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1506 ERR("Can't find opened printer %s in registry\n",
1507 debugstr_w(name));
1508 RegCloseKey(hkeyPrinters);
1509 return ERROR_INVALID_PRINTER_NAME; /* ? */
1511 RegCloseKey(hkeyPrinters);
1512 return ERROR_SUCCESS;
1515 void WINSPOOL_LoadSystemPrinters(void)
1517 HKEY hkey, hkeyPrinters;
1518 HANDLE hprn;
1519 DWORD needed, num, i;
1520 WCHAR PrinterName[256];
1521 BOOL done = FALSE;
1523 /* This ensures that all printer entries have a valid Name value. If causes
1524 problems later if they don't. If one is found to be missed we create one
1525 and set it equal to the name of the key */
1526 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1527 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1528 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1529 for(i = 0; i < num; i++) {
1530 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1531 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1532 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1533 set_reg_szW(hkey, NameW, PrinterName);
1535 RegCloseKey(hkey);
1540 RegCloseKey(hkeyPrinters);
1543 /* We want to avoid calling AddPrinter on printers as much as
1544 possible, because on cups printers this will (eventually) lead
1545 to a call to cupsGetPPD which takes forever, even with non-cups
1546 printers AddPrinter takes a while. So we'll tag all printers that
1547 were automatically added last time around, if they still exist
1548 we'll leave them be otherwise we'll delete them. */
1549 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1550 if(needed) {
1551 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1552 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1553 for(i = 0; i < num; i++) {
1554 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1555 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1556 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1557 DWORD dw = 1;
1558 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1559 RegCloseKey(hkey);
1561 ClosePrinter(hprn);
1566 HeapFree(GetProcessHeap(), 0, pi);
1570 #ifdef HAVE_CUPS_CUPS_H
1571 done = CUPS_LoadPrinters();
1572 #endif
1574 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1575 PRINTCAP_LoadPrinters();
1577 /* Now enumerate the list again and delete any printers that a still tagged */
1578 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1579 if(needed) {
1580 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1581 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1582 for(i = 0; i < num; i++) {
1583 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1584 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1585 BOOL delete_driver = FALSE;
1586 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1587 DWORD dw, type, size = sizeof(dw);
1588 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1589 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1590 DeletePrinter(hprn);
1591 delete_driver = TRUE;
1593 RegCloseKey(hkey);
1595 ClosePrinter(hprn);
1596 if(delete_driver)
1597 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1602 HeapFree(GetProcessHeap(), 0, pi);
1605 return;
1609 /******************************************************************
1610 * get_job
1612 * Get the pointer to the specified job.
1613 * Should hold the printer_handles_cs before calling.
1615 static job_t *get_job(HANDLE hprn, DWORD JobId)
1617 opened_printer_t *printer = get_opened_printer(hprn);
1618 job_t *job;
1620 if(!printer) return NULL;
1621 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1623 if(job->job_id == JobId)
1624 return job;
1626 return NULL;
1629 /***********************************************************
1630 * DEVMODEcpyAtoW
1632 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1634 BOOL Formname;
1635 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1636 DWORD size;
1638 Formname = (dmA->dmSize > off_formname);
1639 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1640 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1641 dmW->dmDeviceName, CCHDEVICENAME);
1642 if(!Formname) {
1643 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1644 dmA->dmSize - CCHDEVICENAME);
1645 } else {
1646 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1647 off_formname - CCHDEVICENAME);
1648 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1649 dmW->dmFormName, CCHFORMNAME);
1650 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1651 (off_formname + CCHFORMNAME));
1653 dmW->dmSize = size;
1654 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1655 dmA->dmDriverExtra);
1656 return dmW;
1659 /***********************************************************
1660 * DEVMODEdupWtoA
1661 * Creates an ascii copy of supplied devmode on heap
1663 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1665 LPDEVMODEA dmA;
1666 DWORD size;
1667 BOOL Formname;
1668 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1670 if(!dmW) return NULL;
1671 Formname = (dmW->dmSize > off_formname);
1672 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1673 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1674 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1675 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1676 if(!Formname) {
1677 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1678 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1679 } else {
1680 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1681 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1682 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1683 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1684 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1685 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1687 dmA->dmSize = size;
1688 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1689 dmW->dmDriverExtra);
1690 return dmA;
1693 /***********************************************************
1694 * PRINTER_INFO_2AtoW
1695 * Creates a unicode copy of PRINTER_INFO_2A on heap
1697 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1699 LPPRINTER_INFO_2W piW;
1700 UNICODE_STRING usBuffer;
1702 if(!piA) return NULL;
1703 piW = HeapAlloc(heap, 0, sizeof(*piW));
1704 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1706 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1707 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1708 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1709 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1710 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1711 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1712 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1713 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1714 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1715 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1716 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1717 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1718 return piW;
1721 /***********************************************************
1722 * FREE_PRINTER_INFO_2W
1723 * Free PRINTER_INFO_2W and all strings
1725 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1727 if(!piW) return;
1729 HeapFree(heap,0,piW->pServerName);
1730 HeapFree(heap,0,piW->pPrinterName);
1731 HeapFree(heap,0,piW->pShareName);
1732 HeapFree(heap,0,piW->pPortName);
1733 HeapFree(heap,0,piW->pDriverName);
1734 HeapFree(heap,0,piW->pComment);
1735 HeapFree(heap,0,piW->pLocation);
1736 HeapFree(heap,0,piW->pDevMode);
1737 HeapFree(heap,0,piW->pSepFile);
1738 HeapFree(heap,0,piW->pPrintProcessor);
1739 HeapFree(heap,0,piW->pDatatype);
1740 HeapFree(heap,0,piW->pParameters);
1741 HeapFree(heap,0,piW);
1742 return;
1745 /******************************************************************
1746 * DeviceCapabilities [WINSPOOL.@]
1747 * DeviceCapabilitiesA [WINSPOOL.@]
1750 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1751 LPSTR pOutput, LPDEVMODEA lpdm)
1753 INT ret;
1755 if (!GDI_CallDeviceCapabilities16)
1757 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1758 (LPCSTR)104 );
1759 if (!GDI_CallDeviceCapabilities16) return -1;
1761 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1763 /* If DC_PAPERSIZE map POINT16s to POINTs */
1764 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1765 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1766 POINT *pt = (POINT *)pOutput;
1767 INT i;
1768 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1769 for(i = 0; i < ret; i++, pt++)
1771 pt->x = tmp[i].x;
1772 pt->y = tmp[i].y;
1774 HeapFree( GetProcessHeap(), 0, tmp );
1776 return ret;
1780 /*****************************************************************************
1781 * DeviceCapabilitiesW [WINSPOOL.@]
1783 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1786 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1787 WORD fwCapability, LPWSTR pOutput,
1788 const DEVMODEW *pDevMode)
1790 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1791 LPSTR pDeviceA = strdupWtoA(pDevice);
1792 LPSTR pPortA = strdupWtoA(pPort);
1793 INT ret;
1795 if(pOutput && (fwCapability == DC_BINNAMES ||
1796 fwCapability == DC_FILEDEPENDENCIES ||
1797 fwCapability == DC_PAPERNAMES)) {
1798 /* These need A -> W translation */
1799 INT size = 0, i;
1800 LPSTR pOutputA;
1801 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1802 dmA);
1803 if(ret == -1)
1804 return ret;
1805 switch(fwCapability) {
1806 case DC_BINNAMES:
1807 size = 24;
1808 break;
1809 case DC_PAPERNAMES:
1810 case DC_FILEDEPENDENCIES:
1811 size = 64;
1812 break;
1814 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1815 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1816 dmA);
1817 for(i = 0; i < ret; i++)
1818 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1819 pOutput + (i * size), size);
1820 HeapFree(GetProcessHeap(), 0, pOutputA);
1821 } else {
1822 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1823 (LPSTR)pOutput, dmA);
1825 HeapFree(GetProcessHeap(),0,pPortA);
1826 HeapFree(GetProcessHeap(),0,pDeviceA);
1827 HeapFree(GetProcessHeap(),0,dmA);
1828 return ret;
1831 /******************************************************************
1832 * DocumentPropertiesA [WINSPOOL.@]
1834 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1836 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1837 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1838 LPDEVMODEA pDevModeInput,DWORD fMode )
1840 LPSTR lpName = pDeviceName;
1841 static CHAR port[] = "LPT1:";
1842 LONG ret;
1844 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1845 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1848 if(!pDeviceName) {
1849 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1850 if(!lpNameW) {
1851 ERR("no name from hPrinter?\n");
1852 SetLastError(ERROR_INVALID_HANDLE);
1853 return -1;
1855 lpName = strdupWtoA(lpNameW);
1858 if (!GDI_CallExtDeviceMode16)
1860 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1861 (LPCSTR)102 );
1862 if (!GDI_CallExtDeviceMode16) {
1863 ERR("No CallExtDeviceMode16?\n");
1864 return -1;
1867 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1868 pDevModeInput, NULL, fMode);
1870 if(!pDeviceName)
1871 HeapFree(GetProcessHeap(),0,lpName);
1872 return ret;
1876 /*****************************************************************************
1877 * DocumentPropertiesW (WINSPOOL.@)
1879 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1881 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1882 LPWSTR pDeviceName,
1883 LPDEVMODEW pDevModeOutput,
1884 LPDEVMODEW pDevModeInput, DWORD fMode)
1887 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1888 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1889 LPDEVMODEA pDevModeOutputA = NULL;
1890 LONG ret;
1892 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1893 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1894 fMode);
1895 if(pDevModeOutput) {
1896 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1897 if(ret < 0) return ret;
1898 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1900 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1901 pDevModeInputA, fMode);
1902 if(pDevModeOutput) {
1903 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1904 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1906 if(fMode == 0 && ret > 0)
1907 ret += (CCHDEVICENAME + CCHFORMNAME);
1908 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1909 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1910 return ret;
1913 /******************************************************************
1914 * OpenPrinterA [WINSPOOL.@]
1916 * See OpenPrinterW.
1919 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1920 LPPRINTER_DEFAULTSA pDefault)
1922 UNICODE_STRING lpPrinterNameW;
1923 UNICODE_STRING usBuffer;
1924 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1925 PWSTR pwstrPrinterNameW;
1926 BOOL ret;
1928 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1930 if(pDefault) {
1931 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1932 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1933 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1934 pDefaultW = &DefaultW;
1936 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1937 if(pDefault) {
1938 RtlFreeUnicodeString(&usBuffer);
1939 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1941 RtlFreeUnicodeString(&lpPrinterNameW);
1942 return ret;
1945 /******************************************************************
1946 * OpenPrinterW [WINSPOOL.@]
1948 * Open a Printer / Printserver or a Printer-Object
1950 * PARAMS
1951 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1952 * phPrinter [O] The resulting Handle is stored here
1953 * pDefault [I] PTR to Default Printer Settings or NULL
1955 * RETURNS
1956 * Success: TRUE
1957 * Failure: FALSE
1959 * NOTES
1960 * lpPrinterName is one of:
1961 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1962 *| Printer: "PrinterName"
1963 *| Printer-Object: "PrinterName,Job xxx"
1964 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1965 *| XcvPort: "Servername,XcvPort PortName"
1967 * BUGS
1968 *| Printer-Object not supported
1969 *| pDefaults is ignored
1972 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
1975 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
1976 if (pDefault) {
1977 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
1978 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
1981 if(!phPrinter) {
1982 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
1983 SetLastError(ERROR_INVALID_PARAMETER);
1984 return FALSE;
1987 /* Get the unique handle of the printer or Printserver */
1988 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
1989 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
1990 return (*phPrinter != 0);
1993 /******************************************************************
1994 * AddMonitorA [WINSPOOL.@]
1996 * See AddMonitorW.
1999 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2001 LPWSTR nameW = NULL;
2002 INT len;
2003 BOOL res;
2004 LPMONITOR_INFO_2A mi2a;
2005 MONITOR_INFO_2W mi2w;
2007 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2008 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2009 mi2a ? debugstr_a(mi2a->pName) : NULL,
2010 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2011 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2013 if (Level != 2) {
2014 SetLastError(ERROR_INVALID_LEVEL);
2015 return FALSE;
2018 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2019 if (mi2a == NULL) {
2020 return FALSE;
2023 if (pName) {
2024 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2025 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2026 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2029 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2030 if (mi2a->pName) {
2031 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2032 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2033 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2035 if (mi2a->pEnvironment) {
2036 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2037 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2038 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2040 if (mi2a->pDLLName) {
2041 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2042 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2043 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2046 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2048 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2049 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2050 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2052 HeapFree(GetProcessHeap(), 0, nameW);
2053 return (res);
2056 /******************************************************************************
2057 * AddMonitorW [WINSPOOL.@]
2059 * Install a Printmonitor
2061 * PARAMS
2062 * pName [I] Servername or NULL (local Computer)
2063 * Level [I] Structure-Level (Must be 2)
2064 * pMonitors [I] PTR to MONITOR_INFO_2
2066 * RETURNS
2067 * Success: TRUE
2068 * Failure: FALSE
2070 * NOTES
2071 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2074 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2076 monitor_t * pm = NULL;
2077 LPMONITOR_INFO_2W mi2w;
2078 HKEY hroot = NULL;
2079 HKEY hentry = NULL;
2080 DWORD disposition;
2081 BOOL res = FALSE;
2083 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2084 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2085 mi2w ? debugstr_w(mi2w->pName) : NULL,
2086 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2087 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2089 if (Level != 2) {
2090 SetLastError(ERROR_INVALID_LEVEL);
2091 return FALSE;
2094 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2095 if (mi2w == NULL) {
2096 return FALSE;
2099 if (pName && (pName[0])) {
2100 FIXME("for server %s not implemented\n", debugstr_w(pName));
2101 SetLastError(ERROR_ACCESS_DENIED);
2102 return FALSE;
2106 if (!mi2w->pName || (! mi2w->pName[0])) {
2107 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2108 SetLastError(ERROR_INVALID_PARAMETER);
2109 return FALSE;
2111 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2112 WARN("Environment %s requested (we support only %s)\n",
2113 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2114 SetLastError(ERROR_INVALID_ENVIRONMENT);
2115 return FALSE;
2118 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2119 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2120 SetLastError(ERROR_INVALID_PARAMETER);
2121 return FALSE;
2124 /* Load and initialize the monitor. SetLastError() is called on failure */
2125 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2126 return FALSE;
2128 monitor_unload(pm);
2130 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2131 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2132 return FALSE;
2135 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2136 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2137 &disposition) == ERROR_SUCCESS) {
2139 /* Some installers set options for the port before calling AddMonitor.
2140 We query the "Driver" entry to verify that the monitor is installed,
2141 before we return an error.
2142 When a user installs two print monitors at the same time with the
2143 same name but with a different driver DLL and a task switch comes
2144 between RegQueryValueExW and RegSetValueExW, a race condition
2145 is possible but silently ignored. */
2147 DWORD namesize = 0;
2149 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2150 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2151 &namesize) == ERROR_SUCCESS)) {
2152 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2153 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2154 9x: ERROR_ALREADY_EXISTS (183) */
2155 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2157 else
2159 INT len;
2160 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2161 res = (RegSetValueExW(hentry, DriverW, 0,
2162 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2164 RegCloseKey(hentry);
2167 RegCloseKey(hroot);
2168 return (res);
2171 /******************************************************************
2172 * DeletePrinterDriverA [WINSPOOL.@]
2175 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2177 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2180 /******************************************************************
2181 * DeletePrinterDriverW [WINSPOOL.@]
2184 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2186 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2189 /******************************************************************
2190 * DeleteMonitorA [WINSPOOL.@]
2192 * See DeleteMonitorW.
2195 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2197 LPWSTR nameW = NULL;
2198 LPWSTR EnvironmentW = NULL;
2199 LPWSTR MonitorNameW = NULL;
2200 BOOL res;
2201 INT len;
2203 if (pName) {
2204 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2205 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2206 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2209 if (pEnvironment) {
2210 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2211 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2212 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2214 if (pMonitorName) {
2215 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2216 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2217 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2220 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2222 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2223 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2224 HeapFree(GetProcessHeap(), 0, nameW);
2225 return (res);
2228 /******************************************************************
2229 * DeleteMonitorW [WINSPOOL.@]
2231 * Delete a specific Printmonitor from a Printing-Environment
2233 * PARAMS
2234 * pName [I] Servername or NULL (local Computer)
2235 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2236 * pMonitorName [I] Name of the Monitor, that should be deleted
2238 * RETURNS
2239 * Success: TRUE
2240 * Failure: FALSE
2242 * NOTES
2243 * pEnvironment is ignored in Windows for the local Computer.
2247 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2249 HKEY hroot = NULL;
2251 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2252 debugstr_w(pMonitorName));
2254 if (pName && (pName[0])) {
2255 FIXME("for server %s not implemented\n", debugstr_w(pName));
2256 SetLastError(ERROR_ACCESS_DENIED);
2257 return FALSE;
2260 /* pEnvironment is ignored in Windows for the local Computer */
2262 if (!pMonitorName || !pMonitorName[0]) {
2263 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2264 SetLastError(ERROR_INVALID_PARAMETER);
2265 return FALSE;
2268 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2269 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2270 return FALSE;
2273 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2274 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2275 RegCloseKey(hroot);
2276 return TRUE;
2279 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2280 RegCloseKey(hroot);
2282 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2283 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2284 return (FALSE);
2287 /******************************************************************
2288 * DeletePortA [WINSPOOL.@]
2290 * See DeletePortW.
2293 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2295 LPWSTR nameW = NULL;
2296 LPWSTR portW = NULL;
2297 INT len;
2298 DWORD res;
2300 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2302 /* convert servername to unicode */
2303 if (pName) {
2304 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2305 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2306 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2309 /* convert portname to unicode */
2310 if (pPortName) {
2311 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2312 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2313 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2316 res = DeletePortW(nameW, hWnd, portW);
2317 HeapFree(GetProcessHeap(), 0, nameW);
2318 HeapFree(GetProcessHeap(), 0, portW);
2319 return res;
2322 /******************************************************************
2323 * DeletePortW [WINSPOOL.@]
2325 * Delete a specific Port
2327 * PARAMS
2328 * pName [I] Servername or NULL (local Computer)
2329 * hWnd [I] Handle to parent Window for the Dialog-Box
2330 * pPortName [I] Name of the Port, that should be deleted
2332 * RETURNS
2333 * Success: TRUE
2334 * Failure: FALSE
2337 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2339 monitor_t * pm;
2340 monitor_t * pui;
2341 DWORD res;
2343 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2345 if (pName && pName[0]) {
2346 SetLastError(ERROR_INVALID_PARAMETER);
2347 return FALSE;
2350 if (!pPortName) {
2351 SetLastError(RPC_X_NULL_REF_POINTER);
2352 return FALSE;
2355 /* an empty Portname is Invalid */
2356 if (!pPortName[0]) {
2357 SetLastError(ERROR_NOT_SUPPORTED);
2358 return FALSE;
2361 pm = monitor_load_by_port(pPortName);
2362 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2363 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2364 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2365 TRACE("got %d with %u\n", res, GetLastError());
2367 else
2369 pui = monitor_loadui(pm);
2370 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2371 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2372 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2373 TRACE("got %d with %u\n", res, GetLastError());
2375 else
2377 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2378 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2380 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2381 SetLastError(ERROR_NOT_SUPPORTED);
2382 res = FALSE;
2384 monitor_unload(pui);
2386 monitor_unload(pm);
2388 TRACE("returning %d with %u\n", res, GetLastError());
2389 return res;
2392 /******************************************************************************
2393 * SetPrinterW [WINSPOOL.@]
2395 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2397 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2398 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2399 return FALSE;
2402 /******************************************************************************
2403 * WritePrinter [WINSPOOL.@]
2405 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2407 opened_printer_t *printer;
2408 BOOL ret = FALSE;
2410 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2412 EnterCriticalSection(&printer_handles_cs);
2413 printer = get_opened_printer(hPrinter);
2414 if(!printer)
2416 SetLastError(ERROR_INVALID_HANDLE);
2417 goto end;
2420 if(!printer->doc)
2422 SetLastError(ERROR_SPL_NO_STARTDOC);
2423 goto end;
2426 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2427 end:
2428 LeaveCriticalSection(&printer_handles_cs);
2429 return ret;
2432 /*****************************************************************************
2433 * AddFormA [WINSPOOL.@]
2435 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2437 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2438 return 1;
2441 /*****************************************************************************
2442 * AddFormW [WINSPOOL.@]
2444 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2446 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2447 return 1;
2450 /*****************************************************************************
2451 * AddJobA [WINSPOOL.@]
2453 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2455 BOOL ret;
2456 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2457 DWORD needed;
2459 if(Level != 1) {
2460 SetLastError(ERROR_INVALID_LEVEL);
2461 return FALSE;
2464 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2466 if(ret) {
2467 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2468 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2469 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2470 if(*pcbNeeded > cbBuf) {
2471 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2472 ret = FALSE;
2473 } else {
2474 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2475 addjobA->JobId = addjobW->JobId;
2476 addjobA->Path = (char *)(addjobA + 1);
2477 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2480 return ret;
2483 /*****************************************************************************
2484 * AddJobW [WINSPOOL.@]
2486 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2488 opened_printer_t *printer;
2489 job_t *job;
2490 BOOL ret = FALSE;
2491 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2492 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2493 WCHAR path[MAX_PATH], filename[MAX_PATH];
2494 DWORD len;
2495 ADDJOB_INFO_1W *addjob;
2497 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2499 EnterCriticalSection(&printer_handles_cs);
2501 printer = get_opened_printer(hPrinter);
2503 if(!printer) {
2504 SetLastError(ERROR_INVALID_HANDLE);
2505 goto end;
2508 if(Level != 1) {
2509 SetLastError(ERROR_INVALID_LEVEL);
2510 goto end;
2513 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2514 if(!job)
2515 goto end;
2517 job->job_id = InterlockedIncrement(&next_job_id);
2519 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2520 if(path[len - 1] != '\\')
2521 path[len++] = '\\';
2522 memcpy(path + len, spool_path, sizeof(spool_path));
2523 sprintfW(filename, fmtW, path, job->job_id);
2525 len = strlenW(filename);
2526 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2527 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2528 job->document_title = strdupW(default_doc_title);
2529 list_add_tail(&printer->queue->jobs, &job->entry);
2531 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2532 if(*pcbNeeded <= cbBuf) {
2533 addjob = (ADDJOB_INFO_1W*)pData;
2534 addjob->JobId = job->job_id;
2535 addjob->Path = (WCHAR *)(addjob + 1);
2536 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2537 ret = TRUE;
2538 } else
2539 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2541 end:
2542 LeaveCriticalSection(&printer_handles_cs);
2543 return ret;
2546 /*****************************************************************************
2547 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2549 * Return the PATH for the Print-Processors
2551 * See GetPrintProcessorDirectoryW.
2555 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2556 DWORD level, LPBYTE Info,
2557 DWORD cbBuf, LPDWORD pcbNeeded)
2559 LPWSTR serverW = NULL;
2560 LPWSTR envW = NULL;
2561 BOOL ret;
2562 INT len;
2564 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2565 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2568 if (server) {
2569 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2570 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2571 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2574 if (env) {
2575 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2576 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2577 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2580 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2581 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2583 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2584 cbBuf, pcbNeeded);
2586 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2587 cbBuf, NULL, NULL) > 0;
2590 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2591 HeapFree(GetProcessHeap(), 0, envW);
2592 HeapFree(GetProcessHeap(), 0, serverW);
2593 return ret;
2596 /*****************************************************************************
2597 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2599 * Return the PATH for the Print-Processors
2601 * PARAMS
2602 * server [I] Servername (NT only) or NULL (local Computer)
2603 * env [I] Printing-Environment (see below) or NULL (Default)
2604 * level [I] Structure-Level (must be 1)
2605 * Info [O] PTR to Buffer that receives the Result
2606 * cbBuf [I] Size of Buffer at "Info"
2607 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2608 * required for the Buffer at "Info"
2610 * RETURNS
2611 * Success: TRUE and in pcbNeeded the Bytes used in Info
2612 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2613 * if cbBuf is too small
2615 * Native Values returned in Info on Success:
2616 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2617 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2618 *| win9x(Windows 4.0): "%winsysdir%"
2620 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2622 * BUGS
2623 * Only NULL or "" is supported for server
2626 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2627 DWORD level, LPBYTE Info,
2628 DWORD cbBuf, LPDWORD pcbNeeded)
2630 DWORD needed;
2631 const printenv_t * env_t;
2633 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2634 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2636 if(server != NULL && server[0]) {
2637 FIXME("server not supported: %s\n", debugstr_w(server));
2638 SetLastError(ERROR_INVALID_PARAMETER);
2639 return FALSE;
2642 env_t = validate_envW(env);
2643 if(!env_t) return FALSE; /* environment invalid or unsupported */
2645 if(level != 1) {
2646 WARN("(Level: %d) is ignored in win9x\n", level);
2647 SetLastError(ERROR_INVALID_LEVEL);
2648 return FALSE;
2651 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2652 needed = GetSystemDirectoryW(NULL, 0);
2653 /* add the Size for the Subdirectories */
2654 needed += lstrlenW(spoolprtprocsW);
2655 needed += lstrlenW(env_t->subdir);
2656 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2658 if(pcbNeeded) *pcbNeeded = needed;
2659 TRACE ("required: 0x%x/%d\n", needed, needed);
2660 if (needed > cbBuf) {
2661 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2662 return FALSE;
2664 if(pcbNeeded == NULL) {
2665 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2666 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2667 SetLastError(RPC_X_NULL_REF_POINTER);
2668 return FALSE;
2670 if(Info == NULL) {
2671 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2672 SetLastError(RPC_X_NULL_REF_POINTER);
2673 return FALSE;
2676 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2677 /* add the Subdirectories */
2678 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2679 lstrcatW((LPWSTR) Info, env_t->subdir);
2680 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2681 return TRUE;
2684 /*****************************************************************************
2685 * WINSPOOL_OpenDriverReg [internal]
2687 * opens the registry for the printer drivers depending on the given input
2688 * variable pEnvironment
2690 * RETURNS:
2691 * the opened hkey on success
2692 * NULL on error
2694 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2696 HKEY retval = NULL;
2697 LPWSTR buffer;
2698 const printenv_t * env;
2700 TRACE("(%s, %d)\n",
2701 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2703 if (!pEnvironment || unicode) {
2704 /* pEnvironment was NULL or an Unicode-String: use it direct */
2705 env = validate_envW(pEnvironment);
2707 else
2709 /* pEnvironment was an ANSI-String: convert to unicode first */
2710 LPWSTR buffer;
2711 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2712 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2713 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2714 env = validate_envW(buffer);
2715 HeapFree(GetProcessHeap(), 0, buffer);
2717 if (!env) return NULL;
2719 buffer = HeapAlloc( GetProcessHeap(), 0,
2720 (strlenW(DriversW) + strlenW(env->envname) +
2721 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2722 if(buffer) {
2723 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2724 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2725 HeapFree(GetProcessHeap(), 0, buffer);
2727 return retval;
2730 /*****************************************************************************
2731 * AddPrinterW [WINSPOOL.@]
2733 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2735 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2736 LPDEVMODEA dmA;
2737 LPDEVMODEW dmW;
2738 HANDLE retval;
2739 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2740 LONG size;
2741 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2742 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2743 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2744 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2745 statusW[] = {'S','t','a','t','u','s',0},
2746 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2748 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2750 if(pName != NULL) {
2751 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2752 SetLastError(ERROR_INVALID_PARAMETER);
2753 return 0;
2755 if(Level != 2) {
2756 ERR("Level = %d, unsupported!\n", Level);
2757 SetLastError(ERROR_INVALID_LEVEL);
2758 return 0;
2760 if(!pPrinter) {
2761 SetLastError(ERROR_INVALID_PARAMETER);
2762 return 0;
2764 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2765 ERROR_SUCCESS) {
2766 ERR("Can't create Printers key\n");
2767 return 0;
2769 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2770 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2771 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2772 RegCloseKey(hkeyPrinter);
2773 RegCloseKey(hkeyPrinters);
2774 return 0;
2776 RegCloseKey(hkeyPrinter);
2778 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2779 if(!hkeyDrivers) {
2780 ERR("Can't create Drivers key\n");
2781 RegCloseKey(hkeyPrinters);
2782 return 0;
2784 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2785 ERROR_SUCCESS) {
2786 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2787 RegCloseKey(hkeyPrinters);
2788 RegCloseKey(hkeyDrivers);
2789 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2790 return 0;
2792 RegCloseKey(hkeyDriver);
2793 RegCloseKey(hkeyDrivers);
2795 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2796 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2797 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2798 RegCloseKey(hkeyPrinters);
2799 return 0;
2802 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2803 ERROR_SUCCESS) {
2804 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2805 SetLastError(ERROR_INVALID_PRINTER_NAME);
2806 RegCloseKey(hkeyPrinters);
2807 return 0;
2809 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2810 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2811 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2813 /* See if we can load the driver. We may need the devmode structure anyway
2815 * FIXME:
2816 * Note that DocumentPropertiesW will briefly try to open the printer we
2817 * just create to find a DEVMODEA struct (it will use the WINEPS default
2818 * one in case it is not there, so we are ok).
2820 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2822 if(size < 0) {
2823 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2824 size = sizeof(DEVMODEW);
2826 if(pi->pDevMode)
2827 dmW = pi->pDevMode;
2828 else
2830 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2831 dmW->dmSize = size;
2832 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2834 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2835 HeapFree(GetProcessHeap(),0,dmW);
2836 dmW=NULL;
2838 else
2840 /* set devmode to printer name */
2841 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2845 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2846 and we support these drivers. NT writes DEVMODEW so somehow
2847 we'll need to distinguish between these when we support NT
2848 drivers */
2849 if (dmW)
2851 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2852 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2853 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2854 HeapFree(GetProcessHeap(), 0, dmA);
2855 if(!pi->pDevMode)
2856 HeapFree(GetProcessHeap(), 0, dmW);
2858 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2859 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2860 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2861 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2863 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2864 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2865 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2866 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2867 (LPBYTE)&pi->Priority, sizeof(DWORD));
2868 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2869 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2870 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2871 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2872 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2873 (LPBYTE)&pi->Status, sizeof(DWORD));
2874 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2875 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2877 RegCloseKey(hkeyPrinter);
2878 RegCloseKey(hkeyPrinters);
2879 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2880 ERR("OpenPrinter failing\n");
2881 return 0;
2883 return retval;
2886 /*****************************************************************************
2887 * AddPrinterA [WINSPOOL.@]
2889 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2891 UNICODE_STRING pNameW;
2892 PWSTR pwstrNameW;
2893 PRINTER_INFO_2W *piW;
2894 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2895 HANDLE ret;
2897 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2898 if(Level != 2) {
2899 ERR("Level = %d, unsupported!\n", Level);
2900 SetLastError(ERROR_INVALID_LEVEL);
2901 return 0;
2903 pwstrNameW = asciitounicode(&pNameW,pName);
2904 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2906 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2908 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2909 RtlFreeUnicodeString(&pNameW);
2910 return ret;
2914 /*****************************************************************************
2915 * ClosePrinter [WINSPOOL.@]
2917 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2919 UINT_PTR i = (UINT_PTR)hPrinter;
2920 opened_printer_t *printer = NULL;
2921 BOOL ret = FALSE;
2923 TRACE("(%p)\n", hPrinter);
2925 EnterCriticalSection(&printer_handles_cs);
2927 if ((i > 0) && (i <= nb_printer_handles))
2928 printer = printer_handles[i - 1];
2931 if(printer)
2933 struct list *cursor, *cursor2;
2935 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2936 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2937 printer->hXcv, debugstr_w(printer->name), printer->doc );
2939 if(printer->doc)
2940 EndDocPrinter(hPrinter);
2942 if(InterlockedDecrement(&printer->queue->ref) == 0)
2944 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2946 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2947 ScheduleJob(hPrinter, job->job_id);
2949 HeapFree(GetProcessHeap(), 0, printer->queue);
2951 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2952 monitor_unload(printer->pm);
2953 HeapFree(GetProcessHeap(), 0, printer->printername);
2954 HeapFree(GetProcessHeap(), 0, printer->name);
2955 HeapFree(GetProcessHeap(), 0, printer);
2956 printer_handles[i - 1] = NULL;
2957 ret = TRUE;
2959 LeaveCriticalSection(&printer_handles_cs);
2960 return ret;
2963 /*****************************************************************************
2964 * DeleteFormA [WINSPOOL.@]
2966 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2968 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2969 return 1;
2972 /*****************************************************************************
2973 * DeleteFormW [WINSPOOL.@]
2975 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2977 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2978 return 1;
2981 /*****************************************************************************
2982 * DeletePrinter [WINSPOOL.@]
2984 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2986 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2987 HKEY hkeyPrinters, hkey;
2989 if(!lpNameW) {
2990 SetLastError(ERROR_INVALID_HANDLE);
2991 return FALSE;
2993 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2994 RegDeleteTreeW(hkeyPrinters, lpNameW);
2995 RegCloseKey(hkeyPrinters);
2997 WriteProfileStringW(devicesW, lpNameW, NULL);
2998 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2999 RegDeleteValueW(hkey, lpNameW);
3000 RegCloseKey(hkey);
3002 return TRUE;
3005 /*****************************************************************************
3006 * SetPrinterA [WINSPOOL.@]
3008 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3009 DWORD Command)
3011 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3012 return FALSE;
3015 /*****************************************************************************
3016 * SetJobA [WINSPOOL.@]
3018 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3019 LPBYTE pJob, DWORD Command)
3021 BOOL ret;
3022 LPBYTE JobW;
3023 UNICODE_STRING usBuffer;
3025 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3027 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3028 are all ignored by SetJob, so we don't bother copying them */
3029 switch(Level)
3031 case 0:
3032 JobW = NULL;
3033 break;
3034 case 1:
3036 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3037 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3039 JobW = (LPBYTE)info1W;
3040 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3041 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3042 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3043 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3044 info1W->Status = info1A->Status;
3045 info1W->Priority = info1A->Priority;
3046 info1W->Position = info1A->Position;
3047 info1W->PagesPrinted = info1A->PagesPrinted;
3048 break;
3050 case 2:
3052 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3053 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3055 JobW = (LPBYTE)info2W;
3056 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3057 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3058 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3059 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3060 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3061 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3062 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3063 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3064 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3065 info2W->Status = info2A->Status;
3066 info2W->Priority = info2A->Priority;
3067 info2W->Position = info2A->Position;
3068 info2W->StartTime = info2A->StartTime;
3069 info2W->UntilTime = info2A->UntilTime;
3070 info2W->PagesPrinted = info2A->PagesPrinted;
3071 break;
3073 case 3:
3074 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3075 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3076 break;
3077 default:
3078 SetLastError(ERROR_INVALID_LEVEL);
3079 return FALSE;
3082 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3084 switch(Level)
3086 case 1:
3088 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3089 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3090 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3091 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3092 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3093 break;
3095 case 2:
3097 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3098 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3099 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3100 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3101 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3102 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3103 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3104 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3105 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3106 break;
3109 HeapFree(GetProcessHeap(), 0, JobW);
3111 return ret;
3114 /*****************************************************************************
3115 * SetJobW [WINSPOOL.@]
3117 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3118 LPBYTE pJob, DWORD Command)
3120 BOOL ret = FALSE;
3121 job_t *job;
3123 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3124 FIXME("Ignoring everything other than document title\n");
3126 EnterCriticalSection(&printer_handles_cs);
3127 job = get_job(hPrinter, JobId);
3128 if(!job)
3129 goto end;
3131 switch(Level)
3133 case 0:
3134 break;
3135 case 1:
3137 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3138 HeapFree(GetProcessHeap(), 0, job->document_title);
3139 job->document_title = strdupW(info1->pDocument);
3140 break;
3142 case 2:
3144 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3145 HeapFree(GetProcessHeap(), 0, job->document_title);
3146 job->document_title = strdupW(info2->pDocument);
3147 break;
3149 case 3:
3150 break;
3151 default:
3152 SetLastError(ERROR_INVALID_LEVEL);
3153 goto end;
3155 ret = TRUE;
3156 end:
3157 LeaveCriticalSection(&printer_handles_cs);
3158 return ret;
3161 /*****************************************************************************
3162 * EndDocPrinter [WINSPOOL.@]
3164 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3166 opened_printer_t *printer;
3167 BOOL ret = FALSE;
3168 TRACE("(%p)\n", hPrinter);
3170 EnterCriticalSection(&printer_handles_cs);
3172 printer = get_opened_printer(hPrinter);
3173 if(!printer)
3175 SetLastError(ERROR_INVALID_HANDLE);
3176 goto end;
3179 if(!printer->doc)
3181 SetLastError(ERROR_SPL_NO_STARTDOC);
3182 goto end;
3185 CloseHandle(printer->doc->hf);
3186 ScheduleJob(hPrinter, printer->doc->job_id);
3187 HeapFree(GetProcessHeap(), 0, printer->doc);
3188 printer->doc = NULL;
3189 ret = TRUE;
3190 end:
3191 LeaveCriticalSection(&printer_handles_cs);
3192 return ret;
3195 /*****************************************************************************
3196 * EndPagePrinter [WINSPOOL.@]
3198 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3200 FIXME("(%p): stub\n", hPrinter);
3201 return TRUE;
3204 /*****************************************************************************
3205 * StartDocPrinterA [WINSPOOL.@]
3207 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3209 UNICODE_STRING usBuffer;
3210 DOC_INFO_2W doc2W;
3211 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3212 DWORD ret;
3214 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3215 or one (DOC_INFO_3) extra DWORDs */
3217 switch(Level) {
3218 case 2:
3219 doc2W.JobId = doc2->JobId;
3220 /* fall through */
3221 case 3:
3222 doc2W.dwMode = doc2->dwMode;
3223 /* fall through */
3224 case 1:
3225 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3226 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3227 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3228 break;
3230 default:
3231 SetLastError(ERROR_INVALID_LEVEL);
3232 return FALSE;
3235 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3237 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3238 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3239 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3241 return ret;
3244 /*****************************************************************************
3245 * StartDocPrinterW [WINSPOOL.@]
3247 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3249 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3250 opened_printer_t *printer;
3251 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3252 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3253 JOB_INFO_1W job_info;
3254 DWORD needed, ret = 0;
3255 HANDLE hf;
3256 WCHAR *filename;
3258 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3259 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3260 debugstr_w(doc->pDatatype));
3262 if(Level < 1 || Level > 3)
3264 SetLastError(ERROR_INVALID_LEVEL);
3265 return 0;
3268 EnterCriticalSection(&printer_handles_cs);
3269 printer = get_opened_printer(hPrinter);
3270 if(!printer)
3272 SetLastError(ERROR_INVALID_HANDLE);
3273 goto end;
3276 if(printer->doc)
3278 SetLastError(ERROR_INVALID_PRINTER_STATE);
3279 goto end;
3282 /* Even if we're printing to a file we still add a print job, we'll
3283 just ignore the spool file name */
3285 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3287 ERR("AddJob failed gle %u\n", GetLastError());
3288 goto end;
3291 if(doc->pOutputFile)
3292 filename = doc->pOutputFile;
3293 else
3294 filename = addjob->Path;
3296 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3297 if(hf == INVALID_HANDLE_VALUE)
3298 goto end;
3300 memset(&job_info, 0, sizeof(job_info));
3301 job_info.pDocument = doc->pDocName;
3302 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3304 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3305 printer->doc->hf = hf;
3306 ret = printer->doc->job_id = addjob->JobId;
3307 end:
3308 LeaveCriticalSection(&printer_handles_cs);
3310 return ret;
3313 /*****************************************************************************
3314 * StartPagePrinter [WINSPOOL.@]
3316 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3318 FIXME("(%p): stub\n", hPrinter);
3319 return TRUE;
3322 /*****************************************************************************
3323 * GetFormA [WINSPOOL.@]
3325 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3326 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3328 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3329 Level,pForm,cbBuf,pcbNeeded);
3330 return FALSE;
3333 /*****************************************************************************
3334 * GetFormW [WINSPOOL.@]
3336 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3337 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3339 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3340 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3341 return FALSE;
3344 /*****************************************************************************
3345 * SetFormA [WINSPOOL.@]
3347 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3348 LPBYTE pForm)
3350 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3351 return FALSE;
3354 /*****************************************************************************
3355 * SetFormW [WINSPOOL.@]
3357 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3358 LPBYTE pForm)
3360 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3361 return FALSE;
3364 /*****************************************************************************
3365 * ReadPrinter [WINSPOOL.@]
3367 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3368 LPDWORD pNoBytesRead)
3370 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3371 return FALSE;
3374 /*****************************************************************************
3375 * ResetPrinterA [WINSPOOL.@]
3377 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3379 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3380 return FALSE;
3383 /*****************************************************************************
3384 * ResetPrinterW [WINSPOOL.@]
3386 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3388 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3389 return FALSE;
3392 /*****************************************************************************
3393 * WINSPOOL_GetDWORDFromReg
3395 * Return DWORD associated with ValueName from hkey.
3397 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3399 DWORD sz = sizeof(DWORD), type, value = 0;
3400 LONG ret;
3402 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3404 if(ret != ERROR_SUCCESS) {
3405 WARN("Got ret = %d on name %s\n", ret, ValueName);
3406 return 0;
3408 if(type != REG_DWORD) {
3409 ERR("Got type %d\n", type);
3410 return 0;
3412 return value;
3415 /*****************************************************************************
3416 * WINSPOOL_GetStringFromReg
3418 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3419 * String is stored either as unicode or ascii.
3420 * Bit of a hack here to get the ValueName if we want ascii.
3422 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3423 DWORD buflen, DWORD *needed,
3424 BOOL unicode)
3426 DWORD sz = buflen, type;
3427 LONG ret;
3429 if(unicode)
3430 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3431 else {
3432 LPSTR ValueNameA = strdupWtoA(ValueName);
3433 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3434 HeapFree(GetProcessHeap(),0,ValueNameA);
3436 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3437 WARN("Got ret = %d\n", ret);
3438 *needed = 0;
3439 return FALSE;
3441 /* add space for terminating '\0' */
3442 sz += unicode ? sizeof(WCHAR) : 1;
3443 *needed = sz;
3445 if (ptr)
3446 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3448 return TRUE;
3451 /*****************************************************************************
3452 * WINSPOOL_GetDefaultDevMode
3454 * Get a default DevMode values for wineps.
3455 * FIXME - use ppd.
3458 static void WINSPOOL_GetDefaultDevMode(
3459 LPBYTE ptr,
3460 DWORD buflen, DWORD *needed,
3461 BOOL unicode)
3463 DEVMODEA dm;
3464 static const char szwps[] = "wineps.drv";
3466 /* fill default DEVMODE - should be read from ppd... */
3467 ZeroMemory( &dm, sizeof(dm) );
3468 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3469 dm.dmSpecVersion = DM_SPECVERSION;
3470 dm.dmDriverVersion = 1;
3471 dm.dmSize = sizeof(DEVMODEA);
3472 dm.dmDriverExtra = 0;
3473 dm.dmFields =
3474 DM_ORIENTATION | DM_PAPERSIZE |
3475 DM_PAPERLENGTH | DM_PAPERWIDTH |
3476 DM_SCALE |
3477 DM_COPIES |
3478 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3479 DM_YRESOLUTION | DM_TTOPTION;
3481 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3482 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3483 dm.u1.s1.dmPaperLength = 2970;
3484 dm.u1.s1.dmPaperWidth = 2100;
3486 dm.dmScale = 100;
3487 dm.dmCopies = 1;
3488 dm.dmDefaultSource = DMBIN_AUTO;
3489 dm.dmPrintQuality = DMRES_MEDIUM;
3490 /* dm.dmColor */
3491 /* dm.dmDuplex */
3492 dm.dmYResolution = 300; /* 300dpi */
3493 dm.dmTTOption = DMTT_BITMAP;
3494 /* dm.dmCollate */
3495 /* dm.dmFormName */
3496 /* dm.dmLogPixels */
3497 /* dm.dmBitsPerPel */
3498 /* dm.dmPelsWidth */
3499 /* dm.dmPelsHeight */
3500 /* dm.dmDisplayFlags */
3501 /* dm.dmDisplayFrequency */
3502 /* dm.dmICMMethod */
3503 /* dm.dmICMIntent */
3504 /* dm.dmMediaType */
3505 /* dm.dmDitherType */
3506 /* dm.dmReserved1 */
3507 /* dm.dmReserved2 */
3508 /* dm.dmPanningWidth */
3509 /* dm.dmPanningHeight */
3511 if(unicode) {
3512 if(buflen >= sizeof(DEVMODEW)) {
3513 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3514 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3515 HeapFree(GetProcessHeap(),0,pdmW);
3517 *needed = sizeof(DEVMODEW);
3519 else
3521 if(buflen >= sizeof(DEVMODEA)) {
3522 memcpy(ptr, &dm, sizeof(DEVMODEA));
3524 *needed = sizeof(DEVMODEA);
3528 /*****************************************************************************
3529 * WINSPOOL_GetDevModeFromReg
3531 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3532 * DevMode is stored either as unicode or ascii.
3534 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3535 LPBYTE ptr,
3536 DWORD buflen, DWORD *needed,
3537 BOOL unicode)
3539 DWORD sz = buflen, type;
3540 LONG ret;
3542 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3543 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3544 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3545 if (sz < sizeof(DEVMODEA))
3547 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3548 return FALSE;
3550 /* ensures that dmSize is not erratically bogus if registry is invalid */
3551 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3552 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3553 if(unicode) {
3554 sz += (CCHDEVICENAME + CCHFORMNAME);
3555 if(buflen >= sz) {
3556 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3557 memcpy(ptr, dmW, sz);
3558 HeapFree(GetProcessHeap(),0,dmW);
3561 *needed = sz;
3562 return TRUE;
3565 /*********************************************************************
3566 * WINSPOOL_GetPrinter_1
3568 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3569 * The strings are either stored as unicode or ascii.
3571 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3572 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3573 BOOL unicode)
3575 DWORD size, left = cbBuf;
3576 BOOL space = (cbBuf > 0);
3577 LPBYTE ptr = buf;
3579 *pcbNeeded = 0;
3581 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3582 unicode)) {
3583 if(space && size <= left) {
3584 pi1->pName = (LPWSTR)ptr;
3585 ptr += size;
3586 left -= size;
3587 } else
3588 space = FALSE;
3589 *pcbNeeded += size;
3592 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3593 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3594 unicode)) {
3595 if(space && size <= left) {
3596 pi1->pDescription = (LPWSTR)ptr;
3597 ptr += size;
3598 left -= size;
3599 } else
3600 space = FALSE;
3601 *pcbNeeded += size;
3604 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3605 unicode)) {
3606 if(space && size <= left) {
3607 pi1->pComment = (LPWSTR)ptr;
3608 ptr += size;
3609 left -= size;
3610 } else
3611 space = FALSE;
3612 *pcbNeeded += size;
3615 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3617 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3618 memset(pi1, 0, sizeof(*pi1));
3620 return space;
3622 /*********************************************************************
3623 * WINSPOOL_GetPrinter_2
3625 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3626 * The strings are either stored as unicode or ascii.
3628 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3629 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3630 BOOL unicode)
3632 DWORD size, left = cbBuf;
3633 BOOL space = (cbBuf > 0);
3634 LPBYTE ptr = buf;
3636 *pcbNeeded = 0;
3638 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3639 unicode)) {
3640 if(space && size <= left) {
3641 pi2->pPrinterName = (LPWSTR)ptr;
3642 ptr += size;
3643 left -= size;
3644 } else
3645 space = FALSE;
3646 *pcbNeeded += size;
3648 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3649 unicode)) {
3650 if(space && size <= left) {
3651 pi2->pShareName = (LPWSTR)ptr;
3652 ptr += size;
3653 left -= size;
3654 } else
3655 space = FALSE;
3656 *pcbNeeded += size;
3658 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3659 unicode)) {
3660 if(space && size <= left) {
3661 pi2->pPortName = (LPWSTR)ptr;
3662 ptr += size;
3663 left -= size;
3664 } else
3665 space = FALSE;
3666 *pcbNeeded += size;
3668 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3669 &size, unicode)) {
3670 if(space && size <= left) {
3671 pi2->pDriverName = (LPWSTR)ptr;
3672 ptr += size;
3673 left -= size;
3674 } else
3675 space = FALSE;
3676 *pcbNeeded += size;
3678 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3679 unicode)) {
3680 if(space && size <= left) {
3681 pi2->pComment = (LPWSTR)ptr;
3682 ptr += size;
3683 left -= size;
3684 } else
3685 space = FALSE;
3686 *pcbNeeded += size;
3688 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3689 unicode)) {
3690 if(space && size <= left) {
3691 pi2->pLocation = (LPWSTR)ptr;
3692 ptr += size;
3693 left -= size;
3694 } else
3695 space = FALSE;
3696 *pcbNeeded += size;
3698 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3699 &size, unicode)) {
3700 if(space && size <= left) {
3701 pi2->pDevMode = (LPDEVMODEW)ptr;
3702 ptr += size;
3703 left -= size;
3704 } else
3705 space = FALSE;
3706 *pcbNeeded += size;
3708 else
3710 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3711 if(space && size <= left) {
3712 pi2->pDevMode = (LPDEVMODEW)ptr;
3713 ptr += size;
3714 left -= size;
3715 } else
3716 space = FALSE;
3717 *pcbNeeded += size;
3719 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3720 &size, unicode)) {
3721 if(space && size <= left) {
3722 pi2->pSepFile = (LPWSTR)ptr;
3723 ptr += size;
3724 left -= size;
3725 } else
3726 space = FALSE;
3727 *pcbNeeded += size;
3729 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3730 &size, unicode)) {
3731 if(space && size <= left) {
3732 pi2->pPrintProcessor = (LPWSTR)ptr;
3733 ptr += size;
3734 left -= size;
3735 } else
3736 space = FALSE;
3737 *pcbNeeded += size;
3739 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3740 &size, unicode)) {
3741 if(space && size <= left) {
3742 pi2->pDatatype = (LPWSTR)ptr;
3743 ptr += size;
3744 left -= size;
3745 } else
3746 space = FALSE;
3747 *pcbNeeded += size;
3749 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3750 &size, unicode)) {
3751 if(space && size <= left) {
3752 pi2->pParameters = (LPWSTR)ptr;
3753 ptr += size;
3754 left -= size;
3755 } else
3756 space = FALSE;
3757 *pcbNeeded += size;
3759 if(pi2) {
3760 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3761 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3762 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3763 "Default Priority");
3764 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3765 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3768 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3769 memset(pi2, 0, sizeof(*pi2));
3771 return space;
3774 /*********************************************************************
3775 * WINSPOOL_GetPrinter_4
3777 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3779 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3780 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3781 BOOL unicode)
3783 DWORD size, left = cbBuf;
3784 BOOL space = (cbBuf > 0);
3785 LPBYTE ptr = buf;
3787 *pcbNeeded = 0;
3789 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3790 unicode)) {
3791 if(space && size <= left) {
3792 pi4->pPrinterName = (LPWSTR)ptr;
3793 ptr += size;
3794 left -= size;
3795 } else
3796 space = FALSE;
3797 *pcbNeeded += size;
3799 if(pi4) {
3800 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3803 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3804 memset(pi4, 0, sizeof(*pi4));
3806 return space;
3809 /*********************************************************************
3810 * WINSPOOL_GetPrinter_5
3812 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3814 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3815 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3816 BOOL unicode)
3818 DWORD size, left = cbBuf;
3819 BOOL space = (cbBuf > 0);
3820 LPBYTE ptr = buf;
3822 *pcbNeeded = 0;
3824 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3825 unicode)) {
3826 if(space && size <= left) {
3827 pi5->pPrinterName = (LPWSTR)ptr;
3828 ptr += size;
3829 left -= size;
3830 } else
3831 space = FALSE;
3832 *pcbNeeded += size;
3834 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3835 unicode)) {
3836 if(space && size <= left) {
3837 pi5->pPortName = (LPWSTR)ptr;
3838 ptr += size;
3839 left -= size;
3840 } else
3841 space = FALSE;
3842 *pcbNeeded += size;
3844 if(pi5) {
3845 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3846 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3847 "dnsTimeout");
3848 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3849 "txTimeout");
3852 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3853 memset(pi5, 0, sizeof(*pi5));
3855 return space;
3858 /*****************************************************************************
3859 * WINSPOOL_GetPrinter
3861 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3862 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3863 * just a collection of pointers to strings.
3865 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3866 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3868 LPCWSTR name;
3869 DWORD size, needed = 0;
3870 LPBYTE ptr = NULL;
3871 HKEY hkeyPrinter, hkeyPrinters;
3872 BOOL ret;
3874 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3876 if (!(name = get_opened_printer_name(hPrinter))) {
3877 SetLastError(ERROR_INVALID_HANDLE);
3878 return FALSE;
3881 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3882 ERROR_SUCCESS) {
3883 ERR("Can't create Printers key\n");
3884 return FALSE;
3886 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3888 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3889 RegCloseKey(hkeyPrinters);
3890 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3891 return FALSE;
3894 switch(Level) {
3895 case 2:
3897 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3899 size = sizeof(PRINTER_INFO_2W);
3900 if(size <= cbBuf) {
3901 ptr = pPrinter + size;
3902 cbBuf -= size;
3903 memset(pPrinter, 0, size);
3904 } else {
3905 pi2 = NULL;
3906 cbBuf = 0;
3908 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3909 unicode);
3910 needed += size;
3911 break;
3914 case 4:
3916 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3918 size = sizeof(PRINTER_INFO_4W);
3919 if(size <= cbBuf) {
3920 ptr = pPrinter + size;
3921 cbBuf -= size;
3922 memset(pPrinter, 0, size);
3923 } else {
3924 pi4 = NULL;
3925 cbBuf = 0;
3927 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3928 unicode);
3929 needed += size;
3930 break;
3934 case 5:
3936 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3938 size = sizeof(PRINTER_INFO_5W);
3939 if(size <= cbBuf) {
3940 ptr = pPrinter + size;
3941 cbBuf -= size;
3942 memset(pPrinter, 0, size);
3943 } else {
3944 pi5 = NULL;
3945 cbBuf = 0;
3948 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3949 unicode);
3950 needed += size;
3951 break;
3954 default:
3955 FIXME("Unimplemented level %d\n", Level);
3956 SetLastError(ERROR_INVALID_LEVEL);
3957 RegCloseKey(hkeyPrinters);
3958 RegCloseKey(hkeyPrinter);
3959 return FALSE;
3962 RegCloseKey(hkeyPrinter);
3963 RegCloseKey(hkeyPrinters);
3965 TRACE("returning %d needed = %d\n", ret, needed);
3966 if(pcbNeeded) *pcbNeeded = needed;
3967 if(!ret)
3968 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3969 return ret;
3972 /*****************************************************************************
3973 * GetPrinterW [WINSPOOL.@]
3975 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3976 DWORD cbBuf, LPDWORD pcbNeeded)
3978 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3979 TRUE);
3982 /*****************************************************************************
3983 * GetPrinterA [WINSPOOL.@]
3985 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3986 DWORD cbBuf, LPDWORD pcbNeeded)
3988 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3989 FALSE);
3992 /*****************************************************************************
3993 * WINSPOOL_EnumPrinters
3995 * Implementation of EnumPrintersA|W
3997 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3998 DWORD dwLevel, LPBYTE lpbPrinters,
3999 DWORD cbBuf, LPDWORD lpdwNeeded,
4000 LPDWORD lpdwReturned, BOOL unicode)
4003 HKEY hkeyPrinters, hkeyPrinter;
4004 WCHAR PrinterName[255];
4005 DWORD needed = 0, number = 0;
4006 DWORD used, i, left;
4007 PBYTE pi, buf;
4009 if(lpbPrinters)
4010 memset(lpbPrinters, 0, cbBuf);
4011 if(lpdwReturned)
4012 *lpdwReturned = 0;
4013 if(lpdwNeeded)
4014 *lpdwNeeded = 0;
4016 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4017 if(dwType == PRINTER_ENUM_DEFAULT)
4018 return TRUE;
4020 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4021 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4022 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4023 if (!dwType) {
4024 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4025 *lpdwNeeded = 0;
4026 *lpdwReturned = 0;
4027 return TRUE;
4032 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4033 FIXME("dwType = %08x\n", dwType);
4034 SetLastError(ERROR_INVALID_FLAGS);
4035 return FALSE;
4038 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4039 ERROR_SUCCESS) {
4040 ERR("Can't create Printers key\n");
4041 return FALSE;
4044 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4045 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4046 RegCloseKey(hkeyPrinters);
4047 ERR("Can't query Printers key\n");
4048 return FALSE;
4050 TRACE("Found %d printers\n", number);
4052 switch(dwLevel) {
4053 case 1:
4054 used = number * sizeof(PRINTER_INFO_1W);
4055 break;
4056 case 2:
4057 used = number * sizeof(PRINTER_INFO_2W);
4058 break;
4059 case 4:
4060 used = number * sizeof(PRINTER_INFO_4W);
4061 break;
4062 case 5:
4063 used = number * sizeof(PRINTER_INFO_5W);
4064 break;
4066 default:
4067 SetLastError(ERROR_INVALID_LEVEL);
4068 RegCloseKey(hkeyPrinters);
4069 return FALSE;
4071 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4073 for(i = 0; i < number; i++) {
4074 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4075 ERROR_SUCCESS) {
4076 ERR("Can't enum key number %d\n", i);
4077 RegCloseKey(hkeyPrinters);
4078 return FALSE;
4080 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4081 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4082 ERROR_SUCCESS) {
4083 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4084 RegCloseKey(hkeyPrinters);
4085 return FALSE;
4088 if(cbBuf > used) {
4089 buf = lpbPrinters + used;
4090 left = cbBuf - used;
4091 } else {
4092 buf = NULL;
4093 left = 0;
4096 switch(dwLevel) {
4097 case 1:
4098 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4099 left, &needed, unicode);
4100 used += needed;
4101 if(pi) pi += sizeof(PRINTER_INFO_1W);
4102 break;
4103 case 2:
4104 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4105 left, &needed, unicode);
4106 used += needed;
4107 if(pi) pi += sizeof(PRINTER_INFO_2W);
4108 break;
4109 case 4:
4110 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4111 left, &needed, unicode);
4112 used += needed;
4113 if(pi) pi += sizeof(PRINTER_INFO_4W);
4114 break;
4115 case 5:
4116 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4117 left, &needed, unicode);
4118 used += needed;
4119 if(pi) pi += sizeof(PRINTER_INFO_5W);
4120 break;
4121 default:
4122 ERR("Shouldn't be here!\n");
4123 RegCloseKey(hkeyPrinter);
4124 RegCloseKey(hkeyPrinters);
4125 return FALSE;
4127 RegCloseKey(hkeyPrinter);
4129 RegCloseKey(hkeyPrinters);
4131 if(lpdwNeeded)
4132 *lpdwNeeded = used;
4134 if(used > cbBuf) {
4135 if(lpbPrinters)
4136 memset(lpbPrinters, 0, cbBuf);
4137 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4138 return FALSE;
4140 if(lpdwReturned)
4141 *lpdwReturned = number;
4142 SetLastError(ERROR_SUCCESS);
4143 return TRUE;
4147 /******************************************************************
4148 * EnumPrintersW [WINSPOOL.@]
4150 * Enumerates the available printers, print servers and print
4151 * providers, depending on the specified flags, name and level.
4153 * RETURNS:
4155 * If level is set to 1:
4156 * Returns an array of PRINTER_INFO_1 data structures in the
4157 * lpbPrinters buffer.
4159 * If level is set to 2:
4160 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4161 * Returns an array of PRINTER_INFO_2 data structures in the
4162 * lpbPrinters buffer. Note that according to MSDN also an
4163 * OpenPrinter should be performed on every remote printer.
4165 * If level is set to 4 (officially WinNT only):
4166 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4167 * Fast: Only the registry is queried to retrieve printer names,
4168 * no connection to the driver is made.
4169 * Returns an array of PRINTER_INFO_4 data structures in the
4170 * lpbPrinters buffer.
4172 * If level is set to 5 (officially WinNT4/Win9x only):
4173 * Fast: Only the registry is queried to retrieve printer names,
4174 * no connection to the driver is made.
4175 * Returns an array of PRINTER_INFO_5 data structures in the
4176 * lpbPrinters buffer.
4178 * If level set to 3 or 6+:
4179 * returns zero (failure!)
4181 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4182 * for information.
4184 * BUGS:
4185 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4186 * - Only levels 2, 4 and 5 are implemented at the moment.
4187 * - 16-bit printer drivers are not enumerated.
4188 * - Returned amount of bytes used/needed does not match the real Windoze
4189 * implementation (as in this implementation, all strings are part
4190 * of the buffer, whereas Win32 keeps them somewhere else)
4191 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4193 * NOTE:
4194 * - In a regular Wine installation, no registry settings for printers
4195 * exist, which makes this function return an empty list.
4197 BOOL WINAPI EnumPrintersW(
4198 DWORD dwType, /* [in] Types of print objects to enumerate */
4199 LPWSTR lpszName, /* [in] name of objects to enumerate */
4200 DWORD dwLevel, /* [in] type of printer info structure */
4201 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4202 DWORD cbBuf, /* [in] max size of buffer in bytes */
4203 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4204 LPDWORD lpdwReturned /* [out] number of entries returned */
4207 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4208 lpdwNeeded, lpdwReturned, TRUE);
4211 /******************************************************************
4212 * EnumPrintersA [WINSPOOL.@]
4215 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4216 DWORD dwLevel, LPBYTE lpbPrinters,
4217 DWORD cbBuf, LPDWORD lpdwNeeded,
4218 LPDWORD lpdwReturned)
4220 BOOL ret, unicode = FALSE;
4221 UNICODE_STRING lpszNameW;
4222 PWSTR pwstrNameW;
4224 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4225 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4226 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4227 lpdwNeeded, lpdwReturned, unicode);
4228 RtlFreeUnicodeString(&lpszNameW);
4229 return ret;
4232 /*****************************************************************************
4233 * WINSPOOL_GetDriverInfoFromReg [internal]
4235 * Enters the information from the registry into the DRIVER_INFO struct
4237 * RETURNS
4238 * zero if the printer driver does not exist in the registry
4239 * (only if Level > 1) otherwise nonzero
4241 static BOOL WINSPOOL_GetDriverInfoFromReg(
4242 HKEY hkeyDrivers,
4243 LPWSTR DriverName,
4244 LPCWSTR pEnvironment,
4245 DWORD Level,
4246 LPBYTE ptr, /* DRIVER_INFO */
4247 LPBYTE pDriverStrings, /* strings buffer */
4248 DWORD cbBuf, /* size of string buffer */
4249 LPDWORD pcbNeeded, /* space needed for str. */
4250 BOOL unicode) /* type of strings */
4252 DWORD size, tmp;
4253 HKEY hkeyDriver;
4254 LPBYTE strPtr = pDriverStrings;
4256 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4257 debugstr_w(DriverName), debugstr_w(pEnvironment),
4258 Level, ptr, pDriverStrings, cbBuf, unicode);
4260 if(unicode) {
4261 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4262 if (*pcbNeeded <= cbBuf)
4263 strcpyW((LPWSTR)strPtr, DriverName);
4264 } else {
4265 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4266 NULL, NULL);
4267 if(*pcbNeeded <= cbBuf)
4268 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4269 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4271 if(Level == 1) {
4272 if(ptr)
4273 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4274 return TRUE;
4275 } else {
4276 if(ptr)
4277 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4278 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4281 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4282 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4283 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4284 return FALSE;
4287 if(ptr)
4288 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4290 if(!pEnvironment)
4291 pEnvironment = DefaultEnvironmentW;
4292 if(unicode)
4293 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4294 else
4295 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4296 NULL, NULL);
4297 *pcbNeeded += size;
4298 if(*pcbNeeded <= cbBuf) {
4299 if(unicode)
4300 strcpyW((LPWSTR)strPtr, pEnvironment);
4301 else
4302 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4303 (LPSTR)strPtr, size, NULL, NULL);
4304 if(ptr)
4305 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4306 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4309 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4310 unicode)) {
4311 *pcbNeeded += size;
4312 if(*pcbNeeded <= cbBuf)
4313 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4314 unicode);
4315 if(ptr)
4316 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4317 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4320 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4321 unicode)) {
4322 *pcbNeeded += size;
4323 if(*pcbNeeded <= cbBuf)
4324 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4325 &tmp, unicode);
4326 if(ptr)
4327 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4328 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4331 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4332 0, &size, unicode)) {
4333 *pcbNeeded += size;
4334 if(*pcbNeeded <= cbBuf)
4335 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4336 size, &tmp, unicode);
4337 if(ptr)
4338 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4339 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4342 if(Level == 2 ) {
4343 RegCloseKey(hkeyDriver);
4344 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4345 return TRUE;
4348 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4349 unicode)) {
4350 *pcbNeeded += size;
4351 if(*pcbNeeded <= cbBuf)
4352 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4353 size, &tmp, unicode);
4354 if(ptr)
4355 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4356 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4359 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4360 &size, unicode)) {
4361 *pcbNeeded += size;
4362 if(*pcbNeeded <= cbBuf)
4363 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4364 size, &tmp, unicode);
4365 if(ptr)
4366 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4367 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4370 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4371 unicode)) {
4372 *pcbNeeded += size;
4373 if(*pcbNeeded <= cbBuf)
4374 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4375 size, &tmp, unicode);
4376 if(ptr)
4377 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4378 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4381 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4382 unicode)) {
4383 *pcbNeeded += size;
4384 if(*pcbNeeded <= cbBuf)
4385 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4386 size, &tmp, unicode);
4387 if(ptr)
4388 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4389 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4392 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4393 RegCloseKey(hkeyDriver);
4394 return TRUE;
4397 /*****************************************************************************
4398 * WINSPOOL_GetPrinterDriver
4400 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4401 DWORD Level, LPBYTE pDriverInfo,
4402 DWORD cbBuf, LPDWORD pcbNeeded,
4403 BOOL unicode)
4405 LPCWSTR name;
4406 WCHAR DriverName[100];
4407 DWORD ret, type, size, needed = 0;
4408 LPBYTE ptr = NULL;
4409 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4411 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4412 Level,pDriverInfo,cbBuf, pcbNeeded);
4414 ZeroMemory(pDriverInfo, cbBuf);
4416 if (!(name = get_opened_printer_name(hPrinter))) {
4417 SetLastError(ERROR_INVALID_HANDLE);
4418 return FALSE;
4420 if(Level < 1 || Level > 6) {
4421 SetLastError(ERROR_INVALID_LEVEL);
4422 return FALSE;
4424 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4425 ERROR_SUCCESS) {
4426 ERR("Can't create Printers key\n");
4427 return FALSE;
4429 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4430 != ERROR_SUCCESS) {
4431 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4432 RegCloseKey(hkeyPrinters);
4433 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4434 return FALSE;
4436 size = sizeof(DriverName);
4437 DriverName[0] = 0;
4438 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4439 (LPBYTE)DriverName, &size);
4440 RegCloseKey(hkeyPrinter);
4441 RegCloseKey(hkeyPrinters);
4442 if(ret != ERROR_SUCCESS) {
4443 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4444 return FALSE;
4447 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4448 if(!hkeyDrivers) {
4449 ERR("Can't create Drivers key\n");
4450 return FALSE;
4453 switch(Level) {
4454 case 1:
4455 size = sizeof(DRIVER_INFO_1W);
4456 break;
4457 case 2:
4458 size = sizeof(DRIVER_INFO_2W);
4459 break;
4460 case 3:
4461 size = sizeof(DRIVER_INFO_3W);
4462 break;
4463 case 4:
4464 size = sizeof(DRIVER_INFO_4W);
4465 break;
4466 case 5:
4467 size = sizeof(DRIVER_INFO_5W);
4468 break;
4469 case 6:
4470 size = sizeof(DRIVER_INFO_6W);
4471 break;
4472 default:
4473 ERR("Invalid level\n");
4474 return FALSE;
4477 if(size <= cbBuf)
4478 ptr = pDriverInfo + size;
4480 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4481 pEnvironment, Level, pDriverInfo,
4482 (cbBuf < size) ? NULL : ptr,
4483 (cbBuf < size) ? 0 : cbBuf - size,
4484 &needed, unicode)) {
4485 RegCloseKey(hkeyDrivers);
4486 return FALSE;
4489 RegCloseKey(hkeyDrivers);
4491 if(pcbNeeded) *pcbNeeded = size + needed;
4492 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4493 if(cbBuf >= needed) return TRUE;
4494 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4495 return FALSE;
4498 /*****************************************************************************
4499 * GetPrinterDriverA [WINSPOOL.@]
4501 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4502 DWORD Level, LPBYTE pDriverInfo,
4503 DWORD cbBuf, LPDWORD pcbNeeded)
4505 BOOL ret;
4506 UNICODE_STRING pEnvW;
4507 PWSTR pwstrEnvW;
4509 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4510 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4511 cbBuf, pcbNeeded, FALSE);
4512 RtlFreeUnicodeString(&pEnvW);
4513 return ret;
4515 /*****************************************************************************
4516 * GetPrinterDriverW [WINSPOOL.@]
4518 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4519 DWORD Level, LPBYTE pDriverInfo,
4520 DWORD cbBuf, LPDWORD pcbNeeded)
4522 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4523 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4526 /*****************************************************************************
4527 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4529 * Return the PATH for the Printer-Drivers (UNICODE)
4531 * PARAMS
4532 * pName [I] Servername (NT only) or NULL (local Computer)
4533 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4534 * Level [I] Structure-Level (must be 1)
4535 * pDriverDirectory [O] PTR to Buffer that receives the Result
4536 * cbBuf [I] Size of Buffer at pDriverDirectory
4537 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4538 * required for pDriverDirectory
4540 * RETURNS
4541 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4542 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4543 * if cbBuf is too small
4545 * Native Values returned in pDriverDirectory on Success:
4546 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4547 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4548 *| win9x(Windows 4.0): "%winsysdir%"
4550 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4552 * FIXME
4553 *- Only NULL or "" is supported for pName
4556 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4557 DWORD Level, LPBYTE pDriverDirectory,
4558 DWORD cbBuf, LPDWORD pcbNeeded)
4560 DWORD needed;
4561 const printenv_t * env;
4563 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4564 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4565 if(pName != NULL && pName[0]) {
4566 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4567 SetLastError(ERROR_INVALID_PARAMETER);
4568 return FALSE;
4571 env = validate_envW(pEnvironment);
4572 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4574 if(Level != 1) {
4575 WARN("(Level: %d) is ignored in win9x\n", Level);
4576 SetLastError(ERROR_INVALID_LEVEL);
4577 return FALSE;
4580 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4581 needed = GetSystemDirectoryW(NULL, 0);
4582 /* add the Size for the Subdirectories */
4583 needed += lstrlenW(spooldriversW);
4584 needed += lstrlenW(env->subdir);
4585 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4587 if(pcbNeeded)
4588 *pcbNeeded = needed;
4589 TRACE("required: 0x%x/%d\n", needed, needed);
4590 if(needed > cbBuf) {
4591 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4592 return FALSE;
4594 if(pcbNeeded == NULL) {
4595 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4596 SetLastError(RPC_X_NULL_REF_POINTER);
4597 return FALSE;
4599 if(pDriverDirectory == NULL) {
4600 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4601 SetLastError(ERROR_INVALID_USER_BUFFER);
4602 return FALSE;
4605 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4606 /* add the Subdirectories */
4607 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4608 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4609 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4610 return TRUE;
4614 /*****************************************************************************
4615 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4617 * Return the PATH for the Printer-Drivers (ANSI)
4619 * See GetPrinterDriverDirectoryW.
4621 * NOTES
4622 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4625 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4626 DWORD Level, LPBYTE pDriverDirectory,
4627 DWORD cbBuf, LPDWORD pcbNeeded)
4629 UNICODE_STRING nameW, environmentW;
4630 BOOL ret;
4631 DWORD pcbNeededW;
4632 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4633 WCHAR *driverDirectoryW = NULL;
4635 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4636 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4638 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4640 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4641 else nameW.Buffer = NULL;
4642 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4643 else environmentW.Buffer = NULL;
4645 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4646 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4647 if (ret) {
4648 DWORD needed;
4649 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4650 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4651 if(pcbNeeded)
4652 *pcbNeeded = needed;
4653 ret = (needed <= cbBuf) ? TRUE : FALSE;
4654 } else
4655 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4657 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4659 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4660 RtlFreeUnicodeString(&environmentW);
4661 RtlFreeUnicodeString(&nameW);
4663 return ret;
4666 /*****************************************************************************
4667 * AddPrinterDriverA [WINSPOOL.@]
4669 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4671 DRIVER_INFO_3A di3;
4672 HKEY hkeyDrivers, hkeyName;
4673 static CHAR empty[] = "",
4674 nullnull[] = "\0";
4676 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4678 if(level != 2 && level != 3) {
4679 SetLastError(ERROR_INVALID_LEVEL);
4680 return FALSE;
4682 if ((pName) && (pName[0])) {
4683 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4684 SetLastError(ERROR_INVALID_PARAMETER);
4685 return FALSE;
4687 if(!pDriverInfo) {
4688 WARN("pDriverInfo == NULL\n");
4689 SetLastError(ERROR_INVALID_PARAMETER);
4690 return FALSE;
4693 if(level == 3)
4694 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4695 else {
4696 memset(&di3, 0, sizeof(di3));
4697 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4700 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4701 !di3.pDataFile) {
4702 SetLastError(ERROR_INVALID_PARAMETER);
4703 return FALSE;
4706 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4707 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4708 if(!di3.pHelpFile) di3.pHelpFile = empty;
4709 if(!di3.pMonitorName) di3.pMonitorName = empty;
4711 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4713 if(!hkeyDrivers) {
4714 ERR("Can't create Drivers key\n");
4715 return FALSE;
4718 if(level == 2) { /* apparently can't overwrite with level2 */
4719 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4720 RegCloseKey(hkeyName);
4721 RegCloseKey(hkeyDrivers);
4722 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4723 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4724 return FALSE;
4727 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4728 RegCloseKey(hkeyDrivers);
4729 ERR("Can't create Name key\n");
4730 return FALSE;
4732 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4733 lstrlenA(di3.pConfigFile) + 1);
4734 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4735 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4736 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4737 sizeof(DWORD));
4738 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4739 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4740 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4741 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4742 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4743 RegCloseKey(hkeyName);
4744 RegCloseKey(hkeyDrivers);
4746 return TRUE;
4749 /*****************************************************************************
4750 * AddPrinterDriverW [WINSPOOL.@]
4752 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4753 LPBYTE pDriverInfo)
4755 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4756 level,pDriverInfo);
4757 return FALSE;
4760 /*****************************************************************************
4761 * AddPrintProcessorA [WINSPOOL.@]
4763 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4764 LPSTR pPrintProcessorName)
4766 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4767 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4768 return FALSE;
4771 /*****************************************************************************
4772 * AddPrintProcessorW [WINSPOOL.@]
4774 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4775 LPWSTR pPrintProcessorName)
4777 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4778 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4779 return FALSE;
4782 /*****************************************************************************
4783 * AddPrintProvidorA [WINSPOOL.@]
4785 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4787 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4788 return FALSE;
4791 /*****************************************************************************
4792 * AddPrintProvidorW [WINSPOOL.@]
4794 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4796 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4797 return FALSE;
4800 /*****************************************************************************
4801 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4803 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4804 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4806 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4807 pDevModeOutput, pDevModeInput);
4808 return 0;
4811 /*****************************************************************************
4812 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4814 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4815 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4817 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4818 pDevModeOutput, pDevModeInput);
4819 return 0;
4822 /*****************************************************************************
4823 * PrinterProperties [WINSPOOL.@]
4825 * Displays a dialog to set the properties of the printer.
4827 * RETURNS
4828 * nonzero on success or zero on failure
4830 * BUGS
4831 * implemented as stub only
4833 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4834 HANDLE hPrinter /* [in] handle to printer object */
4836 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4837 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4838 return FALSE;
4841 /*****************************************************************************
4842 * EnumJobsA [WINSPOOL.@]
4845 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4846 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4847 LPDWORD pcReturned)
4849 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4850 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4852 if(pcbNeeded) *pcbNeeded = 0;
4853 if(pcReturned) *pcReturned = 0;
4854 return FALSE;
4858 /*****************************************************************************
4859 * EnumJobsW [WINSPOOL.@]
4862 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4863 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4864 LPDWORD pcReturned)
4866 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4867 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4869 if(pcbNeeded) *pcbNeeded = 0;
4870 if(pcReturned) *pcReturned = 0;
4871 return FALSE;
4874 /*****************************************************************************
4875 * WINSPOOL_EnumPrinterDrivers [internal]
4877 * Delivers information about all printer drivers installed on the
4878 * localhost or a given server
4880 * RETURNS
4881 * nonzero on success or zero on failure. If the buffer for the returned
4882 * information is too small the function will return an error
4884 * BUGS
4885 * - only implemented for localhost, foreign hosts will return an error
4887 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4888 DWORD Level, LPBYTE pDriverInfo,
4889 DWORD cbBuf, LPDWORD pcbNeeded,
4890 LPDWORD pcReturned, BOOL unicode)
4892 { HKEY hkeyDrivers;
4893 DWORD i, needed, number = 0, size = 0;
4894 WCHAR DriverNameW[255];
4895 PBYTE ptr;
4897 TRACE("%s,%s,%d,%p,%d,%d\n",
4898 debugstr_w(pName), debugstr_w(pEnvironment),
4899 Level, pDriverInfo, cbBuf, unicode);
4901 /* check for local drivers */
4902 if((pName) && (pName[0])) {
4903 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4904 SetLastError(ERROR_ACCESS_DENIED);
4905 return FALSE;
4908 /* check input parameter */
4909 if((Level < 1) || (Level > 3)) {
4910 ERR("unsupported level %d\n", Level);
4911 SetLastError(ERROR_INVALID_LEVEL);
4912 return FALSE;
4915 /* initialize return values */
4916 if(pDriverInfo)
4917 memset( pDriverInfo, 0, cbBuf);
4918 *pcbNeeded = 0;
4919 *pcReturned = 0;
4921 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4922 if(!hkeyDrivers) {
4923 ERR("Can't open Drivers key\n");
4924 return FALSE;
4927 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4928 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4929 RegCloseKey(hkeyDrivers);
4930 ERR("Can't query Drivers key\n");
4931 return FALSE;
4933 TRACE("Found %d Drivers\n", number);
4935 /* get size of single struct
4936 * unicode and ascii structure have the same size
4938 switch (Level) {
4939 case 1:
4940 size = sizeof(DRIVER_INFO_1A);
4941 break;
4942 case 2:
4943 size = sizeof(DRIVER_INFO_2A);
4944 break;
4945 case 3:
4946 size = sizeof(DRIVER_INFO_3A);
4947 break;
4950 /* calculate required buffer size */
4951 *pcbNeeded = size * number;
4953 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4954 i < number;
4955 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4956 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4957 != ERROR_SUCCESS) {
4958 ERR("Can't enum key number %d\n", i);
4959 RegCloseKey(hkeyDrivers);
4960 return FALSE;
4962 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4963 pEnvironment, Level, ptr,
4964 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4965 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4966 &needed, unicode)) {
4967 RegCloseKey(hkeyDrivers);
4968 return FALSE;
4970 (*pcbNeeded) += needed;
4973 RegCloseKey(hkeyDrivers);
4975 if(cbBuf < *pcbNeeded){
4976 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4977 return FALSE;
4980 *pcReturned = number;
4981 return TRUE;
4984 /*****************************************************************************
4985 * EnumPrinterDriversW [WINSPOOL.@]
4987 * see function EnumPrinterDrivers for RETURNS, BUGS
4989 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4990 LPBYTE pDriverInfo, DWORD cbBuf,
4991 LPDWORD pcbNeeded, LPDWORD pcReturned)
4993 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4994 cbBuf, pcbNeeded, pcReturned, TRUE);
4997 /*****************************************************************************
4998 * EnumPrinterDriversA [WINSPOOL.@]
5000 * see function EnumPrinterDrivers for RETURNS, BUGS
5002 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5003 LPBYTE pDriverInfo, DWORD cbBuf,
5004 LPDWORD pcbNeeded, LPDWORD pcReturned)
5005 { BOOL ret;
5006 UNICODE_STRING pNameW, pEnvironmentW;
5007 PWSTR pwstrNameW, pwstrEnvironmentW;
5009 pwstrNameW = asciitounicode(&pNameW, pName);
5010 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5012 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5013 Level, pDriverInfo, cbBuf, pcbNeeded,
5014 pcReturned, FALSE);
5015 RtlFreeUnicodeString(&pNameW);
5016 RtlFreeUnicodeString(&pEnvironmentW);
5018 return ret;
5021 /******************************************************************************
5022 * EnumPortsA (WINSPOOL.@)
5024 * See EnumPortsW.
5027 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5028 LPDWORD pcbNeeded, LPDWORD pcReturned)
5030 BOOL res;
5031 LPBYTE bufferW = NULL;
5032 LPWSTR nameW = NULL;
5033 DWORD needed = 0;
5034 DWORD numentries = 0;
5035 INT len;
5037 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5038 cbBuf, pcbNeeded, pcReturned);
5040 /* convert servername to unicode */
5041 if (pName) {
5042 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5043 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5044 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5046 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5047 needed = cbBuf * sizeof(WCHAR);
5048 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5049 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5051 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5052 if (pcbNeeded) needed = *pcbNeeded;
5053 /* HeapReAlloc return NULL, when bufferW was NULL */
5054 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5055 HeapAlloc(GetProcessHeap(), 0, needed);
5057 /* Try again with the large Buffer */
5058 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5060 needed = pcbNeeded ? *pcbNeeded : 0;
5061 numentries = pcReturned ? *pcReturned : 0;
5064 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5065 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5067 if (res) {
5068 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5069 DWORD entrysize = 0;
5070 DWORD index;
5071 LPSTR ptr;
5072 LPPORT_INFO_2W pi2w;
5073 LPPORT_INFO_2A pi2a;
5075 needed = 0;
5076 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5078 /* First pass: calculate the size for all Entries */
5079 pi2w = (LPPORT_INFO_2W) bufferW;
5080 pi2a = (LPPORT_INFO_2A) pPorts;
5081 index = 0;
5082 while (index < numentries) {
5083 index++;
5084 needed += entrysize; /* PORT_INFO_?A */
5085 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5087 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5088 NULL, 0, NULL, NULL);
5089 if (Level > 1) {
5090 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5091 NULL, 0, NULL, NULL);
5092 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5093 NULL, 0, NULL, NULL);
5095 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5096 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5097 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5100 /* check for errors and quit on failure */
5101 if (cbBuf < needed) {
5102 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5103 res = FALSE;
5104 goto cleanup;
5106 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5107 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5108 cbBuf -= len ; /* free Bytes in the user-Buffer */
5109 pi2w = (LPPORT_INFO_2W) bufferW;
5110 pi2a = (LPPORT_INFO_2A) pPorts;
5111 index = 0;
5112 /* Second Pass: Fill the User Buffer (if we have one) */
5113 while ((index < numentries) && pPorts) {
5114 index++;
5115 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5116 pi2a->pPortName = ptr;
5117 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5118 ptr, cbBuf , NULL, NULL);
5119 ptr += len;
5120 cbBuf -= len;
5121 if (Level > 1) {
5122 pi2a->pMonitorName = ptr;
5123 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5124 ptr, cbBuf, NULL, NULL);
5125 ptr += len;
5126 cbBuf -= len;
5128 pi2a->pDescription = ptr;
5129 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5130 ptr, cbBuf, NULL, NULL);
5131 ptr += len;
5132 cbBuf -= len;
5134 pi2a->fPortType = pi2w->fPortType;
5135 pi2a->Reserved = 0; /* documented: "must be zero" */
5138 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5139 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5140 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5144 cleanup:
5145 if (pcbNeeded) *pcbNeeded = needed;
5146 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5148 HeapFree(GetProcessHeap(), 0, nameW);
5149 HeapFree(GetProcessHeap(), 0, bufferW);
5151 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5152 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5154 return (res);
5158 /******************************************************************************
5159 * EnumPortsW (WINSPOOL.@)
5161 * Enumerate available Ports
5163 * PARAMS
5164 * name [I] Servername or NULL (local Computer)
5165 * level [I] Structure-Level (1 or 2)
5166 * buffer [O] PTR to Buffer that receives the Result
5167 * bufsize [I] Size of Buffer at buffer
5168 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5169 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5171 * RETURNS
5172 * Success: TRUE
5173 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5177 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5179 DWORD needed = 0;
5180 DWORD numentries = 0;
5181 BOOL res = FALSE;
5183 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5184 cbBuf, pcbNeeded, pcReturned);
5186 if (pName && (pName[0])) {
5187 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5188 SetLastError(ERROR_ACCESS_DENIED);
5189 goto emP_cleanup;
5192 /* Level is not checked in win9x */
5193 if (!Level || (Level > 2)) {
5194 WARN("level (%d) is ignored in win9x\n", Level);
5195 SetLastError(ERROR_INVALID_LEVEL);
5196 goto emP_cleanup;
5198 if (!pcbNeeded) {
5199 SetLastError(RPC_X_NULL_REF_POINTER);
5200 goto emP_cleanup;
5203 EnterCriticalSection(&monitor_handles_cs);
5204 monitor_loadall();
5206 /* Scan all local Ports */
5207 numentries = 0;
5208 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5210 /* we calculated the needed buffersize. now do the error-checks */
5211 if (cbBuf < needed) {
5212 monitor_unloadall();
5213 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5214 goto emP_cleanup_cs;
5216 else if (!pPorts || !pcReturned) {
5217 monitor_unloadall();
5218 SetLastError(RPC_X_NULL_REF_POINTER);
5219 goto emP_cleanup_cs;
5222 /* Fill the Buffer */
5223 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5224 res = TRUE;
5225 monitor_unloadall();
5227 emP_cleanup_cs:
5228 LeaveCriticalSection(&monitor_handles_cs);
5230 emP_cleanup:
5231 if (pcbNeeded) *pcbNeeded = needed;
5232 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5234 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5235 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5237 return (res);
5240 /******************************************************************************
5241 * GetDefaultPrinterW (WINSPOOL.@)
5243 * FIXME
5244 * This function must read the value from data 'device' of key
5245 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5247 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5249 BOOL retval = TRUE;
5250 DWORD insize, len;
5251 WCHAR *buffer, *ptr;
5253 if (!namesize)
5255 SetLastError(ERROR_INVALID_PARAMETER);
5256 return FALSE;
5259 /* make the buffer big enough for the stuff from the profile/registry,
5260 * the content must fit into the local buffer to compute the correct
5261 * size even if the extern buffer is too small or not given.
5262 * (20 for ,driver,port) */
5263 insize = *namesize;
5264 len = max(100, (insize + 20));
5265 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5267 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5269 SetLastError (ERROR_FILE_NOT_FOUND);
5270 retval = FALSE;
5271 goto end;
5273 TRACE("%s\n", debugstr_w(buffer));
5275 if ((ptr = strchrW(buffer, ',')) == NULL)
5277 SetLastError(ERROR_INVALID_NAME);
5278 retval = FALSE;
5279 goto end;
5282 *ptr = 0;
5283 *namesize = strlenW(buffer) + 1;
5284 if(!name || (*namesize > insize))
5286 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5287 retval = FALSE;
5288 goto end;
5290 strcpyW(name, buffer);
5292 end:
5293 HeapFree( GetProcessHeap(), 0, buffer);
5294 return retval;
5298 /******************************************************************************
5299 * GetDefaultPrinterA (WINSPOOL.@)
5301 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5303 BOOL retval = TRUE;
5304 DWORD insize = 0;
5305 WCHAR *bufferW = NULL;
5307 if (!namesize)
5309 SetLastError(ERROR_INVALID_PARAMETER);
5310 return FALSE;
5313 if(name && *namesize) {
5314 insize = *namesize;
5315 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5318 if(!GetDefaultPrinterW( bufferW, namesize)) {
5319 retval = FALSE;
5320 goto end;
5323 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5324 NULL, NULL);
5325 if (!*namesize)
5327 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5328 retval = FALSE;
5330 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5332 end:
5333 HeapFree( GetProcessHeap(), 0, bufferW);
5334 return retval;
5338 /******************************************************************************
5339 * SetDefaultPrinterW (WINSPOOL.204)
5341 * Set the Name of the Default Printer
5343 * PARAMS
5344 * pszPrinter [I] Name of the Printer or NULL
5346 * RETURNS
5347 * Success: True
5348 * Failure: FALSE
5350 * NOTES
5351 * When the Parameter is NULL or points to an Empty String and
5352 * a Default Printer was already present, then this Function changes nothing.
5353 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5354 * the First enumerated local Printer is used.
5357 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5360 TRACE("(%s)\n", debugstr_w(pszPrinter));
5362 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5363 return FALSE;
5366 /******************************************************************************
5367 * SetDefaultPrinterA (WINSPOOL.202)
5369 * See SetDefaultPrinterW.
5372 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5375 TRACE("(%s)\n", debugstr_a(pszPrinter));
5377 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5378 return FALSE;
5382 /******************************************************************************
5383 * SetPrinterDataExA (WINSPOOL.@)
5385 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5386 LPCSTR pValueName, DWORD Type,
5387 LPBYTE pData, DWORD cbData)
5389 HKEY hkeyPrinter, hkeySubkey;
5390 DWORD ret;
5392 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5393 debugstr_a(pValueName), Type, pData, cbData);
5395 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5396 != ERROR_SUCCESS)
5397 return ret;
5399 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5400 != ERROR_SUCCESS) {
5401 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5402 RegCloseKey(hkeyPrinter);
5403 return ret;
5405 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5406 RegCloseKey(hkeySubkey);
5407 RegCloseKey(hkeyPrinter);
5408 return ret;
5411 /******************************************************************************
5412 * SetPrinterDataExW (WINSPOOL.@)
5414 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5415 LPCWSTR pValueName, DWORD Type,
5416 LPBYTE pData, DWORD cbData)
5418 HKEY hkeyPrinter, hkeySubkey;
5419 DWORD ret;
5421 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5422 debugstr_w(pValueName), Type, pData, cbData);
5424 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5425 != ERROR_SUCCESS)
5426 return ret;
5428 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5429 != ERROR_SUCCESS) {
5430 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5431 RegCloseKey(hkeyPrinter);
5432 return ret;
5434 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5435 RegCloseKey(hkeySubkey);
5436 RegCloseKey(hkeyPrinter);
5437 return ret;
5440 /******************************************************************************
5441 * SetPrinterDataA (WINSPOOL.@)
5443 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5444 LPBYTE pData, DWORD cbData)
5446 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5447 pData, cbData);
5450 /******************************************************************************
5451 * SetPrinterDataW (WINSPOOL.@)
5453 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5454 LPBYTE pData, DWORD cbData)
5456 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5457 pData, cbData);
5460 /******************************************************************************
5461 * GetPrinterDataExA (WINSPOOL.@)
5463 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5464 LPCSTR pValueName, LPDWORD pType,
5465 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5467 HKEY hkeyPrinter, hkeySubkey;
5468 DWORD ret;
5470 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5471 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5472 pcbNeeded);
5474 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5475 != ERROR_SUCCESS)
5476 return ret;
5478 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5479 != ERROR_SUCCESS) {
5480 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5481 RegCloseKey(hkeyPrinter);
5482 return ret;
5484 *pcbNeeded = nSize;
5485 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5486 RegCloseKey(hkeySubkey);
5487 RegCloseKey(hkeyPrinter);
5488 return ret;
5491 /******************************************************************************
5492 * GetPrinterDataExW (WINSPOOL.@)
5494 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5495 LPCWSTR pValueName, LPDWORD pType,
5496 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5498 HKEY hkeyPrinter, hkeySubkey;
5499 DWORD ret;
5501 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5502 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5503 pcbNeeded);
5505 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5506 != ERROR_SUCCESS)
5507 return ret;
5509 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5510 != ERROR_SUCCESS) {
5511 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5512 RegCloseKey(hkeyPrinter);
5513 return ret;
5515 *pcbNeeded = nSize;
5516 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5517 RegCloseKey(hkeySubkey);
5518 RegCloseKey(hkeyPrinter);
5519 return ret;
5522 /******************************************************************************
5523 * GetPrinterDataA (WINSPOOL.@)
5525 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5526 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5528 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5529 pData, nSize, pcbNeeded);
5532 /******************************************************************************
5533 * GetPrinterDataW (WINSPOOL.@)
5535 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5536 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5538 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5539 pData, nSize, pcbNeeded);
5542 /*******************************************************************************
5543 * EnumPrinterDataExW [WINSPOOL.@]
5545 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5546 LPBYTE pEnumValues, DWORD cbEnumValues,
5547 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5549 HKEY hkPrinter, hkSubKey;
5550 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5551 cbValueNameLen, cbMaxValueLen, cbValueLen,
5552 cbBufSize, dwType;
5553 LPWSTR lpValueName;
5554 HANDLE hHeap;
5555 PBYTE lpValue;
5556 PPRINTER_ENUM_VALUESW ppev;
5558 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5560 if (pKeyName == NULL || *pKeyName == 0)
5561 return ERROR_INVALID_PARAMETER;
5563 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5564 if (ret != ERROR_SUCCESS)
5566 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5567 hPrinter, ret);
5568 return ret;
5571 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5572 if (ret != ERROR_SUCCESS)
5574 r = RegCloseKey (hkPrinter);
5575 if (r != ERROR_SUCCESS)
5576 WARN ("RegCloseKey returned %i\n", r);
5577 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5578 debugstr_w (pKeyName), ret);
5579 return ret;
5582 ret = RegCloseKey (hkPrinter);
5583 if (ret != ERROR_SUCCESS)
5585 ERR ("RegCloseKey returned %i\n", ret);
5586 r = RegCloseKey (hkSubKey);
5587 if (r != ERROR_SUCCESS)
5588 WARN ("RegCloseKey returned %i\n", r);
5589 return ret;
5592 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5593 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5594 if (ret != ERROR_SUCCESS)
5596 r = RegCloseKey (hkSubKey);
5597 if (r != ERROR_SUCCESS)
5598 WARN ("RegCloseKey returned %i\n", r);
5599 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5600 return ret;
5603 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5604 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5606 if (cValues == 0) /* empty key */
5608 r = RegCloseKey (hkSubKey);
5609 if (r != ERROR_SUCCESS)
5610 WARN ("RegCloseKey returned %i\n", r);
5611 *pcbEnumValues = *pnEnumValues = 0;
5612 return ERROR_SUCCESS;
5615 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5617 hHeap = GetProcessHeap ();
5618 if (hHeap == NULL)
5620 ERR ("GetProcessHeap failed\n");
5621 r = RegCloseKey (hkSubKey);
5622 if (r != ERROR_SUCCESS)
5623 WARN ("RegCloseKey returned %i\n", r);
5624 return ERROR_OUTOFMEMORY;
5627 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5628 if (lpValueName == NULL)
5630 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5631 r = RegCloseKey (hkSubKey);
5632 if (r != ERROR_SUCCESS)
5633 WARN ("RegCloseKey returned %i\n", r);
5634 return ERROR_OUTOFMEMORY;
5637 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5638 if (lpValue == NULL)
5640 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5641 if (HeapFree (hHeap, 0, lpValueName) == 0)
5642 WARN ("HeapFree failed with code %i\n", GetLastError ());
5643 r = RegCloseKey (hkSubKey);
5644 if (r != ERROR_SUCCESS)
5645 WARN ("RegCloseKey returned %i\n", r);
5646 return ERROR_OUTOFMEMORY;
5649 TRACE ("pass 1: calculating buffer required for all names and values\n");
5651 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5653 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5655 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5657 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5658 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5659 NULL, NULL, lpValue, &cbValueLen);
5660 if (ret != ERROR_SUCCESS)
5662 if (HeapFree (hHeap, 0, lpValue) == 0)
5663 WARN ("HeapFree failed with code %i\n", GetLastError ());
5664 if (HeapFree (hHeap, 0, lpValueName) == 0)
5665 WARN ("HeapFree failed with code %i\n", GetLastError ());
5666 r = RegCloseKey (hkSubKey);
5667 if (r != ERROR_SUCCESS)
5668 WARN ("RegCloseKey returned %i\n", r);
5669 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5670 return ret;
5673 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5674 debugstr_w (lpValueName), dwIndex,
5675 cbValueNameLen + 1, cbValueLen);
5677 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5678 cbBufSize += cbValueLen;
5681 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5683 *pcbEnumValues = cbBufSize;
5684 *pnEnumValues = cValues;
5686 if (cbEnumValues < cbBufSize) /* buffer too small */
5688 if (HeapFree (hHeap, 0, lpValue) == 0)
5689 WARN ("HeapFree failed with code %i\n", GetLastError ());
5690 if (HeapFree (hHeap, 0, lpValueName) == 0)
5691 WARN ("HeapFree failed with code %i\n", GetLastError ());
5692 r = RegCloseKey (hkSubKey);
5693 if (r != ERROR_SUCCESS)
5694 WARN ("RegCloseKey returned %i\n", r);
5695 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5696 return ERROR_MORE_DATA;
5699 TRACE ("pass 2: copying all names and values to buffer\n");
5701 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5702 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5704 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5706 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5707 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5708 NULL, &dwType, lpValue, &cbValueLen);
5709 if (ret != ERROR_SUCCESS)
5711 if (HeapFree (hHeap, 0, lpValue) == 0)
5712 WARN ("HeapFree failed with code %i\n", GetLastError ());
5713 if (HeapFree (hHeap, 0, lpValueName) == 0)
5714 WARN ("HeapFree failed with code %i\n", GetLastError ());
5715 r = RegCloseKey (hkSubKey);
5716 if (r != ERROR_SUCCESS)
5717 WARN ("RegCloseKey returned %i\n", r);
5718 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5719 return ret;
5722 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5723 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5724 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5725 pEnumValues += cbValueNameLen;
5727 /* return # of *bytes* (including trailing \0), not # of chars */
5728 ppev[dwIndex].cbValueName = cbValueNameLen;
5730 ppev[dwIndex].dwType = dwType;
5732 memcpy (pEnumValues, lpValue, cbValueLen);
5733 ppev[dwIndex].pData = pEnumValues;
5734 pEnumValues += cbValueLen;
5736 ppev[dwIndex].cbData = cbValueLen;
5738 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5739 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5742 if (HeapFree (hHeap, 0, lpValue) == 0)
5744 ret = GetLastError ();
5745 ERR ("HeapFree failed with code %i\n", ret);
5746 if (HeapFree (hHeap, 0, lpValueName) == 0)
5747 WARN ("HeapFree failed with code %i\n", GetLastError ());
5748 r = RegCloseKey (hkSubKey);
5749 if (r != ERROR_SUCCESS)
5750 WARN ("RegCloseKey returned %i\n", r);
5751 return ret;
5754 if (HeapFree (hHeap, 0, lpValueName) == 0)
5756 ret = GetLastError ();
5757 ERR ("HeapFree failed with code %i\n", ret);
5758 r = RegCloseKey (hkSubKey);
5759 if (r != ERROR_SUCCESS)
5760 WARN ("RegCloseKey returned %i\n", r);
5761 return ret;
5764 ret = RegCloseKey (hkSubKey);
5765 if (ret != ERROR_SUCCESS)
5767 ERR ("RegCloseKey returned %i\n", ret);
5768 return ret;
5771 return ERROR_SUCCESS;
5774 /*******************************************************************************
5775 * EnumPrinterDataExA [WINSPOOL.@]
5777 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5778 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5779 * what Windows 2000 SP1 does.
5782 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5783 LPBYTE pEnumValues, DWORD cbEnumValues,
5784 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5786 INT len;
5787 LPWSTR pKeyNameW;
5788 DWORD ret, dwIndex, dwBufSize;
5789 HANDLE hHeap;
5790 LPSTR pBuffer;
5792 TRACE ("%p %s\n", hPrinter, pKeyName);
5794 if (pKeyName == NULL || *pKeyName == 0)
5795 return ERROR_INVALID_PARAMETER;
5797 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5798 if (len == 0)
5800 ret = GetLastError ();
5801 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5802 return ret;
5805 hHeap = GetProcessHeap ();
5806 if (hHeap == NULL)
5808 ERR ("GetProcessHeap failed\n");
5809 return ERROR_OUTOFMEMORY;
5812 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5813 if (pKeyNameW == NULL)
5815 ERR ("Failed to allocate %i bytes from process heap\n",
5816 (LONG)(len * sizeof (WCHAR)));
5817 return ERROR_OUTOFMEMORY;
5820 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5822 ret = GetLastError ();
5823 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5824 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5825 WARN ("HeapFree failed with code %i\n", GetLastError ());
5826 return ret;
5829 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5830 pcbEnumValues, pnEnumValues);
5831 if (ret != ERROR_SUCCESS)
5833 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5834 WARN ("HeapFree failed with code %i\n", GetLastError ());
5835 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5836 return ret;
5839 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5841 ret = GetLastError ();
5842 ERR ("HeapFree failed with code %i\n", ret);
5843 return ret;
5846 if (*pnEnumValues == 0) /* empty key */
5847 return ERROR_SUCCESS;
5849 dwBufSize = 0;
5850 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5852 PPRINTER_ENUM_VALUESW ppev =
5853 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5855 if (dwBufSize < ppev->cbValueName)
5856 dwBufSize = ppev->cbValueName;
5858 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5859 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5860 dwBufSize = ppev->cbData;
5863 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5865 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5866 if (pBuffer == NULL)
5868 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5869 return ERROR_OUTOFMEMORY;
5872 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5874 PPRINTER_ENUM_VALUESW ppev =
5875 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5877 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5878 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5879 NULL);
5880 if (len == 0)
5882 ret = GetLastError ();
5883 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5884 if (HeapFree (hHeap, 0, pBuffer) == 0)
5885 WARN ("HeapFree failed with code %i\n", GetLastError ());
5886 return ret;
5889 memcpy (ppev->pValueName, pBuffer, len);
5891 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5893 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5894 ppev->dwType != REG_MULTI_SZ)
5895 continue;
5897 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5898 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5899 if (len == 0)
5901 ret = GetLastError ();
5902 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5903 if (HeapFree (hHeap, 0, pBuffer) == 0)
5904 WARN ("HeapFree failed with code %i\n", GetLastError ());
5905 return ret;
5908 memcpy (ppev->pData, pBuffer, len);
5910 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5911 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5914 if (HeapFree (hHeap, 0, pBuffer) == 0)
5916 ret = GetLastError ();
5917 ERR ("HeapFree failed with code %i\n", ret);
5918 return ret;
5921 return ERROR_SUCCESS;
5924 /******************************************************************************
5925 * AbortPrinter (WINSPOOL.@)
5927 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5929 FIXME("(%p), stub!\n", hPrinter);
5930 return TRUE;
5933 /******************************************************************************
5934 * AddPortA (WINSPOOL.@)
5936 * See AddPortW.
5939 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5941 LPWSTR nameW = NULL;
5942 LPWSTR monitorW = NULL;
5943 DWORD len;
5944 BOOL res;
5946 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5948 if (pName) {
5949 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5950 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5951 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5954 if (pMonitorName) {
5955 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5956 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5957 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5959 res = AddPortW(nameW, hWnd, monitorW);
5960 HeapFree(GetProcessHeap(), 0, nameW);
5961 HeapFree(GetProcessHeap(), 0, monitorW);
5962 return res;
5965 /******************************************************************************
5966 * AddPortW (WINSPOOL.@)
5968 * Add a Port for a specific Monitor
5970 * PARAMS
5971 * pName [I] Servername or NULL (local Computer)
5972 * hWnd [I] Handle to parent Window for the Dialog-Box
5973 * pMonitorName [I] Name of the Monitor that manage the Port
5975 * RETURNS
5976 * Success: TRUE
5977 * Failure: FALSE
5980 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5982 monitor_t * pm;
5983 monitor_t * pui;
5984 DWORD res;
5986 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5988 if (pName && pName[0]) {
5989 SetLastError(ERROR_INVALID_PARAMETER);
5990 return FALSE;
5993 if (!pMonitorName) {
5994 SetLastError(RPC_X_NULL_REF_POINTER);
5995 return FALSE;
5998 /* an empty Monitorname is Invalid */
5999 if (!pMonitorName[0]) {
6000 SetLastError(ERROR_NOT_SUPPORTED);
6001 return FALSE;
6004 pm = monitor_load(pMonitorName, NULL);
6005 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6006 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6007 TRACE("got %d with %u\n", res, GetLastError());
6008 res = TRUE;
6010 else
6012 pui = monitor_loadui(pm);
6013 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6014 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6015 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6016 TRACE("got %d with %u\n", res, GetLastError());
6017 res = TRUE;
6019 else
6021 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6022 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6024 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6025 SetLastError(ERROR_NOT_SUPPORTED);
6026 res = FALSE;
6028 monitor_unload(pui);
6030 monitor_unload(pm);
6031 TRACE("returning %d with %u\n", res, GetLastError());
6032 return res;
6035 /******************************************************************************
6036 * AddPortExA (WINSPOOL.@)
6038 * See AddPortExW.
6041 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6043 PORT_INFO_2W pi2W;
6044 PORT_INFO_2A * pi2A;
6045 LPWSTR nameW = NULL;
6046 LPWSTR monitorW = NULL;
6047 DWORD len;
6048 BOOL res;
6050 pi2A = (PORT_INFO_2A *) pBuffer;
6052 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6053 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6055 if ((level < 1) || (level > 2)) {
6056 SetLastError(ERROR_INVALID_LEVEL);
6057 return FALSE;
6060 if (!pi2A) {
6061 SetLastError(ERROR_INVALID_PARAMETER);
6062 return FALSE;
6065 if (pName) {
6066 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6067 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6068 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6071 if (pMonitorName) {
6072 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6073 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6074 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6077 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6079 if (pi2A->pPortName) {
6080 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6081 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6082 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6085 if (level > 1) {
6086 if (pi2A->pMonitorName) {
6087 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6088 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6089 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6092 if (pi2A->pDescription) {
6093 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6094 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6095 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6097 pi2W.fPortType = pi2A->fPortType;
6098 pi2W.Reserved = pi2A->Reserved;
6101 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6103 HeapFree(GetProcessHeap(), 0, nameW);
6104 HeapFree(GetProcessHeap(), 0, monitorW);
6105 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6106 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6107 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6108 return res;
6112 /******************************************************************************
6113 * AddPortExW (WINSPOOL.@)
6115 * Add a Port for a specific Monitor, without presenting a user interface
6117 * PARAMS
6118 * pName [I] Servername or NULL (local Computer)
6119 * level [I] Structure-Level (1 or 2) for pBuffer
6120 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6121 * pMonitorName [I] Name of the Monitor that manage the Port
6123 * RETURNS
6124 * Success: TRUE
6125 * Failure: FALSE
6128 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6130 PORT_INFO_2W * pi2;
6131 monitor_t * pm;
6132 DWORD res = FALSE;
6134 pi2 = (PORT_INFO_2W *) pBuffer;
6136 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6137 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6138 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6139 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6142 if ((level < 1) || (level > 2)) {
6143 SetLastError(ERROR_INVALID_LEVEL);
6144 return FALSE;
6147 if (!pi2) {
6148 SetLastError(ERROR_INVALID_PARAMETER);
6149 return FALSE;
6152 /* we need a valid Monitorname */
6153 if (!pMonitorName) {
6154 SetLastError(RPC_X_NULL_REF_POINTER);
6155 return FALSE;
6157 if (!pMonitorName[0]) {
6158 SetLastError(ERROR_NOT_SUPPORTED);
6159 return FALSE;
6162 /* load the Monitor */
6163 pm = monitor_load(pMonitorName, NULL);
6164 if (!pm) return FALSE;
6166 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6167 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6168 TRACE("got %u with %u\n", res, GetLastError());
6170 monitor_unload(pm);
6171 return res;
6174 /******************************************************************************
6175 * AddPrinterConnectionA (WINSPOOL.@)
6177 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6179 FIXME("%s\n", debugstr_a(pName));
6180 return FALSE;
6183 /******************************************************************************
6184 * AddPrinterConnectionW (WINSPOOL.@)
6186 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6188 FIXME("%s\n", debugstr_w(pName));
6189 return FALSE;
6192 /******************************************************************************
6193 * AddPrinterDriverExW (WINSPOOL.@)
6195 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6196 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6198 FIXME("%s %d %p %d\n", debugstr_w(pName),
6199 Level, pDriverInfo, dwFileCopyFlags);
6200 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6201 return FALSE;
6204 /******************************************************************************
6205 * AddPrinterDriverExA (WINSPOOL.@)
6207 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6208 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6210 FIXME("%s %d %p %d\n", debugstr_a(pName),
6211 Level, pDriverInfo, dwFileCopyFlags);
6212 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6213 return FALSE;
6216 /******************************************************************************
6217 * ConfigurePortA (WINSPOOL.@)
6219 * See ConfigurePortW.
6222 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6224 LPWSTR nameW = NULL;
6225 LPWSTR portW = NULL;
6226 INT len;
6227 DWORD res;
6229 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6231 /* convert servername to unicode */
6232 if (pName) {
6233 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6234 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6235 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6238 /* convert portname to unicode */
6239 if (pPortName) {
6240 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6241 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6242 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6245 res = ConfigurePortW(nameW, hWnd, portW);
6246 HeapFree(GetProcessHeap(), 0, nameW);
6247 HeapFree(GetProcessHeap(), 0, portW);
6248 return res;
6251 /******************************************************************************
6252 * ConfigurePortW (WINSPOOL.@)
6254 * Display the Configuration-Dialog for a specific Port
6256 * PARAMS
6257 * pName [I] Servername or NULL (local Computer)
6258 * hWnd [I] Handle to parent Window for the Dialog-Box
6259 * pPortName [I] Name of the Port, that should be configured
6261 * RETURNS
6262 * Success: TRUE
6263 * Failure: FALSE
6266 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6268 monitor_t * pm;
6269 monitor_t * pui;
6270 DWORD res;
6272 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6274 if (pName && pName[0]) {
6275 SetLastError(ERROR_INVALID_PARAMETER);
6276 return FALSE;
6279 if (!pPortName) {
6280 SetLastError(RPC_X_NULL_REF_POINTER);
6281 return FALSE;
6284 /* an empty Portname is Invalid, but can popup a Dialog */
6285 if (!pPortName[0]) {
6286 SetLastError(ERROR_NOT_SUPPORTED);
6287 return FALSE;
6290 pm = monitor_load_by_port(pPortName);
6291 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6292 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6293 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6294 TRACE("got %d with %u\n", res, GetLastError());
6296 else
6298 pui = monitor_loadui(pm);
6299 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6300 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6301 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6302 TRACE("got %d with %u\n", res, GetLastError());
6304 else
6306 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6307 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6309 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6310 SetLastError(ERROR_NOT_SUPPORTED);
6311 res = FALSE;
6313 monitor_unload(pui);
6315 monitor_unload(pm);
6317 TRACE("returning %d with %u\n", res, GetLastError());
6318 return res;
6321 /******************************************************************************
6322 * ConnectToPrinterDlg (WINSPOOL.@)
6324 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6326 FIXME("%p %x\n", hWnd, Flags);
6327 return NULL;
6330 /******************************************************************************
6331 * DeletePrinterConnectionA (WINSPOOL.@)
6333 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6335 FIXME("%s\n", debugstr_a(pName));
6336 return TRUE;
6339 /******************************************************************************
6340 * DeletePrinterConnectionW (WINSPOOL.@)
6342 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6344 FIXME("%s\n", debugstr_w(pName));
6345 return TRUE;
6348 /******************************************************************************
6349 * DeletePrinterDriverExW (WINSPOOL.@)
6351 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6352 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6354 HKEY hkey_drivers;
6355 BOOL ret = FALSE;
6357 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6358 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6360 if(pName && pName[0])
6362 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6363 SetLastError(ERROR_INVALID_PARAMETER);
6364 return FALSE;
6367 if(dwDeleteFlag)
6369 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6370 SetLastError(ERROR_INVALID_PARAMETER);
6371 return FALSE;
6374 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6376 if(!hkey_drivers)
6378 ERR("Can't open drivers key\n");
6379 return FALSE;
6382 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6383 ret = TRUE;
6385 RegCloseKey(hkey_drivers);
6387 return ret;
6390 /******************************************************************************
6391 * DeletePrinterDriverExA (WINSPOOL.@)
6393 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6394 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6396 UNICODE_STRING NameW, EnvW, DriverW;
6397 BOOL ret;
6399 asciitounicode(&NameW, pName);
6400 asciitounicode(&EnvW, pEnvironment);
6401 asciitounicode(&DriverW, pDriverName);
6403 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6405 RtlFreeUnicodeString(&DriverW);
6406 RtlFreeUnicodeString(&EnvW);
6407 RtlFreeUnicodeString(&NameW);
6409 return ret;
6412 /******************************************************************************
6413 * DeletePrinterDataExW (WINSPOOL.@)
6415 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6416 LPCWSTR pValueName)
6418 FIXME("%p %s %s\n", hPrinter,
6419 debugstr_w(pKeyName), debugstr_w(pValueName));
6420 return ERROR_INVALID_PARAMETER;
6423 /******************************************************************************
6424 * DeletePrinterDataExA (WINSPOOL.@)
6426 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6427 LPCSTR pValueName)
6429 FIXME("%p %s %s\n", hPrinter,
6430 debugstr_a(pKeyName), debugstr_a(pValueName));
6431 return ERROR_INVALID_PARAMETER;
6434 /******************************************************************************
6435 * DeletePrintProcessorA (WINSPOOL.@)
6437 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6439 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6440 debugstr_a(pPrintProcessorName));
6441 return TRUE;
6444 /******************************************************************************
6445 * DeletePrintProcessorW (WINSPOOL.@)
6447 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6449 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6450 debugstr_w(pPrintProcessorName));
6451 return TRUE;
6454 /******************************************************************************
6455 * DeletePrintProvidorA (WINSPOOL.@)
6457 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6459 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6460 debugstr_a(pPrintProviderName));
6461 return TRUE;
6464 /******************************************************************************
6465 * DeletePrintProvidorW (WINSPOOL.@)
6467 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6469 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6470 debugstr_w(pPrintProviderName));
6471 return TRUE;
6474 /******************************************************************************
6475 * EnumFormsA (WINSPOOL.@)
6477 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6478 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6480 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6482 return FALSE;
6485 /******************************************************************************
6486 * EnumFormsW (WINSPOOL.@)
6488 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6489 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6491 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6492 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6493 return FALSE;
6496 /*****************************************************************************
6497 * EnumMonitorsA [WINSPOOL.@]
6499 * See EnumMonitorsW.
6502 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6503 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6505 BOOL res;
6506 LPBYTE bufferW = NULL;
6507 LPWSTR nameW = NULL;
6508 DWORD needed = 0;
6509 DWORD numentries = 0;
6510 INT len;
6512 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6513 cbBuf, pcbNeeded, pcReturned);
6515 /* convert servername to unicode */
6516 if (pName) {
6517 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6518 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6519 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6521 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6522 needed = cbBuf * sizeof(WCHAR);
6523 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6524 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6526 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6527 if (pcbNeeded) needed = *pcbNeeded;
6528 /* HeapReAlloc return NULL, when bufferW was NULL */
6529 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6530 HeapAlloc(GetProcessHeap(), 0, needed);
6532 /* Try again with the large Buffer */
6533 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6535 numentries = pcReturned ? *pcReturned : 0;
6536 needed = 0;
6538 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6539 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6541 if (res) {
6542 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6543 DWORD entrysize = 0;
6544 DWORD index;
6545 LPSTR ptr;
6546 LPMONITOR_INFO_2W mi2w;
6547 LPMONITOR_INFO_2A mi2a;
6549 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6550 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6552 /* First pass: calculate the size for all Entries */
6553 mi2w = (LPMONITOR_INFO_2W) bufferW;
6554 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6555 index = 0;
6556 while (index < numentries) {
6557 index++;
6558 needed += entrysize; /* MONITOR_INFO_?A */
6559 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6561 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6562 NULL, 0, NULL, NULL);
6563 if (Level > 1) {
6564 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6565 NULL, 0, NULL, NULL);
6566 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6567 NULL, 0, NULL, NULL);
6569 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6570 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6571 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6574 /* check for errors and quit on failure */
6575 if (cbBuf < needed) {
6576 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6577 res = FALSE;
6578 goto emA_cleanup;
6580 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6581 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6582 cbBuf -= len ; /* free Bytes in the user-Buffer */
6583 mi2w = (LPMONITOR_INFO_2W) bufferW;
6584 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6585 index = 0;
6586 /* Second Pass: Fill the User Buffer (if we have one) */
6587 while ((index < numentries) && pMonitors) {
6588 index++;
6589 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6590 mi2a->pName = ptr;
6591 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6592 ptr, cbBuf , NULL, NULL);
6593 ptr += len;
6594 cbBuf -= len;
6595 if (Level > 1) {
6596 mi2a->pEnvironment = ptr;
6597 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6598 ptr, cbBuf, NULL, NULL);
6599 ptr += len;
6600 cbBuf -= len;
6602 mi2a->pDLLName = ptr;
6603 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6604 ptr, cbBuf, NULL, NULL);
6605 ptr += len;
6606 cbBuf -= len;
6608 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6609 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6610 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6613 emA_cleanup:
6614 if (pcbNeeded) *pcbNeeded = needed;
6615 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6617 HeapFree(GetProcessHeap(), 0, nameW);
6618 HeapFree(GetProcessHeap(), 0, bufferW);
6620 TRACE("returning %d with %d (%d byte for %d entries)\n",
6621 (res), GetLastError(), needed, numentries);
6623 return (res);
6627 /*****************************************************************************
6628 * EnumMonitorsW [WINSPOOL.@]
6630 * Enumerate available Port-Monitors
6632 * PARAMS
6633 * pName [I] Servername or NULL (local Computer)
6634 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6635 * pMonitors [O] PTR to Buffer that receives the Result
6636 * cbBuf [I] Size of Buffer at pMonitors
6637 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6638 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6640 * RETURNS
6641 * Success: TRUE
6642 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6644 * NOTES
6645 * Windows reads the Registry once and cache the Results.
6647 *| Language-Monitors are also installed in the same Registry-Location but
6648 *| they are filtered in Windows (not returned by EnumMonitors).
6649 *| We do no filtering to simplify our Code.
6652 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6653 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6655 DWORD needed = 0;
6656 DWORD numentries = 0;
6657 BOOL res = FALSE;
6659 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6660 cbBuf, pcbNeeded, pcReturned);
6662 if (pName && (lstrlenW(pName))) {
6663 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6664 SetLastError(ERROR_ACCESS_DENIED);
6665 goto emW_cleanup;
6668 /* Level is not checked in win9x */
6669 if (!Level || (Level > 2)) {
6670 WARN("level (%d) is ignored in win9x\n", Level);
6671 SetLastError(ERROR_INVALID_LEVEL);
6672 goto emW_cleanup;
6674 if (!pcbNeeded) {
6675 SetLastError(RPC_X_NULL_REF_POINTER);
6676 goto emW_cleanup;
6679 /* Scan all Monitor-Keys */
6680 numentries = 0;
6681 needed = get_local_monitors(Level, NULL, 0, &numentries);
6683 /* we calculated the needed buffersize. now do the error-checks */
6684 if (cbBuf < needed) {
6685 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6686 goto emW_cleanup;
6688 else if (!pMonitors || !pcReturned) {
6689 SetLastError(RPC_X_NULL_REF_POINTER);
6690 goto emW_cleanup;
6693 /* fill the Buffer with the Monitor-Keys */
6694 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6695 res = TRUE;
6697 emW_cleanup:
6698 if (pcbNeeded) *pcbNeeded = needed;
6699 if (pcReturned) *pcReturned = numentries;
6701 TRACE("returning %d with %d (%d byte for %d entries)\n",
6702 res, GetLastError(), needed, numentries);
6704 return (res);
6707 /******************************************************************************
6708 * XcvDataW (WINSPOOL.@)
6710 * Execute commands in the Printmonitor DLL
6712 * PARAMS
6713 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6714 * pszDataName [i] Name of the command to execute
6715 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6716 * cbInputData [i] Size in Bytes of Buffer at pInputData
6717 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6718 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6719 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6720 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6722 * RETURNS
6723 * Success: TRUE
6724 * Failure: FALSE
6726 * NOTES
6727 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6728 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6730 * Minimal List of commands, that a Printmonitor DLL should support:
6732 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6733 *| "AddPort" : Add a Port
6734 *| "DeletePort": Delete a Port
6736 * Many Printmonitors support additional commands. Examples for localspl.dll:
6737 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6738 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6741 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6742 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6743 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6745 opened_printer_t *printer;
6747 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6748 pInputData, cbInputData, pOutputData,
6749 cbOutputData, pcbOutputNeeded, pdwStatus);
6751 printer = get_opened_printer(hXcv);
6752 if (!printer || (!printer->hXcv)) {
6753 SetLastError(ERROR_INVALID_HANDLE);
6754 return FALSE;
6757 if (!pcbOutputNeeded) {
6758 SetLastError(ERROR_INVALID_PARAMETER);
6759 return FALSE;
6762 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6763 SetLastError(RPC_X_NULL_REF_POINTER);
6764 return FALSE;
6767 *pcbOutputNeeded = 0;
6769 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6770 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6772 return TRUE;
6775 /*****************************************************************************
6776 * EnumPrinterDataA [WINSPOOL.@]
6779 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6780 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6781 DWORD cbData, LPDWORD pcbData )
6783 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6784 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6785 return ERROR_NO_MORE_ITEMS;
6788 /*****************************************************************************
6789 * EnumPrinterDataW [WINSPOOL.@]
6792 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6793 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6794 DWORD cbData, LPDWORD pcbData )
6796 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6797 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6798 return ERROR_NO_MORE_ITEMS;
6801 /*****************************************************************************
6802 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6805 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6806 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6807 LPDWORD pcbNeeded, LPDWORD pcReturned)
6809 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6810 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6811 pcbNeeded, pcReturned);
6812 return FALSE;
6815 /*****************************************************************************
6816 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6819 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6820 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6821 LPDWORD pcbNeeded, LPDWORD pcReturned)
6823 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6824 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6825 pcbNeeded, pcReturned);
6826 return FALSE;
6829 /*****************************************************************************
6830 * EnumPrintProcessorsA [WINSPOOL.@]
6833 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6834 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6836 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6837 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6838 return FALSE;
6841 /*****************************************************************************
6842 * EnumPrintProcessorsW [WINSPOOL.@]
6845 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6846 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6848 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6849 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6850 cbBuf, pcbNeeded, pcbReturned);
6851 return FALSE;
6854 /*****************************************************************************
6855 * ExtDeviceMode [WINSPOOL.@]
6858 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6859 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6860 DWORD fMode)
6862 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6863 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6864 debugstr_a(pProfile), fMode);
6865 return -1;
6868 /*****************************************************************************
6869 * FindClosePrinterChangeNotification [WINSPOOL.@]
6872 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6874 FIXME("Stub: %p\n", hChange);
6875 return TRUE;
6878 /*****************************************************************************
6879 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6882 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6883 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6885 FIXME("Stub: %p %x %x %p\n",
6886 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6887 return INVALID_HANDLE_VALUE;
6890 /*****************************************************************************
6891 * FindNextPrinterChangeNotification [WINSPOOL.@]
6894 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6895 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6897 FIXME("Stub: %p %p %p %p\n",
6898 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6899 return FALSE;
6902 /*****************************************************************************
6903 * FreePrinterNotifyInfo [WINSPOOL.@]
6906 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6908 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6909 return TRUE;
6912 /*****************************************************************************
6913 * string_to_buf
6915 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6916 * ansi depending on the unicode parameter.
6918 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6920 if(!str)
6922 *size = 0;
6923 return TRUE;
6926 if(unicode)
6928 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6929 if(*size <= cb)
6931 memcpy(ptr, str, *size);
6932 return TRUE;
6934 return FALSE;
6936 else
6938 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6939 if(*size <= cb)
6941 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6942 return TRUE;
6944 return FALSE;
6948 /*****************************************************************************
6949 * get_job_info_1
6951 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6952 LPDWORD pcbNeeded, BOOL unicode)
6954 DWORD size, left = cbBuf;
6955 BOOL space = (cbBuf > 0);
6956 LPBYTE ptr = buf;
6958 *pcbNeeded = 0;
6960 if(space)
6962 ji1->JobId = job->job_id;
6965 string_to_buf(job->document_title, ptr, left, &size, unicode);
6966 if(space && size <= left)
6968 ji1->pDocument = (LPWSTR)ptr;
6969 ptr += size;
6970 left -= size;
6972 else
6973 space = FALSE;
6974 *pcbNeeded += size;
6976 return space;
6979 /*****************************************************************************
6980 * get_job_info_2
6982 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6983 LPDWORD pcbNeeded, BOOL unicode)
6985 DWORD size, left = cbBuf;
6986 BOOL space = (cbBuf > 0);
6987 LPBYTE ptr = buf;
6989 *pcbNeeded = 0;
6991 if(space)
6993 ji2->JobId = job->job_id;
6996 string_to_buf(job->document_title, ptr, left, &size, unicode);
6997 if(space && size <= left)
6999 ji2->pDocument = (LPWSTR)ptr;
7000 ptr += size;
7001 left -= size;
7003 else
7004 space = FALSE;
7005 *pcbNeeded += size;
7007 return space;
7010 /*****************************************************************************
7011 * get_job_info
7013 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7014 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7016 BOOL ret = FALSE;
7017 DWORD needed = 0, size;
7018 job_t *job;
7019 LPBYTE ptr = pJob;
7021 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7023 EnterCriticalSection(&printer_handles_cs);
7024 job = get_job(hPrinter, JobId);
7025 if(!job)
7026 goto end;
7028 switch(Level)
7030 case 1:
7031 size = sizeof(JOB_INFO_1W);
7032 if(cbBuf >= size)
7034 cbBuf -= size;
7035 ptr += size;
7036 memset(pJob, 0, size);
7038 else
7039 cbBuf = 0;
7040 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7041 needed += size;
7042 break;
7044 case 2:
7045 size = sizeof(JOB_INFO_2W);
7046 if(cbBuf >= size)
7048 cbBuf -= size;
7049 ptr += size;
7050 memset(pJob, 0, size);
7052 else
7053 cbBuf = 0;
7054 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7055 needed += size;
7056 break;
7058 case 3:
7059 size = sizeof(JOB_INFO_3);
7060 if(cbBuf >= size)
7062 cbBuf -= size;
7063 memset(pJob, 0, size);
7064 ret = TRUE;
7066 else
7067 cbBuf = 0;
7068 needed = size;
7069 break;
7071 default:
7072 SetLastError(ERROR_INVALID_LEVEL);
7073 goto end;
7075 if(pcbNeeded)
7076 *pcbNeeded = needed;
7077 end:
7078 LeaveCriticalSection(&printer_handles_cs);
7079 return ret;
7082 /*****************************************************************************
7083 * GetJobA [WINSPOOL.@]
7086 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7087 DWORD cbBuf, LPDWORD pcbNeeded)
7089 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7092 /*****************************************************************************
7093 * GetJobW [WINSPOOL.@]
7096 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7097 DWORD cbBuf, LPDWORD pcbNeeded)
7099 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7102 /*****************************************************************************
7103 * schedule_lpr
7105 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7107 char *unixname, *queue, *cmd;
7108 char fmt[] = "lpr -P%s %s";
7109 DWORD len;
7111 if(!(unixname = wine_get_unix_file_name(filename)))
7112 return FALSE;
7114 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7115 queue = HeapAlloc(GetProcessHeap(), 0, len);
7116 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7118 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7119 sprintf(cmd, fmt, queue, unixname);
7121 TRACE("printing with: %s\n", cmd);
7122 system(cmd);
7124 HeapFree(GetProcessHeap(), 0, cmd);
7125 HeapFree(GetProcessHeap(), 0, queue);
7126 HeapFree(GetProcessHeap(), 0, unixname);
7127 return TRUE;
7130 /*****************************************************************************
7131 * schedule_cups
7133 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7135 #if HAVE_CUPS_CUPS_H
7136 if(pcupsPrintFile)
7138 char *unixname, *queue, *doc_titleA;
7139 DWORD len;
7140 BOOL ret;
7142 if(!(unixname = wine_get_unix_file_name(filename)))
7143 return FALSE;
7145 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7146 queue = HeapAlloc(GetProcessHeap(), 0, len);
7147 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7149 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7150 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7151 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7153 TRACE("printing via cups\n");
7154 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7155 HeapFree(GetProcessHeap(), 0, doc_titleA);
7156 HeapFree(GetProcessHeap(), 0, queue);
7157 HeapFree(GetProcessHeap(), 0, unixname);
7158 return ret;
7160 else
7161 #endif
7163 return schedule_lpr(printer_name, filename);
7167 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7169 LPWSTR filename;
7171 switch(msg)
7173 case WM_INITDIALOG:
7174 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7175 return TRUE;
7177 case WM_COMMAND:
7178 if(HIWORD(wparam) == BN_CLICKED)
7180 if(LOWORD(wparam) == IDOK)
7182 HANDLE hf;
7183 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7184 LPWSTR *output;
7186 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7187 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7189 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7191 WCHAR caption[200], message[200];
7192 int mb_ret;
7194 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7195 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7196 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7197 if(mb_ret == IDCANCEL)
7199 HeapFree(GetProcessHeap(), 0, filename);
7200 return TRUE;
7203 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7204 if(hf == INVALID_HANDLE_VALUE)
7206 WCHAR caption[200], message[200];
7208 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7209 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7210 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7211 HeapFree(GetProcessHeap(), 0, filename);
7212 return TRUE;
7214 CloseHandle(hf);
7215 DeleteFileW(filename);
7216 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7217 *output = filename;
7218 EndDialog(hwnd, IDOK);
7219 return TRUE;
7221 if(LOWORD(wparam) == IDCANCEL)
7223 EndDialog(hwnd, IDCANCEL);
7224 return TRUE;
7227 return FALSE;
7229 return FALSE;
7232 /*****************************************************************************
7233 * get_filename
7235 static BOOL get_filename(LPWSTR *filename)
7237 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7238 file_dlg_proc, (LPARAM)filename) == IDOK;
7241 /*****************************************************************************
7242 * schedule_file
7244 static BOOL schedule_file(LPCWSTR filename)
7246 LPWSTR output = NULL;
7248 if(get_filename(&output))
7250 TRACE("copy to %s\n", debugstr_w(output));
7251 CopyFileW(filename, output, FALSE);
7252 HeapFree(GetProcessHeap(), 0, output);
7253 return TRUE;
7255 return FALSE;
7258 /*****************************************************************************
7259 * schedule_pipe
7261 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7263 #ifdef HAVE_FORK
7264 char *unixname, *cmdA;
7265 DWORD len;
7266 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7267 BOOL ret = FALSE;
7268 char buf[1024];
7270 if(!(unixname = wine_get_unix_file_name(filename)))
7271 return FALSE;
7273 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7274 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7275 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7277 TRACE("printing with: %s\n", cmdA);
7279 if((file_fd = open(unixname, O_RDONLY)) == -1)
7280 goto end;
7282 if (pipe(fds))
7284 ERR("pipe() failed!\n");
7285 goto end;
7288 if (fork() == 0)
7290 close(0);
7291 dup2(fds[0], 0);
7292 close(fds[1]);
7294 /* reset signals that we previously set to SIG_IGN */
7295 signal(SIGPIPE, SIG_DFL);
7296 signal(SIGCHLD, SIG_DFL);
7298 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7299 _exit(1);
7302 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7303 write(fds[1], buf, no_read);
7305 ret = TRUE;
7307 end:
7308 if(file_fd != -1) close(file_fd);
7309 if(fds[0] != -1) close(fds[0]);
7310 if(fds[1] != -1) close(fds[1]);
7312 HeapFree(GetProcessHeap(), 0, cmdA);
7313 HeapFree(GetProcessHeap(), 0, unixname);
7314 return ret;
7315 #else
7316 return FALSE;
7317 #endif
7320 /*****************************************************************************
7321 * schedule_unixfile
7323 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7325 int in_fd, out_fd, no_read;
7326 char buf[1024];
7327 BOOL ret = FALSE;
7328 char *unixname, *outputA;
7329 DWORD len;
7331 if(!(unixname = wine_get_unix_file_name(filename)))
7332 return FALSE;
7334 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7335 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7336 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7338 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7339 in_fd = open(unixname, O_RDONLY);
7340 if(out_fd == -1 || in_fd == -1)
7341 goto end;
7343 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7344 write(out_fd, buf, no_read);
7346 ret = TRUE;
7347 end:
7348 if(in_fd != -1) close(in_fd);
7349 if(out_fd != -1) close(out_fd);
7350 HeapFree(GetProcessHeap(), 0, outputA);
7351 HeapFree(GetProcessHeap(), 0, unixname);
7352 return ret;
7355 /*****************************************************************************
7356 * ScheduleJob [WINSPOOL.@]
7359 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7361 opened_printer_t *printer;
7362 BOOL ret = FALSE;
7363 struct list *cursor, *cursor2;
7365 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7366 EnterCriticalSection(&printer_handles_cs);
7367 printer = get_opened_printer(hPrinter);
7368 if(!printer)
7369 goto end;
7371 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7373 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7374 HANDLE hf;
7376 if(job->job_id != dwJobID) continue;
7378 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7379 if(hf != INVALID_HANDLE_VALUE)
7381 PRINTER_INFO_5W *pi5;
7382 DWORD needed;
7383 HKEY hkey;
7384 WCHAR output[1024];
7385 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7386 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7388 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7389 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7390 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7391 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7392 debugstr_w(pi5->pPortName));
7394 output[0] = 0;
7396 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7397 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7399 DWORD type, count = sizeof(output);
7400 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7401 RegCloseKey(hkey);
7403 if(output[0] == '|')
7405 schedule_pipe(output + 1, job->filename);
7407 else if(output[0])
7409 schedule_unixfile(output, job->filename);
7411 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7413 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7415 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7417 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7419 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7421 schedule_file(job->filename);
7423 else
7425 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7427 HeapFree(GetProcessHeap(), 0, pi5);
7428 CloseHandle(hf);
7429 DeleteFileW(job->filename);
7431 list_remove(cursor);
7432 HeapFree(GetProcessHeap(), 0, job->document_title);
7433 HeapFree(GetProcessHeap(), 0, job->filename);
7434 HeapFree(GetProcessHeap(), 0, job);
7435 ret = TRUE;
7436 break;
7438 end:
7439 LeaveCriticalSection(&printer_handles_cs);
7440 return ret;
7443 /*****************************************************************************
7444 * StartDocDlgA [WINSPOOL.@]
7446 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7448 UNICODE_STRING usBuffer;
7449 DOCINFOW docW;
7450 LPWSTR retW;
7451 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7452 LPSTR ret = NULL;
7454 docW.cbSize = sizeof(docW);
7455 if (doc->lpszDocName)
7457 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7458 if (!(docW.lpszDocName = docnameW)) return NULL;
7460 if (doc->lpszOutput)
7462 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7463 if (!(docW.lpszOutput = outputW)) return NULL;
7465 if (doc->lpszDatatype)
7467 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7468 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7470 docW.fwType = doc->fwType;
7472 retW = StartDocDlgW(hPrinter, &docW);
7474 if(retW)
7476 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7477 ret = HeapAlloc(GetProcessHeap(), 0, len);
7478 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7479 HeapFree(GetProcessHeap(), 0, retW);
7482 HeapFree(GetProcessHeap(), 0, datatypeW);
7483 HeapFree(GetProcessHeap(), 0, outputW);
7484 HeapFree(GetProcessHeap(), 0, docnameW);
7486 return ret;
7489 /*****************************************************************************
7490 * StartDocDlgW [WINSPOOL.@]
7492 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7493 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7494 * port is "FILE:". Also returns the full path if passed a relative path.
7496 * The caller should free the returned string from the process heap.
7498 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7500 LPWSTR ret = NULL;
7501 DWORD len, attr;
7503 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7505 PRINTER_INFO_5W *pi5;
7506 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7507 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7508 return NULL;
7509 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7510 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7511 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7513 HeapFree(GetProcessHeap(), 0, pi5);
7514 return NULL;
7516 HeapFree(GetProcessHeap(), 0, pi5);
7519 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7521 LPWSTR name;
7523 if (get_filename(&name))
7525 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7527 HeapFree(GetProcessHeap(), 0, name);
7528 return NULL;
7530 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7531 GetFullPathNameW(name, len, ret, NULL);
7532 HeapFree(GetProcessHeap(), 0, name);
7534 return ret;
7537 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7538 return NULL;
7540 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7541 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7543 attr = GetFileAttributesW(ret);
7544 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7546 HeapFree(GetProcessHeap(), 0, ret);
7547 ret = NULL;
7549 return ret;