winspool.drv: Replace WINSPOOL_SHDeleteKeyW with RegDeleteTreeW.
[wine/multimedia.git] / dlls / winspool.drv / info.c
blob3086d00a17d59763490c7d5cdc0c5e2420226f62
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 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2274 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2275 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2276 RegCloseKey(hroot);
2277 return TRUE;
2280 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2281 RegCloseKey(hroot);
2283 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2284 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2285 return (FALSE);
2288 /******************************************************************
2289 * DeletePortA [WINSPOOL.@]
2291 * See DeletePortW.
2294 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2296 LPWSTR nameW = NULL;
2297 LPWSTR portW = NULL;
2298 INT len;
2299 DWORD res;
2301 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2303 /* convert servername to unicode */
2304 if (pName) {
2305 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2306 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2307 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2310 /* convert portname to unicode */
2311 if (pPortName) {
2312 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2313 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2314 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2317 res = DeletePortW(nameW, hWnd, portW);
2318 HeapFree(GetProcessHeap(), 0, nameW);
2319 HeapFree(GetProcessHeap(), 0, portW);
2320 return res;
2323 /******************************************************************
2324 * DeletePortW [WINSPOOL.@]
2326 * Delete a specific Port
2328 * PARAMS
2329 * pName [I] Servername or NULL (local Computer)
2330 * hWnd [I] Handle to parent Window for the Dialog-Box
2331 * pPortName [I] Name of the Port, that should be deleted
2333 * RETURNS
2334 * Success: TRUE
2335 * Failure: FALSE
2338 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2340 monitor_t * pm;
2341 monitor_t * pui;
2342 DWORD res;
2344 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2346 if (pName && pName[0]) {
2347 SetLastError(ERROR_INVALID_PARAMETER);
2348 return FALSE;
2351 if (!pPortName) {
2352 SetLastError(RPC_X_NULL_REF_POINTER);
2353 return FALSE;
2356 /* an empty Portname is Invalid */
2357 if (!pPortName[0]) {
2358 SetLastError(ERROR_NOT_SUPPORTED);
2359 return FALSE;
2362 pm = monitor_load_by_port(pPortName);
2363 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2364 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2365 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2366 TRACE("got %d with %u\n", res, GetLastError());
2368 else
2370 pui = monitor_loadui(pm);
2371 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2372 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2373 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2374 TRACE("got %d with %u\n", res, GetLastError());
2376 else
2378 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2379 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2381 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2382 SetLastError(ERROR_NOT_SUPPORTED);
2383 res = FALSE;
2385 monitor_unload(pui);
2387 monitor_unload(pm);
2389 TRACE("returning %d with %u\n", res, GetLastError());
2390 return res;
2393 /******************************************************************************
2394 * SetPrinterW [WINSPOOL.@]
2396 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2398 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2399 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2400 return FALSE;
2403 /******************************************************************************
2404 * WritePrinter [WINSPOOL.@]
2406 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2408 opened_printer_t *printer;
2409 BOOL ret = FALSE;
2411 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2413 EnterCriticalSection(&printer_handles_cs);
2414 printer = get_opened_printer(hPrinter);
2415 if(!printer)
2417 SetLastError(ERROR_INVALID_HANDLE);
2418 goto end;
2421 if(!printer->doc)
2423 SetLastError(ERROR_SPL_NO_STARTDOC);
2424 goto end;
2427 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2428 end:
2429 LeaveCriticalSection(&printer_handles_cs);
2430 return ret;
2433 /*****************************************************************************
2434 * AddFormA [WINSPOOL.@]
2436 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2438 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2439 return 1;
2442 /*****************************************************************************
2443 * AddFormW [WINSPOOL.@]
2445 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2447 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2448 return 1;
2451 /*****************************************************************************
2452 * AddJobA [WINSPOOL.@]
2454 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2456 BOOL ret;
2457 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2458 DWORD needed;
2460 if(Level != 1) {
2461 SetLastError(ERROR_INVALID_LEVEL);
2462 return FALSE;
2465 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2467 if(ret) {
2468 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2469 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2470 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2471 if(*pcbNeeded > cbBuf) {
2472 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2473 ret = FALSE;
2474 } else {
2475 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2476 addjobA->JobId = addjobW->JobId;
2477 addjobA->Path = (char *)(addjobA + 1);
2478 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2481 return ret;
2484 /*****************************************************************************
2485 * AddJobW [WINSPOOL.@]
2487 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2489 opened_printer_t *printer;
2490 job_t *job;
2491 BOOL ret = FALSE;
2492 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2493 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2494 WCHAR path[MAX_PATH], filename[MAX_PATH];
2495 DWORD len;
2496 ADDJOB_INFO_1W *addjob;
2498 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2500 EnterCriticalSection(&printer_handles_cs);
2502 printer = get_opened_printer(hPrinter);
2504 if(!printer) {
2505 SetLastError(ERROR_INVALID_HANDLE);
2506 goto end;
2509 if(Level != 1) {
2510 SetLastError(ERROR_INVALID_LEVEL);
2511 goto end;
2514 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2515 if(!job)
2516 goto end;
2518 job->job_id = InterlockedIncrement(&next_job_id);
2520 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2521 if(path[len - 1] != '\\')
2522 path[len++] = '\\';
2523 memcpy(path + len, spool_path, sizeof(spool_path));
2524 sprintfW(filename, fmtW, path, job->job_id);
2526 len = strlenW(filename);
2527 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2528 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2529 job->document_title = strdupW(default_doc_title);
2530 list_add_tail(&printer->queue->jobs, &job->entry);
2532 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2533 if(*pcbNeeded <= cbBuf) {
2534 addjob = (ADDJOB_INFO_1W*)pData;
2535 addjob->JobId = job->job_id;
2536 addjob->Path = (WCHAR *)(addjob + 1);
2537 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2538 ret = TRUE;
2539 } else
2540 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2542 end:
2543 LeaveCriticalSection(&printer_handles_cs);
2544 return ret;
2547 /*****************************************************************************
2548 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2550 * Return the PATH for the Print-Processors
2552 * See GetPrintProcessorDirectoryW.
2556 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2557 DWORD level, LPBYTE Info,
2558 DWORD cbBuf, LPDWORD pcbNeeded)
2560 LPWSTR serverW = NULL;
2561 LPWSTR envW = NULL;
2562 BOOL ret;
2563 INT len;
2565 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2566 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2569 if (server) {
2570 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2571 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2572 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2575 if (env) {
2576 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2577 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2578 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2581 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2582 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2584 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2585 cbBuf, pcbNeeded);
2587 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2588 cbBuf, NULL, NULL) > 0;
2591 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2592 HeapFree(GetProcessHeap(), 0, envW);
2593 HeapFree(GetProcessHeap(), 0, serverW);
2594 return ret;
2597 /*****************************************************************************
2598 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2600 * Return the PATH for the Print-Processors
2602 * PARAMS
2603 * server [I] Servername (NT only) or NULL (local Computer)
2604 * env [I] Printing-Environment (see below) or NULL (Default)
2605 * level [I] Structure-Level (must be 1)
2606 * Info [O] PTR to Buffer that receives the Result
2607 * cbBuf [I] Size of Buffer at "Info"
2608 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2609 * required for the Buffer at "Info"
2611 * RETURNS
2612 * Success: TRUE and in pcbNeeded the Bytes used in Info
2613 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2614 * if cbBuf is too small
2616 * Native Values returned in Info on Success:
2617 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2618 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2619 *| win9x(Windows 4.0): "%winsysdir%"
2621 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2623 * BUGS
2624 * Only NULL or "" is supported for server
2627 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2628 DWORD level, LPBYTE Info,
2629 DWORD cbBuf, LPDWORD pcbNeeded)
2631 DWORD needed;
2632 const printenv_t * env_t;
2634 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2635 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2637 if(server != NULL && server[0]) {
2638 FIXME("server not supported: %s\n", debugstr_w(server));
2639 SetLastError(ERROR_INVALID_PARAMETER);
2640 return FALSE;
2643 env_t = validate_envW(env);
2644 if(!env_t) return FALSE; /* environment invalid or unsupported */
2646 if(level != 1) {
2647 WARN("(Level: %d) is ignored in win9x\n", level);
2648 SetLastError(ERROR_INVALID_LEVEL);
2649 return FALSE;
2652 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2653 needed = GetSystemDirectoryW(NULL, 0);
2654 /* add the Size for the Subdirectories */
2655 needed += lstrlenW(spoolprtprocsW);
2656 needed += lstrlenW(env_t->subdir);
2657 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2659 if(pcbNeeded) *pcbNeeded = needed;
2660 TRACE ("required: 0x%x/%d\n", needed, needed);
2661 if (needed > cbBuf) {
2662 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2663 return FALSE;
2665 if(pcbNeeded == NULL) {
2666 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2667 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2668 SetLastError(RPC_X_NULL_REF_POINTER);
2669 return FALSE;
2671 if(Info == NULL) {
2672 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2673 SetLastError(RPC_X_NULL_REF_POINTER);
2674 return FALSE;
2677 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2678 /* add the Subdirectories */
2679 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2680 lstrcatW((LPWSTR) Info, env_t->subdir);
2681 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2682 return TRUE;
2685 /*****************************************************************************
2686 * WINSPOOL_OpenDriverReg [internal]
2688 * opens the registry for the printer drivers depending on the given input
2689 * variable pEnvironment
2691 * RETURNS:
2692 * the opened hkey on success
2693 * NULL on error
2695 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2697 HKEY retval = NULL;
2698 LPWSTR buffer;
2699 const printenv_t * env;
2701 TRACE("(%s, %d)\n",
2702 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2704 if (!pEnvironment || unicode) {
2705 /* pEnvironment was NULL or an Unicode-String: use it direct */
2706 env = validate_envW(pEnvironment);
2708 else
2710 /* pEnvironment was an ANSI-String: convert to unicode first */
2711 LPWSTR buffer;
2712 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2713 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2714 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2715 env = validate_envW(buffer);
2716 HeapFree(GetProcessHeap(), 0, buffer);
2718 if (!env) return NULL;
2720 buffer = HeapAlloc( GetProcessHeap(), 0,
2721 (strlenW(DriversW) + strlenW(env->envname) +
2722 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2723 if(buffer) {
2724 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2725 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2726 HeapFree(GetProcessHeap(), 0, buffer);
2728 return retval;
2731 /*****************************************************************************
2732 * AddPrinterW [WINSPOOL.@]
2734 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2736 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2737 LPDEVMODEA dmA;
2738 LPDEVMODEW dmW;
2739 HANDLE retval;
2740 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2741 LONG size;
2742 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2743 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2744 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2745 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2746 statusW[] = {'S','t','a','t','u','s',0},
2747 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2749 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2751 if(pName != NULL) {
2752 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2753 SetLastError(ERROR_INVALID_PARAMETER);
2754 return 0;
2756 if(Level != 2) {
2757 ERR("Level = %d, unsupported!\n", Level);
2758 SetLastError(ERROR_INVALID_LEVEL);
2759 return 0;
2761 if(!pPrinter) {
2762 SetLastError(ERROR_INVALID_PARAMETER);
2763 return 0;
2765 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2766 ERROR_SUCCESS) {
2767 ERR("Can't create Printers key\n");
2768 return 0;
2770 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2771 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2772 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2773 RegCloseKey(hkeyPrinter);
2774 RegCloseKey(hkeyPrinters);
2775 return 0;
2777 RegCloseKey(hkeyPrinter);
2779 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2780 if(!hkeyDrivers) {
2781 ERR("Can't create Drivers key\n");
2782 RegCloseKey(hkeyPrinters);
2783 return 0;
2785 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2786 ERROR_SUCCESS) {
2787 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2788 RegCloseKey(hkeyPrinters);
2789 RegCloseKey(hkeyDrivers);
2790 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2791 return 0;
2793 RegCloseKey(hkeyDriver);
2794 RegCloseKey(hkeyDrivers);
2796 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2797 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2798 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2799 RegCloseKey(hkeyPrinters);
2800 return 0;
2803 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2804 ERROR_SUCCESS) {
2805 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2806 SetLastError(ERROR_INVALID_PRINTER_NAME);
2807 RegCloseKey(hkeyPrinters);
2808 return 0;
2810 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2811 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2812 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2814 /* See if we can load the driver. We may need the devmode structure anyway
2816 * FIXME:
2817 * Note that DocumentPropertiesW will briefly try to open the printer we
2818 * just create to find a DEVMODEA struct (it will use the WINEPS default
2819 * one in case it is not there, so we are ok).
2821 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2823 if(size < 0) {
2824 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2825 size = sizeof(DEVMODEW);
2827 if(pi->pDevMode)
2828 dmW = pi->pDevMode;
2829 else
2831 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2832 dmW->dmSize = size;
2833 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2835 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2836 HeapFree(GetProcessHeap(),0,dmW);
2837 dmW=NULL;
2839 else
2841 /* set devmode to printer name */
2842 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2846 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2847 and we support these drivers. NT writes DEVMODEW so somehow
2848 we'll need to distinguish between these when we support NT
2849 drivers */
2850 if (dmW)
2852 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2853 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2854 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2855 HeapFree(GetProcessHeap(), 0, dmA);
2856 if(!pi->pDevMode)
2857 HeapFree(GetProcessHeap(), 0, dmW);
2859 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2860 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2861 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2862 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2864 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2865 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2866 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2867 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2868 (LPBYTE)&pi->Priority, sizeof(DWORD));
2869 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2870 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2871 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2872 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2873 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2874 (LPBYTE)&pi->Status, sizeof(DWORD));
2875 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2876 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2878 RegCloseKey(hkeyPrinter);
2879 RegCloseKey(hkeyPrinters);
2880 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2881 ERR("OpenPrinter failing\n");
2882 return 0;
2884 return retval;
2887 /*****************************************************************************
2888 * AddPrinterA [WINSPOOL.@]
2890 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2892 UNICODE_STRING pNameW;
2893 PWSTR pwstrNameW;
2894 PRINTER_INFO_2W *piW;
2895 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2896 HANDLE ret;
2898 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2899 if(Level != 2) {
2900 ERR("Level = %d, unsupported!\n", Level);
2901 SetLastError(ERROR_INVALID_LEVEL);
2902 return 0;
2904 pwstrNameW = asciitounicode(&pNameW,pName);
2905 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2907 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2909 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2910 RtlFreeUnicodeString(&pNameW);
2911 return ret;
2915 /*****************************************************************************
2916 * ClosePrinter [WINSPOOL.@]
2918 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2920 UINT_PTR i = (UINT_PTR)hPrinter;
2921 opened_printer_t *printer = NULL;
2922 BOOL ret = FALSE;
2924 TRACE("(%p)\n", hPrinter);
2926 EnterCriticalSection(&printer_handles_cs);
2928 if ((i > 0) && (i <= nb_printer_handles))
2929 printer = printer_handles[i - 1];
2932 if(printer)
2934 struct list *cursor, *cursor2;
2936 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2937 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2938 printer->hXcv, debugstr_w(printer->name), printer->doc );
2940 if(printer->doc)
2941 EndDocPrinter(hPrinter);
2943 if(InterlockedDecrement(&printer->queue->ref) == 0)
2945 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2947 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2948 ScheduleJob(hPrinter, job->job_id);
2950 HeapFree(GetProcessHeap(), 0, printer->queue);
2952 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2953 monitor_unload(printer->pm);
2954 HeapFree(GetProcessHeap(), 0, printer->printername);
2955 HeapFree(GetProcessHeap(), 0, printer->name);
2956 HeapFree(GetProcessHeap(), 0, printer);
2957 printer_handles[i - 1] = NULL;
2958 ret = TRUE;
2960 LeaveCriticalSection(&printer_handles_cs);
2961 return ret;
2964 /*****************************************************************************
2965 * DeleteFormA [WINSPOOL.@]
2967 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2969 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2970 return 1;
2973 /*****************************************************************************
2974 * DeleteFormW [WINSPOOL.@]
2976 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2978 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2979 return 1;
2982 /*****************************************************************************
2983 * DeletePrinter [WINSPOOL.@]
2985 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2987 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2988 HKEY hkeyPrinters, hkey;
2990 if(!lpNameW) {
2991 SetLastError(ERROR_INVALID_HANDLE);
2992 return FALSE;
2994 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
2995 RegDeleteTreeW(hkeyPrinters, lpNameW);
2996 RegCloseKey(hkeyPrinters);
2998 WriteProfileStringW(devicesW, lpNameW, NULL);
2999 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3000 RegDeleteValueW(hkey, lpNameW);
3001 RegCloseKey(hkey);
3003 return TRUE;
3006 /*****************************************************************************
3007 * SetPrinterA [WINSPOOL.@]
3009 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3010 DWORD Command)
3012 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3013 return FALSE;
3016 /*****************************************************************************
3017 * SetJobA [WINSPOOL.@]
3019 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3020 LPBYTE pJob, DWORD Command)
3022 BOOL ret;
3023 LPBYTE JobW;
3024 UNICODE_STRING usBuffer;
3026 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3028 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3029 are all ignored by SetJob, so we don't bother copying them */
3030 switch(Level)
3032 case 0:
3033 JobW = NULL;
3034 break;
3035 case 1:
3037 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3038 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3040 JobW = (LPBYTE)info1W;
3041 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3042 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3043 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3044 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3045 info1W->Status = info1A->Status;
3046 info1W->Priority = info1A->Priority;
3047 info1W->Position = info1A->Position;
3048 info1W->PagesPrinted = info1A->PagesPrinted;
3049 break;
3051 case 2:
3053 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3054 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3056 JobW = (LPBYTE)info2W;
3057 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3058 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3059 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3060 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3061 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3062 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3063 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3064 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3065 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3066 info2W->Status = info2A->Status;
3067 info2W->Priority = info2A->Priority;
3068 info2W->Position = info2A->Position;
3069 info2W->StartTime = info2A->StartTime;
3070 info2W->UntilTime = info2A->UntilTime;
3071 info2W->PagesPrinted = info2A->PagesPrinted;
3072 break;
3074 case 3:
3075 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3076 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3077 break;
3078 default:
3079 SetLastError(ERROR_INVALID_LEVEL);
3080 return FALSE;
3083 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3085 switch(Level)
3087 case 1:
3089 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3090 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3091 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3092 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3093 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3094 break;
3096 case 2:
3098 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3099 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3100 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3101 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3102 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3103 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3104 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3105 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3106 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3107 break;
3110 HeapFree(GetProcessHeap(), 0, JobW);
3112 return ret;
3115 /*****************************************************************************
3116 * SetJobW [WINSPOOL.@]
3118 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3119 LPBYTE pJob, DWORD Command)
3121 BOOL ret = FALSE;
3122 job_t *job;
3124 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3125 FIXME("Ignoring everything other than document title\n");
3127 EnterCriticalSection(&printer_handles_cs);
3128 job = get_job(hPrinter, JobId);
3129 if(!job)
3130 goto end;
3132 switch(Level)
3134 case 0:
3135 break;
3136 case 1:
3138 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3139 HeapFree(GetProcessHeap(), 0, job->document_title);
3140 job->document_title = strdupW(info1->pDocument);
3141 break;
3143 case 2:
3145 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3146 HeapFree(GetProcessHeap(), 0, job->document_title);
3147 job->document_title = strdupW(info2->pDocument);
3148 break;
3150 case 3:
3151 break;
3152 default:
3153 SetLastError(ERROR_INVALID_LEVEL);
3154 goto end;
3156 ret = TRUE;
3157 end:
3158 LeaveCriticalSection(&printer_handles_cs);
3159 return ret;
3162 /*****************************************************************************
3163 * EndDocPrinter [WINSPOOL.@]
3165 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3167 opened_printer_t *printer;
3168 BOOL ret = FALSE;
3169 TRACE("(%p)\n", hPrinter);
3171 EnterCriticalSection(&printer_handles_cs);
3173 printer = get_opened_printer(hPrinter);
3174 if(!printer)
3176 SetLastError(ERROR_INVALID_HANDLE);
3177 goto end;
3180 if(!printer->doc)
3182 SetLastError(ERROR_SPL_NO_STARTDOC);
3183 goto end;
3186 CloseHandle(printer->doc->hf);
3187 ScheduleJob(hPrinter, printer->doc->job_id);
3188 HeapFree(GetProcessHeap(), 0, printer->doc);
3189 printer->doc = NULL;
3190 ret = TRUE;
3191 end:
3192 LeaveCriticalSection(&printer_handles_cs);
3193 return ret;
3196 /*****************************************************************************
3197 * EndPagePrinter [WINSPOOL.@]
3199 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3201 FIXME("(%p): stub\n", hPrinter);
3202 return TRUE;
3205 /*****************************************************************************
3206 * StartDocPrinterA [WINSPOOL.@]
3208 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3210 UNICODE_STRING usBuffer;
3211 DOC_INFO_2W doc2W;
3212 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3213 DWORD ret;
3215 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3216 or one (DOC_INFO_3) extra DWORDs */
3218 switch(Level) {
3219 case 2:
3220 doc2W.JobId = doc2->JobId;
3221 /* fall through */
3222 case 3:
3223 doc2W.dwMode = doc2->dwMode;
3224 /* fall through */
3225 case 1:
3226 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3227 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3228 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3229 break;
3231 default:
3232 SetLastError(ERROR_INVALID_LEVEL);
3233 return FALSE;
3236 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3238 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3239 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3240 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3242 return ret;
3245 /*****************************************************************************
3246 * StartDocPrinterW [WINSPOOL.@]
3248 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3250 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3251 opened_printer_t *printer;
3252 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3253 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3254 JOB_INFO_1W job_info;
3255 DWORD needed, ret = 0;
3256 HANDLE hf;
3257 WCHAR *filename;
3259 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3260 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3261 debugstr_w(doc->pDatatype));
3263 if(Level < 1 || Level > 3)
3265 SetLastError(ERROR_INVALID_LEVEL);
3266 return 0;
3269 EnterCriticalSection(&printer_handles_cs);
3270 printer = get_opened_printer(hPrinter);
3271 if(!printer)
3273 SetLastError(ERROR_INVALID_HANDLE);
3274 goto end;
3277 if(printer->doc)
3279 SetLastError(ERROR_INVALID_PRINTER_STATE);
3280 goto end;
3283 /* Even if we're printing to a file we still add a print job, we'll
3284 just ignore the spool file name */
3286 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3288 ERR("AddJob failed gle %u\n", GetLastError());
3289 goto end;
3292 if(doc->pOutputFile)
3293 filename = doc->pOutputFile;
3294 else
3295 filename = addjob->Path;
3297 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3298 if(hf == INVALID_HANDLE_VALUE)
3299 goto end;
3301 memset(&job_info, 0, sizeof(job_info));
3302 job_info.pDocument = doc->pDocName;
3303 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3305 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3306 printer->doc->hf = hf;
3307 ret = printer->doc->job_id = addjob->JobId;
3308 end:
3309 LeaveCriticalSection(&printer_handles_cs);
3311 return ret;
3314 /*****************************************************************************
3315 * StartPagePrinter [WINSPOOL.@]
3317 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3319 FIXME("(%p): stub\n", hPrinter);
3320 return TRUE;
3323 /*****************************************************************************
3324 * GetFormA [WINSPOOL.@]
3326 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3327 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3329 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3330 Level,pForm,cbBuf,pcbNeeded);
3331 return FALSE;
3334 /*****************************************************************************
3335 * GetFormW [WINSPOOL.@]
3337 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3338 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3340 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3341 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3342 return FALSE;
3345 /*****************************************************************************
3346 * SetFormA [WINSPOOL.@]
3348 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3349 LPBYTE pForm)
3351 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3352 return FALSE;
3355 /*****************************************************************************
3356 * SetFormW [WINSPOOL.@]
3358 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3359 LPBYTE pForm)
3361 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3362 return FALSE;
3365 /*****************************************************************************
3366 * ReadPrinter [WINSPOOL.@]
3368 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3369 LPDWORD pNoBytesRead)
3371 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3372 return FALSE;
3375 /*****************************************************************************
3376 * ResetPrinterA [WINSPOOL.@]
3378 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3380 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3381 return FALSE;
3384 /*****************************************************************************
3385 * ResetPrinterW [WINSPOOL.@]
3387 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3389 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3390 return FALSE;
3393 /*****************************************************************************
3394 * WINSPOOL_GetDWORDFromReg
3396 * Return DWORD associated with ValueName from hkey.
3398 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3400 DWORD sz = sizeof(DWORD), type, value = 0;
3401 LONG ret;
3403 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3405 if(ret != ERROR_SUCCESS) {
3406 WARN("Got ret = %d on name %s\n", ret, ValueName);
3407 return 0;
3409 if(type != REG_DWORD) {
3410 ERR("Got type %d\n", type);
3411 return 0;
3413 return value;
3416 /*****************************************************************************
3417 * WINSPOOL_GetStringFromReg
3419 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3420 * String is stored either as unicode or ascii.
3421 * Bit of a hack here to get the ValueName if we want ascii.
3423 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3424 DWORD buflen, DWORD *needed,
3425 BOOL unicode)
3427 DWORD sz = buflen, type;
3428 LONG ret;
3430 if(unicode)
3431 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3432 else {
3433 LPSTR ValueNameA = strdupWtoA(ValueName);
3434 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3435 HeapFree(GetProcessHeap(),0,ValueNameA);
3437 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3438 WARN("Got ret = %d\n", ret);
3439 *needed = 0;
3440 return FALSE;
3442 /* add space for terminating '\0' */
3443 sz += unicode ? sizeof(WCHAR) : 1;
3444 *needed = sz;
3446 if (ptr)
3447 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3449 return TRUE;
3452 /*****************************************************************************
3453 * WINSPOOL_GetDefaultDevMode
3455 * Get a default DevMode values for wineps.
3456 * FIXME - use ppd.
3459 static void WINSPOOL_GetDefaultDevMode(
3460 LPBYTE ptr,
3461 DWORD buflen, DWORD *needed,
3462 BOOL unicode)
3464 DEVMODEA dm;
3465 static const char szwps[] = "wineps.drv";
3467 /* fill default DEVMODE - should be read from ppd... */
3468 ZeroMemory( &dm, sizeof(dm) );
3469 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3470 dm.dmSpecVersion = DM_SPECVERSION;
3471 dm.dmDriverVersion = 1;
3472 dm.dmSize = sizeof(DEVMODEA);
3473 dm.dmDriverExtra = 0;
3474 dm.dmFields =
3475 DM_ORIENTATION | DM_PAPERSIZE |
3476 DM_PAPERLENGTH | DM_PAPERWIDTH |
3477 DM_SCALE |
3478 DM_COPIES |
3479 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3480 DM_YRESOLUTION | DM_TTOPTION;
3482 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3483 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3484 dm.u1.s1.dmPaperLength = 2970;
3485 dm.u1.s1.dmPaperWidth = 2100;
3487 dm.dmScale = 100;
3488 dm.dmCopies = 1;
3489 dm.dmDefaultSource = DMBIN_AUTO;
3490 dm.dmPrintQuality = DMRES_MEDIUM;
3491 /* dm.dmColor */
3492 /* dm.dmDuplex */
3493 dm.dmYResolution = 300; /* 300dpi */
3494 dm.dmTTOption = DMTT_BITMAP;
3495 /* dm.dmCollate */
3496 /* dm.dmFormName */
3497 /* dm.dmLogPixels */
3498 /* dm.dmBitsPerPel */
3499 /* dm.dmPelsWidth */
3500 /* dm.dmPelsHeight */
3501 /* dm.dmDisplayFlags */
3502 /* dm.dmDisplayFrequency */
3503 /* dm.dmICMMethod */
3504 /* dm.dmICMIntent */
3505 /* dm.dmMediaType */
3506 /* dm.dmDitherType */
3507 /* dm.dmReserved1 */
3508 /* dm.dmReserved2 */
3509 /* dm.dmPanningWidth */
3510 /* dm.dmPanningHeight */
3512 if(unicode) {
3513 if(buflen >= sizeof(DEVMODEW)) {
3514 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3515 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3516 HeapFree(GetProcessHeap(),0,pdmW);
3518 *needed = sizeof(DEVMODEW);
3520 else
3522 if(buflen >= sizeof(DEVMODEA)) {
3523 memcpy(ptr, &dm, sizeof(DEVMODEA));
3525 *needed = sizeof(DEVMODEA);
3529 /*****************************************************************************
3530 * WINSPOOL_GetDevModeFromReg
3532 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3533 * DevMode is stored either as unicode or ascii.
3535 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3536 LPBYTE ptr,
3537 DWORD buflen, DWORD *needed,
3538 BOOL unicode)
3540 DWORD sz = buflen, type;
3541 LONG ret;
3543 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3544 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3545 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3546 if (sz < sizeof(DEVMODEA))
3548 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3549 return FALSE;
3551 /* ensures that dmSize is not erratically bogus if registry is invalid */
3552 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3553 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3554 if(unicode) {
3555 sz += (CCHDEVICENAME + CCHFORMNAME);
3556 if(buflen >= sz) {
3557 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3558 memcpy(ptr, dmW, sz);
3559 HeapFree(GetProcessHeap(),0,dmW);
3562 *needed = sz;
3563 return TRUE;
3566 /*********************************************************************
3567 * WINSPOOL_GetPrinter_1
3569 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3570 * The strings are either stored as unicode or ascii.
3572 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3573 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3574 BOOL unicode)
3576 DWORD size, left = cbBuf;
3577 BOOL space = (cbBuf > 0);
3578 LPBYTE ptr = buf;
3580 *pcbNeeded = 0;
3582 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3583 unicode)) {
3584 if(space && size <= left) {
3585 pi1->pName = (LPWSTR)ptr;
3586 ptr += size;
3587 left -= size;
3588 } else
3589 space = FALSE;
3590 *pcbNeeded += size;
3593 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3594 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3595 unicode)) {
3596 if(space && size <= left) {
3597 pi1->pDescription = (LPWSTR)ptr;
3598 ptr += size;
3599 left -= size;
3600 } else
3601 space = FALSE;
3602 *pcbNeeded += size;
3605 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3606 unicode)) {
3607 if(space && size <= left) {
3608 pi1->pComment = (LPWSTR)ptr;
3609 ptr += size;
3610 left -= size;
3611 } else
3612 space = FALSE;
3613 *pcbNeeded += size;
3616 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3618 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3619 memset(pi1, 0, sizeof(*pi1));
3621 return space;
3623 /*********************************************************************
3624 * WINSPOOL_GetPrinter_2
3626 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3627 * The strings are either stored as unicode or ascii.
3629 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3630 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3631 BOOL unicode)
3633 DWORD size, left = cbBuf;
3634 BOOL space = (cbBuf > 0);
3635 LPBYTE ptr = buf;
3637 *pcbNeeded = 0;
3639 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3640 unicode)) {
3641 if(space && size <= left) {
3642 pi2->pPrinterName = (LPWSTR)ptr;
3643 ptr += size;
3644 left -= size;
3645 } else
3646 space = FALSE;
3647 *pcbNeeded += size;
3649 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3650 unicode)) {
3651 if(space && size <= left) {
3652 pi2->pShareName = (LPWSTR)ptr;
3653 ptr += size;
3654 left -= size;
3655 } else
3656 space = FALSE;
3657 *pcbNeeded += size;
3659 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3660 unicode)) {
3661 if(space && size <= left) {
3662 pi2->pPortName = (LPWSTR)ptr;
3663 ptr += size;
3664 left -= size;
3665 } else
3666 space = FALSE;
3667 *pcbNeeded += size;
3669 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3670 &size, unicode)) {
3671 if(space && size <= left) {
3672 pi2->pDriverName = (LPWSTR)ptr;
3673 ptr += size;
3674 left -= size;
3675 } else
3676 space = FALSE;
3677 *pcbNeeded += size;
3679 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3680 unicode)) {
3681 if(space && size <= left) {
3682 pi2->pComment = (LPWSTR)ptr;
3683 ptr += size;
3684 left -= size;
3685 } else
3686 space = FALSE;
3687 *pcbNeeded += size;
3689 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3690 unicode)) {
3691 if(space && size <= left) {
3692 pi2->pLocation = (LPWSTR)ptr;
3693 ptr += size;
3694 left -= size;
3695 } else
3696 space = FALSE;
3697 *pcbNeeded += size;
3699 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3700 &size, unicode)) {
3701 if(space && size <= left) {
3702 pi2->pDevMode = (LPDEVMODEW)ptr;
3703 ptr += size;
3704 left -= size;
3705 } else
3706 space = FALSE;
3707 *pcbNeeded += size;
3709 else
3711 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3712 if(space && size <= left) {
3713 pi2->pDevMode = (LPDEVMODEW)ptr;
3714 ptr += size;
3715 left -= size;
3716 } else
3717 space = FALSE;
3718 *pcbNeeded += size;
3720 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3721 &size, unicode)) {
3722 if(space && size <= left) {
3723 pi2->pSepFile = (LPWSTR)ptr;
3724 ptr += size;
3725 left -= size;
3726 } else
3727 space = FALSE;
3728 *pcbNeeded += size;
3730 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3731 &size, unicode)) {
3732 if(space && size <= left) {
3733 pi2->pPrintProcessor = (LPWSTR)ptr;
3734 ptr += size;
3735 left -= size;
3736 } else
3737 space = FALSE;
3738 *pcbNeeded += size;
3740 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3741 &size, unicode)) {
3742 if(space && size <= left) {
3743 pi2->pDatatype = (LPWSTR)ptr;
3744 ptr += size;
3745 left -= size;
3746 } else
3747 space = FALSE;
3748 *pcbNeeded += size;
3750 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3751 &size, unicode)) {
3752 if(space && size <= left) {
3753 pi2->pParameters = (LPWSTR)ptr;
3754 ptr += size;
3755 left -= size;
3756 } else
3757 space = FALSE;
3758 *pcbNeeded += size;
3760 if(pi2) {
3761 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3762 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3763 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3764 "Default Priority");
3765 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3766 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3769 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3770 memset(pi2, 0, sizeof(*pi2));
3772 return space;
3775 /*********************************************************************
3776 * WINSPOOL_GetPrinter_4
3778 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3780 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3781 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3782 BOOL unicode)
3784 DWORD size, left = cbBuf;
3785 BOOL space = (cbBuf > 0);
3786 LPBYTE ptr = buf;
3788 *pcbNeeded = 0;
3790 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3791 unicode)) {
3792 if(space && size <= left) {
3793 pi4->pPrinterName = (LPWSTR)ptr;
3794 ptr += size;
3795 left -= size;
3796 } else
3797 space = FALSE;
3798 *pcbNeeded += size;
3800 if(pi4) {
3801 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3804 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3805 memset(pi4, 0, sizeof(*pi4));
3807 return space;
3810 /*********************************************************************
3811 * WINSPOOL_GetPrinter_5
3813 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3815 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3816 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3817 BOOL unicode)
3819 DWORD size, left = cbBuf;
3820 BOOL space = (cbBuf > 0);
3821 LPBYTE ptr = buf;
3823 *pcbNeeded = 0;
3825 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3826 unicode)) {
3827 if(space && size <= left) {
3828 pi5->pPrinterName = (LPWSTR)ptr;
3829 ptr += size;
3830 left -= size;
3831 } else
3832 space = FALSE;
3833 *pcbNeeded += size;
3835 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3836 unicode)) {
3837 if(space && size <= left) {
3838 pi5->pPortName = (LPWSTR)ptr;
3839 ptr += size;
3840 left -= size;
3841 } else
3842 space = FALSE;
3843 *pcbNeeded += size;
3845 if(pi5) {
3846 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3847 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3848 "dnsTimeout");
3849 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3850 "txTimeout");
3853 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3854 memset(pi5, 0, sizeof(*pi5));
3856 return space;
3859 /*****************************************************************************
3860 * WINSPOOL_GetPrinter
3862 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3863 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3864 * just a collection of pointers to strings.
3866 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3867 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3869 LPCWSTR name;
3870 DWORD size, needed = 0;
3871 LPBYTE ptr = NULL;
3872 HKEY hkeyPrinter, hkeyPrinters;
3873 BOOL ret;
3875 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3877 if (!(name = get_opened_printer_name(hPrinter))) {
3878 SetLastError(ERROR_INVALID_HANDLE);
3879 return FALSE;
3882 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3883 ERROR_SUCCESS) {
3884 ERR("Can't create Printers key\n");
3885 return FALSE;
3887 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3889 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3890 RegCloseKey(hkeyPrinters);
3891 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3892 return FALSE;
3895 switch(Level) {
3896 case 2:
3898 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3900 size = sizeof(PRINTER_INFO_2W);
3901 if(size <= cbBuf) {
3902 ptr = pPrinter + size;
3903 cbBuf -= size;
3904 memset(pPrinter, 0, size);
3905 } else {
3906 pi2 = NULL;
3907 cbBuf = 0;
3909 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3910 unicode);
3911 needed += size;
3912 break;
3915 case 4:
3917 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3919 size = sizeof(PRINTER_INFO_4W);
3920 if(size <= cbBuf) {
3921 ptr = pPrinter + size;
3922 cbBuf -= size;
3923 memset(pPrinter, 0, size);
3924 } else {
3925 pi4 = NULL;
3926 cbBuf = 0;
3928 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3929 unicode);
3930 needed += size;
3931 break;
3935 case 5:
3937 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3939 size = sizeof(PRINTER_INFO_5W);
3940 if(size <= cbBuf) {
3941 ptr = pPrinter + size;
3942 cbBuf -= size;
3943 memset(pPrinter, 0, size);
3944 } else {
3945 pi5 = NULL;
3946 cbBuf = 0;
3949 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3950 unicode);
3951 needed += size;
3952 break;
3955 default:
3956 FIXME("Unimplemented level %d\n", Level);
3957 SetLastError(ERROR_INVALID_LEVEL);
3958 RegCloseKey(hkeyPrinters);
3959 RegCloseKey(hkeyPrinter);
3960 return FALSE;
3963 RegCloseKey(hkeyPrinter);
3964 RegCloseKey(hkeyPrinters);
3966 TRACE("returning %d needed = %d\n", ret, needed);
3967 if(pcbNeeded) *pcbNeeded = needed;
3968 if(!ret)
3969 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3970 return ret;
3973 /*****************************************************************************
3974 * GetPrinterW [WINSPOOL.@]
3976 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3977 DWORD cbBuf, LPDWORD pcbNeeded)
3979 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3980 TRUE);
3983 /*****************************************************************************
3984 * GetPrinterA [WINSPOOL.@]
3986 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3987 DWORD cbBuf, LPDWORD pcbNeeded)
3989 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3990 FALSE);
3993 /*****************************************************************************
3994 * WINSPOOL_EnumPrinters
3996 * Implementation of EnumPrintersA|W
3998 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3999 DWORD dwLevel, LPBYTE lpbPrinters,
4000 DWORD cbBuf, LPDWORD lpdwNeeded,
4001 LPDWORD lpdwReturned, BOOL unicode)
4004 HKEY hkeyPrinters, hkeyPrinter;
4005 WCHAR PrinterName[255];
4006 DWORD needed = 0, number = 0;
4007 DWORD used, i, left;
4008 PBYTE pi, buf;
4010 if(lpbPrinters)
4011 memset(lpbPrinters, 0, cbBuf);
4012 if(lpdwReturned)
4013 *lpdwReturned = 0;
4014 if(lpdwNeeded)
4015 *lpdwNeeded = 0;
4017 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4018 if(dwType == PRINTER_ENUM_DEFAULT)
4019 return TRUE;
4021 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4022 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4023 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4024 if (!dwType) {
4025 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4026 *lpdwNeeded = 0;
4027 *lpdwReturned = 0;
4028 return TRUE;
4033 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4034 FIXME("dwType = %08x\n", dwType);
4035 SetLastError(ERROR_INVALID_FLAGS);
4036 return FALSE;
4039 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4040 ERROR_SUCCESS) {
4041 ERR("Can't create Printers key\n");
4042 return FALSE;
4045 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4046 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4047 RegCloseKey(hkeyPrinters);
4048 ERR("Can't query Printers key\n");
4049 return FALSE;
4051 TRACE("Found %d printers\n", number);
4053 switch(dwLevel) {
4054 case 1:
4055 used = number * sizeof(PRINTER_INFO_1W);
4056 break;
4057 case 2:
4058 used = number * sizeof(PRINTER_INFO_2W);
4059 break;
4060 case 4:
4061 used = number * sizeof(PRINTER_INFO_4W);
4062 break;
4063 case 5:
4064 used = number * sizeof(PRINTER_INFO_5W);
4065 break;
4067 default:
4068 SetLastError(ERROR_INVALID_LEVEL);
4069 RegCloseKey(hkeyPrinters);
4070 return FALSE;
4072 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4074 for(i = 0; i < number; i++) {
4075 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4076 ERROR_SUCCESS) {
4077 ERR("Can't enum key number %d\n", i);
4078 RegCloseKey(hkeyPrinters);
4079 return FALSE;
4081 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4082 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4083 ERROR_SUCCESS) {
4084 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4085 RegCloseKey(hkeyPrinters);
4086 return FALSE;
4089 if(cbBuf > used) {
4090 buf = lpbPrinters + used;
4091 left = cbBuf - used;
4092 } else {
4093 buf = NULL;
4094 left = 0;
4097 switch(dwLevel) {
4098 case 1:
4099 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4100 left, &needed, unicode);
4101 used += needed;
4102 if(pi) pi += sizeof(PRINTER_INFO_1W);
4103 break;
4104 case 2:
4105 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4106 left, &needed, unicode);
4107 used += needed;
4108 if(pi) pi += sizeof(PRINTER_INFO_2W);
4109 break;
4110 case 4:
4111 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4112 left, &needed, unicode);
4113 used += needed;
4114 if(pi) pi += sizeof(PRINTER_INFO_4W);
4115 break;
4116 case 5:
4117 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4118 left, &needed, unicode);
4119 used += needed;
4120 if(pi) pi += sizeof(PRINTER_INFO_5W);
4121 break;
4122 default:
4123 ERR("Shouldn't be here!\n");
4124 RegCloseKey(hkeyPrinter);
4125 RegCloseKey(hkeyPrinters);
4126 return FALSE;
4128 RegCloseKey(hkeyPrinter);
4130 RegCloseKey(hkeyPrinters);
4132 if(lpdwNeeded)
4133 *lpdwNeeded = used;
4135 if(used > cbBuf) {
4136 if(lpbPrinters)
4137 memset(lpbPrinters, 0, cbBuf);
4138 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4139 return FALSE;
4141 if(lpdwReturned)
4142 *lpdwReturned = number;
4143 SetLastError(ERROR_SUCCESS);
4144 return TRUE;
4148 /******************************************************************
4149 * EnumPrintersW [WINSPOOL.@]
4151 * Enumerates the available printers, print servers and print
4152 * providers, depending on the specified flags, name and level.
4154 * RETURNS:
4156 * If level is set to 1:
4157 * Returns an array of PRINTER_INFO_1 data structures in the
4158 * lpbPrinters buffer.
4160 * If level is set to 2:
4161 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4162 * Returns an array of PRINTER_INFO_2 data structures in the
4163 * lpbPrinters buffer. Note that according to MSDN also an
4164 * OpenPrinter should be performed on every remote printer.
4166 * If level is set to 4 (officially WinNT only):
4167 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4168 * Fast: Only the registry is queried to retrieve printer names,
4169 * no connection to the driver is made.
4170 * Returns an array of PRINTER_INFO_4 data structures in the
4171 * lpbPrinters buffer.
4173 * If level is set to 5 (officially WinNT4/Win9x only):
4174 * Fast: Only the registry is queried to retrieve printer names,
4175 * no connection to the driver is made.
4176 * Returns an array of PRINTER_INFO_5 data structures in the
4177 * lpbPrinters buffer.
4179 * If level set to 3 or 6+:
4180 * returns zero (failure!)
4182 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4183 * for information.
4185 * BUGS:
4186 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4187 * - Only levels 2, 4 and 5 are implemented at the moment.
4188 * - 16-bit printer drivers are not enumerated.
4189 * - Returned amount of bytes used/needed does not match the real Windoze
4190 * implementation (as in this implementation, all strings are part
4191 * of the buffer, whereas Win32 keeps them somewhere else)
4192 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4194 * NOTE:
4195 * - In a regular Wine installation, no registry settings for printers
4196 * exist, which makes this function return an empty list.
4198 BOOL WINAPI EnumPrintersW(
4199 DWORD dwType, /* [in] Types of print objects to enumerate */
4200 LPWSTR lpszName, /* [in] name of objects to enumerate */
4201 DWORD dwLevel, /* [in] type of printer info structure */
4202 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4203 DWORD cbBuf, /* [in] max size of buffer in bytes */
4204 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4205 LPDWORD lpdwReturned /* [out] number of entries returned */
4208 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4209 lpdwNeeded, lpdwReturned, TRUE);
4212 /******************************************************************
4213 * EnumPrintersA [WINSPOOL.@]
4216 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4217 DWORD dwLevel, LPBYTE lpbPrinters,
4218 DWORD cbBuf, LPDWORD lpdwNeeded,
4219 LPDWORD lpdwReturned)
4221 BOOL ret, unicode = FALSE;
4222 UNICODE_STRING lpszNameW;
4223 PWSTR pwstrNameW;
4225 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4226 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4227 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4228 lpdwNeeded, lpdwReturned, unicode);
4229 RtlFreeUnicodeString(&lpszNameW);
4230 return ret;
4233 /*****************************************************************************
4234 * WINSPOOL_GetDriverInfoFromReg [internal]
4236 * Enters the information from the registry into the DRIVER_INFO struct
4238 * RETURNS
4239 * zero if the printer driver does not exist in the registry
4240 * (only if Level > 1) otherwise nonzero
4242 static BOOL WINSPOOL_GetDriverInfoFromReg(
4243 HKEY hkeyDrivers,
4244 LPWSTR DriverName,
4245 LPCWSTR pEnvironment,
4246 DWORD Level,
4247 LPBYTE ptr, /* DRIVER_INFO */
4248 LPBYTE pDriverStrings, /* strings buffer */
4249 DWORD cbBuf, /* size of string buffer */
4250 LPDWORD pcbNeeded, /* space needed for str. */
4251 BOOL unicode) /* type of strings */
4253 DWORD size, tmp;
4254 HKEY hkeyDriver;
4255 LPBYTE strPtr = pDriverStrings;
4257 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4258 debugstr_w(DriverName), debugstr_w(pEnvironment),
4259 Level, ptr, pDriverStrings, cbBuf, unicode);
4261 if(unicode) {
4262 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4263 if (*pcbNeeded <= cbBuf)
4264 strcpyW((LPWSTR)strPtr, DriverName);
4265 } else {
4266 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4267 NULL, NULL);
4268 if(*pcbNeeded <= cbBuf)
4269 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4270 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4272 if(Level == 1) {
4273 if(ptr)
4274 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4275 return TRUE;
4276 } else {
4277 if(ptr)
4278 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4279 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4282 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4283 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4284 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4285 return FALSE;
4288 if(ptr)
4289 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4291 if(!pEnvironment)
4292 pEnvironment = DefaultEnvironmentW;
4293 if(unicode)
4294 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4295 else
4296 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4297 NULL, NULL);
4298 *pcbNeeded += size;
4299 if(*pcbNeeded <= cbBuf) {
4300 if(unicode)
4301 strcpyW((LPWSTR)strPtr, pEnvironment);
4302 else
4303 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4304 (LPSTR)strPtr, size, NULL, NULL);
4305 if(ptr)
4306 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4307 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4310 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4311 unicode)) {
4312 *pcbNeeded += size;
4313 if(*pcbNeeded <= cbBuf)
4314 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4315 unicode);
4316 if(ptr)
4317 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4318 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4321 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4322 unicode)) {
4323 *pcbNeeded += size;
4324 if(*pcbNeeded <= cbBuf)
4325 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4326 &tmp, unicode);
4327 if(ptr)
4328 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4329 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4332 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4333 0, &size, unicode)) {
4334 *pcbNeeded += size;
4335 if(*pcbNeeded <= cbBuf)
4336 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4337 size, &tmp, unicode);
4338 if(ptr)
4339 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4340 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4343 if(Level == 2 ) {
4344 RegCloseKey(hkeyDriver);
4345 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4346 return TRUE;
4349 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4350 unicode)) {
4351 *pcbNeeded += size;
4352 if(*pcbNeeded <= cbBuf)
4353 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4354 size, &tmp, unicode);
4355 if(ptr)
4356 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4357 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4360 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4361 &size, unicode)) {
4362 *pcbNeeded += size;
4363 if(*pcbNeeded <= cbBuf)
4364 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4365 size, &tmp, unicode);
4366 if(ptr)
4367 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4368 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4371 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4372 unicode)) {
4373 *pcbNeeded += size;
4374 if(*pcbNeeded <= cbBuf)
4375 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4376 size, &tmp, unicode);
4377 if(ptr)
4378 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4379 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4382 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4383 unicode)) {
4384 *pcbNeeded += size;
4385 if(*pcbNeeded <= cbBuf)
4386 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4387 size, &tmp, unicode);
4388 if(ptr)
4389 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4390 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4393 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4394 RegCloseKey(hkeyDriver);
4395 return TRUE;
4398 /*****************************************************************************
4399 * WINSPOOL_GetPrinterDriver
4401 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4402 DWORD Level, LPBYTE pDriverInfo,
4403 DWORD cbBuf, LPDWORD pcbNeeded,
4404 BOOL unicode)
4406 LPCWSTR name;
4407 WCHAR DriverName[100];
4408 DWORD ret, type, size, needed = 0;
4409 LPBYTE ptr = NULL;
4410 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4412 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4413 Level,pDriverInfo,cbBuf, pcbNeeded);
4415 ZeroMemory(pDriverInfo, cbBuf);
4417 if (!(name = get_opened_printer_name(hPrinter))) {
4418 SetLastError(ERROR_INVALID_HANDLE);
4419 return FALSE;
4421 if(Level < 1 || Level > 6) {
4422 SetLastError(ERROR_INVALID_LEVEL);
4423 return FALSE;
4425 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4426 ERROR_SUCCESS) {
4427 ERR("Can't create Printers key\n");
4428 return FALSE;
4430 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4431 != ERROR_SUCCESS) {
4432 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4433 RegCloseKey(hkeyPrinters);
4434 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4435 return FALSE;
4437 size = sizeof(DriverName);
4438 DriverName[0] = 0;
4439 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4440 (LPBYTE)DriverName, &size);
4441 RegCloseKey(hkeyPrinter);
4442 RegCloseKey(hkeyPrinters);
4443 if(ret != ERROR_SUCCESS) {
4444 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4445 return FALSE;
4448 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4449 if(!hkeyDrivers) {
4450 ERR("Can't create Drivers key\n");
4451 return FALSE;
4454 switch(Level) {
4455 case 1:
4456 size = sizeof(DRIVER_INFO_1W);
4457 break;
4458 case 2:
4459 size = sizeof(DRIVER_INFO_2W);
4460 break;
4461 case 3:
4462 size = sizeof(DRIVER_INFO_3W);
4463 break;
4464 case 4:
4465 size = sizeof(DRIVER_INFO_4W);
4466 break;
4467 case 5:
4468 size = sizeof(DRIVER_INFO_5W);
4469 break;
4470 case 6:
4471 size = sizeof(DRIVER_INFO_6W);
4472 break;
4473 default:
4474 ERR("Invalid level\n");
4475 return FALSE;
4478 if(size <= cbBuf)
4479 ptr = pDriverInfo + size;
4481 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4482 pEnvironment, Level, pDriverInfo,
4483 (cbBuf < size) ? NULL : ptr,
4484 (cbBuf < size) ? 0 : cbBuf - size,
4485 &needed, unicode)) {
4486 RegCloseKey(hkeyDrivers);
4487 return FALSE;
4490 RegCloseKey(hkeyDrivers);
4492 if(pcbNeeded) *pcbNeeded = size + needed;
4493 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4494 if(cbBuf >= needed) return TRUE;
4495 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4496 return FALSE;
4499 /*****************************************************************************
4500 * GetPrinterDriverA [WINSPOOL.@]
4502 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4503 DWORD Level, LPBYTE pDriverInfo,
4504 DWORD cbBuf, LPDWORD pcbNeeded)
4506 BOOL ret;
4507 UNICODE_STRING pEnvW;
4508 PWSTR pwstrEnvW;
4510 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4511 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4512 cbBuf, pcbNeeded, FALSE);
4513 RtlFreeUnicodeString(&pEnvW);
4514 return ret;
4516 /*****************************************************************************
4517 * GetPrinterDriverW [WINSPOOL.@]
4519 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4520 DWORD Level, LPBYTE pDriverInfo,
4521 DWORD cbBuf, LPDWORD pcbNeeded)
4523 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4524 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4527 /*****************************************************************************
4528 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4530 * Return the PATH for the Printer-Drivers (UNICODE)
4532 * PARAMS
4533 * pName [I] Servername (NT only) or NULL (local Computer)
4534 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4535 * Level [I] Structure-Level (must be 1)
4536 * pDriverDirectory [O] PTR to Buffer that receives the Result
4537 * cbBuf [I] Size of Buffer at pDriverDirectory
4538 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4539 * required for pDriverDirectory
4541 * RETURNS
4542 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4543 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4544 * if cbBuf is too small
4546 * Native Values returned in pDriverDirectory on Success:
4547 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4548 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4549 *| win9x(Windows 4.0): "%winsysdir%"
4551 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4553 * FIXME
4554 *- Only NULL or "" is supported for pName
4557 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4558 DWORD Level, LPBYTE pDriverDirectory,
4559 DWORD cbBuf, LPDWORD pcbNeeded)
4561 DWORD needed;
4562 const printenv_t * env;
4564 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4565 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4566 if(pName != NULL && pName[0]) {
4567 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4568 SetLastError(ERROR_INVALID_PARAMETER);
4569 return FALSE;
4572 env = validate_envW(pEnvironment);
4573 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4575 if(Level != 1) {
4576 WARN("(Level: %d) is ignored in win9x\n", Level);
4577 SetLastError(ERROR_INVALID_LEVEL);
4578 return FALSE;
4581 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4582 needed = GetSystemDirectoryW(NULL, 0);
4583 /* add the Size for the Subdirectories */
4584 needed += lstrlenW(spooldriversW);
4585 needed += lstrlenW(env->subdir);
4586 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4588 if(pcbNeeded)
4589 *pcbNeeded = needed;
4590 TRACE("required: 0x%x/%d\n", needed, needed);
4591 if(needed > cbBuf) {
4592 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4593 return FALSE;
4595 if(pcbNeeded == NULL) {
4596 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4597 SetLastError(RPC_X_NULL_REF_POINTER);
4598 return FALSE;
4600 if(pDriverDirectory == NULL) {
4601 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4602 SetLastError(ERROR_INVALID_USER_BUFFER);
4603 return FALSE;
4606 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4607 /* add the Subdirectories */
4608 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4609 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4610 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4611 return TRUE;
4615 /*****************************************************************************
4616 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4618 * Return the PATH for the Printer-Drivers (ANSI)
4620 * See GetPrinterDriverDirectoryW.
4622 * NOTES
4623 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4626 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4627 DWORD Level, LPBYTE pDriverDirectory,
4628 DWORD cbBuf, LPDWORD pcbNeeded)
4630 UNICODE_STRING nameW, environmentW;
4631 BOOL ret;
4632 DWORD pcbNeededW;
4633 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4634 WCHAR *driverDirectoryW = NULL;
4636 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4637 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4639 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4641 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4642 else nameW.Buffer = NULL;
4643 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4644 else environmentW.Buffer = NULL;
4646 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4647 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4648 if (ret) {
4649 DWORD needed;
4650 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4651 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4652 if(pcbNeeded)
4653 *pcbNeeded = needed;
4654 ret = (needed <= cbBuf) ? TRUE : FALSE;
4655 } else
4656 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4658 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4660 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4661 RtlFreeUnicodeString(&environmentW);
4662 RtlFreeUnicodeString(&nameW);
4664 return ret;
4667 /*****************************************************************************
4668 * AddPrinterDriverA [WINSPOOL.@]
4670 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4672 DRIVER_INFO_3A di3;
4673 HKEY hkeyDrivers, hkeyName;
4674 static CHAR empty[] = "",
4675 nullnull[] = "\0";
4677 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4679 if(level != 2 && level != 3) {
4680 SetLastError(ERROR_INVALID_LEVEL);
4681 return FALSE;
4683 if ((pName) && (pName[0])) {
4684 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4685 SetLastError(ERROR_INVALID_PARAMETER);
4686 return FALSE;
4688 if(!pDriverInfo) {
4689 WARN("pDriverInfo == NULL\n");
4690 SetLastError(ERROR_INVALID_PARAMETER);
4691 return FALSE;
4694 if(level == 3)
4695 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4696 else {
4697 memset(&di3, 0, sizeof(di3));
4698 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4701 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4702 !di3.pDataFile) {
4703 SetLastError(ERROR_INVALID_PARAMETER);
4704 return FALSE;
4707 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4708 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4709 if(!di3.pHelpFile) di3.pHelpFile = empty;
4710 if(!di3.pMonitorName) di3.pMonitorName = empty;
4712 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4714 if(!hkeyDrivers) {
4715 ERR("Can't create Drivers key\n");
4716 return FALSE;
4719 if(level == 2) { /* apparently can't overwrite with level2 */
4720 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4721 RegCloseKey(hkeyName);
4722 RegCloseKey(hkeyDrivers);
4723 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4724 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4725 return FALSE;
4728 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4729 RegCloseKey(hkeyDrivers);
4730 ERR("Can't create Name key\n");
4731 return FALSE;
4733 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4734 lstrlenA(di3.pConfigFile) + 1);
4735 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4736 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4737 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4738 sizeof(DWORD));
4739 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4740 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4741 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4742 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4743 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4744 RegCloseKey(hkeyName);
4745 RegCloseKey(hkeyDrivers);
4747 return TRUE;
4750 /*****************************************************************************
4751 * AddPrinterDriverW [WINSPOOL.@]
4753 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4754 LPBYTE pDriverInfo)
4756 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4757 level,pDriverInfo);
4758 return FALSE;
4761 /*****************************************************************************
4762 * AddPrintProcessorA [WINSPOOL.@]
4764 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4765 LPSTR pPrintProcessorName)
4767 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4768 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4769 return FALSE;
4772 /*****************************************************************************
4773 * AddPrintProcessorW [WINSPOOL.@]
4775 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4776 LPWSTR pPrintProcessorName)
4778 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4779 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4780 return FALSE;
4783 /*****************************************************************************
4784 * AddPrintProvidorA [WINSPOOL.@]
4786 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4788 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4789 return FALSE;
4792 /*****************************************************************************
4793 * AddPrintProvidorW [WINSPOOL.@]
4795 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4797 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4798 return FALSE;
4801 /*****************************************************************************
4802 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4804 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4805 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4807 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4808 pDevModeOutput, pDevModeInput);
4809 return 0;
4812 /*****************************************************************************
4813 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4815 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4816 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4818 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4819 pDevModeOutput, pDevModeInput);
4820 return 0;
4823 /*****************************************************************************
4824 * PrinterProperties [WINSPOOL.@]
4826 * Displays a dialog to set the properties of the printer.
4828 * RETURNS
4829 * nonzero on success or zero on failure
4831 * BUGS
4832 * implemented as stub only
4834 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4835 HANDLE hPrinter /* [in] handle to printer object */
4837 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4838 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4839 return FALSE;
4842 /*****************************************************************************
4843 * EnumJobsA [WINSPOOL.@]
4846 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4847 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4848 LPDWORD pcReturned)
4850 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4851 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4853 if(pcbNeeded) *pcbNeeded = 0;
4854 if(pcReturned) *pcReturned = 0;
4855 return FALSE;
4859 /*****************************************************************************
4860 * EnumJobsW [WINSPOOL.@]
4863 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4864 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4865 LPDWORD pcReturned)
4867 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4868 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4870 if(pcbNeeded) *pcbNeeded = 0;
4871 if(pcReturned) *pcReturned = 0;
4872 return FALSE;
4875 /*****************************************************************************
4876 * WINSPOOL_EnumPrinterDrivers [internal]
4878 * Delivers information about all printer drivers installed on the
4879 * localhost or a given server
4881 * RETURNS
4882 * nonzero on success or zero on failure. If the buffer for the returned
4883 * information is too small the function will return an error
4885 * BUGS
4886 * - only implemented for localhost, foreign hosts will return an error
4888 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4889 DWORD Level, LPBYTE pDriverInfo,
4890 DWORD cbBuf, LPDWORD pcbNeeded,
4891 LPDWORD pcReturned, BOOL unicode)
4893 { HKEY hkeyDrivers;
4894 DWORD i, needed, number = 0, size = 0;
4895 WCHAR DriverNameW[255];
4896 PBYTE ptr;
4898 TRACE("%s,%s,%d,%p,%d,%d\n",
4899 debugstr_w(pName), debugstr_w(pEnvironment),
4900 Level, pDriverInfo, cbBuf, unicode);
4902 /* check for local drivers */
4903 if((pName) && (pName[0])) {
4904 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4905 SetLastError(ERROR_ACCESS_DENIED);
4906 return FALSE;
4909 /* check input parameter */
4910 if((Level < 1) || (Level > 3)) {
4911 ERR("unsupported level %d\n", Level);
4912 SetLastError(ERROR_INVALID_LEVEL);
4913 return FALSE;
4916 /* initialize return values */
4917 if(pDriverInfo)
4918 memset( pDriverInfo, 0, cbBuf);
4919 *pcbNeeded = 0;
4920 *pcReturned = 0;
4922 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4923 if(!hkeyDrivers) {
4924 ERR("Can't open Drivers key\n");
4925 return FALSE;
4928 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4929 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4930 RegCloseKey(hkeyDrivers);
4931 ERR("Can't query Drivers key\n");
4932 return FALSE;
4934 TRACE("Found %d Drivers\n", number);
4936 /* get size of single struct
4937 * unicode and ascii structure have the same size
4939 switch (Level) {
4940 case 1:
4941 size = sizeof(DRIVER_INFO_1A);
4942 break;
4943 case 2:
4944 size = sizeof(DRIVER_INFO_2A);
4945 break;
4946 case 3:
4947 size = sizeof(DRIVER_INFO_3A);
4948 break;
4951 /* calculate required buffer size */
4952 *pcbNeeded = size * number;
4954 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4955 i < number;
4956 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4957 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4958 != ERROR_SUCCESS) {
4959 ERR("Can't enum key number %d\n", i);
4960 RegCloseKey(hkeyDrivers);
4961 return FALSE;
4963 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4964 pEnvironment, Level, ptr,
4965 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4966 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4967 &needed, unicode)) {
4968 RegCloseKey(hkeyDrivers);
4969 return FALSE;
4971 (*pcbNeeded) += needed;
4974 RegCloseKey(hkeyDrivers);
4976 if(cbBuf < *pcbNeeded){
4977 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4978 return FALSE;
4981 *pcReturned = number;
4982 return TRUE;
4985 /*****************************************************************************
4986 * EnumPrinterDriversW [WINSPOOL.@]
4988 * see function EnumPrinterDrivers for RETURNS, BUGS
4990 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4991 LPBYTE pDriverInfo, DWORD cbBuf,
4992 LPDWORD pcbNeeded, LPDWORD pcReturned)
4994 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4995 cbBuf, pcbNeeded, pcReturned, TRUE);
4998 /*****************************************************************************
4999 * EnumPrinterDriversA [WINSPOOL.@]
5001 * see function EnumPrinterDrivers for RETURNS, BUGS
5003 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5004 LPBYTE pDriverInfo, DWORD cbBuf,
5005 LPDWORD pcbNeeded, LPDWORD pcReturned)
5006 { BOOL ret;
5007 UNICODE_STRING pNameW, pEnvironmentW;
5008 PWSTR pwstrNameW, pwstrEnvironmentW;
5010 pwstrNameW = asciitounicode(&pNameW, pName);
5011 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5013 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5014 Level, pDriverInfo, cbBuf, pcbNeeded,
5015 pcReturned, FALSE);
5016 RtlFreeUnicodeString(&pNameW);
5017 RtlFreeUnicodeString(&pEnvironmentW);
5019 return ret;
5022 /******************************************************************************
5023 * EnumPortsA (WINSPOOL.@)
5025 * See EnumPortsW.
5028 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5029 LPDWORD pcbNeeded, LPDWORD pcReturned)
5031 BOOL res;
5032 LPBYTE bufferW = NULL;
5033 LPWSTR nameW = NULL;
5034 DWORD needed = 0;
5035 DWORD numentries = 0;
5036 INT len;
5038 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5039 cbBuf, pcbNeeded, pcReturned);
5041 /* convert servername to unicode */
5042 if (pName) {
5043 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5044 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5045 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5047 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5048 needed = cbBuf * sizeof(WCHAR);
5049 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5050 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5052 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5053 if (pcbNeeded) needed = *pcbNeeded;
5054 /* HeapReAlloc return NULL, when bufferW was NULL */
5055 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5056 HeapAlloc(GetProcessHeap(), 0, needed);
5058 /* Try again with the large Buffer */
5059 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5061 needed = pcbNeeded ? *pcbNeeded : 0;
5062 numentries = pcReturned ? *pcReturned : 0;
5065 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5066 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5068 if (res) {
5069 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5070 DWORD entrysize = 0;
5071 DWORD index;
5072 LPSTR ptr;
5073 LPPORT_INFO_2W pi2w;
5074 LPPORT_INFO_2A pi2a;
5076 needed = 0;
5077 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5079 /* First pass: calculate the size for all Entries */
5080 pi2w = (LPPORT_INFO_2W) bufferW;
5081 pi2a = (LPPORT_INFO_2A) pPorts;
5082 index = 0;
5083 while (index < numentries) {
5084 index++;
5085 needed += entrysize; /* PORT_INFO_?A */
5086 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5088 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5089 NULL, 0, NULL, NULL);
5090 if (Level > 1) {
5091 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5092 NULL, 0, NULL, NULL);
5093 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5094 NULL, 0, NULL, NULL);
5096 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5097 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5098 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5101 /* check for errors and quit on failure */
5102 if (cbBuf < needed) {
5103 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5104 res = FALSE;
5105 goto cleanup;
5107 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5108 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5109 cbBuf -= len ; /* free Bytes in the user-Buffer */
5110 pi2w = (LPPORT_INFO_2W) bufferW;
5111 pi2a = (LPPORT_INFO_2A) pPorts;
5112 index = 0;
5113 /* Second Pass: Fill the User Buffer (if we have one) */
5114 while ((index < numentries) && pPorts) {
5115 index++;
5116 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5117 pi2a->pPortName = ptr;
5118 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5119 ptr, cbBuf , NULL, NULL);
5120 ptr += len;
5121 cbBuf -= len;
5122 if (Level > 1) {
5123 pi2a->pMonitorName = ptr;
5124 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5125 ptr, cbBuf, NULL, NULL);
5126 ptr += len;
5127 cbBuf -= len;
5129 pi2a->pDescription = ptr;
5130 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5131 ptr, cbBuf, NULL, NULL);
5132 ptr += len;
5133 cbBuf -= len;
5135 pi2a->fPortType = pi2w->fPortType;
5136 pi2a->Reserved = 0; /* documented: "must be zero" */
5139 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5140 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5141 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5145 cleanup:
5146 if (pcbNeeded) *pcbNeeded = needed;
5147 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5149 HeapFree(GetProcessHeap(), 0, nameW);
5150 HeapFree(GetProcessHeap(), 0, bufferW);
5152 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5153 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5155 return (res);
5159 /******************************************************************************
5160 * EnumPortsW (WINSPOOL.@)
5162 * Enumerate available Ports
5164 * PARAMS
5165 * name [I] Servername or NULL (local Computer)
5166 * level [I] Structure-Level (1 or 2)
5167 * buffer [O] PTR to Buffer that receives the Result
5168 * bufsize [I] Size of Buffer at buffer
5169 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5170 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5172 * RETURNS
5173 * Success: TRUE
5174 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5178 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5180 DWORD needed = 0;
5181 DWORD numentries = 0;
5182 BOOL res = FALSE;
5184 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5185 cbBuf, pcbNeeded, pcReturned);
5187 if (pName && (pName[0])) {
5188 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5189 SetLastError(ERROR_ACCESS_DENIED);
5190 goto emP_cleanup;
5193 /* Level is not checked in win9x */
5194 if (!Level || (Level > 2)) {
5195 WARN("level (%d) is ignored in win9x\n", Level);
5196 SetLastError(ERROR_INVALID_LEVEL);
5197 goto emP_cleanup;
5199 if (!pcbNeeded) {
5200 SetLastError(RPC_X_NULL_REF_POINTER);
5201 goto emP_cleanup;
5204 EnterCriticalSection(&monitor_handles_cs);
5205 monitor_loadall();
5207 /* Scan all local Ports */
5208 numentries = 0;
5209 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5211 /* we calculated the needed buffersize. now do the error-checks */
5212 if (cbBuf < needed) {
5213 monitor_unloadall();
5214 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5215 goto emP_cleanup_cs;
5217 else if (!pPorts || !pcReturned) {
5218 monitor_unloadall();
5219 SetLastError(RPC_X_NULL_REF_POINTER);
5220 goto emP_cleanup_cs;
5223 /* Fill the Buffer */
5224 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5225 res = TRUE;
5226 monitor_unloadall();
5228 emP_cleanup_cs:
5229 LeaveCriticalSection(&monitor_handles_cs);
5231 emP_cleanup:
5232 if (pcbNeeded) *pcbNeeded = needed;
5233 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5235 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5236 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5238 return (res);
5241 /******************************************************************************
5242 * GetDefaultPrinterW (WINSPOOL.@)
5244 * FIXME
5245 * This function must read the value from data 'device' of key
5246 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5248 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5250 BOOL retval = TRUE;
5251 DWORD insize, len;
5252 WCHAR *buffer, *ptr;
5254 if (!namesize)
5256 SetLastError(ERROR_INVALID_PARAMETER);
5257 return FALSE;
5260 /* make the buffer big enough for the stuff from the profile/registry,
5261 * the content must fit into the local buffer to compute the correct
5262 * size even if the extern buffer is too small or not given.
5263 * (20 for ,driver,port) */
5264 insize = *namesize;
5265 len = max(100, (insize + 20));
5266 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5268 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5270 SetLastError (ERROR_FILE_NOT_FOUND);
5271 retval = FALSE;
5272 goto end;
5274 TRACE("%s\n", debugstr_w(buffer));
5276 if ((ptr = strchrW(buffer, ',')) == NULL)
5278 SetLastError(ERROR_INVALID_NAME);
5279 retval = FALSE;
5280 goto end;
5283 *ptr = 0;
5284 *namesize = strlenW(buffer) + 1;
5285 if(!name || (*namesize > insize))
5287 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5288 retval = FALSE;
5289 goto end;
5291 strcpyW(name, buffer);
5293 end:
5294 HeapFree( GetProcessHeap(), 0, buffer);
5295 return retval;
5299 /******************************************************************************
5300 * GetDefaultPrinterA (WINSPOOL.@)
5302 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5304 BOOL retval = TRUE;
5305 DWORD insize = 0;
5306 WCHAR *bufferW = NULL;
5308 if (!namesize)
5310 SetLastError(ERROR_INVALID_PARAMETER);
5311 return FALSE;
5314 if(name && *namesize) {
5315 insize = *namesize;
5316 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5319 if(!GetDefaultPrinterW( bufferW, namesize)) {
5320 retval = FALSE;
5321 goto end;
5324 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5325 NULL, NULL);
5326 if (!*namesize)
5328 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5329 retval = FALSE;
5331 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5333 end:
5334 HeapFree( GetProcessHeap(), 0, bufferW);
5335 return retval;
5339 /******************************************************************************
5340 * SetDefaultPrinterW (WINSPOOL.204)
5342 * Set the Name of the Default Printer
5344 * PARAMS
5345 * pszPrinter [I] Name of the Printer or NULL
5347 * RETURNS
5348 * Success: True
5349 * Failure: FALSE
5351 * NOTES
5352 * When the Parameter is NULL or points to an Empty String and
5353 * a Default Printer was already present, then this Function changes nothing.
5354 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5355 * the First enumerated local Printer is used.
5358 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5361 TRACE("(%s)\n", debugstr_w(pszPrinter));
5363 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5364 return FALSE;
5367 /******************************************************************************
5368 * SetDefaultPrinterA (WINSPOOL.202)
5370 * See SetDefaultPrinterW.
5373 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5376 TRACE("(%s)\n", debugstr_a(pszPrinter));
5378 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5379 return FALSE;
5383 /******************************************************************************
5384 * SetPrinterDataExA (WINSPOOL.@)
5386 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5387 LPCSTR pValueName, DWORD Type,
5388 LPBYTE pData, DWORD cbData)
5390 HKEY hkeyPrinter, hkeySubkey;
5391 DWORD ret;
5393 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5394 debugstr_a(pValueName), Type, pData, cbData);
5396 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5397 != ERROR_SUCCESS)
5398 return ret;
5400 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5401 != ERROR_SUCCESS) {
5402 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5403 RegCloseKey(hkeyPrinter);
5404 return ret;
5406 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5407 RegCloseKey(hkeySubkey);
5408 RegCloseKey(hkeyPrinter);
5409 return ret;
5412 /******************************************************************************
5413 * SetPrinterDataExW (WINSPOOL.@)
5415 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5416 LPCWSTR pValueName, DWORD Type,
5417 LPBYTE pData, DWORD cbData)
5419 HKEY hkeyPrinter, hkeySubkey;
5420 DWORD ret;
5422 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5423 debugstr_w(pValueName), Type, pData, cbData);
5425 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5426 != ERROR_SUCCESS)
5427 return ret;
5429 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5430 != ERROR_SUCCESS) {
5431 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5432 RegCloseKey(hkeyPrinter);
5433 return ret;
5435 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5436 RegCloseKey(hkeySubkey);
5437 RegCloseKey(hkeyPrinter);
5438 return ret;
5441 /******************************************************************************
5442 * SetPrinterDataA (WINSPOOL.@)
5444 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5445 LPBYTE pData, DWORD cbData)
5447 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5448 pData, cbData);
5451 /******************************************************************************
5452 * SetPrinterDataW (WINSPOOL.@)
5454 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5455 LPBYTE pData, DWORD cbData)
5457 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5458 pData, cbData);
5461 /******************************************************************************
5462 * GetPrinterDataExA (WINSPOOL.@)
5464 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5465 LPCSTR pValueName, LPDWORD pType,
5466 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5468 HKEY hkeyPrinter, hkeySubkey;
5469 DWORD ret;
5471 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5472 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5473 pcbNeeded);
5475 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5476 != ERROR_SUCCESS)
5477 return ret;
5479 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5480 != ERROR_SUCCESS) {
5481 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5482 RegCloseKey(hkeyPrinter);
5483 return ret;
5485 *pcbNeeded = nSize;
5486 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5487 RegCloseKey(hkeySubkey);
5488 RegCloseKey(hkeyPrinter);
5489 return ret;
5492 /******************************************************************************
5493 * GetPrinterDataExW (WINSPOOL.@)
5495 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5496 LPCWSTR pValueName, LPDWORD pType,
5497 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5499 HKEY hkeyPrinter, hkeySubkey;
5500 DWORD ret;
5502 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5503 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5504 pcbNeeded);
5506 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5507 != ERROR_SUCCESS)
5508 return ret;
5510 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5511 != ERROR_SUCCESS) {
5512 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5513 RegCloseKey(hkeyPrinter);
5514 return ret;
5516 *pcbNeeded = nSize;
5517 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5518 RegCloseKey(hkeySubkey);
5519 RegCloseKey(hkeyPrinter);
5520 return ret;
5523 /******************************************************************************
5524 * GetPrinterDataA (WINSPOOL.@)
5526 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5527 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5529 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5530 pData, nSize, pcbNeeded);
5533 /******************************************************************************
5534 * GetPrinterDataW (WINSPOOL.@)
5536 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5537 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5539 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5540 pData, nSize, pcbNeeded);
5543 /*******************************************************************************
5544 * EnumPrinterDataExW [WINSPOOL.@]
5546 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5547 LPBYTE pEnumValues, DWORD cbEnumValues,
5548 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5550 HKEY hkPrinter, hkSubKey;
5551 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5552 cbValueNameLen, cbMaxValueLen, cbValueLen,
5553 cbBufSize, dwType;
5554 LPWSTR lpValueName;
5555 HANDLE hHeap;
5556 PBYTE lpValue;
5557 PPRINTER_ENUM_VALUESW ppev;
5559 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5561 if (pKeyName == NULL || *pKeyName == 0)
5562 return ERROR_INVALID_PARAMETER;
5564 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5565 if (ret != ERROR_SUCCESS)
5567 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5568 hPrinter, ret);
5569 return ret;
5572 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5573 if (ret != ERROR_SUCCESS)
5575 r = RegCloseKey (hkPrinter);
5576 if (r != ERROR_SUCCESS)
5577 WARN ("RegCloseKey returned %i\n", r);
5578 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5579 debugstr_w (pKeyName), ret);
5580 return ret;
5583 ret = RegCloseKey (hkPrinter);
5584 if (ret != ERROR_SUCCESS)
5586 ERR ("RegCloseKey returned %i\n", ret);
5587 r = RegCloseKey (hkSubKey);
5588 if (r != ERROR_SUCCESS)
5589 WARN ("RegCloseKey returned %i\n", r);
5590 return ret;
5593 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5594 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5595 if (ret != ERROR_SUCCESS)
5597 r = RegCloseKey (hkSubKey);
5598 if (r != ERROR_SUCCESS)
5599 WARN ("RegCloseKey returned %i\n", r);
5600 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5601 return ret;
5604 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5605 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5607 if (cValues == 0) /* empty key */
5609 r = RegCloseKey (hkSubKey);
5610 if (r != ERROR_SUCCESS)
5611 WARN ("RegCloseKey returned %i\n", r);
5612 *pcbEnumValues = *pnEnumValues = 0;
5613 return ERROR_SUCCESS;
5616 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5618 hHeap = GetProcessHeap ();
5619 if (hHeap == NULL)
5621 ERR ("GetProcessHeap failed\n");
5622 r = RegCloseKey (hkSubKey);
5623 if (r != ERROR_SUCCESS)
5624 WARN ("RegCloseKey returned %i\n", r);
5625 return ERROR_OUTOFMEMORY;
5628 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5629 if (lpValueName == NULL)
5631 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5632 r = RegCloseKey (hkSubKey);
5633 if (r != ERROR_SUCCESS)
5634 WARN ("RegCloseKey returned %i\n", r);
5635 return ERROR_OUTOFMEMORY;
5638 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5639 if (lpValue == NULL)
5641 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5642 if (HeapFree (hHeap, 0, lpValueName) == 0)
5643 WARN ("HeapFree failed with code %i\n", GetLastError ());
5644 r = RegCloseKey (hkSubKey);
5645 if (r != ERROR_SUCCESS)
5646 WARN ("RegCloseKey returned %i\n", r);
5647 return ERROR_OUTOFMEMORY;
5650 TRACE ("pass 1: calculating buffer required for all names and values\n");
5652 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5654 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5656 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5658 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5659 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5660 NULL, NULL, lpValue, &cbValueLen);
5661 if (ret != ERROR_SUCCESS)
5663 if (HeapFree (hHeap, 0, lpValue) == 0)
5664 WARN ("HeapFree failed with code %i\n", GetLastError ());
5665 if (HeapFree (hHeap, 0, lpValueName) == 0)
5666 WARN ("HeapFree failed with code %i\n", GetLastError ());
5667 r = RegCloseKey (hkSubKey);
5668 if (r != ERROR_SUCCESS)
5669 WARN ("RegCloseKey returned %i\n", r);
5670 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5671 return ret;
5674 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5675 debugstr_w (lpValueName), dwIndex,
5676 cbValueNameLen + 1, cbValueLen);
5678 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5679 cbBufSize += cbValueLen;
5682 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5684 *pcbEnumValues = cbBufSize;
5685 *pnEnumValues = cValues;
5687 if (cbEnumValues < cbBufSize) /* buffer too small */
5689 if (HeapFree (hHeap, 0, lpValue) == 0)
5690 WARN ("HeapFree failed with code %i\n", GetLastError ());
5691 if (HeapFree (hHeap, 0, lpValueName) == 0)
5692 WARN ("HeapFree failed with code %i\n", GetLastError ());
5693 r = RegCloseKey (hkSubKey);
5694 if (r != ERROR_SUCCESS)
5695 WARN ("RegCloseKey returned %i\n", r);
5696 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5697 return ERROR_MORE_DATA;
5700 TRACE ("pass 2: copying all names and values to buffer\n");
5702 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5703 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5705 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5707 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5708 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5709 NULL, &dwType, lpValue, &cbValueLen);
5710 if (ret != ERROR_SUCCESS)
5712 if (HeapFree (hHeap, 0, lpValue) == 0)
5713 WARN ("HeapFree failed with code %i\n", GetLastError ());
5714 if (HeapFree (hHeap, 0, lpValueName) == 0)
5715 WARN ("HeapFree failed with code %i\n", GetLastError ());
5716 r = RegCloseKey (hkSubKey);
5717 if (r != ERROR_SUCCESS)
5718 WARN ("RegCloseKey returned %i\n", r);
5719 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5720 return ret;
5723 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5724 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5725 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5726 pEnumValues += cbValueNameLen;
5728 /* return # of *bytes* (including trailing \0), not # of chars */
5729 ppev[dwIndex].cbValueName = cbValueNameLen;
5731 ppev[dwIndex].dwType = dwType;
5733 memcpy (pEnumValues, lpValue, cbValueLen);
5734 ppev[dwIndex].pData = pEnumValues;
5735 pEnumValues += cbValueLen;
5737 ppev[dwIndex].cbData = cbValueLen;
5739 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5740 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5743 if (HeapFree (hHeap, 0, lpValue) == 0)
5745 ret = GetLastError ();
5746 ERR ("HeapFree failed with code %i\n", ret);
5747 if (HeapFree (hHeap, 0, lpValueName) == 0)
5748 WARN ("HeapFree failed with code %i\n", GetLastError ());
5749 r = RegCloseKey (hkSubKey);
5750 if (r != ERROR_SUCCESS)
5751 WARN ("RegCloseKey returned %i\n", r);
5752 return ret;
5755 if (HeapFree (hHeap, 0, lpValueName) == 0)
5757 ret = GetLastError ();
5758 ERR ("HeapFree failed with code %i\n", ret);
5759 r = RegCloseKey (hkSubKey);
5760 if (r != ERROR_SUCCESS)
5761 WARN ("RegCloseKey returned %i\n", r);
5762 return ret;
5765 ret = RegCloseKey (hkSubKey);
5766 if (ret != ERROR_SUCCESS)
5768 ERR ("RegCloseKey returned %i\n", ret);
5769 return ret;
5772 return ERROR_SUCCESS;
5775 /*******************************************************************************
5776 * EnumPrinterDataExA [WINSPOOL.@]
5778 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5779 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5780 * what Windows 2000 SP1 does.
5783 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5784 LPBYTE pEnumValues, DWORD cbEnumValues,
5785 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5787 INT len;
5788 LPWSTR pKeyNameW;
5789 DWORD ret, dwIndex, dwBufSize;
5790 HANDLE hHeap;
5791 LPSTR pBuffer;
5793 TRACE ("%p %s\n", hPrinter, pKeyName);
5795 if (pKeyName == NULL || *pKeyName == 0)
5796 return ERROR_INVALID_PARAMETER;
5798 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5799 if (len == 0)
5801 ret = GetLastError ();
5802 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5803 return ret;
5806 hHeap = GetProcessHeap ();
5807 if (hHeap == NULL)
5809 ERR ("GetProcessHeap failed\n");
5810 return ERROR_OUTOFMEMORY;
5813 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5814 if (pKeyNameW == NULL)
5816 ERR ("Failed to allocate %i bytes from process heap\n",
5817 (LONG)(len * sizeof (WCHAR)));
5818 return ERROR_OUTOFMEMORY;
5821 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5823 ret = GetLastError ();
5824 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5825 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5826 WARN ("HeapFree failed with code %i\n", GetLastError ());
5827 return ret;
5830 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5831 pcbEnumValues, pnEnumValues);
5832 if (ret != ERROR_SUCCESS)
5834 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5835 WARN ("HeapFree failed with code %i\n", GetLastError ());
5836 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5837 return ret;
5840 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5842 ret = GetLastError ();
5843 ERR ("HeapFree failed with code %i\n", ret);
5844 return ret;
5847 if (*pnEnumValues == 0) /* empty key */
5848 return ERROR_SUCCESS;
5850 dwBufSize = 0;
5851 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5853 PPRINTER_ENUM_VALUESW ppev =
5854 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5856 if (dwBufSize < ppev->cbValueName)
5857 dwBufSize = ppev->cbValueName;
5859 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5860 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5861 dwBufSize = ppev->cbData;
5864 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5866 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5867 if (pBuffer == NULL)
5869 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5870 return ERROR_OUTOFMEMORY;
5873 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5875 PPRINTER_ENUM_VALUESW ppev =
5876 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5878 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5879 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5880 NULL);
5881 if (len == 0)
5883 ret = GetLastError ();
5884 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5885 if (HeapFree (hHeap, 0, pBuffer) == 0)
5886 WARN ("HeapFree failed with code %i\n", GetLastError ());
5887 return ret;
5890 memcpy (ppev->pValueName, pBuffer, len);
5892 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5894 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5895 ppev->dwType != REG_MULTI_SZ)
5896 continue;
5898 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5899 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5900 if (len == 0)
5902 ret = GetLastError ();
5903 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5904 if (HeapFree (hHeap, 0, pBuffer) == 0)
5905 WARN ("HeapFree failed with code %i\n", GetLastError ());
5906 return ret;
5909 memcpy (ppev->pData, pBuffer, len);
5911 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5912 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5915 if (HeapFree (hHeap, 0, pBuffer) == 0)
5917 ret = GetLastError ();
5918 ERR ("HeapFree failed with code %i\n", ret);
5919 return ret;
5922 return ERROR_SUCCESS;
5925 /******************************************************************************
5926 * AbortPrinter (WINSPOOL.@)
5928 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5930 FIXME("(%p), stub!\n", hPrinter);
5931 return TRUE;
5934 /******************************************************************************
5935 * AddPortA (WINSPOOL.@)
5937 * See AddPortW.
5940 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5942 LPWSTR nameW = NULL;
5943 LPWSTR monitorW = NULL;
5944 DWORD len;
5945 BOOL res;
5947 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5949 if (pName) {
5950 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5951 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5952 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5955 if (pMonitorName) {
5956 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5957 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5958 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5960 res = AddPortW(nameW, hWnd, monitorW);
5961 HeapFree(GetProcessHeap(), 0, nameW);
5962 HeapFree(GetProcessHeap(), 0, monitorW);
5963 return res;
5966 /******************************************************************************
5967 * AddPortW (WINSPOOL.@)
5969 * Add a Port for a specific Monitor
5971 * PARAMS
5972 * pName [I] Servername or NULL (local Computer)
5973 * hWnd [I] Handle to parent Window for the Dialog-Box
5974 * pMonitorName [I] Name of the Monitor that manage the Port
5976 * RETURNS
5977 * Success: TRUE
5978 * Failure: FALSE
5981 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5983 monitor_t * pm;
5984 monitor_t * pui;
5985 DWORD res;
5987 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
5989 if (pName && pName[0]) {
5990 SetLastError(ERROR_INVALID_PARAMETER);
5991 return FALSE;
5994 if (!pMonitorName) {
5995 SetLastError(RPC_X_NULL_REF_POINTER);
5996 return FALSE;
5999 /* an empty Monitorname is Invalid */
6000 if (!pMonitorName[0]) {
6001 SetLastError(ERROR_NOT_SUPPORTED);
6002 return FALSE;
6005 pm = monitor_load(pMonitorName, NULL);
6006 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6007 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6008 TRACE("got %d with %u\n", res, GetLastError());
6009 res = TRUE;
6011 else
6013 pui = monitor_loadui(pm);
6014 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6015 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6016 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6017 TRACE("got %d with %u\n", res, GetLastError());
6018 res = TRUE;
6020 else
6022 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6023 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6025 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6026 SetLastError(ERROR_NOT_SUPPORTED);
6027 res = FALSE;
6029 monitor_unload(pui);
6031 monitor_unload(pm);
6032 TRACE("returning %d with %u\n", res, GetLastError());
6033 return res;
6036 /******************************************************************************
6037 * AddPortExA (WINSPOOL.@)
6039 * See AddPortExW.
6042 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6044 PORT_INFO_2W pi2W;
6045 PORT_INFO_2A * pi2A;
6046 LPWSTR nameW = NULL;
6047 LPWSTR monitorW = NULL;
6048 DWORD len;
6049 BOOL res;
6051 pi2A = (PORT_INFO_2A *) pBuffer;
6053 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6054 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6056 if ((level < 1) || (level > 2)) {
6057 SetLastError(ERROR_INVALID_LEVEL);
6058 return FALSE;
6061 if (!pi2A) {
6062 SetLastError(ERROR_INVALID_PARAMETER);
6063 return FALSE;
6066 if (pName) {
6067 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6068 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6069 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6072 if (pMonitorName) {
6073 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6074 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6075 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6078 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6080 if (pi2A->pPortName) {
6081 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6082 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6083 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6086 if (level > 1) {
6087 if (pi2A->pMonitorName) {
6088 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6089 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6090 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6093 if (pi2A->pDescription) {
6094 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6095 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6096 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6098 pi2W.fPortType = pi2A->fPortType;
6099 pi2W.Reserved = pi2A->Reserved;
6102 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6104 HeapFree(GetProcessHeap(), 0, nameW);
6105 HeapFree(GetProcessHeap(), 0, monitorW);
6106 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6107 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6108 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6109 return res;
6113 /******************************************************************************
6114 * AddPortExW (WINSPOOL.@)
6116 * Add a Port for a specific Monitor, without presenting a user interface
6118 * PARAMS
6119 * pName [I] Servername or NULL (local Computer)
6120 * level [I] Structure-Level (1 or 2) for pBuffer
6121 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6122 * pMonitorName [I] Name of the Monitor that manage the Port
6124 * RETURNS
6125 * Success: TRUE
6126 * Failure: FALSE
6129 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6131 PORT_INFO_2W * pi2;
6132 monitor_t * pm;
6133 DWORD res = FALSE;
6135 pi2 = (PORT_INFO_2W *) pBuffer;
6137 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6138 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6139 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6140 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6143 if ((level < 1) || (level > 2)) {
6144 SetLastError(ERROR_INVALID_LEVEL);
6145 return FALSE;
6148 if (!pi2) {
6149 SetLastError(ERROR_INVALID_PARAMETER);
6150 return FALSE;
6153 /* we need a valid Monitorname */
6154 if (!pMonitorName) {
6155 SetLastError(RPC_X_NULL_REF_POINTER);
6156 return FALSE;
6158 if (!pMonitorName[0]) {
6159 SetLastError(ERROR_NOT_SUPPORTED);
6160 return FALSE;
6163 /* load the Monitor */
6164 pm = monitor_load(pMonitorName, NULL);
6165 if (!pm) return FALSE;
6167 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6168 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6169 TRACE("got %u with %u\n", res, GetLastError());
6171 monitor_unload(pm);
6172 return res;
6175 /******************************************************************************
6176 * AddPrinterConnectionA (WINSPOOL.@)
6178 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6180 FIXME("%s\n", debugstr_a(pName));
6181 return FALSE;
6184 /******************************************************************************
6185 * AddPrinterConnectionW (WINSPOOL.@)
6187 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6189 FIXME("%s\n", debugstr_w(pName));
6190 return FALSE;
6193 /******************************************************************************
6194 * AddPrinterDriverExW (WINSPOOL.@)
6196 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6197 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6199 FIXME("%s %d %p %d\n", debugstr_w(pName),
6200 Level, pDriverInfo, dwFileCopyFlags);
6201 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6202 return FALSE;
6205 /******************************************************************************
6206 * AddPrinterDriverExA (WINSPOOL.@)
6208 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6209 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6211 FIXME("%s %d %p %d\n", debugstr_a(pName),
6212 Level, pDriverInfo, dwFileCopyFlags);
6213 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6214 return FALSE;
6217 /******************************************************************************
6218 * ConfigurePortA (WINSPOOL.@)
6220 * See ConfigurePortW.
6223 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6225 LPWSTR nameW = NULL;
6226 LPWSTR portW = NULL;
6227 INT len;
6228 DWORD res;
6230 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6232 /* convert servername to unicode */
6233 if (pName) {
6234 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6235 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6236 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6239 /* convert portname to unicode */
6240 if (pPortName) {
6241 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6242 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6243 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6246 res = ConfigurePortW(nameW, hWnd, portW);
6247 HeapFree(GetProcessHeap(), 0, nameW);
6248 HeapFree(GetProcessHeap(), 0, portW);
6249 return res;
6252 /******************************************************************************
6253 * ConfigurePortW (WINSPOOL.@)
6255 * Display the Configuration-Dialog for a specific Port
6257 * PARAMS
6258 * pName [I] Servername or NULL (local Computer)
6259 * hWnd [I] Handle to parent Window for the Dialog-Box
6260 * pPortName [I] Name of the Port, that should be configured
6262 * RETURNS
6263 * Success: TRUE
6264 * Failure: FALSE
6267 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6269 monitor_t * pm;
6270 monitor_t * pui;
6271 DWORD res;
6273 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6275 if (pName && pName[0]) {
6276 SetLastError(ERROR_INVALID_PARAMETER);
6277 return FALSE;
6280 if (!pPortName) {
6281 SetLastError(RPC_X_NULL_REF_POINTER);
6282 return FALSE;
6285 /* an empty Portname is Invalid, but can popup a Dialog */
6286 if (!pPortName[0]) {
6287 SetLastError(ERROR_NOT_SUPPORTED);
6288 return FALSE;
6291 pm = monitor_load_by_port(pPortName);
6292 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6293 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6294 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6295 TRACE("got %d with %u\n", res, GetLastError());
6297 else
6299 pui = monitor_loadui(pm);
6300 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6301 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6302 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6303 TRACE("got %d with %u\n", res, GetLastError());
6305 else
6307 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6308 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6310 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6311 SetLastError(ERROR_NOT_SUPPORTED);
6312 res = FALSE;
6314 monitor_unload(pui);
6316 monitor_unload(pm);
6318 TRACE("returning %d with %u\n", res, GetLastError());
6319 return res;
6322 /******************************************************************************
6323 * ConnectToPrinterDlg (WINSPOOL.@)
6325 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6327 FIXME("%p %x\n", hWnd, Flags);
6328 return NULL;
6331 /******************************************************************************
6332 * DeletePrinterConnectionA (WINSPOOL.@)
6334 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6336 FIXME("%s\n", debugstr_a(pName));
6337 return TRUE;
6340 /******************************************************************************
6341 * DeletePrinterConnectionW (WINSPOOL.@)
6343 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6345 FIXME("%s\n", debugstr_w(pName));
6346 return TRUE;
6349 /******************************************************************************
6350 * DeletePrinterDriverExW (WINSPOOL.@)
6352 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6353 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6355 HKEY hkey_drivers;
6356 BOOL ret = FALSE;
6358 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6359 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6361 if(pName && pName[0])
6363 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6364 SetLastError(ERROR_INVALID_PARAMETER);
6365 return FALSE;
6368 if(dwDeleteFlag)
6370 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6371 SetLastError(ERROR_INVALID_PARAMETER);
6372 return FALSE;
6375 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6377 if(!hkey_drivers)
6379 ERR("Can't open drivers key\n");
6380 return FALSE;
6383 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6384 ret = TRUE;
6386 RegCloseKey(hkey_drivers);
6388 return ret;
6391 /******************************************************************************
6392 * DeletePrinterDriverExA (WINSPOOL.@)
6394 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6395 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6397 UNICODE_STRING NameW, EnvW, DriverW;
6398 BOOL ret;
6400 asciitounicode(&NameW, pName);
6401 asciitounicode(&EnvW, pEnvironment);
6402 asciitounicode(&DriverW, pDriverName);
6404 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6406 RtlFreeUnicodeString(&DriverW);
6407 RtlFreeUnicodeString(&EnvW);
6408 RtlFreeUnicodeString(&NameW);
6410 return ret;
6413 /******************************************************************************
6414 * DeletePrinterDataExW (WINSPOOL.@)
6416 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6417 LPCWSTR pValueName)
6419 FIXME("%p %s %s\n", hPrinter,
6420 debugstr_w(pKeyName), debugstr_w(pValueName));
6421 return ERROR_INVALID_PARAMETER;
6424 /******************************************************************************
6425 * DeletePrinterDataExA (WINSPOOL.@)
6427 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6428 LPCSTR pValueName)
6430 FIXME("%p %s %s\n", hPrinter,
6431 debugstr_a(pKeyName), debugstr_a(pValueName));
6432 return ERROR_INVALID_PARAMETER;
6435 /******************************************************************************
6436 * DeletePrintProcessorA (WINSPOOL.@)
6438 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6440 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6441 debugstr_a(pPrintProcessorName));
6442 return TRUE;
6445 /******************************************************************************
6446 * DeletePrintProcessorW (WINSPOOL.@)
6448 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6450 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6451 debugstr_w(pPrintProcessorName));
6452 return TRUE;
6455 /******************************************************************************
6456 * DeletePrintProvidorA (WINSPOOL.@)
6458 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6460 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6461 debugstr_a(pPrintProviderName));
6462 return TRUE;
6465 /******************************************************************************
6466 * DeletePrintProvidorW (WINSPOOL.@)
6468 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6470 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6471 debugstr_w(pPrintProviderName));
6472 return TRUE;
6475 /******************************************************************************
6476 * EnumFormsA (WINSPOOL.@)
6478 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6479 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6481 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6482 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6483 return FALSE;
6486 /******************************************************************************
6487 * EnumFormsW (WINSPOOL.@)
6489 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6490 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6492 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6493 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6494 return FALSE;
6497 /*****************************************************************************
6498 * EnumMonitorsA [WINSPOOL.@]
6500 * See EnumMonitorsW.
6503 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6504 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6506 BOOL res;
6507 LPBYTE bufferW = NULL;
6508 LPWSTR nameW = NULL;
6509 DWORD needed = 0;
6510 DWORD numentries = 0;
6511 INT len;
6513 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6514 cbBuf, pcbNeeded, pcReturned);
6516 /* convert servername to unicode */
6517 if (pName) {
6518 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6519 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6520 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6522 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6523 needed = cbBuf * sizeof(WCHAR);
6524 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6525 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6527 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6528 if (pcbNeeded) needed = *pcbNeeded;
6529 /* HeapReAlloc return NULL, when bufferW was NULL */
6530 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6531 HeapAlloc(GetProcessHeap(), 0, needed);
6533 /* Try again with the large Buffer */
6534 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6536 numentries = pcReturned ? *pcReturned : 0;
6537 needed = 0;
6539 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6540 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6542 if (res) {
6543 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6544 DWORD entrysize = 0;
6545 DWORD index;
6546 LPSTR ptr;
6547 LPMONITOR_INFO_2W mi2w;
6548 LPMONITOR_INFO_2A mi2a;
6550 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6551 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6553 /* First pass: calculate the size for all Entries */
6554 mi2w = (LPMONITOR_INFO_2W) bufferW;
6555 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6556 index = 0;
6557 while (index < numentries) {
6558 index++;
6559 needed += entrysize; /* MONITOR_INFO_?A */
6560 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6562 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6563 NULL, 0, NULL, NULL);
6564 if (Level > 1) {
6565 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6566 NULL, 0, NULL, NULL);
6567 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6568 NULL, 0, NULL, NULL);
6570 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6571 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6572 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6575 /* check for errors and quit on failure */
6576 if (cbBuf < needed) {
6577 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6578 res = FALSE;
6579 goto emA_cleanup;
6581 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6582 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6583 cbBuf -= len ; /* free Bytes in the user-Buffer */
6584 mi2w = (LPMONITOR_INFO_2W) bufferW;
6585 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6586 index = 0;
6587 /* Second Pass: Fill the User Buffer (if we have one) */
6588 while ((index < numentries) && pMonitors) {
6589 index++;
6590 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6591 mi2a->pName = ptr;
6592 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6593 ptr, cbBuf , NULL, NULL);
6594 ptr += len;
6595 cbBuf -= len;
6596 if (Level > 1) {
6597 mi2a->pEnvironment = ptr;
6598 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6599 ptr, cbBuf, NULL, NULL);
6600 ptr += len;
6601 cbBuf -= len;
6603 mi2a->pDLLName = ptr;
6604 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6605 ptr, cbBuf, NULL, NULL);
6606 ptr += len;
6607 cbBuf -= len;
6609 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6610 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6611 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6614 emA_cleanup:
6615 if (pcbNeeded) *pcbNeeded = needed;
6616 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6618 HeapFree(GetProcessHeap(), 0, nameW);
6619 HeapFree(GetProcessHeap(), 0, bufferW);
6621 TRACE("returning %d with %d (%d byte for %d entries)\n",
6622 (res), GetLastError(), needed, numentries);
6624 return (res);
6628 /*****************************************************************************
6629 * EnumMonitorsW [WINSPOOL.@]
6631 * Enumerate available Port-Monitors
6633 * PARAMS
6634 * pName [I] Servername or NULL (local Computer)
6635 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6636 * pMonitors [O] PTR to Buffer that receives the Result
6637 * cbBuf [I] Size of Buffer at pMonitors
6638 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6639 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6641 * RETURNS
6642 * Success: TRUE
6643 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6645 * NOTES
6646 * Windows reads the Registry once and cache the Results.
6648 *| Language-Monitors are also installed in the same Registry-Location but
6649 *| they are filtered in Windows (not returned by EnumMonitors).
6650 *| We do no filtering to simplify our Code.
6653 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6654 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6656 DWORD needed = 0;
6657 DWORD numentries = 0;
6658 BOOL res = FALSE;
6660 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6661 cbBuf, pcbNeeded, pcReturned);
6663 if (pName && (lstrlenW(pName))) {
6664 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6665 SetLastError(ERROR_ACCESS_DENIED);
6666 goto emW_cleanup;
6669 /* Level is not checked in win9x */
6670 if (!Level || (Level > 2)) {
6671 WARN("level (%d) is ignored in win9x\n", Level);
6672 SetLastError(ERROR_INVALID_LEVEL);
6673 goto emW_cleanup;
6675 if (!pcbNeeded) {
6676 SetLastError(RPC_X_NULL_REF_POINTER);
6677 goto emW_cleanup;
6680 /* Scan all Monitor-Keys */
6681 numentries = 0;
6682 needed = get_local_monitors(Level, NULL, 0, &numentries);
6684 /* we calculated the needed buffersize. now do the error-checks */
6685 if (cbBuf < needed) {
6686 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6687 goto emW_cleanup;
6689 else if (!pMonitors || !pcReturned) {
6690 SetLastError(RPC_X_NULL_REF_POINTER);
6691 goto emW_cleanup;
6694 /* fill the Buffer with the Monitor-Keys */
6695 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6696 res = TRUE;
6698 emW_cleanup:
6699 if (pcbNeeded) *pcbNeeded = needed;
6700 if (pcReturned) *pcReturned = numentries;
6702 TRACE("returning %d with %d (%d byte for %d entries)\n",
6703 res, GetLastError(), needed, numentries);
6705 return (res);
6708 /******************************************************************************
6709 * XcvDataW (WINSPOOL.@)
6711 * Execute commands in the Printmonitor DLL
6713 * PARAMS
6714 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6715 * pszDataName [i] Name of the command to execute
6716 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6717 * cbInputData [i] Size in Bytes of Buffer at pInputData
6718 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6719 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6720 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6721 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6723 * RETURNS
6724 * Success: TRUE
6725 * Failure: FALSE
6727 * NOTES
6728 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6729 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6731 * Minimal List of commands, that a Printmonitor DLL should support:
6733 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6734 *| "AddPort" : Add a Port
6735 *| "DeletePort": Delete a Port
6737 * Many Printmonitors support additional commands. Examples for localspl.dll:
6738 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6739 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6742 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6743 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6744 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6746 opened_printer_t *printer;
6748 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6749 pInputData, cbInputData, pOutputData,
6750 cbOutputData, pcbOutputNeeded, pdwStatus);
6752 printer = get_opened_printer(hXcv);
6753 if (!printer || (!printer->hXcv)) {
6754 SetLastError(ERROR_INVALID_HANDLE);
6755 return FALSE;
6758 if (!pcbOutputNeeded) {
6759 SetLastError(ERROR_INVALID_PARAMETER);
6760 return FALSE;
6763 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6764 SetLastError(RPC_X_NULL_REF_POINTER);
6765 return FALSE;
6768 *pcbOutputNeeded = 0;
6770 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6771 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6773 return TRUE;
6776 /*****************************************************************************
6777 * EnumPrinterDataA [WINSPOOL.@]
6780 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6781 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6782 DWORD cbData, LPDWORD pcbData )
6784 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6785 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6786 return ERROR_NO_MORE_ITEMS;
6789 /*****************************************************************************
6790 * EnumPrinterDataW [WINSPOOL.@]
6793 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6794 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6795 DWORD cbData, LPDWORD pcbData )
6797 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6798 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6799 return ERROR_NO_MORE_ITEMS;
6802 /*****************************************************************************
6803 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6806 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6807 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6808 LPDWORD pcbNeeded, LPDWORD pcReturned)
6810 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6811 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6812 pcbNeeded, pcReturned);
6813 return FALSE;
6816 /*****************************************************************************
6817 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6820 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6821 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6822 LPDWORD pcbNeeded, LPDWORD pcReturned)
6824 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6825 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6826 pcbNeeded, pcReturned);
6827 return FALSE;
6830 /*****************************************************************************
6831 * EnumPrintProcessorsA [WINSPOOL.@]
6834 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6835 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6837 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6838 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6839 return FALSE;
6842 /*****************************************************************************
6843 * EnumPrintProcessorsW [WINSPOOL.@]
6846 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6847 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6849 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6850 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6851 cbBuf, pcbNeeded, pcbReturned);
6852 return FALSE;
6855 /*****************************************************************************
6856 * ExtDeviceMode [WINSPOOL.@]
6859 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6860 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6861 DWORD fMode)
6863 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6864 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6865 debugstr_a(pProfile), fMode);
6866 return -1;
6869 /*****************************************************************************
6870 * FindClosePrinterChangeNotification [WINSPOOL.@]
6873 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6875 FIXME("Stub: %p\n", hChange);
6876 return TRUE;
6879 /*****************************************************************************
6880 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6883 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6884 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6886 FIXME("Stub: %p %x %x %p\n",
6887 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6888 return INVALID_HANDLE_VALUE;
6891 /*****************************************************************************
6892 * FindNextPrinterChangeNotification [WINSPOOL.@]
6895 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6896 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6898 FIXME("Stub: %p %p %p %p\n",
6899 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6900 return FALSE;
6903 /*****************************************************************************
6904 * FreePrinterNotifyInfo [WINSPOOL.@]
6907 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6909 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6910 return TRUE;
6913 /*****************************************************************************
6914 * string_to_buf
6916 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6917 * ansi depending on the unicode parameter.
6919 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6921 if(!str)
6923 *size = 0;
6924 return TRUE;
6927 if(unicode)
6929 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6930 if(*size <= cb)
6932 memcpy(ptr, str, *size);
6933 return TRUE;
6935 return FALSE;
6937 else
6939 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6940 if(*size <= cb)
6942 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6943 return TRUE;
6945 return FALSE;
6949 /*****************************************************************************
6950 * get_job_info_1
6952 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6953 LPDWORD pcbNeeded, BOOL unicode)
6955 DWORD size, left = cbBuf;
6956 BOOL space = (cbBuf > 0);
6957 LPBYTE ptr = buf;
6959 *pcbNeeded = 0;
6961 if(space)
6963 ji1->JobId = job->job_id;
6966 string_to_buf(job->document_title, ptr, left, &size, unicode);
6967 if(space && size <= left)
6969 ji1->pDocument = (LPWSTR)ptr;
6970 ptr += size;
6971 left -= size;
6973 else
6974 space = FALSE;
6975 *pcbNeeded += size;
6977 return space;
6980 /*****************************************************************************
6981 * get_job_info_2
6983 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6984 LPDWORD pcbNeeded, BOOL unicode)
6986 DWORD size, left = cbBuf;
6987 BOOL space = (cbBuf > 0);
6988 LPBYTE ptr = buf;
6990 *pcbNeeded = 0;
6992 if(space)
6994 ji2->JobId = job->job_id;
6997 string_to_buf(job->document_title, ptr, left, &size, unicode);
6998 if(space && size <= left)
7000 ji2->pDocument = (LPWSTR)ptr;
7001 ptr += size;
7002 left -= size;
7004 else
7005 space = FALSE;
7006 *pcbNeeded += size;
7008 return space;
7011 /*****************************************************************************
7012 * get_job_info
7014 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7015 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7017 BOOL ret = FALSE;
7018 DWORD needed = 0, size;
7019 job_t *job;
7020 LPBYTE ptr = pJob;
7022 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7024 EnterCriticalSection(&printer_handles_cs);
7025 job = get_job(hPrinter, JobId);
7026 if(!job)
7027 goto end;
7029 switch(Level)
7031 case 1:
7032 size = sizeof(JOB_INFO_1W);
7033 if(cbBuf >= size)
7035 cbBuf -= size;
7036 ptr += size;
7037 memset(pJob, 0, size);
7039 else
7040 cbBuf = 0;
7041 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7042 needed += size;
7043 break;
7045 case 2:
7046 size = sizeof(JOB_INFO_2W);
7047 if(cbBuf >= size)
7049 cbBuf -= size;
7050 ptr += size;
7051 memset(pJob, 0, size);
7053 else
7054 cbBuf = 0;
7055 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7056 needed += size;
7057 break;
7059 case 3:
7060 size = sizeof(JOB_INFO_3);
7061 if(cbBuf >= size)
7063 cbBuf -= size;
7064 memset(pJob, 0, size);
7065 ret = TRUE;
7067 else
7068 cbBuf = 0;
7069 needed = size;
7070 break;
7072 default:
7073 SetLastError(ERROR_INVALID_LEVEL);
7074 goto end;
7076 if(pcbNeeded)
7077 *pcbNeeded = needed;
7078 end:
7079 LeaveCriticalSection(&printer_handles_cs);
7080 return ret;
7083 /*****************************************************************************
7084 * GetJobA [WINSPOOL.@]
7087 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7088 DWORD cbBuf, LPDWORD pcbNeeded)
7090 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7093 /*****************************************************************************
7094 * GetJobW [WINSPOOL.@]
7097 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7098 DWORD cbBuf, LPDWORD pcbNeeded)
7100 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7103 /*****************************************************************************
7104 * schedule_lpr
7106 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7108 char *unixname, *queue, *cmd;
7109 char fmt[] = "lpr -P%s %s";
7110 DWORD len;
7112 if(!(unixname = wine_get_unix_file_name(filename)))
7113 return FALSE;
7115 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7116 queue = HeapAlloc(GetProcessHeap(), 0, len);
7117 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7119 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7120 sprintf(cmd, fmt, queue, unixname);
7122 TRACE("printing with: %s\n", cmd);
7123 system(cmd);
7125 HeapFree(GetProcessHeap(), 0, cmd);
7126 HeapFree(GetProcessHeap(), 0, queue);
7127 HeapFree(GetProcessHeap(), 0, unixname);
7128 return TRUE;
7131 /*****************************************************************************
7132 * schedule_cups
7134 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7136 #if HAVE_CUPS_CUPS_H
7137 if(pcupsPrintFile)
7139 char *unixname, *queue, *doc_titleA;
7140 DWORD len;
7141 BOOL ret;
7143 if(!(unixname = wine_get_unix_file_name(filename)))
7144 return FALSE;
7146 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7147 queue = HeapAlloc(GetProcessHeap(), 0, len);
7148 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7150 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7151 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7152 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7154 TRACE("printing via cups\n");
7155 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7156 HeapFree(GetProcessHeap(), 0, doc_titleA);
7157 HeapFree(GetProcessHeap(), 0, queue);
7158 HeapFree(GetProcessHeap(), 0, unixname);
7159 return ret;
7161 else
7162 #endif
7164 return schedule_lpr(printer_name, filename);
7168 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7170 LPWSTR filename;
7172 switch(msg)
7174 case WM_INITDIALOG:
7175 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7176 return TRUE;
7178 case WM_COMMAND:
7179 if(HIWORD(wparam) == BN_CLICKED)
7181 if(LOWORD(wparam) == IDOK)
7183 HANDLE hf;
7184 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7185 LPWSTR *output;
7187 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7188 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7190 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7192 WCHAR caption[200], message[200];
7193 int mb_ret;
7195 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7196 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7197 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7198 if(mb_ret == IDCANCEL)
7200 HeapFree(GetProcessHeap(), 0, filename);
7201 return TRUE;
7204 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7205 if(hf == INVALID_HANDLE_VALUE)
7207 WCHAR caption[200], message[200];
7209 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7210 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7211 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7212 HeapFree(GetProcessHeap(), 0, filename);
7213 return TRUE;
7215 CloseHandle(hf);
7216 DeleteFileW(filename);
7217 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7218 *output = filename;
7219 EndDialog(hwnd, IDOK);
7220 return TRUE;
7222 if(LOWORD(wparam) == IDCANCEL)
7224 EndDialog(hwnd, IDCANCEL);
7225 return TRUE;
7228 return FALSE;
7230 return FALSE;
7233 /*****************************************************************************
7234 * get_filename
7236 static BOOL get_filename(LPWSTR *filename)
7238 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7239 file_dlg_proc, (LPARAM)filename) == IDOK;
7242 /*****************************************************************************
7243 * schedule_file
7245 static BOOL schedule_file(LPCWSTR filename)
7247 LPWSTR output = NULL;
7249 if(get_filename(&output))
7251 TRACE("copy to %s\n", debugstr_w(output));
7252 CopyFileW(filename, output, FALSE);
7253 HeapFree(GetProcessHeap(), 0, output);
7254 return TRUE;
7256 return FALSE;
7259 /*****************************************************************************
7260 * schedule_pipe
7262 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7264 #ifdef HAVE_FORK
7265 char *unixname, *cmdA;
7266 DWORD len;
7267 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7268 BOOL ret = FALSE;
7269 char buf[1024];
7271 if(!(unixname = wine_get_unix_file_name(filename)))
7272 return FALSE;
7274 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7275 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7276 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7278 TRACE("printing with: %s\n", cmdA);
7280 if((file_fd = open(unixname, O_RDONLY)) == -1)
7281 goto end;
7283 if (pipe(fds))
7285 ERR("pipe() failed!\n");
7286 goto end;
7289 if (fork() == 0)
7291 close(0);
7292 dup2(fds[0], 0);
7293 close(fds[1]);
7295 /* reset signals that we previously set to SIG_IGN */
7296 signal(SIGPIPE, SIG_DFL);
7297 signal(SIGCHLD, SIG_DFL);
7299 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7300 _exit(1);
7303 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7304 write(fds[1], buf, no_read);
7306 ret = TRUE;
7308 end:
7309 if(file_fd != -1) close(file_fd);
7310 if(fds[0] != -1) close(fds[0]);
7311 if(fds[1] != -1) close(fds[1]);
7313 HeapFree(GetProcessHeap(), 0, cmdA);
7314 HeapFree(GetProcessHeap(), 0, unixname);
7315 return ret;
7316 #else
7317 return FALSE;
7318 #endif
7321 /*****************************************************************************
7322 * schedule_unixfile
7324 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7326 int in_fd, out_fd, no_read;
7327 char buf[1024];
7328 BOOL ret = FALSE;
7329 char *unixname, *outputA;
7330 DWORD len;
7332 if(!(unixname = wine_get_unix_file_name(filename)))
7333 return FALSE;
7335 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7336 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7337 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7339 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7340 in_fd = open(unixname, O_RDONLY);
7341 if(out_fd == -1 || in_fd == -1)
7342 goto end;
7344 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7345 write(out_fd, buf, no_read);
7347 ret = TRUE;
7348 end:
7349 if(in_fd != -1) close(in_fd);
7350 if(out_fd != -1) close(out_fd);
7351 HeapFree(GetProcessHeap(), 0, outputA);
7352 HeapFree(GetProcessHeap(), 0, unixname);
7353 return ret;
7356 /*****************************************************************************
7357 * ScheduleJob [WINSPOOL.@]
7360 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7362 opened_printer_t *printer;
7363 BOOL ret = FALSE;
7364 struct list *cursor, *cursor2;
7366 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7367 EnterCriticalSection(&printer_handles_cs);
7368 printer = get_opened_printer(hPrinter);
7369 if(!printer)
7370 goto end;
7372 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7374 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7375 HANDLE hf;
7377 if(job->job_id != dwJobID) continue;
7379 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7380 if(hf != INVALID_HANDLE_VALUE)
7382 PRINTER_INFO_5W *pi5;
7383 DWORD needed;
7384 HKEY hkey;
7385 WCHAR output[1024];
7386 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7387 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7389 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7390 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7391 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7392 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7393 debugstr_w(pi5->pPortName));
7395 output[0] = 0;
7397 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7398 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7400 DWORD type, count = sizeof(output);
7401 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7402 RegCloseKey(hkey);
7404 if(output[0] == '|')
7406 schedule_pipe(output + 1, job->filename);
7408 else if(output[0])
7410 schedule_unixfile(output, job->filename);
7412 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7414 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7416 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7418 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7420 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7422 schedule_file(job->filename);
7424 else
7426 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7428 HeapFree(GetProcessHeap(), 0, pi5);
7429 CloseHandle(hf);
7430 DeleteFileW(job->filename);
7432 list_remove(cursor);
7433 HeapFree(GetProcessHeap(), 0, job->document_title);
7434 HeapFree(GetProcessHeap(), 0, job->filename);
7435 HeapFree(GetProcessHeap(), 0, job);
7436 ret = TRUE;
7437 break;
7439 end:
7440 LeaveCriticalSection(&printer_handles_cs);
7441 return ret;
7444 /*****************************************************************************
7445 * StartDocDlgA [WINSPOOL.@]
7447 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7449 UNICODE_STRING usBuffer;
7450 DOCINFOW docW;
7451 LPWSTR retW;
7452 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7453 LPSTR ret = NULL;
7455 docW.cbSize = sizeof(docW);
7456 if (doc->lpszDocName)
7458 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7459 if (!(docW.lpszDocName = docnameW)) return NULL;
7461 if (doc->lpszOutput)
7463 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7464 if (!(docW.lpszOutput = outputW)) return NULL;
7466 if (doc->lpszDatatype)
7468 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7469 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7471 docW.fwType = doc->fwType;
7473 retW = StartDocDlgW(hPrinter, &docW);
7475 if(retW)
7477 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7478 ret = HeapAlloc(GetProcessHeap(), 0, len);
7479 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7480 HeapFree(GetProcessHeap(), 0, retW);
7483 HeapFree(GetProcessHeap(), 0, datatypeW);
7484 HeapFree(GetProcessHeap(), 0, outputW);
7485 HeapFree(GetProcessHeap(), 0, docnameW);
7487 return ret;
7490 /*****************************************************************************
7491 * StartDocDlgW [WINSPOOL.@]
7493 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7494 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7495 * port is "FILE:". Also returns the full path if passed a relative path.
7497 * The caller should free the returned string from the process heap.
7499 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7501 LPWSTR ret = NULL;
7502 DWORD len, attr;
7504 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7506 PRINTER_INFO_5W *pi5;
7507 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7508 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7509 return NULL;
7510 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7511 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7512 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7514 HeapFree(GetProcessHeap(), 0, pi5);
7515 return NULL;
7517 HeapFree(GetProcessHeap(), 0, pi5);
7520 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7522 LPWSTR name;
7524 if (get_filename(&name))
7526 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7528 HeapFree(GetProcessHeap(), 0, name);
7529 return NULL;
7531 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7532 GetFullPathNameW(name, len, ret, NULL);
7533 HeapFree(GetProcessHeap(), 0, name);
7535 return ret;
7538 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7539 return NULL;
7541 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7542 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7544 attr = GetFileAttributesW(ret);
7545 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7547 HeapFree(GetProcessHeap(), 0, ret);
7548 ret = NULL;
7550 return ret;