winspool: Improve trace for ClosePrinter.
[wine/gsoc_dplay.git] / dlls / winspool.drv / info.c
blobf3a51d879aa9ce96849ebb408efcc004ab851a29
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 LPPORT_INFO_2W cache; /* cached PORT_INFO_2W data */
101 DWORD pi1_needed; /* size for PORT_INFO_1W */
102 DWORD pi2_needed; /* size for PORT_INFO_2W */
103 DWORD returned; /* number of cached PORT_INFO_2W - entries */
104 } monitor_t;
106 typedef struct {
107 DWORD job_id;
108 HANDLE hf;
109 } started_doc_t;
111 typedef struct {
112 struct list jobs;
113 LONG ref;
114 } jobqueue_t;
116 typedef struct {
117 LPWSTR name;
118 LPWSTR printername;
119 monitor_t *pm;
120 HANDLE hXcv;
121 jobqueue_t *queue;
122 started_doc_t *doc;
123 } opened_printer_t;
125 typedef struct {
126 struct list entry;
127 DWORD job_id;
128 WCHAR *filename;
129 WCHAR *document_title;
130 } job_t;
133 typedef struct {
134 LPCWSTR envname;
135 LPCWSTR subdir;
136 DWORD driverversion;
137 LPCWSTR versionregpath;
138 LPCWSTR versionsubdir;
139 } printenv_t;
141 /* ############################### */
143 static struct list monitor_handles = LIST_INIT( monitor_handles );
144 static monitor_t * pm_localport;
146 static opened_printer_t **printer_handles;
147 static int nb_printer_handles;
148 static LONG next_job_id = 1;
150 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
151 WORD fwCapability, LPSTR lpszOutput,
152 LPDEVMODEA lpdm );
153 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
154 LPSTR lpszDevice, LPSTR lpszPort,
155 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
156 DWORD fwMode );
158 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'c','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
163 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
165 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
166 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
167 'C','o','n','t','r','o','l','\\',
168 'P','r','i','n','t','\\',
169 'M','o','n','i','t','o','r','s','\\',0};
171 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
172 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
173 'C','o','n','t','r','o','l','\\',
174 'P','r','i','n','t','\\',
175 'P','r','i','n','t','e','r','s',0};
177 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
179 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
180 'M','i','c','r','o','s','o','f','t','\\',
181 'W','i','n','d','o','w','s',' ','N','T','\\',
182 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
183 'W','i','n','d','o','w','s',0};
185 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
186 'M','i','c','r','o','s','o','f','t','\\',
187 'W','i','n','d','o','w','s',' ','N','T','\\',
188 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
189 'D','e','v','i','c','e','s',0};
191 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
192 'M','i','c','r','o','s','o','f','t','\\',
193 'W','i','n','d','o','w','s',' ','N','T','\\',
194 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
195 'P','o','r','t','s',0};
197 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
198 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
199 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
200 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
201 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
202 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
203 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
205 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
206 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
208 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
209 'i','o','n',' ','F','i','l','e',0};
210 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
211 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
212 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
213 'M','o','d','e',0};
214 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
215 'i','l','e','s',0};
216 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
217 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
218 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
219 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
220 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
221 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
222 static const WCHAR NameW[] = {'N','a','m','e',0};
223 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
224 static const WCHAR PortW[] = {'P','o','r','t',0};
225 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
226 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
227 's','s','o','r',0};
228 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
229 'v','e','r',0};
230 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
231 'v','e','r','D','a','t','a',0};
232 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
233 'i','l','e',0};
234 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
235 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
236 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
237 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
238 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
239 static const WCHAR emptyStringW[] = {0};
240 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
241 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
243 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
245 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
246 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
247 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
249 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
250 'D','o','c','u','m','e','n','t',0};
252 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
253 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
254 DWORD Level, LPBYTE pDriverInfo,
255 DWORD cbBuf, LPDWORD pcbNeeded,
256 BOOL unicode);
257 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
258 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey);
260 /******************************************************************
261 * validate the user-supplied printing-environment [internal]
263 * PARAMS
264 * env [I] PTR to Environment-String or NULL
266 * RETURNS
267 * Failure: NULL
268 * Success: PTR to printenv_t
270 * NOTES
271 * An empty string is handled the same way as NULL.
272 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
276 static const printenv_t * validate_envW(LPCWSTR env)
278 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
279 3, Version3_RegPathW, Version3_SubdirW};
280 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
281 0, emptyStringW, emptyStringW};
282 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
284 const printenv_t *result = NULL;
285 unsigned int i;
287 TRACE("testing %s\n", debugstr_w(env));
288 if (env && env[0])
290 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
292 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
294 result = all_printenv[i];
295 break;
299 if (result == NULL) {
300 FIXME("unsupported Environment: %s\n", debugstr_w(env));
301 SetLastError(ERROR_INVALID_ENVIRONMENT);
303 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
305 else
307 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
309 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
311 return result;
315 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
316 if passed a NULL string. This returns NULLs to the result.
318 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
320 if ( (src) )
322 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
323 return usBufferPtr->Buffer;
325 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
326 return NULL;
329 static LPWSTR strdupW(LPCWSTR p)
331 LPWSTR ret;
332 DWORD len;
334 if(!p) return NULL;
335 len = (strlenW(p) + 1) * sizeof(WCHAR);
336 ret = HeapAlloc(GetProcessHeap(), 0, len);
337 memcpy(ret, p, len);
338 return ret;
341 static LPSTR strdupWtoA( LPCWSTR str )
343 LPSTR ret;
344 INT len;
346 if (!str) return NULL;
347 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
348 ret = HeapAlloc( GetProcessHeap(), 0, len );
349 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
350 return ret;
353 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
354 The result includes all \0s (specifically the last two). */
355 static int multi_sz_lenA(const char *str)
357 const char *ptr = str;
358 if(!str) return 0;
361 ptr += lstrlenA(ptr) + 1;
362 } while(*ptr);
364 return ptr - str + 1;
367 static void
368 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
369 char qbuf[200];
371 /* If forcing, or no profile string entry for device yet, set the entry
373 * The always change entry if not WINEPS yet is discussable.
375 if (force ||
376 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
377 !strcmp(qbuf,"*") ||
378 !strstr(qbuf,"WINEPS.DRV")
380 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
381 HKEY hkey;
383 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
384 WriteProfileStringA("windows","device",buf);
385 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
386 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
387 RegCloseKey(hkey);
389 HeapFree(GetProcessHeap(),0,buf);
393 static BOOL add_printer_driver(char *name)
395 DRIVER_INFO_3A di3a;
397 static char driver_path[] = "wineps16",
398 data_file[] = "<datafile?>",
399 config_file[] = "wineps16",
400 help_file[] = "<helpfile?>",
401 dep_file[] = "<dependent files?>\0",
402 monitor_name[] = "<monitor name?>",
403 default_data_type[] = "RAW";
405 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
406 di3a.pName = (char *)name;
407 di3a.pEnvironment = NULL; /* NULL means auto */
408 di3a.pDriverPath = driver_path;
409 di3a.pDataFile = data_file;
410 di3a.pConfigFile = config_file;
411 di3a.pHelpFile = help_file;
412 di3a.pDependentFiles = dep_file;
413 di3a.pMonitorName = monitor_name;
414 di3a.pDefaultDataType = default_data_type;
416 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
418 ERR("Failed adding driver (%d)\n", GetLastError());
419 return FALSE;
421 return TRUE;
424 #ifdef HAVE_CUPS_CUPS_H
425 static typeof(cupsGetDests) *pcupsGetDests;
426 static typeof(cupsGetPPD) *pcupsGetPPD;
427 static typeof(cupsPrintFile) *pcupsPrintFile;
428 static void *cupshandle;
430 static BOOL CUPS_LoadPrinters(void)
432 int i, nrofdests;
433 BOOL hadprinter = FALSE;
434 cups_dest_t *dests;
435 PRINTER_INFO_2A pinfo2a;
436 char *port,*devline;
437 HKEY hkeyPrinter, hkeyPrinters, hkey;
439 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
440 if (!cupshandle)
441 return FALSE;
442 TRACE("loaded %s\n", SONAME_LIBCUPS);
444 #define DYNCUPS(x) \
445 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
446 if (!p##x) return FALSE;
448 DYNCUPS(cupsGetPPD);
449 DYNCUPS(cupsGetDests);
450 DYNCUPS(cupsPrintFile);
451 #undef DYNCUPS
453 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
454 ERROR_SUCCESS) {
455 ERR("Can't create Printers key\n");
456 return FALSE;
459 nrofdests = pcupsGetDests(&dests);
460 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
461 for (i=0;i<nrofdests;i++) {
462 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
463 sprintf(port,"LPR:%s",dests[i].name);
464 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
465 sprintf(devline,"WINEPS.DRV,%s",port);
466 WriteProfileStringA("devices",dests[i].name,devline);
467 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
468 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
469 RegCloseKey(hkey);
471 HeapFree(GetProcessHeap(),0,devline);
473 TRACE("Printer %d: %s\n", i, dests[i].name);
474 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
475 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
476 and continue */
477 TRACE("Printer already exists\n");
478 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
479 RegCloseKey(hkeyPrinter);
480 } else {
481 static CHAR data_type[] = "RAW",
482 print_proc[] = "WinPrint",
483 comment[] = "WINEPS Printer using CUPS",
484 location[] = "<physical location of printer>",
485 params[] = "<parameters?>",
486 share_name[] = "<share name?>",
487 sep_file[] = "<sep file?>";
489 add_printer_driver(dests[i].name);
491 memset(&pinfo2a,0,sizeof(pinfo2a));
492 pinfo2a.pPrinterName = dests[i].name;
493 pinfo2a.pDatatype = data_type;
494 pinfo2a.pPrintProcessor = print_proc;
495 pinfo2a.pDriverName = dests[i].name;
496 pinfo2a.pComment = comment;
497 pinfo2a.pLocation = location;
498 pinfo2a.pPortName = port;
499 pinfo2a.pParameters = params;
500 pinfo2a.pShareName = share_name;
501 pinfo2a.pSepFile = sep_file;
503 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
504 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
505 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
508 HeapFree(GetProcessHeap(),0,port);
510 hadprinter = TRUE;
511 if (dests[i].is_default)
512 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
514 RegCloseKey(hkeyPrinters);
515 return hadprinter;
517 #endif
519 static BOOL
520 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
521 PRINTER_INFO_2A pinfo2a;
522 char *e,*s,*name,*prettyname,*devname;
523 BOOL ret = FALSE, set_default = FALSE;
524 char *port,*devline,*env_default;
525 HKEY hkeyPrinter, hkeyPrinters, hkey;
527 while (isspace(*pent)) pent++;
528 s = strchr(pent,':');
529 if(s) *s='\0';
530 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
531 strcpy(name,pent);
532 if(s) {
533 *s=':';
534 pent = s;
535 } else
536 pent = "";
538 TRACE("name=%s entry=%s\n",name, pent);
540 if(ispunct(*name)) { /* a tc entry, not a real printer */
541 TRACE("skipping tc entry\n");
542 goto end;
545 if(strstr(pent,":server")) { /* server only version so skip */
546 TRACE("skipping server entry\n");
547 goto end;
550 /* Determine whether this is a postscript printer. */
552 ret = TRUE;
553 env_default = getenv("PRINTER");
554 prettyname = name;
555 /* Get longest name, usually the one at the right for later display. */
556 while((s=strchr(prettyname,'|'))) {
557 *s = '\0';
558 e = s;
559 while(isspace(*--e)) *e = '\0';
560 TRACE("\t%s\n", debugstr_a(prettyname));
561 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
562 for(prettyname = s+1; isspace(*prettyname); prettyname++)
565 e = prettyname + strlen(prettyname);
566 while(isspace(*--e)) *e = '\0';
567 TRACE("\t%s\n", debugstr_a(prettyname));
568 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
570 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
571 * if it is too long, we use it as comment below. */
572 devname = prettyname;
573 if (strlen(devname)>=CCHDEVICENAME-1)
574 devname = name;
575 if (strlen(devname)>=CCHDEVICENAME-1) {
576 ret = FALSE;
577 goto end;
580 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
581 sprintf(port,"LPR:%s",name);
583 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
584 sprintf(devline,"WINEPS.DRV,%s",port);
585 WriteProfileStringA("devices",devname,devline);
586 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
587 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
588 RegCloseKey(hkey);
590 HeapFree(GetProcessHeap(),0,devline);
592 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
593 ERROR_SUCCESS) {
594 ERR("Can't create Printers key\n");
595 ret = FALSE;
596 goto end;
598 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
599 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
600 and continue */
601 TRACE("Printer already exists\n");
602 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
603 RegCloseKey(hkeyPrinter);
604 } else {
605 static CHAR data_type[] = "RAW",
606 print_proc[] = "WinPrint",
607 comment[] = "WINEPS Printer using LPR",
608 params[] = "<parameters?>",
609 share_name[] = "<share name?>",
610 sep_file[] = "<sep file?>";
612 add_printer_driver(devname);
614 memset(&pinfo2a,0,sizeof(pinfo2a));
615 pinfo2a.pPrinterName = devname;
616 pinfo2a.pDatatype = data_type;
617 pinfo2a.pPrintProcessor = print_proc;
618 pinfo2a.pDriverName = devname;
619 pinfo2a.pComment = comment;
620 pinfo2a.pLocation = prettyname;
621 pinfo2a.pPortName = port;
622 pinfo2a.pParameters = params;
623 pinfo2a.pShareName = share_name;
624 pinfo2a.pSepFile = sep_file;
626 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
627 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
628 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
631 RegCloseKey(hkeyPrinters);
633 if (isfirst || set_default)
634 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
636 HeapFree(GetProcessHeap(), 0, port);
637 end:
638 HeapFree(GetProcessHeap(), 0, name);
639 return ret;
642 static BOOL
643 PRINTCAP_LoadPrinters(void) {
644 BOOL hadprinter = FALSE;
645 char buf[200];
646 FILE *f;
647 char *pent = NULL;
648 BOOL had_bash = FALSE;
650 f = fopen("/etc/printcap","r");
651 if (!f)
652 return FALSE;
654 while(fgets(buf,sizeof(buf),f)) {
655 char *start, *end;
657 end=strchr(buf,'\n');
658 if (end) *end='\0';
660 start = buf;
661 while(isspace(*start)) start++;
662 if(*start == '#' || *start == '\0')
663 continue;
665 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
666 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
667 HeapFree(GetProcessHeap(),0,pent);
668 pent = NULL;
671 if (end && *--end == '\\') {
672 *end = '\0';
673 had_bash = TRUE;
674 } else
675 had_bash = FALSE;
677 if (pent) {
678 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
679 strcat(pent,start);
680 } else {
681 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
682 strcpy(pent,start);
686 if(pent) {
687 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
688 HeapFree(GetProcessHeap(),0,pent);
690 fclose(f);
691 return hadprinter;
694 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
696 if (value)
697 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
698 (lstrlenW(value) + 1) * sizeof(WCHAR));
699 else
700 return ERROR_FILE_NOT_FOUND;
703 void WINSPOOL_LoadSystemPrinters(void)
705 HKEY hkey, hkeyPrinters;
706 HANDLE hprn;
707 DWORD needed, num, i;
708 WCHAR PrinterName[256];
709 BOOL done = FALSE;
711 /* This ensures that all printer entries have a valid Name value. If causes
712 problems later if they don't. If one is found to be missed we create one
713 and set it equal to the name of the key */
714 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
715 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
716 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
717 for(i = 0; i < num; i++) {
718 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
719 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
720 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
721 set_reg_szW(hkey, NameW, PrinterName);
723 RegCloseKey(hkey);
728 RegCloseKey(hkeyPrinters);
731 /* We want to avoid calling AddPrinter on printers as much as
732 possible, because on cups printers this will (eventually) lead
733 to a call to cupsGetPPD which takes forever, even with non-cups
734 printers AddPrinter takes a while. So we'll tag all printers that
735 were automatically added last time around, if they still exist
736 we'll leave them be otherwise we'll delete them. */
737 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
738 if(needed) {
739 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
740 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
741 for(i = 0; i < num; i++) {
742 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
743 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
744 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
745 DWORD dw = 1;
746 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
747 RegCloseKey(hkey);
749 ClosePrinter(hprn);
754 HeapFree(GetProcessHeap(), 0, pi);
758 #ifdef HAVE_CUPS_CUPS_H
759 done = CUPS_LoadPrinters();
760 #endif
762 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
763 /* Check for [ppd] section in config file before parsing /etc/printcap */
764 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
765 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
766 &hkey) == ERROR_SUCCESS) {
767 RegCloseKey(hkey);
768 PRINTCAP_LoadPrinters();
772 /* Now enumerate the list again and delete any printers that a still tagged */
773 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
774 if(needed) {
775 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
776 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
777 for(i = 0; i < num; i++) {
778 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
779 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
780 BOOL delete_driver = FALSE;
781 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
782 DWORD dw, type, size = sizeof(dw);
783 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
784 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
785 DeletePrinter(hprn);
786 delete_driver = TRUE;
788 RegCloseKey(hkey);
790 ClosePrinter(hprn);
791 if(delete_driver)
792 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
797 HeapFree(GetProcessHeap(), 0, pi);
800 return;
804 /*****************************************************************************
805 * enumerate the local monitors (INTERNAL)
807 * returns the needed size (in bytes) for pMonitors
808 * and *lpreturned is set to number of entries returned in pMonitors
811 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
813 HKEY hroot = NULL;
814 HKEY hentry = NULL;
815 LPWSTR ptr;
816 LPMONITOR_INFO_2W mi;
817 WCHAR buffer[MAX_PATH];
818 WCHAR dllname[MAX_PATH];
819 DWORD dllsize;
820 DWORD len;
821 DWORD index = 0;
822 DWORD needed = 0;
823 DWORD numentries;
824 DWORD entrysize;
826 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
828 numentries = *lpreturned; /* this is 0, when we scan the registry */
829 len = entrysize * numentries;
830 ptr = (LPWSTR) &pMonitors[len];
832 numentries = 0;
833 len = sizeof(buffer);
834 buffer[0] = '\0';
836 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
837 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
838 /* Scan all Monitor-Registry-Keys */
839 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
840 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
841 dllsize = sizeof(dllname);
842 dllname[0] = '\0';
844 /* The Monitor must have a Driver-DLL */
845 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
846 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
847 /* We found a valid DLL for this Monitor. */
848 TRACE("using Driver: %s\n", debugstr_w(dllname));
850 RegCloseKey(hentry);
853 /* Windows returns only Port-Monitors here, but to simplify our code,
854 we do no filtering for Language-Monitors */
855 if (dllname[0]) {
856 numentries++;
857 needed += entrysize;
858 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
859 if (level > 1) {
860 /* we install and return only monitors for "Windows NT x86" */
861 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
862 needed += dllsize;
865 /* required size is calculated. Now fill the user-buffer */
866 if (pMonitors && (cbBuf >= needed)){
867 mi = (LPMONITOR_INFO_2W) pMonitors;
868 pMonitors += entrysize;
870 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
871 mi->pName = ptr;
872 lstrcpyW(ptr, buffer); /* Name of the Monitor */
873 ptr += (len+1); /* len is lstrlenW(monitorname) */
874 if (level > 1) {
875 mi->pEnvironment = ptr;
876 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
877 ptr += (lstrlenW(envname_x86W)+1);
879 mi->pDLLName = ptr;
880 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
881 ptr += (dllsize / sizeof(WCHAR));
885 index++;
886 len = sizeof(buffer);
887 buffer[0] = '\0';
889 RegCloseKey(hroot);
891 *lpreturned = numentries;
892 TRACE("need %d byte for %d entries\n", needed, numentries);
893 return needed;
896 /******************************************************************
897 * monitor_flush [internal]
899 * flush the cached PORT_INFO_2W - data
902 void monitor_flush(monitor_t * pm)
904 if (!pm) return;
906 EnterCriticalSection(&monitor_handles_cs);
908 TRACE("%p (%s) cache: %p (%d, %d)\n", pm, debugstr_w(pm->name), pm->cache, pm->pi1_needed, pm->pi2_needed);
910 HeapFree(GetProcessHeap(), 0, pm->cache);
911 pm->cache = NULL;
912 pm->pi1_needed = 0;
913 pm->pi2_needed = 0;
914 pm->returned = 0;
915 LeaveCriticalSection(&monitor_handles_cs);
918 /******************************************************************
919 * monitor_unload [internal]
921 * release a printmonitor and unload it from memory, when needed
924 static void monitor_unload(monitor_t * pm)
926 if (pm == NULL) return;
927 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
929 EnterCriticalSection(&monitor_handles_cs);
931 if (pm->refcount) pm->refcount--;
933 if (pm->refcount == 0) {
934 list_remove(&pm->entry);
935 FreeLibrary(pm->hdll);
936 HeapFree(GetProcessHeap(), 0, pm->name);
937 HeapFree(GetProcessHeap(), 0, pm->dllname);
938 HeapFree(GetProcessHeap(), 0, pm);
940 LeaveCriticalSection(&monitor_handles_cs);
943 /******************************************************************
944 * monitor_unloadall [internal]
946 * release all printmonitors and unload them from memory, when needed
949 static void monitor_unloadall(void)
951 monitor_t * pm;
952 monitor_t * next;
954 EnterCriticalSection(&monitor_handles_cs);
955 /* iterate through the list, with safety against removal */
956 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
958 monitor_unload(pm);
960 LeaveCriticalSection(&monitor_handles_cs);
963 /******************************************************************
964 * monitor_load [internal]
966 * load a printmonitor, get the dllname from the registry, when needed
967 * initialize the monitor and dump found function-pointers
969 * On failure, SetLastError() is called and NULL is returned
972 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
974 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
975 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
976 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
977 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
978 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
980 monitor_t * pm = NULL;
981 monitor_t * cursor;
982 LPWSTR regroot = NULL;
983 LPWSTR driver = dllname;
985 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
986 /* Is the Monitor already loaded? */
987 EnterCriticalSection(&monitor_handles_cs);
989 if (name) {
990 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
992 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
993 pm = cursor;
994 break;
999 if (pm == NULL) {
1000 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
1001 if (pm == NULL) goto cleanup;
1002 list_add_tail(&monitor_handles, &pm->entry);
1004 pm->refcount++;
1006 if (pm->name == NULL) {
1007 /* Load the monitor */
1008 LPMONITOREX pmonitorEx;
1009 DWORD len;
1011 if (name) {
1012 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
1013 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1016 if (regroot) {
1017 lstrcpyW(regroot, MonitorsW);
1018 lstrcatW(regroot, name);
1019 /* Get the Driver from the Registry */
1020 if (driver == NULL) {
1021 HKEY hroot;
1022 DWORD namesize;
1023 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
1024 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
1025 &namesize) == ERROR_SUCCESS) {
1026 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
1027 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
1029 RegCloseKey(hroot);
1034 pm->name = strdupW(name);
1035 pm->dllname = strdupW(driver);
1037 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
1038 monitor_unload(pm);
1039 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1040 pm = NULL;
1041 goto cleanup;
1044 pm->hdll = LoadLibraryW(driver);
1045 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
1047 if (pm->hdll == NULL) {
1048 monitor_unload(pm);
1049 SetLastError(ERROR_MOD_NOT_FOUND);
1050 pm = NULL;
1051 goto cleanup;
1054 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1055 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1056 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1057 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1058 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1061 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1062 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1063 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1064 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1065 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1067 if (pInitializePrintMonitorUI != NULL) {
1068 pm->monitorUI = pInitializePrintMonitorUI();
1069 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1070 if (pm->monitorUI) {
1071 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1072 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1077 if (pInitializePrintMonitor && regroot) {
1078 pmonitorEx = pInitializePrintMonitor(regroot);
1079 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1080 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1082 if (pmonitorEx) {
1083 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1084 pm->monitor = &(pmonitorEx->Monitor);
1088 if (pm->monitor) {
1089 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1093 if (!pm->monitor && regroot) {
1094 if (pInitializePrintMonitor2 != NULL) {
1095 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1097 if (pInitializeMonitorEx != NULL) {
1098 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1100 if (pInitializeMonitor != NULL) {
1101 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1104 if (!pm->monitor && !pm->monitorUI) {
1105 monitor_unload(pm);
1106 SetLastError(ERROR_PROC_NOT_FOUND);
1107 pm = NULL;
1110 cleanup:
1111 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1112 pm->refcount++;
1113 pm_localport = pm;
1115 LeaveCriticalSection(&monitor_handles_cs);
1116 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1117 HeapFree(GetProcessHeap(), 0, regroot);
1118 TRACE("=> %p\n", pm);
1119 return pm;
1122 /******************************************************************
1123 * monitor_loadall [internal]
1125 * Load all registered monitors
1128 static DWORD monitor_loadall(void)
1130 monitor_t * pm;
1131 DWORD registered = 0;
1132 DWORD loaded = 0;
1133 HKEY hmonitors;
1134 WCHAR buffer[MAX_PATH];
1135 DWORD id = 0;
1137 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1138 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1139 NULL, NULL, NULL, NULL, NULL);
1141 TRACE("%d monitors registered\n", registered);
1143 EnterCriticalSection(&monitor_handles_cs);
1144 while (id < registered) {
1145 buffer[0] = '\0';
1146 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1147 pm = monitor_load(buffer, NULL);
1148 if (pm) loaded++;
1149 id++;
1151 LeaveCriticalSection(&monitor_handles_cs);
1152 RegCloseKey(hmonitors);
1154 TRACE("%d monitors loaded\n", loaded);
1155 return loaded;
1158 /******************************************************************
1159 * monitor_loadui [internal]
1161 * load the userinterface-dll for a given portmonitor
1163 * On failure, NULL is returned
1166 static monitor_t * monitor_loadui(monitor_t * pm)
1168 monitor_t * pui = NULL;
1169 LPWSTR buffer[MAX_PATH];
1170 HANDLE hXcv;
1171 DWORD len;
1172 DWORD res;
1174 if (pm == NULL) return NULL;
1175 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1177 /* Try the Portmonitor first; works for many monitors */
1178 if (pm->monitorUI) {
1179 EnterCriticalSection(&monitor_handles_cs);
1180 pm->refcount++;
1181 LeaveCriticalSection(&monitor_handles_cs);
1182 return pm;
1185 /* query the userinterface-dllname from the Portmonitor */
1186 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1187 /* building (",XcvMonitor %s",pm->name) not needed yet */
1188 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1189 TRACE("got %u with %p\n", res, hXcv);
1190 if (res) {
1191 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1192 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1193 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1194 pm->monitor->pfnXcvClosePort(hXcv);
1197 return pui;
1201 /******************************************************************
1202 * monitor_load_by_port [internal]
1204 * load a printmonitor for a given port
1206 * On failure, NULL is returned
1209 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1211 HKEY hroot;
1212 HKEY hport;
1213 LPWSTR buffer;
1214 monitor_t * pm = NULL;
1215 DWORD registered = 0;
1216 DWORD id = 0;
1217 DWORD len;
1219 TRACE("(%s)\n", debugstr_w(portname));
1221 /* Try the Local Monitor first */
1222 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1223 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1224 /* found the portname */
1225 RegCloseKey(hroot);
1226 return monitor_load(LocalPortW, NULL);
1228 RegCloseKey(hroot);
1231 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1232 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1233 if (buffer == NULL) return NULL;
1235 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1236 EnterCriticalSection(&monitor_handles_cs);
1237 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1239 while ((pm == NULL) && (id < registered)) {
1240 buffer[0] = '\0';
1241 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1242 TRACE("testing %s\n", debugstr_w(buffer));
1243 len = lstrlenW(buffer);
1244 lstrcatW(buffer, bs_Ports_bsW);
1245 lstrcatW(buffer, portname);
1246 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1247 RegCloseKey(hport);
1248 buffer[len] = '\0'; /* use only the Monitor-Name */
1249 pm = monitor_load(buffer, NULL);
1251 id++;
1253 LeaveCriticalSection(&monitor_handles_cs);
1254 RegCloseKey(hroot);
1256 HeapFree(GetProcessHeap(), 0, buffer);
1257 return pm;
1260 /******************************************************************
1261 * enumerate the local Ports from all loaded monitors (internal)
1263 * returns the needed size (in bytes) for pPorts
1264 * and *lpreturned is set to number of entries returned in pPorts
1267 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1269 monitor_t * pm;
1270 LPWSTR ptr;
1271 LPPORT_INFO_2W cache;
1272 LPPORT_INFO_2W out;
1273 DWORD res;
1274 DWORD cacheindex;
1275 DWORD outindex = 0;
1276 DWORD needed = 0;
1277 DWORD numentries;
1278 DWORD entrysize;
1281 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1282 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1284 numentries = *lpreturned; /* this is 0, when we scan the registry */
1285 needed = entrysize * numentries;
1286 ptr = (LPWSTR) &pPorts[needed];
1288 numentries = 0;
1289 needed = 0;
1291 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1293 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1294 if (pm->cache == NULL) {
1295 res = pm->monitor->pfnEnumPorts(NULL, 2, NULL, 0, &(pm->pi2_needed), &(pm->returned));
1296 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1297 pm->cache = HeapAlloc(GetProcessHeap(), 0, (pm->pi2_needed));
1298 res = pm->monitor->pfnEnumPorts(NULL, 2, (LPBYTE) pm->cache, pm->pi2_needed, &(pm->pi2_needed), &(pm->returned));
1300 TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
1301 debugstr_w(pm->name), res, GetLastError(), pm->pi2_needed, pm->returned);
1302 res = FALSE;
1304 if (pm->cache && (level == 1) && (pm->pi1_needed == 0) && (pm->returned > 0)) {
1305 cacheindex = 0;
1306 cache = pm->cache;
1307 while (cacheindex < (pm->returned)) {
1308 pm->pi1_needed += sizeof(PORT_INFO_1W);
1309 pm->pi1_needed += (lstrlenW(cache->pPortName) + 1) * sizeof(WCHAR);
1310 cache++;
1311 cacheindex++;
1313 TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
1314 pm->pi1_needed, cacheindex, debugstr_w(pm->name));
1316 numentries += pm->returned;
1317 needed += (level == 1) ? pm->pi1_needed : pm->pi2_needed;
1319 /* fill the buffer, if we have one */
1320 if (pPorts && (cbBuf >= needed )) {
1321 cacheindex = 0;
1322 cache = pm->cache;
1323 while (cacheindex < pm->returned) {
1324 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1325 out->pPortName = ptr;
1326 lstrcpyW(ptr, cache->pPortName);
1327 ptr += (lstrlenW(ptr)+1);
1328 if (level > 1) {
1329 out->pMonitorName = ptr;
1330 lstrcpyW(ptr, cache->pMonitorName);
1331 ptr += (lstrlenW(ptr)+1);
1333 out->pDescription = ptr;
1334 lstrcpyW(ptr, cache->pDescription);
1335 ptr += (lstrlenW(ptr)+1);
1336 out->fPortType = cache->fPortType;
1337 out->Reserved = cache->Reserved;
1339 cache++;
1340 cacheindex++;
1341 outindex++;
1347 *lpreturned = numentries;
1348 TRACE("need %d byte for %d entries\n", needed, numentries);
1349 return needed;
1352 /******************************************************************
1353 * get_servername_from_name (internal)
1355 * for an external server, a copy of the serverpart from the full name is returned
1358 static LPWSTR get_servername_from_name(LPCWSTR name)
1360 LPWSTR server;
1361 LPWSTR ptr;
1362 WCHAR buffer[MAX_PATH];
1363 DWORD len;
1365 if (name == NULL) return NULL;
1366 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1368 server = strdupW(&name[2]); /* skip over both backslash */
1369 if (server == NULL) return NULL;
1371 /* strip '\' and the printername */
1372 ptr = strchrW(server, '\\');
1373 if (ptr) ptr[0] = '\0';
1375 TRACE("found %s\n", debugstr_w(server));
1377 len = sizeof(buffer)/sizeof(buffer[0]);
1378 if (GetComputerNameW(buffer, &len)) {
1379 if (lstrcmpW(buffer, server) == 0) {
1380 /* The requested Servername is our computername */
1381 HeapFree(GetProcessHeap(), 0, server);
1382 return NULL;
1385 return server;
1388 /******************************************************************
1389 * get_basename_from_name (internal)
1391 * skip over the serverpart from the full name
1394 static LPCWSTR get_basename_from_name(LPCWSTR name)
1396 if (name == NULL) return NULL;
1397 if ((name[0] == '\\') && (name[1] == '\\')) {
1398 /* skip over the servername and search for the following '\' */
1399 name = strchrW(&name[2], '\\');
1400 if ((name) && (name[1])) {
1401 /* found a seperator ('\') followed by a name:
1402 skip over the seperator and return the rest */
1403 name++;
1405 else
1407 /* no basename present (we found only a servername) */
1408 return NULL;
1411 return name;
1414 /******************************************************************
1415 * get_opened_printer_entry
1416 * Get the first place empty in the opened printer table
1418 * ToDo:
1419 * - pDefault is ignored
1421 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1423 UINT_PTR handle = nb_printer_handles, i;
1424 jobqueue_t *queue = NULL;
1425 opened_printer_t *printer = NULL;
1426 LPWSTR servername;
1427 LPCWSTR printername;
1428 HKEY hkeyPrinters;
1429 HKEY hkeyPrinter;
1430 DWORD len;
1432 servername = get_servername_from_name(name);
1433 if (servername) {
1434 FIXME("server %s not supported\n", debugstr_w(servername));
1435 HeapFree(GetProcessHeap(), 0, servername);
1436 SetLastError(ERROR_INVALID_PRINTER_NAME);
1437 return NULL;
1440 printername = get_basename_from_name(name);
1441 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1443 /* an empty printername is invalid */
1444 if (printername && (!printername[0])) {
1445 SetLastError(ERROR_INVALID_PARAMETER);
1446 return NULL;
1449 EnterCriticalSection(&printer_handles_cs);
1451 for (i = 0; i < nb_printer_handles; i++)
1453 if (!printer_handles[i])
1455 if(handle == nb_printer_handles)
1456 handle = i;
1458 else
1460 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1461 queue = printer_handles[i]->queue;
1465 if (handle >= nb_printer_handles)
1467 opened_printer_t **new_array;
1468 if (printer_handles)
1469 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1470 (nb_printer_handles + 16) * sizeof(*new_array) );
1471 else
1472 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1473 (nb_printer_handles + 16) * sizeof(*new_array) );
1475 if (!new_array)
1477 handle = 0;
1478 goto end;
1480 printer_handles = new_array;
1481 nb_printer_handles += 16;
1484 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1486 handle = 0;
1487 goto end;
1491 /* clone the base name. This is NULL for the printserver */
1492 printer->printername = strdupW(printername);
1494 /* clone the full name */
1495 printer->name = strdupW(name);
1496 if (name && (!printer->name)) {
1497 handle = 0;
1498 goto end;
1501 if (printername) {
1502 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1503 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1504 /* OpenPrinter(",XcvMonitor " detected */
1505 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1506 printer->pm = monitor_load(&printername[len], NULL);
1507 if (printer->pm == NULL) {
1508 SetLastError(ERROR_INVALID_PARAMETER);
1509 handle = 0;
1510 goto end;
1513 else
1515 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1516 if (strncmpW( printername, XcvPortW, len) == 0) {
1517 /* OpenPrinter(",XcvPort " detected */
1518 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1519 printer->pm = monitor_load_by_port(&printername[len]);
1520 if (printer->pm == NULL) {
1521 SetLastError(ERROR_INVALID_PARAMETER);
1522 handle = 0;
1523 goto end;
1528 if (printer->pm) {
1529 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1530 printer->pm->monitor->pfnXcvOpenPort(&printername[len], pDefault->DesiredAccess, &printer->hXcv);
1532 if (printer->hXcv == NULL) {
1533 SetLastError(ERROR_INVALID_PARAMETER);
1534 handle = 0;
1535 goto end;
1538 else
1540 /* Does the Printer exist? */
1541 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1542 ERR("Can't create Printers key\n");
1543 handle = 0;
1544 goto end;
1546 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1547 WARN("Printer not found in Registry: '%s'\n", debugstr_w(printername));
1548 RegCloseKey(hkeyPrinters);
1549 SetLastError(ERROR_INVALID_PRINTER_NAME);
1550 handle = 0;
1551 goto end;
1553 RegCloseKey(hkeyPrinter);
1554 RegCloseKey(hkeyPrinters);
1557 else
1559 TRACE("using the local printserver\n");
1562 if(queue)
1563 printer->queue = queue;
1564 else
1566 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1567 if (!printer->queue) {
1568 handle = 0;
1569 goto end;
1571 list_init(&printer->queue->jobs);
1572 printer->queue->ref = 0;
1574 InterlockedIncrement(&printer->queue->ref);
1576 printer_handles[handle] = printer;
1577 handle++;
1578 end:
1579 LeaveCriticalSection(&printer_handles_cs);
1580 if (!handle && printer) {
1581 /* Something failed: Free all resources */
1582 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1583 monitor_unload(printer->pm);
1584 HeapFree(GetProcessHeap(), 0, printer->printername);
1585 HeapFree(GetProcessHeap(), 0, printer->name);
1586 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1587 HeapFree(GetProcessHeap(), 0, printer);
1590 return (HANDLE)handle;
1593 /******************************************************************
1594 * get_opened_printer
1595 * Get the pointer to the opened printer referred by the handle
1597 static opened_printer_t *get_opened_printer(HANDLE hprn)
1599 UINT_PTR idx = (UINT_PTR)hprn;
1600 opened_printer_t *ret = NULL;
1602 EnterCriticalSection(&printer_handles_cs);
1604 if ((idx <= 0) || (idx > nb_printer_handles))
1605 goto end;
1607 ret = printer_handles[idx - 1];
1608 end:
1609 LeaveCriticalSection(&printer_handles_cs);
1610 return ret;
1613 /******************************************************************
1614 * get_opened_printer_name
1615 * Get the pointer to the opened printer name referred by the handle
1617 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1619 opened_printer_t *printer = get_opened_printer(hprn);
1620 if(!printer) return NULL;
1621 return printer->name;
1624 /******************************************************************
1625 * WINSPOOL_GetOpenedPrinterRegKey
1628 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1630 LPCWSTR name = get_opened_printer_name(hPrinter);
1631 DWORD ret;
1632 HKEY hkeyPrinters;
1634 if(!name) return ERROR_INVALID_HANDLE;
1636 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1637 ERROR_SUCCESS)
1638 return ret;
1640 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1642 ERR("Can't find opened printer %s in registry\n",
1643 debugstr_w(name));
1644 RegCloseKey(hkeyPrinters);
1645 return ERROR_INVALID_PRINTER_NAME; /* ? */
1647 RegCloseKey(hkeyPrinters);
1648 return ERROR_SUCCESS;
1651 /******************************************************************
1652 * get_job
1654 * Get the pointer to the specified job.
1655 * Should hold the printer_handles_cs before calling.
1657 static job_t *get_job(HANDLE hprn, DWORD JobId)
1659 opened_printer_t *printer = get_opened_printer(hprn);
1660 job_t *job;
1662 if(!printer) return NULL;
1663 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1665 if(job->job_id == JobId)
1666 return job;
1668 return NULL;
1671 /***********************************************************
1672 * DEVMODEcpyAtoW
1674 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1676 BOOL Formname;
1677 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1678 DWORD size;
1680 Formname = (dmA->dmSize > off_formname);
1681 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1682 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1683 dmW->dmDeviceName, CCHDEVICENAME);
1684 if(!Formname) {
1685 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1686 dmA->dmSize - CCHDEVICENAME);
1687 } else {
1688 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1689 off_formname - CCHDEVICENAME);
1690 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1691 dmW->dmFormName, CCHFORMNAME);
1692 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1693 (off_formname + CCHFORMNAME));
1695 dmW->dmSize = size;
1696 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1697 dmA->dmDriverExtra);
1698 return dmW;
1701 /***********************************************************
1702 * DEVMODEdupWtoA
1703 * Creates an ascii copy of supplied devmode on heap
1705 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1707 LPDEVMODEA dmA;
1708 DWORD size;
1709 BOOL Formname;
1710 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1712 if(!dmW) return NULL;
1713 Formname = (dmW->dmSize > off_formname);
1714 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1715 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1716 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1717 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1718 if(!Formname) {
1719 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1720 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1721 } else {
1722 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1723 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1724 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1725 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1726 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1727 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1729 dmA->dmSize = size;
1730 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1731 dmW->dmDriverExtra);
1732 return dmA;
1735 /***********************************************************
1736 * PRINTER_INFO_2AtoW
1737 * Creates a unicode copy of PRINTER_INFO_2A on heap
1739 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1741 LPPRINTER_INFO_2W piW;
1742 UNICODE_STRING usBuffer;
1744 if(!piA) return NULL;
1745 piW = HeapAlloc(heap, 0, sizeof(*piW));
1746 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1748 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1749 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1750 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1751 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1752 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1753 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1754 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1755 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1756 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1757 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1758 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1759 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1760 return piW;
1763 /***********************************************************
1764 * FREE_PRINTER_INFO_2W
1765 * Free PRINTER_INFO_2W and all strings
1767 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1769 if(!piW) return;
1771 HeapFree(heap,0,piW->pServerName);
1772 HeapFree(heap,0,piW->pPrinterName);
1773 HeapFree(heap,0,piW->pShareName);
1774 HeapFree(heap,0,piW->pPortName);
1775 HeapFree(heap,0,piW->pDriverName);
1776 HeapFree(heap,0,piW->pComment);
1777 HeapFree(heap,0,piW->pLocation);
1778 HeapFree(heap,0,piW->pDevMode);
1779 HeapFree(heap,0,piW->pSepFile);
1780 HeapFree(heap,0,piW->pPrintProcessor);
1781 HeapFree(heap,0,piW->pDatatype);
1782 HeapFree(heap,0,piW->pParameters);
1783 HeapFree(heap,0,piW);
1784 return;
1787 /******************************************************************
1788 * DeviceCapabilities [WINSPOOL.@]
1789 * DeviceCapabilitiesA [WINSPOOL.@]
1792 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1793 LPSTR pOutput, LPDEVMODEA lpdm)
1795 INT ret;
1797 if (!GDI_CallDeviceCapabilities16)
1799 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1800 (LPCSTR)104 );
1801 if (!GDI_CallDeviceCapabilities16) return -1;
1803 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1805 /* If DC_PAPERSIZE map POINT16s to POINTs */
1806 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1807 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1808 POINT *pt = (POINT *)pOutput;
1809 INT i;
1810 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1811 for(i = 0; i < ret; i++, pt++)
1813 pt->x = tmp[i].x;
1814 pt->y = tmp[i].y;
1816 HeapFree( GetProcessHeap(), 0, tmp );
1818 return ret;
1822 /*****************************************************************************
1823 * DeviceCapabilitiesW [WINSPOOL.@]
1825 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1828 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1829 WORD fwCapability, LPWSTR pOutput,
1830 const DEVMODEW *pDevMode)
1832 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1833 LPSTR pDeviceA = strdupWtoA(pDevice);
1834 LPSTR pPortA = strdupWtoA(pPort);
1835 INT ret;
1837 if(pOutput && (fwCapability == DC_BINNAMES ||
1838 fwCapability == DC_FILEDEPENDENCIES ||
1839 fwCapability == DC_PAPERNAMES)) {
1840 /* These need A -> W translation */
1841 INT size = 0, i;
1842 LPSTR pOutputA;
1843 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1844 dmA);
1845 if(ret == -1)
1846 return ret;
1847 switch(fwCapability) {
1848 case DC_BINNAMES:
1849 size = 24;
1850 break;
1851 case DC_PAPERNAMES:
1852 case DC_FILEDEPENDENCIES:
1853 size = 64;
1854 break;
1856 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1857 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1858 dmA);
1859 for(i = 0; i < ret; i++)
1860 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1861 pOutput + (i * size), size);
1862 HeapFree(GetProcessHeap(), 0, pOutputA);
1863 } else {
1864 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1865 (LPSTR)pOutput, dmA);
1867 HeapFree(GetProcessHeap(),0,pPortA);
1868 HeapFree(GetProcessHeap(),0,pDeviceA);
1869 HeapFree(GetProcessHeap(),0,dmA);
1870 return ret;
1873 /******************************************************************
1874 * DocumentPropertiesA [WINSPOOL.@]
1876 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1878 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1879 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1880 LPDEVMODEA pDevModeInput,DWORD fMode )
1882 LPSTR lpName = pDeviceName;
1883 static CHAR port[] = "LPT1:";
1884 LONG ret;
1886 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1887 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1890 if(!pDeviceName) {
1891 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1892 if(!lpNameW) {
1893 ERR("no name from hPrinter?\n");
1894 SetLastError(ERROR_INVALID_HANDLE);
1895 return -1;
1897 lpName = strdupWtoA(lpNameW);
1900 if (!GDI_CallExtDeviceMode16)
1902 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1903 (LPCSTR)102 );
1904 if (!GDI_CallExtDeviceMode16) {
1905 ERR("No CallExtDeviceMode16?\n");
1906 return -1;
1909 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1910 pDevModeInput, NULL, fMode);
1912 if(!pDeviceName)
1913 HeapFree(GetProcessHeap(),0,lpName);
1914 return ret;
1918 /*****************************************************************************
1919 * DocumentPropertiesW (WINSPOOL.@)
1921 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1923 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1924 LPWSTR pDeviceName,
1925 LPDEVMODEW pDevModeOutput,
1926 LPDEVMODEW pDevModeInput, DWORD fMode)
1929 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1930 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1931 LPDEVMODEA pDevModeOutputA = NULL;
1932 LONG ret;
1934 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1935 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1936 fMode);
1937 if(pDevModeOutput) {
1938 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1939 if(ret < 0) return ret;
1940 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1942 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1943 pDevModeInputA, fMode);
1944 if(pDevModeOutput) {
1945 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1946 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1948 if(fMode == 0 && ret > 0)
1949 ret += (CCHDEVICENAME + CCHFORMNAME);
1950 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1951 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1952 return ret;
1955 /******************************************************************
1956 * OpenPrinterA [WINSPOOL.@]
1958 * See OpenPrinterW.
1961 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1962 LPPRINTER_DEFAULTSA pDefault)
1964 UNICODE_STRING lpPrinterNameW;
1965 UNICODE_STRING usBuffer;
1966 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1967 PWSTR pwstrPrinterNameW;
1968 BOOL ret;
1970 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1972 if(pDefault) {
1973 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1974 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1975 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1976 pDefaultW = &DefaultW;
1978 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1979 if(pDefault) {
1980 RtlFreeUnicodeString(&usBuffer);
1981 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1983 RtlFreeUnicodeString(&lpPrinterNameW);
1984 return ret;
1987 /******************************************************************
1988 * OpenPrinterW [WINSPOOL.@]
1990 * Open a Printer / Printserver or a Printer-Object
1992 * PARAMS
1993 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1994 * phPrinter [O] The resulting Handle is stored here
1995 * pDefault [I] PTR to Default Printer Settings or NULL
1997 * RETURNS
1998 * Success: TRUE
1999 * Failure: FALSE
2001 * NOTES
2002 * lpPrinterName is one of:
2003 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2004 *| Printer: "PrinterName"
2005 *| Printer-Object: "PrinterName,Job xxx"
2006 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2007 *| XcvPort: "Servername,XcvPort PortName"
2009 * BUGS
2010 *| Printer-Object not supported
2011 *| pDefaults is ignored
2014 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2017 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2018 if (pDefault) {
2019 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2020 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2023 if(!phPrinter) {
2024 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2025 SetLastError(ERROR_INVALID_PARAMETER);
2026 return FALSE;
2029 /* Get the unique handle of the printer or Printserver */
2030 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2031 TRACE("returning %d with 0x%x and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2032 return (*phPrinter != 0);
2035 /******************************************************************
2036 * AddMonitorA [WINSPOOL.@]
2038 * See AddMonitorW.
2041 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2043 LPWSTR nameW = NULL;
2044 INT len;
2045 BOOL res;
2046 LPMONITOR_INFO_2A mi2a;
2047 MONITOR_INFO_2W mi2w;
2049 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2050 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2051 mi2a ? debugstr_a(mi2a->pName) : NULL,
2052 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2053 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2055 if (Level != 2) {
2056 SetLastError(ERROR_INVALID_LEVEL);
2057 return FALSE;
2060 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2061 if (mi2a == NULL) {
2062 return FALSE;
2065 if (pName) {
2066 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2067 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2068 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2071 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2072 if (mi2a->pName) {
2073 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2074 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2075 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2077 if (mi2a->pEnvironment) {
2078 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2079 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2080 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2082 if (mi2a->pDLLName) {
2083 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2084 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2085 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2088 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2090 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2091 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2092 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2094 HeapFree(GetProcessHeap(), 0, nameW);
2095 return (res);
2098 /******************************************************************************
2099 * AddMonitorW [WINSPOOL.@]
2101 * Install a Printmonitor
2103 * PARAMS
2104 * pName [I] Servername or NULL (local Computer)
2105 * Level [I] Structure-Level (Must be 2)
2106 * pMonitors [I] PTR to MONITOR_INFO_2
2108 * RETURNS
2109 * Success: TRUE
2110 * Failure: FALSE
2112 * NOTES
2113 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2116 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2118 monitor_t * pm = NULL;
2119 LPMONITOR_INFO_2W mi2w;
2120 HKEY hroot = NULL;
2121 HKEY hentry = NULL;
2122 DWORD disposition;
2123 BOOL res = FALSE;
2125 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2126 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2127 mi2w ? debugstr_w(mi2w->pName) : NULL,
2128 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2129 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2131 if (Level != 2) {
2132 SetLastError(ERROR_INVALID_LEVEL);
2133 return FALSE;
2136 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2137 if (mi2w == NULL) {
2138 return FALSE;
2141 if (pName && (pName[0])) {
2142 FIXME("for server %s not implemented\n", debugstr_w(pName));
2143 SetLastError(ERROR_ACCESS_DENIED);
2144 return FALSE;
2148 if (!mi2w->pName || (! mi2w->pName[0])) {
2149 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2150 SetLastError(ERROR_INVALID_PARAMETER);
2151 return FALSE;
2153 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2154 WARN("Environment %s requested (we support only %s)\n",
2155 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2156 SetLastError(ERROR_INVALID_ENVIRONMENT);
2157 return FALSE;
2160 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2161 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2162 SetLastError(ERROR_INVALID_PARAMETER);
2163 return FALSE;
2166 /* Load and initialize the monitor. SetLastError() is called on failure */
2167 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2168 return FALSE;
2170 monitor_unload(pm);
2172 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2173 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2174 return FALSE;
2177 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2178 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2179 &disposition) == ERROR_SUCCESS) {
2181 /* Some installers set options for the port before calling AddMonitor.
2182 We query the "Driver" entry to verify that the monitor is installed,
2183 before we return an error.
2184 When a user installs two print monitors at the same time with the
2185 same name but with a different driver DLL and a task switch comes
2186 between RegQueryValueExW and RegSetValueExW, a race condition
2187 is possible but silently ignored. */
2189 DWORD namesize = 0;
2191 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2192 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2193 &namesize) == ERROR_SUCCESS)) {
2194 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2195 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2196 9x: ERROR_ALREADY_EXISTS (183) */
2197 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2199 else
2201 INT len;
2202 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2203 res = (RegSetValueExW(hentry, DriverW, 0,
2204 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2206 RegCloseKey(hentry);
2209 RegCloseKey(hroot);
2210 return (res);
2213 /******************************************************************
2214 * DeletePrinterDriverA [WINSPOOL.@]
2217 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2219 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2222 /******************************************************************
2223 * DeletePrinterDriverW [WINSPOOL.@]
2226 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2228 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2231 /******************************************************************
2232 * DeleteMonitorA [WINSPOOL.@]
2234 * See DeleteMonitorW.
2237 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2239 LPWSTR nameW = NULL;
2240 LPWSTR EnvironmentW = NULL;
2241 LPWSTR MonitorNameW = NULL;
2242 BOOL res;
2243 INT len;
2245 if (pName) {
2246 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2247 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2248 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2251 if (pEnvironment) {
2252 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2253 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2254 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2256 if (pMonitorName) {
2257 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2258 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2259 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2262 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2264 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2265 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2266 HeapFree(GetProcessHeap(), 0, nameW);
2267 return (res);
2270 /******************************************************************
2271 * DeleteMonitorW [WINSPOOL.@]
2273 * Delete a specific Printmonitor from a Printing-Environment
2275 * PARAMS
2276 * pName [I] Servername or NULL (local Computer)
2277 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2278 * pMonitorName [I] Name of the Monitor, that should be deleted
2280 * RETURNS
2281 * Success: TRUE
2282 * Failure: FALSE
2284 * NOTES
2285 * pEnvironment is ignored in Windows for the local Computer.
2289 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2291 HKEY hroot = NULL;
2293 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2294 debugstr_w(pMonitorName));
2296 if (pName && (pName[0])) {
2297 FIXME("for server %s not implemented\n", debugstr_w(pName));
2298 SetLastError(ERROR_ACCESS_DENIED);
2299 return FALSE;
2302 /* pEnvironment is ignored in Windows for the local Computer */
2304 if (!pMonitorName || !pMonitorName[0]) {
2305 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2306 SetLastError(ERROR_INVALID_PARAMETER);
2307 return FALSE;
2310 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2311 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2312 return FALSE;
2315 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2316 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2317 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2318 RegCloseKey(hroot);
2319 return TRUE;
2322 WARN("monitor %s does not exists\n", debugstr_w(pMonitorName));
2323 RegCloseKey(hroot);
2325 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2326 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2327 return (FALSE);
2330 /******************************************************************
2331 * DeletePortA [WINSPOOL.@]
2333 * See DeletePortW.
2336 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2338 LPWSTR nameW = NULL;
2339 LPWSTR portW = NULL;
2340 INT len;
2341 DWORD res;
2343 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2345 /* convert servername to unicode */
2346 if (pName) {
2347 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2348 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2349 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2352 /* convert portname to unicode */
2353 if (pPortName) {
2354 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2355 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2356 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2359 res = DeletePortW(nameW, hWnd, portW);
2360 HeapFree(GetProcessHeap(), 0, nameW);
2361 HeapFree(GetProcessHeap(), 0, portW);
2362 return res;
2365 /******************************************************************
2366 * DeletePortW [WINSPOOL.@]
2368 * Delete a specific Port
2370 * PARAMS
2371 * pName [I] Servername or NULL (local Computer)
2372 * hWnd [I] Handle to parent Window for the Dialog-Box
2373 * pPortName [I] Name of the Port, that should be deleted
2375 * RETURNS
2376 * Success: TRUE
2377 * Failure: FALSE
2380 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2382 monitor_t * pm;
2383 monitor_t * pui;
2384 DWORD res;
2386 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2388 if (pName && pName[0]) {
2389 SetLastError(ERROR_INVALID_PARAMETER);
2390 return FALSE;
2393 if (!pPortName) {
2394 SetLastError(RPC_X_NULL_REF_POINTER);
2395 return FALSE;
2398 /* an empty Portname is Invalid */
2399 if (!pPortName[0]) {
2400 SetLastError(ERROR_NOT_SUPPORTED);
2401 return FALSE;
2404 pm = monitor_load_by_port(pPortName);
2405 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2406 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2407 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2408 TRACE("got %d with %u\n", res, GetLastError());
2410 else
2412 pui = monitor_loadui(pm);
2413 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2414 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2415 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2416 TRACE("got %d with %u\n", res, GetLastError());
2418 else
2420 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2421 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2423 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2424 SetLastError(ERROR_NOT_SUPPORTED);
2425 res = FALSE;
2427 monitor_unload(pui);
2429 /* always invalidate cached PORT_INFO_2W */
2430 monitor_flush(pm);
2432 monitor_unload(pm);
2434 TRACE("returning %d with %u\n", res, GetLastError());
2435 return res;
2438 /******************************************************************************
2439 * SetPrinterW [WINSPOOL.@]
2441 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2443 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2444 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2445 return FALSE;
2448 /******************************************************************************
2449 * WritePrinter [WINSPOOL.@]
2451 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2453 opened_printer_t *printer;
2454 BOOL ret = FALSE;
2456 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2458 EnterCriticalSection(&printer_handles_cs);
2459 printer = get_opened_printer(hPrinter);
2460 if(!printer)
2462 SetLastError(ERROR_INVALID_HANDLE);
2463 goto end;
2466 if(!printer->doc)
2468 SetLastError(ERROR_SPL_NO_STARTDOC);
2469 goto end;
2472 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2473 end:
2474 LeaveCriticalSection(&printer_handles_cs);
2475 return ret;
2478 /*****************************************************************************
2479 * AddFormA [WINSPOOL.@]
2481 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2483 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2484 return 1;
2487 /*****************************************************************************
2488 * AddFormW [WINSPOOL.@]
2490 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2492 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2493 return 1;
2496 /*****************************************************************************
2497 * AddJobA [WINSPOOL.@]
2499 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2501 BOOL ret;
2502 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2503 DWORD needed;
2505 if(Level != 1) {
2506 SetLastError(ERROR_INVALID_LEVEL);
2507 return FALSE;
2510 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2512 if(ret) {
2513 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2514 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2515 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2516 if(*pcbNeeded > cbBuf) {
2517 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2518 ret = FALSE;
2519 } else {
2520 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2521 addjobA->JobId = addjobW->JobId;
2522 addjobA->Path = (char *)(addjobA + 1);
2523 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2526 return ret;
2529 /*****************************************************************************
2530 * AddJobW [WINSPOOL.@]
2532 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2534 opened_printer_t *printer;
2535 job_t *job;
2536 BOOL ret = FALSE;
2537 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2538 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2539 WCHAR path[MAX_PATH], filename[MAX_PATH];
2540 DWORD len;
2541 ADDJOB_INFO_1W *addjob;
2543 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2545 EnterCriticalSection(&printer_handles_cs);
2547 printer = get_opened_printer(hPrinter);
2549 if(!printer) {
2550 SetLastError(ERROR_INVALID_HANDLE);
2551 goto end;
2554 if(Level != 1) {
2555 SetLastError(ERROR_INVALID_LEVEL);
2556 goto end;
2559 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2560 if(!job)
2561 goto end;
2563 job->job_id = InterlockedIncrement(&next_job_id);
2565 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2566 if(path[len - 1] != '\\')
2567 path[len++] = '\\';
2568 memcpy(path + len, spool_path, sizeof(spool_path));
2569 sprintfW(filename, fmtW, path, job->job_id);
2571 len = strlenW(filename);
2572 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2573 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2574 job->document_title = strdupW(default_doc_title);
2575 list_add_tail(&printer->queue->jobs, &job->entry);
2577 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2578 if(*pcbNeeded <= cbBuf) {
2579 addjob = (ADDJOB_INFO_1W*)pData;
2580 addjob->JobId = job->job_id;
2581 addjob->Path = (WCHAR *)(addjob + 1);
2582 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2583 ret = TRUE;
2584 } else
2585 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2587 end:
2588 LeaveCriticalSection(&printer_handles_cs);
2589 return ret;
2592 /*****************************************************************************
2593 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2595 * Return the PATH for the Print-Processors
2597 * See GetPrintProcessorDirectoryW.
2601 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2602 DWORD level, LPBYTE Info,
2603 DWORD cbBuf, LPDWORD pcbNeeded)
2605 LPWSTR serverW = NULL;
2606 LPWSTR envW = NULL;
2607 BOOL ret;
2608 INT len;
2610 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2611 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2614 if (server) {
2615 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2616 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2617 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2620 if (env) {
2621 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2622 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2623 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2626 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2627 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2629 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2630 cbBuf, pcbNeeded);
2632 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2633 cbBuf, NULL, NULL) > 0;
2636 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2637 HeapFree(GetProcessHeap(), 0, envW);
2638 HeapFree(GetProcessHeap(), 0, serverW);
2639 return ret;
2642 /*****************************************************************************
2643 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2645 * Return the PATH for the Print-Processors
2647 * PARAMS
2648 * server [I] Servername (NT only) or NULL (local Computer)
2649 * env [I] Printing-Environment (see below) or NULL (Default)
2650 * level [I] Structure-Level (must be 1)
2651 * Info [O] PTR to Buffer that receives the Result
2652 * cbBuf [I] Size of Buffer at "Info"
2653 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2654 * required for the Buffer at "Info"
2656 * RETURNS
2657 * Success: TRUE and in pcbNeeded the Bytes used in Info
2658 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2659 * if cbBuf is too small
2661 * Native Values returned in Info on Success:
2662 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2663 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2664 *| win9x(Windows 4.0): "%winsysdir%"
2666 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2668 * BUGS
2669 * Only NULL or "" is supported for server
2672 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2673 DWORD level, LPBYTE Info,
2674 DWORD cbBuf, LPDWORD pcbNeeded)
2676 DWORD needed;
2677 const printenv_t * env_t;
2679 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2680 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2682 if(server != NULL && server[0]) {
2683 FIXME("server not supported: %s\n", debugstr_w(server));
2684 SetLastError(ERROR_INVALID_PARAMETER);
2685 return FALSE;
2688 env_t = validate_envW(env);
2689 if(!env_t) return FALSE; /* environment invalid or unsupported */
2691 if(level != 1) {
2692 WARN("(Level: %d) is ignored in win9x\n", level);
2693 SetLastError(ERROR_INVALID_LEVEL);
2694 return FALSE;
2697 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2698 needed = GetSystemDirectoryW(NULL, 0);
2699 /* add the Size for the Subdirectories */
2700 needed += lstrlenW(spoolprtprocsW);
2701 needed += lstrlenW(env_t->subdir);
2702 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2704 if(pcbNeeded) *pcbNeeded = needed;
2705 TRACE ("required: 0x%x/%d\n", needed, needed);
2706 if (needed > cbBuf) {
2707 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2708 return FALSE;
2710 if(pcbNeeded == NULL) {
2711 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2712 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2713 SetLastError(RPC_X_NULL_REF_POINTER);
2714 return FALSE;
2716 if(Info == NULL) {
2717 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2718 SetLastError(RPC_X_NULL_REF_POINTER);
2719 return FALSE;
2722 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2723 /* add the Subdirectories */
2724 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2725 lstrcatW((LPWSTR) Info, env_t->subdir);
2726 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2727 return TRUE;
2730 /*****************************************************************************
2731 * WINSPOOL_OpenDriverReg [internal]
2733 * opens the registry for the printer drivers depending on the given input
2734 * variable pEnvironment
2736 * RETURNS:
2737 * the opened hkey on success
2738 * NULL on error
2740 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
2742 HKEY retval = NULL;
2743 LPWSTR buffer;
2744 const printenv_t * env;
2746 TRACE("(%s, %d)\n",
2747 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2749 if (!pEnvironment || unicode) {
2750 /* pEnvironment was NULL or an Unicode-String: use it direct */
2751 env = validate_envW(pEnvironment);
2753 else
2755 /* pEnvironment was an ANSI-String: convert to unicode first */
2756 LPWSTR buffer;
2757 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2758 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2759 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2760 env = validate_envW(buffer);
2761 HeapFree(GetProcessHeap(), 0, buffer);
2763 if (!env) return NULL;
2765 buffer = HeapAlloc( GetProcessHeap(), 0,
2766 (strlenW(DriversW) + strlenW(env->envname) +
2767 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2768 if(buffer) {
2769 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2770 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2771 HeapFree(GetProcessHeap(), 0, buffer);
2773 return retval;
2776 /*****************************************************************************
2777 * AddPrinterW [WINSPOOL.@]
2779 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2781 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2782 LPDEVMODEA dmA;
2783 LPDEVMODEW dmW;
2784 HANDLE retval;
2785 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2786 LONG size;
2788 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2790 if(pName != NULL) {
2791 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2792 SetLastError(ERROR_INVALID_PARAMETER);
2793 return 0;
2795 if(Level != 2) {
2796 ERR("Level = %d, unsupported!\n", Level);
2797 SetLastError(ERROR_INVALID_LEVEL);
2798 return 0;
2800 if(!pPrinter) {
2801 SetLastError(ERROR_INVALID_PARAMETER);
2802 return 0;
2804 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2805 ERROR_SUCCESS) {
2806 ERR("Can't create Printers key\n");
2807 return 0;
2809 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2810 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2811 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2812 RegCloseKey(hkeyPrinter);
2813 RegCloseKey(hkeyPrinters);
2814 return 0;
2816 RegCloseKey(hkeyPrinter);
2818 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2819 if(!hkeyDrivers) {
2820 ERR("Can't create Drivers key\n");
2821 RegCloseKey(hkeyPrinters);
2822 return 0;
2824 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2825 ERROR_SUCCESS) {
2826 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2827 RegCloseKey(hkeyPrinters);
2828 RegCloseKey(hkeyDrivers);
2829 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2830 return 0;
2832 RegCloseKey(hkeyDriver);
2833 RegCloseKey(hkeyDrivers);
2835 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2836 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2837 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2838 RegCloseKey(hkeyPrinters);
2839 return 0;
2842 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2843 ERROR_SUCCESS) {
2844 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2845 SetLastError(ERROR_INVALID_PRINTER_NAME);
2846 RegCloseKey(hkeyPrinters);
2847 return 0;
2849 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2850 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2851 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2853 /* See if we can load the driver. We may need the devmode structure anyway
2855 * FIXME:
2856 * Note that DocumentPropertiesW will briefly try to open the printer we
2857 * just create to find a DEVMODEA struct (it will use the WINEPS default
2858 * one in case it is not there, so we are ok).
2860 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2862 if(size < 0) {
2863 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2864 size = sizeof(DEVMODEW);
2866 if(pi->pDevMode)
2867 dmW = pi->pDevMode;
2868 else
2870 dmW = HeapAlloc(GetProcessHeap(), 0, size);
2871 ZeroMemory(dmW,size);
2872 dmW->dmSize = size;
2873 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2875 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2876 HeapFree(GetProcessHeap(),0,dmW);
2877 dmW=NULL;
2879 else
2881 /* set devmode to printer name */
2882 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2886 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2887 and we support these drivers. NT writes DEVMODEW so somehow
2888 we'll need to distinguish between these when we support NT
2889 drivers */
2890 if (dmW)
2892 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2893 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
2894 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2895 HeapFree(GetProcessHeap(), 0, dmA);
2896 if(!pi->pDevMode)
2897 HeapFree(GetProcessHeap(), 0, dmW);
2899 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2900 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2901 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2902 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2904 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2905 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2906 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2907 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2908 (LPBYTE)&pi->Priority, sizeof(DWORD));
2909 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2910 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2911 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2912 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2913 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2914 (LPBYTE)&pi->Status, sizeof(DWORD));
2915 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2916 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2918 RegCloseKey(hkeyPrinter);
2919 RegCloseKey(hkeyPrinters);
2920 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2921 ERR("OpenPrinter failing\n");
2922 return 0;
2924 return retval;
2927 /*****************************************************************************
2928 * AddPrinterA [WINSPOOL.@]
2930 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2932 UNICODE_STRING pNameW;
2933 PWSTR pwstrNameW;
2934 PRINTER_INFO_2W *piW;
2935 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2936 HANDLE ret;
2938 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2939 if(Level != 2) {
2940 ERR("Level = %d, unsupported!\n", Level);
2941 SetLastError(ERROR_INVALID_LEVEL);
2942 return 0;
2944 pwstrNameW = asciitounicode(&pNameW,pName);
2945 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2947 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2949 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2950 RtlFreeUnicodeString(&pNameW);
2951 return ret;
2955 /*****************************************************************************
2956 * ClosePrinter [WINSPOOL.@]
2958 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2960 UINT_PTR i = (UINT_PTR)hPrinter;
2961 opened_printer_t *printer = NULL;
2962 BOOL ret = FALSE;
2964 TRACE("(%p)\n", hPrinter);
2966 EnterCriticalSection(&printer_handles_cs);
2968 if ((i > 0) && (i <= nb_printer_handles))
2969 printer = printer_handles[i - 1];
2972 if(printer)
2974 struct list *cursor, *cursor2;
2976 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2977 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2978 printer->hXcv, debugstr_w(printer->name), printer->doc );
2980 if(printer->doc)
2981 EndDocPrinter(hPrinter);
2983 if(InterlockedDecrement(&printer->queue->ref) == 0)
2985 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2987 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2988 ScheduleJob(hPrinter, job->job_id);
2990 HeapFree(GetProcessHeap(), 0, printer->queue);
2992 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
2993 monitor_unload(printer->pm);
2994 HeapFree(GetProcessHeap(), 0, printer->printername);
2995 HeapFree(GetProcessHeap(), 0, printer->name);
2996 HeapFree(GetProcessHeap(), 0, printer);
2997 printer_handles[i - 1] = NULL;
2998 ret = TRUE;
3000 LeaveCriticalSection(&printer_handles_cs);
3001 return ret;
3004 /*****************************************************************************
3005 * DeleteFormA [WINSPOOL.@]
3007 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3009 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3010 return 1;
3013 /*****************************************************************************
3014 * DeleteFormW [WINSPOOL.@]
3016 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3018 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3019 return 1;
3022 /*****************************************************************************
3023 * WINSPOOL_SHRegDeleteKey
3025 * Recursively delete subkeys.
3026 * Cut & paste from shlwapi.
3029 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
3031 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
3032 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
3033 HKEY hSubKey = 0;
3035 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
3036 if(!dwRet)
3038 /* Find how many subkeys there are */
3039 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
3040 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
3041 if(!dwRet)
3043 dwMaxSubkeyLen++;
3044 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
3045 /* Name too big: alloc a buffer for it */
3046 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
3048 if(!lpszName)
3049 dwRet = ERROR_NOT_ENOUGH_MEMORY;
3050 else
3052 /* Recursively delete all the subkeys */
3053 for(i = 0; i < dwKeyCount && !dwRet; i++)
3055 dwSize = dwMaxSubkeyLen;
3056 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
3057 if(!dwRet)
3058 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
3061 if (lpszName != szNameBuf)
3062 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
3066 RegCloseKey(hSubKey);
3067 if(!dwRet)
3068 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
3070 return dwRet;
3073 /*****************************************************************************
3074 * DeletePrinter [WINSPOOL.@]
3076 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3078 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3079 HKEY hkeyPrinters, hkey;
3081 if(!lpNameW) {
3082 SetLastError(ERROR_INVALID_HANDLE);
3083 return FALSE;
3085 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3086 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
3087 RegCloseKey(hkeyPrinters);
3089 WriteProfileStringW(devicesW, lpNameW, NULL);
3090 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3091 RegDeleteValueW(hkey, lpNameW);
3092 RegCloseKey(hkey);
3094 return TRUE;
3097 /*****************************************************************************
3098 * SetPrinterA [WINSPOOL.@]
3100 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3101 DWORD Command)
3103 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3104 return FALSE;
3107 /*****************************************************************************
3108 * SetJobA [WINSPOOL.@]
3110 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3111 LPBYTE pJob, DWORD Command)
3113 BOOL ret;
3114 LPBYTE JobW;
3115 UNICODE_STRING usBuffer;
3117 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3119 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3120 are all ignored by SetJob, so we don't bother copying them */
3121 switch(Level)
3123 case 0:
3124 JobW = NULL;
3125 break;
3126 case 1:
3128 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3129 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3131 JobW = (LPBYTE)info1W;
3132 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3133 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3134 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3135 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3136 info1W->Status = info1A->Status;
3137 info1W->Priority = info1A->Priority;
3138 info1W->Position = info1A->Position;
3139 info1W->PagesPrinted = info1A->PagesPrinted;
3140 break;
3142 case 2:
3144 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3145 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3147 JobW = (LPBYTE)info2W;
3148 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3149 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3150 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3151 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3152 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3153 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3154 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3155 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3156 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3157 info2W->Status = info2A->Status;
3158 info2W->Priority = info2A->Priority;
3159 info2W->Position = info2A->Position;
3160 info2W->StartTime = info2A->StartTime;
3161 info2W->UntilTime = info2A->UntilTime;
3162 info2W->PagesPrinted = info2A->PagesPrinted;
3163 break;
3165 case 3:
3166 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3167 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3168 break;
3169 default:
3170 SetLastError(ERROR_INVALID_LEVEL);
3171 return FALSE;
3174 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3176 switch(Level)
3178 case 1:
3180 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3181 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3182 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3183 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3184 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3185 break;
3187 case 2:
3189 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3190 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3191 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3192 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3193 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3194 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3195 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3196 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3197 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3198 break;
3201 HeapFree(GetProcessHeap(), 0, JobW);
3203 return ret;
3206 /*****************************************************************************
3207 * SetJobW [WINSPOOL.@]
3209 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3210 LPBYTE pJob, DWORD Command)
3212 BOOL ret = FALSE;
3213 job_t *job;
3215 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3216 FIXME("Ignoring everything other than document title\n");
3218 EnterCriticalSection(&printer_handles_cs);
3219 job = get_job(hPrinter, JobId);
3220 if(!job)
3221 goto end;
3223 switch(Level)
3225 case 0:
3226 break;
3227 case 1:
3229 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3230 HeapFree(GetProcessHeap(), 0, job->document_title);
3231 job->document_title = strdupW(info1->pDocument);
3232 break;
3234 case 2:
3236 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3237 HeapFree(GetProcessHeap(), 0, job->document_title);
3238 job->document_title = strdupW(info2->pDocument);
3239 break;
3241 case 3:
3242 break;
3243 default:
3244 SetLastError(ERROR_INVALID_LEVEL);
3245 goto end;
3247 ret = TRUE;
3248 end:
3249 LeaveCriticalSection(&printer_handles_cs);
3250 return ret;
3253 /*****************************************************************************
3254 * EndDocPrinter [WINSPOOL.@]
3256 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3258 opened_printer_t *printer;
3259 BOOL ret = FALSE;
3260 TRACE("(%p)\n", hPrinter);
3262 EnterCriticalSection(&printer_handles_cs);
3264 printer = get_opened_printer(hPrinter);
3265 if(!printer)
3267 SetLastError(ERROR_INVALID_HANDLE);
3268 goto end;
3271 if(!printer->doc)
3273 SetLastError(ERROR_SPL_NO_STARTDOC);
3274 goto end;
3277 CloseHandle(printer->doc->hf);
3278 ScheduleJob(hPrinter, printer->doc->job_id);
3279 HeapFree(GetProcessHeap(), 0, printer->doc);
3280 printer->doc = NULL;
3281 ret = TRUE;
3282 end:
3283 LeaveCriticalSection(&printer_handles_cs);
3284 return ret;
3287 /*****************************************************************************
3288 * EndPagePrinter [WINSPOOL.@]
3290 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3292 FIXME("(%p): stub\n", hPrinter);
3293 return TRUE;
3296 /*****************************************************************************
3297 * StartDocPrinterA [WINSPOOL.@]
3299 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3301 UNICODE_STRING usBuffer;
3302 DOC_INFO_2W doc2W;
3303 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3304 DWORD ret;
3306 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3307 or one (DOC_INFO_3) extra DWORDs */
3309 switch(Level) {
3310 case 2:
3311 doc2W.JobId = doc2->JobId;
3312 /* fall through */
3313 case 3:
3314 doc2W.dwMode = doc2->dwMode;
3315 /* fall through */
3316 case 1:
3317 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3318 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3319 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3320 break;
3322 default:
3323 SetLastError(ERROR_INVALID_LEVEL);
3324 return FALSE;
3327 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3329 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3330 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3331 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3333 return ret;
3336 /*****************************************************************************
3337 * StartDocPrinterW [WINSPOOL.@]
3339 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3341 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3342 opened_printer_t *printer;
3343 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3344 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3345 JOB_INFO_1W job_info;
3346 DWORD needed, ret = 0;
3347 HANDLE hf;
3348 WCHAR *filename;
3350 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3351 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3352 debugstr_w(doc->pDatatype));
3354 if(Level < 1 || Level > 3)
3356 SetLastError(ERROR_INVALID_LEVEL);
3357 return 0;
3360 EnterCriticalSection(&printer_handles_cs);
3361 printer = get_opened_printer(hPrinter);
3362 if(!printer)
3364 SetLastError(ERROR_INVALID_HANDLE);
3365 goto end;
3368 if(printer->doc)
3370 SetLastError(ERROR_INVALID_PRINTER_STATE);
3371 goto end;
3374 /* Even if we're printing to a file we still add a print job, we'll
3375 just ignore the spool file name */
3377 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3379 ERR("AddJob failed gle %08x\n", GetLastError());
3380 goto end;
3383 if(doc->pOutputFile)
3384 filename = doc->pOutputFile;
3385 else
3386 filename = addjob->Path;
3388 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3389 if(hf == INVALID_HANDLE_VALUE)
3390 goto end;
3392 memset(&job_info, 0, sizeof(job_info));
3393 job_info.pDocument = doc->pDocName;
3394 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3396 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3397 printer->doc->hf = hf;
3398 ret = printer->doc->job_id = addjob->JobId;
3399 end:
3400 LeaveCriticalSection(&printer_handles_cs);
3402 return ret;
3405 /*****************************************************************************
3406 * StartPagePrinter [WINSPOOL.@]
3408 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3410 FIXME("(%p): stub\n", hPrinter);
3411 return TRUE;
3414 /*****************************************************************************
3415 * GetFormA [WINSPOOL.@]
3417 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3418 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3420 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3421 Level,pForm,cbBuf,pcbNeeded);
3422 return FALSE;
3425 /*****************************************************************************
3426 * GetFormW [WINSPOOL.@]
3428 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3429 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3431 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3432 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3433 return FALSE;
3436 /*****************************************************************************
3437 * SetFormA [WINSPOOL.@]
3439 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3440 LPBYTE pForm)
3442 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3443 return FALSE;
3446 /*****************************************************************************
3447 * SetFormW [WINSPOOL.@]
3449 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3450 LPBYTE pForm)
3452 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3453 return FALSE;
3456 /*****************************************************************************
3457 * ReadPrinter [WINSPOOL.@]
3459 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3460 LPDWORD pNoBytesRead)
3462 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3463 return FALSE;
3466 /*****************************************************************************
3467 * ResetPrinterA [WINSPOOL.@]
3469 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3471 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3472 return FALSE;
3475 /*****************************************************************************
3476 * ResetPrinterW [WINSPOOL.@]
3478 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3480 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3481 return FALSE;
3484 /*****************************************************************************
3485 * WINSPOOL_GetDWORDFromReg
3487 * Return DWORD associated with ValueName from hkey.
3489 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3491 DWORD sz = sizeof(DWORD), type, value = 0;
3492 LONG ret;
3494 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3496 if(ret != ERROR_SUCCESS) {
3497 WARN("Got ret = %d on name %s\n", ret, ValueName);
3498 return 0;
3500 if(type != REG_DWORD) {
3501 ERR("Got type %d\n", type);
3502 return 0;
3504 return value;
3507 /*****************************************************************************
3508 * WINSPOOL_GetStringFromReg
3510 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3511 * String is stored either as unicode or ascii.
3512 * Bit of a hack here to get the ValueName if we want ascii.
3514 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3515 DWORD buflen, DWORD *needed,
3516 BOOL unicode)
3518 DWORD sz = buflen, type;
3519 LONG ret;
3521 if(unicode)
3522 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3523 else {
3524 LPSTR ValueNameA = strdupWtoA(ValueName);
3525 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3526 HeapFree(GetProcessHeap(),0,ValueNameA);
3528 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3529 WARN("Got ret = %d\n", ret);
3530 *needed = 0;
3531 return FALSE;
3533 /* add space for terminating '\0' */
3534 sz += unicode ? sizeof(WCHAR) : 1;
3535 *needed = sz;
3537 if (ptr)
3538 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3540 return TRUE;
3543 /*****************************************************************************
3544 * WINSPOOL_GetDefaultDevMode
3546 * Get a default DevMode values for wineps.
3547 * FIXME - use ppd.
3550 static void WINSPOOL_GetDefaultDevMode(
3551 LPBYTE ptr,
3552 DWORD buflen, DWORD *needed,
3553 BOOL unicode)
3555 DEVMODEA dm;
3556 static const char szwps[] = "wineps.drv";
3558 /* fill default DEVMODE - should be read from ppd... */
3559 ZeroMemory( &dm, sizeof(dm) );
3560 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3561 dm.dmSpecVersion = DM_SPECVERSION;
3562 dm.dmDriverVersion = 1;
3563 dm.dmSize = sizeof(DEVMODEA);
3564 dm.dmDriverExtra = 0;
3565 dm.dmFields =
3566 DM_ORIENTATION | DM_PAPERSIZE |
3567 DM_PAPERLENGTH | DM_PAPERWIDTH |
3568 DM_SCALE |
3569 DM_COPIES |
3570 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3571 DM_YRESOLUTION | DM_TTOPTION;
3573 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3574 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3575 dm.u1.s1.dmPaperLength = 2970;
3576 dm.u1.s1.dmPaperWidth = 2100;
3578 dm.dmScale = 100;
3579 dm.dmCopies = 1;
3580 dm.dmDefaultSource = DMBIN_AUTO;
3581 dm.dmPrintQuality = DMRES_MEDIUM;
3582 /* dm.dmColor */
3583 /* dm.dmDuplex */
3584 dm.dmYResolution = 300; /* 300dpi */
3585 dm.dmTTOption = DMTT_BITMAP;
3586 /* dm.dmCollate */
3587 /* dm.dmFormName */
3588 /* dm.dmLogPixels */
3589 /* dm.dmBitsPerPel */
3590 /* dm.dmPelsWidth */
3591 /* dm.dmPelsHeight */
3592 /* dm.dmDisplayFlags */
3593 /* dm.dmDisplayFrequency */
3594 /* dm.dmICMMethod */
3595 /* dm.dmICMIntent */
3596 /* dm.dmMediaType */
3597 /* dm.dmDitherType */
3598 /* dm.dmReserved1 */
3599 /* dm.dmReserved2 */
3600 /* dm.dmPanningWidth */
3601 /* dm.dmPanningHeight */
3603 if(unicode) {
3604 if(buflen >= sizeof(DEVMODEW)) {
3605 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3606 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3607 HeapFree(GetProcessHeap(),0,pdmW);
3609 *needed = sizeof(DEVMODEW);
3611 else
3613 if(buflen >= sizeof(DEVMODEA)) {
3614 memcpy(ptr, &dm, sizeof(DEVMODEA));
3616 *needed = sizeof(DEVMODEA);
3620 /*****************************************************************************
3621 * WINSPOOL_GetDevModeFromReg
3623 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3624 * DevMode is stored either as unicode or ascii.
3626 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3627 LPBYTE ptr,
3628 DWORD buflen, DWORD *needed,
3629 BOOL unicode)
3631 DWORD sz = buflen, type;
3632 LONG ret;
3634 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3635 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3636 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3637 if (sz < sizeof(DEVMODEA))
3639 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3640 return FALSE;
3642 /* ensures that dmSize is not erratically bogus if registry is invalid */
3643 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3644 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3645 if(unicode) {
3646 sz += (CCHDEVICENAME + CCHFORMNAME);
3647 if(buflen >= sz) {
3648 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3649 memcpy(ptr, dmW, sz);
3650 HeapFree(GetProcessHeap(),0,dmW);
3653 *needed = sz;
3654 return TRUE;
3657 /*********************************************************************
3658 * WINSPOOL_GetPrinter_2
3660 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3661 * The strings are either stored as unicode or ascii.
3663 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3664 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3665 BOOL unicode)
3667 DWORD size, left = cbBuf;
3668 BOOL space = (cbBuf > 0);
3669 LPBYTE ptr = buf;
3671 *pcbNeeded = 0;
3673 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3674 unicode)) {
3675 if(space && size <= left) {
3676 pi2->pPrinterName = (LPWSTR)ptr;
3677 ptr += size;
3678 left -= size;
3679 } else
3680 space = FALSE;
3681 *pcbNeeded += size;
3683 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3684 unicode)) {
3685 if(space && size <= left) {
3686 pi2->pShareName = (LPWSTR)ptr;
3687 ptr += size;
3688 left -= size;
3689 } else
3690 space = FALSE;
3691 *pcbNeeded += size;
3693 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3694 unicode)) {
3695 if(space && size <= left) {
3696 pi2->pPortName = (LPWSTR)ptr;
3697 ptr += size;
3698 left -= size;
3699 } else
3700 space = FALSE;
3701 *pcbNeeded += size;
3703 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3704 &size, unicode)) {
3705 if(space && size <= left) {
3706 pi2->pDriverName = (LPWSTR)ptr;
3707 ptr += size;
3708 left -= size;
3709 } else
3710 space = FALSE;
3711 *pcbNeeded += size;
3713 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3714 unicode)) {
3715 if(space && size <= left) {
3716 pi2->pComment = (LPWSTR)ptr;
3717 ptr += size;
3718 left -= size;
3719 } else
3720 space = FALSE;
3721 *pcbNeeded += size;
3723 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3724 unicode)) {
3725 if(space && size <= left) {
3726 pi2->pLocation = (LPWSTR)ptr;
3727 ptr += size;
3728 left -= size;
3729 } else
3730 space = FALSE;
3731 *pcbNeeded += size;
3733 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3734 &size, unicode)) {
3735 if(space && size <= left) {
3736 pi2->pDevMode = (LPDEVMODEW)ptr;
3737 ptr += size;
3738 left -= size;
3739 } else
3740 space = FALSE;
3741 *pcbNeeded += size;
3743 else
3745 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3746 if(space && size <= left) {
3747 pi2->pDevMode = (LPDEVMODEW)ptr;
3748 ptr += size;
3749 left -= size;
3750 } else
3751 space = FALSE;
3752 *pcbNeeded += size;
3754 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3755 &size, unicode)) {
3756 if(space && size <= left) {
3757 pi2->pSepFile = (LPWSTR)ptr;
3758 ptr += size;
3759 left -= size;
3760 } else
3761 space = FALSE;
3762 *pcbNeeded += size;
3764 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3765 &size, unicode)) {
3766 if(space && size <= left) {
3767 pi2->pPrintProcessor = (LPWSTR)ptr;
3768 ptr += size;
3769 left -= size;
3770 } else
3771 space = FALSE;
3772 *pcbNeeded += size;
3774 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3775 &size, unicode)) {
3776 if(space && size <= left) {
3777 pi2->pDatatype = (LPWSTR)ptr;
3778 ptr += size;
3779 left -= size;
3780 } else
3781 space = FALSE;
3782 *pcbNeeded += size;
3784 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3785 &size, unicode)) {
3786 if(space && size <= left) {
3787 pi2->pParameters = (LPWSTR)ptr;
3788 ptr += size;
3789 left -= size;
3790 } else
3791 space = FALSE;
3792 *pcbNeeded += size;
3794 if(pi2) {
3795 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3796 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3797 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3798 "Default Priority");
3799 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3800 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3803 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3804 memset(pi2, 0, sizeof(*pi2));
3806 return space;
3809 /*********************************************************************
3810 * WINSPOOL_GetPrinter_4
3812 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3814 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3815 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3816 BOOL unicode)
3818 DWORD size, left = cbBuf;
3819 BOOL space = (cbBuf > 0);
3820 LPBYTE ptr = buf;
3822 *pcbNeeded = 0;
3824 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3825 unicode)) {
3826 if(space && size <= left) {
3827 pi4->pPrinterName = (LPWSTR)ptr;
3828 ptr += size;
3829 left -= size;
3830 } else
3831 space = FALSE;
3832 *pcbNeeded += size;
3834 if(pi4) {
3835 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3838 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3839 memset(pi4, 0, sizeof(*pi4));
3841 return space;
3844 /*********************************************************************
3845 * WINSPOOL_GetPrinter_5
3847 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3849 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3850 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3851 BOOL unicode)
3853 DWORD size, left = cbBuf;
3854 BOOL space = (cbBuf > 0);
3855 LPBYTE ptr = buf;
3857 *pcbNeeded = 0;
3859 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3860 unicode)) {
3861 if(space && size <= left) {
3862 pi5->pPrinterName = (LPWSTR)ptr;
3863 ptr += size;
3864 left -= size;
3865 } else
3866 space = FALSE;
3867 *pcbNeeded += size;
3869 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3870 unicode)) {
3871 if(space && size <= left) {
3872 pi5->pPortName = (LPWSTR)ptr;
3873 ptr += size;
3874 left -= size;
3875 } else
3876 space = FALSE;
3877 *pcbNeeded += size;
3879 if(pi5) {
3880 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3881 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3882 "dnsTimeout");
3883 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3884 "txTimeout");
3887 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3888 memset(pi5, 0, sizeof(*pi5));
3890 return space;
3893 /*****************************************************************************
3894 * WINSPOOL_GetPrinter
3896 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3897 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3898 * just a collection of pointers to strings.
3900 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3901 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3903 LPCWSTR name;
3904 DWORD size, needed = 0;
3905 LPBYTE ptr = NULL;
3906 HKEY hkeyPrinter, hkeyPrinters;
3907 BOOL ret;
3909 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3911 if (!(name = get_opened_printer_name(hPrinter))) {
3912 SetLastError(ERROR_INVALID_HANDLE);
3913 return FALSE;
3916 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3917 ERROR_SUCCESS) {
3918 ERR("Can't create Printers key\n");
3919 return FALSE;
3921 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3923 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3924 RegCloseKey(hkeyPrinters);
3925 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3926 return FALSE;
3929 switch(Level) {
3930 case 2:
3932 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3934 size = sizeof(PRINTER_INFO_2W);
3935 if(size <= cbBuf) {
3936 ptr = pPrinter + size;
3937 cbBuf -= size;
3938 memset(pPrinter, 0, size);
3939 } else {
3940 pi2 = NULL;
3941 cbBuf = 0;
3943 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3944 unicode);
3945 needed += size;
3946 break;
3949 case 4:
3951 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3953 size = sizeof(PRINTER_INFO_4W);
3954 if(size <= cbBuf) {
3955 ptr = pPrinter + size;
3956 cbBuf -= size;
3957 memset(pPrinter, 0, size);
3958 } else {
3959 pi4 = NULL;
3960 cbBuf = 0;
3962 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3963 unicode);
3964 needed += size;
3965 break;
3969 case 5:
3971 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3973 size = sizeof(PRINTER_INFO_5W);
3974 if(size <= cbBuf) {
3975 ptr = pPrinter + size;
3976 cbBuf -= size;
3977 memset(pPrinter, 0, size);
3978 } else {
3979 pi5 = NULL;
3980 cbBuf = 0;
3983 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3984 unicode);
3985 needed += size;
3986 break;
3989 default:
3990 FIXME("Unimplemented level %d\n", Level);
3991 SetLastError(ERROR_INVALID_LEVEL);
3992 RegCloseKey(hkeyPrinters);
3993 RegCloseKey(hkeyPrinter);
3994 return FALSE;
3997 RegCloseKey(hkeyPrinter);
3998 RegCloseKey(hkeyPrinters);
4000 TRACE("returning %d needed = %d\n", ret, needed);
4001 if(pcbNeeded) *pcbNeeded = needed;
4002 if(!ret)
4003 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4004 return ret;
4007 /*****************************************************************************
4008 * GetPrinterW [WINSPOOL.@]
4010 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4011 DWORD cbBuf, LPDWORD pcbNeeded)
4013 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4014 TRUE);
4017 /*****************************************************************************
4018 * GetPrinterA [WINSPOOL.@]
4020 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4021 DWORD cbBuf, LPDWORD pcbNeeded)
4023 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4024 FALSE);
4027 /*****************************************************************************
4028 * WINSPOOL_EnumPrinters
4030 * Implementation of EnumPrintersA|W
4032 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4033 DWORD dwLevel, LPBYTE lpbPrinters,
4034 DWORD cbBuf, LPDWORD lpdwNeeded,
4035 LPDWORD lpdwReturned, BOOL unicode)
4038 HKEY hkeyPrinters, hkeyPrinter;
4039 WCHAR PrinterName[255];
4040 DWORD needed = 0, number = 0;
4041 DWORD used, i, left;
4042 PBYTE pi, buf;
4044 if(lpbPrinters)
4045 memset(lpbPrinters, 0, cbBuf);
4046 if(lpdwReturned)
4047 *lpdwReturned = 0;
4048 if(lpdwNeeded)
4049 *lpdwNeeded = 0;
4051 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4052 if(dwType == PRINTER_ENUM_DEFAULT)
4053 return TRUE;
4055 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4056 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4057 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4058 if(!dwType) return TRUE;
4061 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4062 FIXME("dwType = %08x\n", dwType);
4063 SetLastError(ERROR_INVALID_FLAGS);
4064 return FALSE;
4067 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4068 ERROR_SUCCESS) {
4069 ERR("Can't create Printers key\n");
4070 return FALSE;
4073 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4074 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4075 RegCloseKey(hkeyPrinters);
4076 ERR("Can't query Printers key\n");
4077 return FALSE;
4079 TRACE("Found %d printers\n", number);
4081 switch(dwLevel) {
4082 case 1:
4083 RegCloseKey(hkeyPrinters);
4084 if (lpdwReturned)
4085 *lpdwReturned = number;
4086 return TRUE;
4088 case 2:
4089 used = number * sizeof(PRINTER_INFO_2W);
4090 break;
4091 case 4:
4092 used = number * sizeof(PRINTER_INFO_4W);
4093 break;
4094 case 5:
4095 used = number * sizeof(PRINTER_INFO_5W);
4096 break;
4098 default:
4099 SetLastError(ERROR_INVALID_LEVEL);
4100 RegCloseKey(hkeyPrinters);
4101 return FALSE;
4103 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4105 for(i = 0; i < number; i++) {
4106 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4107 ERROR_SUCCESS) {
4108 ERR("Can't enum key number %d\n", i);
4109 RegCloseKey(hkeyPrinters);
4110 return FALSE;
4112 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4113 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4114 ERROR_SUCCESS) {
4115 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4116 RegCloseKey(hkeyPrinters);
4117 return FALSE;
4120 if(cbBuf > used) {
4121 buf = lpbPrinters + used;
4122 left = cbBuf - used;
4123 } else {
4124 buf = NULL;
4125 left = 0;
4128 switch(dwLevel) {
4129 case 2:
4130 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4131 left, &needed, unicode);
4132 used += needed;
4133 if(pi) pi += sizeof(PRINTER_INFO_2W);
4134 break;
4135 case 4:
4136 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4137 left, &needed, unicode);
4138 used += needed;
4139 if(pi) pi += sizeof(PRINTER_INFO_4W);
4140 break;
4141 case 5:
4142 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4143 left, &needed, unicode);
4144 used += needed;
4145 if(pi) pi += sizeof(PRINTER_INFO_5W);
4146 break;
4147 default:
4148 ERR("Shouldn't be here!\n");
4149 RegCloseKey(hkeyPrinter);
4150 RegCloseKey(hkeyPrinters);
4151 return FALSE;
4153 RegCloseKey(hkeyPrinter);
4155 RegCloseKey(hkeyPrinters);
4157 if(lpdwNeeded)
4158 *lpdwNeeded = used;
4160 if(used > cbBuf) {
4161 if(lpbPrinters)
4162 memset(lpbPrinters, 0, cbBuf);
4163 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4164 return FALSE;
4166 if(lpdwReturned)
4167 *lpdwReturned = number;
4168 SetLastError(ERROR_SUCCESS);
4169 return TRUE;
4173 /******************************************************************
4174 * EnumPrintersW [WINSPOOL.@]
4176 * Enumerates the available printers, print servers and print
4177 * providers, depending on the specified flags, name and level.
4179 * RETURNS:
4181 * If level is set to 1:
4182 * Not implemented yet!
4183 * Returns TRUE with an empty list.
4185 * If level is set to 2:
4186 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4187 * Returns an array of PRINTER_INFO_2 data structures in the
4188 * lpbPrinters buffer. Note that according to MSDN also an
4189 * OpenPrinter should be performed on every remote printer.
4191 * If level is set to 4 (officially WinNT only):
4192 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4193 * Fast: Only the registry is queried to retrieve printer names,
4194 * no connection to the driver is made.
4195 * Returns an array of PRINTER_INFO_4 data structures in the
4196 * lpbPrinters buffer.
4198 * If level is set to 5 (officially WinNT4/Win9x only):
4199 * Fast: Only the registry is queried to retrieve printer names,
4200 * no connection to the driver is made.
4201 * Returns an array of PRINTER_INFO_5 data structures in the
4202 * lpbPrinters buffer.
4204 * If level set to 3 or 6+:
4205 * returns zero (failure!)
4207 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4208 * for information.
4210 * BUGS:
4211 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4212 * - Only levels 2, 4 and 5 are implemented at the moment.
4213 * - 16-bit printer drivers are not enumerated.
4214 * - Returned amount of bytes used/needed does not match the real Windoze
4215 * implementation (as in this implementation, all strings are part
4216 * of the buffer, whereas Win32 keeps them somewhere else)
4217 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4219 * NOTE:
4220 * - In a regular Wine installation, no registry settings for printers
4221 * exist, which makes this function return an empty list.
4223 BOOL WINAPI EnumPrintersW(
4224 DWORD dwType, /* [in] Types of print objects to enumerate */
4225 LPWSTR lpszName, /* [in] name of objects to enumerate */
4226 DWORD dwLevel, /* [in] type of printer info structure */
4227 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4228 DWORD cbBuf, /* [in] max size of buffer in bytes */
4229 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4230 LPDWORD lpdwReturned /* [out] number of entries returned */
4233 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4234 lpdwNeeded, lpdwReturned, TRUE);
4237 /******************************************************************
4238 * EnumPrintersA [WINSPOOL.@]
4241 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4242 DWORD dwLevel, LPBYTE lpbPrinters,
4243 DWORD cbBuf, LPDWORD lpdwNeeded,
4244 LPDWORD lpdwReturned)
4246 BOOL ret, unicode = FALSE;
4247 UNICODE_STRING lpszNameW;
4248 PWSTR pwstrNameW;
4250 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4251 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4252 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4253 lpdwNeeded, lpdwReturned, unicode);
4254 RtlFreeUnicodeString(&lpszNameW);
4255 return ret;
4258 /*****************************************************************************
4259 * WINSPOOL_GetDriverInfoFromReg [internal]
4261 * Enters the information from the registry into the DRIVER_INFO struct
4263 * RETURNS
4264 * zero if the printer driver does not exist in the registry
4265 * (only if Level > 1) otherwise nonzero
4267 static BOOL WINSPOOL_GetDriverInfoFromReg(
4268 HKEY hkeyDrivers,
4269 LPWSTR DriverName,
4270 LPCWSTR pEnvironment,
4271 DWORD Level,
4272 LPBYTE ptr, /* DRIVER_INFO */
4273 LPBYTE pDriverStrings, /* strings buffer */
4274 DWORD cbBuf, /* size of string buffer */
4275 LPDWORD pcbNeeded, /* space needed for str. */
4276 BOOL unicode) /* type of strings */
4278 DWORD size, tmp;
4279 HKEY hkeyDriver;
4280 LPBYTE strPtr = pDriverStrings;
4282 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4283 debugstr_w(DriverName), debugstr_w(pEnvironment),
4284 Level, ptr, pDriverStrings, cbBuf, unicode);
4286 if(unicode) {
4287 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4288 if (*pcbNeeded <= cbBuf)
4289 strcpyW((LPWSTR)strPtr, DriverName);
4290 } else {
4291 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4292 NULL, NULL);
4293 if(*pcbNeeded <= cbBuf)
4294 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4295 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4297 if(Level == 1) {
4298 if(ptr)
4299 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4300 return TRUE;
4301 } else {
4302 if(ptr)
4303 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4304 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4307 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4308 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
4309 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4310 return FALSE;
4313 if(ptr)
4314 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4316 if(!pEnvironment)
4317 pEnvironment = DefaultEnvironmentW;
4318 if(unicode)
4319 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4320 else
4321 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4322 NULL, NULL);
4323 *pcbNeeded += size;
4324 if(*pcbNeeded <= cbBuf) {
4325 if(unicode)
4326 strcpyW((LPWSTR)strPtr, pEnvironment);
4327 else
4328 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4329 (LPSTR)strPtr, size, NULL, NULL);
4330 if(ptr)
4331 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4332 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4335 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4336 unicode)) {
4337 *pcbNeeded += size;
4338 if(*pcbNeeded <= cbBuf)
4339 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4340 unicode);
4341 if(ptr)
4342 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4343 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4346 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4347 unicode)) {
4348 *pcbNeeded += size;
4349 if(*pcbNeeded <= cbBuf)
4350 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4351 &tmp, unicode);
4352 if(ptr)
4353 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4354 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4357 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4358 0, &size, unicode)) {
4359 *pcbNeeded += size;
4360 if(*pcbNeeded <= cbBuf)
4361 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4362 size, &tmp, unicode);
4363 if(ptr)
4364 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4365 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4368 if(Level == 2 ) {
4369 RegCloseKey(hkeyDriver);
4370 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4371 return TRUE;
4374 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4375 unicode)) {
4376 *pcbNeeded += size;
4377 if(*pcbNeeded <= cbBuf)
4378 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4379 size, &tmp, unicode);
4380 if(ptr)
4381 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4382 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4385 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4386 &size, unicode)) {
4387 *pcbNeeded += size;
4388 if(*pcbNeeded <= cbBuf)
4389 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4390 size, &tmp, unicode);
4391 if(ptr)
4392 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4393 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4396 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4397 unicode)) {
4398 *pcbNeeded += size;
4399 if(*pcbNeeded <= cbBuf)
4400 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4401 size, &tmp, unicode);
4402 if(ptr)
4403 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4404 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4407 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4408 unicode)) {
4409 *pcbNeeded += size;
4410 if(*pcbNeeded <= cbBuf)
4411 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4412 size, &tmp, unicode);
4413 if(ptr)
4414 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4415 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4418 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4419 RegCloseKey(hkeyDriver);
4420 return TRUE;
4423 /*****************************************************************************
4424 * WINSPOOL_GetPrinterDriver
4426 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
4427 DWORD Level, LPBYTE pDriverInfo,
4428 DWORD cbBuf, LPDWORD pcbNeeded,
4429 BOOL unicode)
4431 LPCWSTR name;
4432 WCHAR DriverName[100];
4433 DWORD ret, type, size, needed = 0;
4434 LPBYTE ptr = NULL;
4435 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4437 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4438 Level,pDriverInfo,cbBuf, pcbNeeded);
4440 ZeroMemory(pDriverInfo, cbBuf);
4442 if (!(name = get_opened_printer_name(hPrinter))) {
4443 SetLastError(ERROR_INVALID_HANDLE);
4444 return FALSE;
4446 if(Level < 1 || Level > 6) {
4447 SetLastError(ERROR_INVALID_LEVEL);
4448 return FALSE;
4450 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4451 ERROR_SUCCESS) {
4452 ERR("Can't create Printers key\n");
4453 return FALSE;
4455 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4456 != ERROR_SUCCESS) {
4457 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4458 RegCloseKey(hkeyPrinters);
4459 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4460 return FALSE;
4462 size = sizeof(DriverName);
4463 DriverName[0] = 0;
4464 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4465 (LPBYTE)DriverName, &size);
4466 RegCloseKey(hkeyPrinter);
4467 RegCloseKey(hkeyPrinters);
4468 if(ret != ERROR_SUCCESS) {
4469 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4470 return FALSE;
4473 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4474 if(!hkeyDrivers) {
4475 ERR("Can't create Drivers key\n");
4476 return FALSE;
4479 switch(Level) {
4480 case 1:
4481 size = sizeof(DRIVER_INFO_1W);
4482 break;
4483 case 2:
4484 size = sizeof(DRIVER_INFO_2W);
4485 break;
4486 case 3:
4487 size = sizeof(DRIVER_INFO_3W);
4488 break;
4489 case 4:
4490 size = sizeof(DRIVER_INFO_4W);
4491 break;
4492 case 5:
4493 size = sizeof(DRIVER_INFO_5W);
4494 break;
4495 case 6:
4496 size = sizeof(DRIVER_INFO_6W);
4497 break;
4498 default:
4499 ERR("Invalid level\n");
4500 return FALSE;
4503 if(size <= cbBuf)
4504 ptr = pDriverInfo + size;
4506 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4507 pEnvironment, Level, pDriverInfo,
4508 (cbBuf < size) ? NULL : ptr,
4509 (cbBuf < size) ? 0 : cbBuf - size,
4510 &needed, unicode)) {
4511 RegCloseKey(hkeyDrivers);
4512 return FALSE;
4515 RegCloseKey(hkeyDrivers);
4517 if(pcbNeeded) *pcbNeeded = size + needed;
4518 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4519 if(cbBuf >= needed) return TRUE;
4520 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4521 return FALSE;
4524 /*****************************************************************************
4525 * GetPrinterDriverA [WINSPOOL.@]
4527 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4528 DWORD Level, LPBYTE pDriverInfo,
4529 DWORD cbBuf, LPDWORD pcbNeeded)
4531 BOOL ret;
4532 UNICODE_STRING pEnvW;
4533 PWSTR pwstrEnvW;
4535 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4536 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4537 cbBuf, pcbNeeded, FALSE);
4538 RtlFreeUnicodeString(&pEnvW);
4539 return ret;
4541 /*****************************************************************************
4542 * GetPrinterDriverW [WINSPOOL.@]
4544 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4545 DWORD Level, LPBYTE pDriverInfo,
4546 DWORD cbBuf, LPDWORD pcbNeeded)
4548 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4549 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4552 /*****************************************************************************
4553 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4555 * Return the PATH for the Printer-Drivers (UNICODE)
4557 * PARAMS
4558 * pName [I] Servername (NT only) or NULL (local Computer)
4559 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4560 * Level [I] Structure-Level (must be 1)
4561 * pDriverDirectory [O] PTR to Buffer that receives the Result
4562 * cbBuf [I] Size of Buffer at pDriverDirectory
4563 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4564 * required for pDriverDirectory
4566 * RETURNS
4567 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4568 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4569 * if cbBuf is too small
4571 * Native Values returned in pDriverDirectory on Success:
4572 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4573 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4574 *| win9x(Windows 4.0): "%winsysdir%"
4576 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4578 * FIXME
4579 *- Only NULL or "" is supported for pName
4582 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4583 DWORD Level, LPBYTE pDriverDirectory,
4584 DWORD cbBuf, LPDWORD pcbNeeded)
4586 DWORD needed;
4587 const printenv_t * env;
4589 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4590 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4591 if(pName != NULL && pName[0]) {
4592 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4593 SetLastError(ERROR_INVALID_PARAMETER);
4594 return FALSE;
4597 env = validate_envW(pEnvironment);
4598 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4600 if(Level != 1) {
4601 WARN("(Level: %d) is ignored in win9x\n", Level);
4602 SetLastError(ERROR_INVALID_LEVEL);
4603 return FALSE;
4606 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4607 needed = GetSystemDirectoryW(NULL, 0);
4608 /* add the Size for the Subdirectories */
4609 needed += lstrlenW(spooldriversW);
4610 needed += lstrlenW(env->subdir);
4611 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4613 if(pcbNeeded)
4614 *pcbNeeded = needed;
4615 TRACE("required: 0x%x/%d\n", needed, needed);
4616 if(needed > cbBuf) {
4617 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4618 return FALSE;
4620 if(pcbNeeded == NULL) {
4621 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4622 SetLastError(RPC_X_NULL_REF_POINTER);
4623 return FALSE;
4625 if(pDriverDirectory == NULL) {
4626 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4627 SetLastError(ERROR_INVALID_USER_BUFFER);
4628 return FALSE;
4631 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4632 /* add the Subdirectories */
4633 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4634 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4635 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4636 return TRUE;
4640 /*****************************************************************************
4641 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4643 * Return the PATH for the Printer-Drivers (ANSI)
4645 * See GetPrinterDriverDirectoryW.
4647 * NOTES
4648 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4651 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4652 DWORD Level, LPBYTE pDriverDirectory,
4653 DWORD cbBuf, LPDWORD pcbNeeded)
4655 UNICODE_STRING nameW, environmentW;
4656 BOOL ret;
4657 DWORD pcbNeededW;
4658 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4659 WCHAR *driverDirectoryW = NULL;
4661 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4662 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4664 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4666 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4667 else nameW.Buffer = NULL;
4668 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4669 else environmentW.Buffer = NULL;
4671 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4672 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4673 if (ret) {
4674 DWORD needed;
4675 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4676 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4677 if(pcbNeeded)
4678 *pcbNeeded = needed;
4679 ret = (needed <= cbBuf) ? TRUE : FALSE;
4680 } else
4681 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4683 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4685 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4686 RtlFreeUnicodeString(&environmentW);
4687 RtlFreeUnicodeString(&nameW);
4689 return ret;
4692 /*****************************************************************************
4693 * AddPrinterDriverA [WINSPOOL.@]
4695 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4697 DRIVER_INFO_3A di3;
4698 HKEY hkeyDrivers, hkeyName;
4699 static CHAR empty[] = "",
4700 nullnull[] = "\0";
4702 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4704 if(level != 2 && level != 3) {
4705 SetLastError(ERROR_INVALID_LEVEL);
4706 return FALSE;
4708 if ((pName) && (pName[0])) {
4709 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4710 SetLastError(ERROR_INVALID_PARAMETER);
4711 return FALSE;
4713 if(!pDriverInfo) {
4714 WARN("pDriverInfo == NULL\n");
4715 SetLastError(ERROR_INVALID_PARAMETER);
4716 return FALSE;
4719 if(level == 3)
4720 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4721 else {
4722 memset(&di3, 0, sizeof(di3));
4723 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4726 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4727 !di3.pDataFile) {
4728 SetLastError(ERROR_INVALID_PARAMETER);
4729 return FALSE;
4732 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4733 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4734 if(!di3.pHelpFile) di3.pHelpFile = empty;
4735 if(!di3.pMonitorName) di3.pMonitorName = empty;
4737 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4739 if(!hkeyDrivers) {
4740 ERR("Can't create Drivers key\n");
4741 return FALSE;
4744 if(level == 2) { /* apparently can't overwrite with level2 */
4745 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4746 RegCloseKey(hkeyName);
4747 RegCloseKey(hkeyDrivers);
4748 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4749 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4750 return FALSE;
4753 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4754 RegCloseKey(hkeyDrivers);
4755 ERR("Can't create Name key\n");
4756 return FALSE;
4758 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4759 lstrlenA(di3.pConfigFile) + 1);
4760 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4761 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4762 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4763 sizeof(DWORD));
4764 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4765 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4766 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4767 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4768 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4769 RegCloseKey(hkeyName);
4770 RegCloseKey(hkeyDrivers);
4772 return TRUE;
4775 /*****************************************************************************
4776 * AddPrinterDriverW [WINSPOOL.@]
4778 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4779 LPBYTE pDriverInfo)
4781 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4782 level,pDriverInfo);
4783 return FALSE;
4786 /*****************************************************************************
4787 * AddPrintProcessorA [WINSPOOL.@]
4789 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4790 LPSTR pPrintProcessorName)
4792 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4793 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4794 return FALSE;
4797 /*****************************************************************************
4798 * AddPrintProcessorW [WINSPOOL.@]
4800 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4801 LPWSTR pPrintProcessorName)
4803 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4804 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4805 return FALSE;
4808 /*****************************************************************************
4809 * AddPrintProvidorA [WINSPOOL.@]
4811 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4813 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4814 return FALSE;
4817 /*****************************************************************************
4818 * AddPrintProvidorW [WINSPOOL.@]
4820 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4822 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4823 return FALSE;
4826 /*****************************************************************************
4827 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4829 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4830 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4832 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4833 pDevModeOutput, pDevModeInput);
4834 return 0;
4837 /*****************************************************************************
4838 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4840 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4841 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4843 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4844 pDevModeOutput, pDevModeInput);
4845 return 0;
4848 /*****************************************************************************
4849 * PrinterProperties [WINSPOOL.@]
4851 * Displays a dialog to set the properties of the printer.
4853 * RETURNS
4854 * nonzero on success or zero on failure
4856 * BUGS
4857 * implemented as stub only
4859 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4860 HANDLE hPrinter /* [in] handle to printer object */
4862 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4863 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4864 return FALSE;
4867 /*****************************************************************************
4868 * EnumJobsA [WINSPOOL.@]
4871 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4872 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4873 LPDWORD pcReturned)
4875 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4876 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4878 if(pcbNeeded) *pcbNeeded = 0;
4879 if(pcReturned) *pcReturned = 0;
4880 return FALSE;
4884 /*****************************************************************************
4885 * EnumJobsW [WINSPOOL.@]
4888 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4889 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4890 LPDWORD pcReturned)
4892 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4893 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4895 if(pcbNeeded) *pcbNeeded = 0;
4896 if(pcReturned) *pcReturned = 0;
4897 return FALSE;
4900 /*****************************************************************************
4901 * WINSPOOL_EnumPrinterDrivers [internal]
4903 * Delivers information about all printer drivers installed on the
4904 * localhost or a given server
4906 * RETURNS
4907 * nonzero on success or zero on failure. If the buffer for the returned
4908 * information is too small the function will return an error
4910 * BUGS
4911 * - only implemented for localhost, foreign hosts will return an error
4913 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
4914 DWORD Level, LPBYTE pDriverInfo,
4915 DWORD cbBuf, LPDWORD pcbNeeded,
4916 LPDWORD pcReturned, BOOL unicode)
4918 { HKEY hkeyDrivers;
4919 DWORD i, needed, number = 0, size = 0;
4920 WCHAR DriverNameW[255];
4921 PBYTE ptr;
4923 TRACE("%s,%s,%d,%p,%d,%d\n",
4924 debugstr_w(pName), debugstr_w(pEnvironment),
4925 Level, pDriverInfo, cbBuf, unicode);
4927 /* check for local drivers */
4928 if((pName) && (pName[0])) {
4929 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4930 SetLastError(ERROR_ACCESS_DENIED);
4931 return FALSE;
4934 /* check input parameter */
4935 if((Level < 1) || (Level > 3)) {
4936 ERR("unsupported level %d\n", Level);
4937 SetLastError(ERROR_INVALID_LEVEL);
4938 return FALSE;
4941 /* initialize return values */
4942 if(pDriverInfo)
4943 memset( pDriverInfo, 0, cbBuf);
4944 *pcbNeeded = 0;
4945 *pcReturned = 0;
4947 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4948 if(!hkeyDrivers) {
4949 ERR("Can't open Drivers key\n");
4950 return FALSE;
4953 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4954 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4955 RegCloseKey(hkeyDrivers);
4956 ERR("Can't query Drivers key\n");
4957 return FALSE;
4959 TRACE("Found %d Drivers\n", number);
4961 /* get size of single struct
4962 * unicode and ascii structure have the same size
4964 switch (Level) {
4965 case 1:
4966 size = sizeof(DRIVER_INFO_1A);
4967 break;
4968 case 2:
4969 size = sizeof(DRIVER_INFO_2A);
4970 break;
4971 case 3:
4972 size = sizeof(DRIVER_INFO_3A);
4973 break;
4976 /* calculate required buffer size */
4977 *pcbNeeded = size * number;
4979 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4980 i < number;
4981 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4982 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4983 != ERROR_SUCCESS) {
4984 ERR("Can't enum key number %d\n", i);
4985 RegCloseKey(hkeyDrivers);
4986 return FALSE;
4988 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4989 pEnvironment, Level, ptr,
4990 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4991 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4992 &needed, unicode)) {
4993 RegCloseKey(hkeyDrivers);
4994 return FALSE;
4996 (*pcbNeeded) += needed;
4999 RegCloseKey(hkeyDrivers);
5001 if(cbBuf < *pcbNeeded){
5002 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5003 return FALSE;
5006 *pcReturned = number;
5007 return TRUE;
5010 /*****************************************************************************
5011 * EnumPrinterDriversW [WINSPOOL.@]
5013 * see function EnumPrinterDrivers for RETURNS, BUGS
5015 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5016 LPBYTE pDriverInfo, DWORD cbBuf,
5017 LPDWORD pcbNeeded, LPDWORD pcReturned)
5019 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5020 cbBuf, pcbNeeded, pcReturned, TRUE);
5023 /*****************************************************************************
5024 * EnumPrinterDriversA [WINSPOOL.@]
5026 * see function EnumPrinterDrivers for RETURNS, BUGS
5028 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5029 LPBYTE pDriverInfo, DWORD cbBuf,
5030 LPDWORD pcbNeeded, LPDWORD pcReturned)
5031 { BOOL ret;
5032 UNICODE_STRING pNameW, pEnvironmentW;
5033 PWSTR pwstrNameW, pwstrEnvironmentW;
5035 pwstrNameW = asciitounicode(&pNameW, pName);
5036 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5038 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5039 Level, pDriverInfo, cbBuf, pcbNeeded,
5040 pcReturned, FALSE);
5041 RtlFreeUnicodeString(&pNameW);
5042 RtlFreeUnicodeString(&pEnvironmentW);
5044 return ret;
5047 /******************************************************************************
5048 * EnumPortsA (WINSPOOL.@)
5050 * See EnumPortsW.
5053 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5054 LPDWORD pcbNeeded, LPDWORD pcReturned)
5056 BOOL res;
5057 LPBYTE bufferW = NULL;
5058 LPWSTR nameW = NULL;
5059 DWORD needed = 0;
5060 DWORD numentries = 0;
5061 INT len;
5063 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5064 cbBuf, pcbNeeded, pcReturned);
5066 /* convert servername to unicode */
5067 if (pName) {
5068 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5069 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5070 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5072 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5073 needed = cbBuf * sizeof(WCHAR);
5074 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5075 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5077 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5078 if (pcbNeeded) needed = *pcbNeeded;
5079 /* HeapReAlloc return NULL, when bufferW was NULL */
5080 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5081 HeapAlloc(GetProcessHeap(), 0, needed);
5083 /* Try again with the large Buffer */
5084 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5086 needed = pcbNeeded ? *pcbNeeded : 0;
5087 numentries = pcReturned ? *pcReturned : 0;
5090 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5091 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5093 if (res) {
5094 /* EnumPortsW collected all Data. Parse them to caclulate ANSI-Size */
5095 DWORD entrysize = 0;
5096 DWORD index;
5097 LPSTR ptr;
5098 LPPORT_INFO_2W pi2w;
5099 LPPORT_INFO_2A pi2a;
5101 needed = 0;
5102 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5104 /* First pass: calculate the size for all Entries */
5105 pi2w = (LPPORT_INFO_2W) bufferW;
5106 pi2a = (LPPORT_INFO_2A) pPorts;
5107 index = 0;
5108 while (index < numentries) {
5109 index++;
5110 needed += entrysize; /* PORT_INFO_?A */
5111 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5113 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5114 NULL, 0, NULL, NULL);
5115 if (Level > 1) {
5116 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5117 NULL, 0, NULL, NULL);
5118 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5119 NULL, 0, NULL, NULL);
5121 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5122 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5123 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5126 /* check for errors and quit on failure */
5127 if (cbBuf < needed) {
5128 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5129 res = FALSE;
5130 goto cleanup;
5132 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5133 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5134 cbBuf -= len ; /* free Bytes in the user-Buffer */
5135 pi2w = (LPPORT_INFO_2W) bufferW;
5136 pi2a = (LPPORT_INFO_2A) pPorts;
5137 index = 0;
5138 /* Second Pass: Fill the User Buffer (if we have one) */
5139 while ((index < numentries) && pPorts) {
5140 index++;
5141 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5142 pi2a->pPortName = ptr;
5143 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5144 ptr, cbBuf , NULL, NULL);
5145 ptr += len;
5146 cbBuf -= len;
5147 if (Level > 1) {
5148 pi2a->pMonitorName = ptr;
5149 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5150 ptr, cbBuf, NULL, NULL);
5151 ptr += len;
5152 cbBuf -= len;
5154 pi2a->pDescription = ptr;
5155 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5156 ptr, cbBuf, NULL, NULL);
5157 ptr += len;
5158 cbBuf -= len;
5160 pi2a->fPortType = pi2w->fPortType;
5161 pi2a->Reserved = 0; /* documented: "must be zero" */
5164 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5165 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5166 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5170 cleanup:
5171 if (pcbNeeded) *pcbNeeded = needed;
5172 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5174 HeapFree(GetProcessHeap(), 0, nameW);
5175 HeapFree(GetProcessHeap(), 0, bufferW);
5177 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5178 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5180 return (res);
5184 /******************************************************************************
5185 * EnumPortsW (WINSPOOL.@)
5187 * Enumerate available Ports
5189 * PARAMS
5190 * name [I] Servername or NULL (local Computer)
5191 * level [I] Structure-Level (1 or 2)
5192 * buffer [O] PTR to Buffer that receives the Result
5193 * bufsize [I] Size of Buffer at buffer
5194 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5195 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5197 * RETURNS
5198 * Success: TRUE
5199 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5203 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5205 DWORD needed = 0;
5206 DWORD numentries = 0;
5207 BOOL res = FALSE;
5209 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5210 cbBuf, pcbNeeded, pcReturned);
5212 if (pName && (pName[0])) {
5213 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5214 SetLastError(ERROR_ACCESS_DENIED);
5215 goto emP_cleanup;
5218 /* Level is not checked in win9x */
5219 if (!Level || (Level > 2)) {
5220 WARN("level (%d) is ignored in win9x\n", Level);
5221 SetLastError(ERROR_INVALID_LEVEL);
5222 goto emP_cleanup;
5224 if (!pcbNeeded) {
5225 SetLastError(RPC_X_NULL_REF_POINTER);
5226 goto emP_cleanup;
5229 EnterCriticalSection(&monitor_handles_cs);
5230 monitor_loadall();
5232 /* Scan all local Ports */
5233 numentries = 0;
5234 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5236 /* we calculated the needed buffersize. now do the error-checks */
5237 if (cbBuf < needed) {
5238 monitor_unloadall();
5239 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5240 goto emP_cleanup_cs;
5242 else if (!pPorts || !pcReturned) {
5243 monitor_unloadall();
5244 SetLastError(RPC_X_NULL_REF_POINTER);
5245 goto emP_cleanup_cs;
5248 /* Fill the Buffer */
5249 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5250 res = TRUE;
5251 monitor_unloadall();
5253 emP_cleanup_cs:
5254 LeaveCriticalSection(&monitor_handles_cs);
5256 emP_cleanup:
5257 if (pcbNeeded) *pcbNeeded = needed;
5258 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5260 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5261 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5263 return (res);
5266 /******************************************************************************
5267 * GetDefaultPrinterW (WINSPOOL.@)
5269 * FIXME
5270 * This function must read the value from data 'device' of key
5271 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5273 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5275 BOOL retval = TRUE;
5276 DWORD insize, len;
5277 WCHAR *buffer, *ptr;
5279 if (!namesize)
5281 SetLastError(ERROR_INVALID_PARAMETER);
5282 return FALSE;
5285 /* make the buffer big enough for the stuff from the profile/registry,
5286 * the content must fit into the local buffer to compute the correct
5287 * size even if the extern buffer is too small or not given.
5288 * (20 for ,driver,port) */
5289 insize = *namesize;
5290 len = max(100, (insize + 20));
5291 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5293 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5295 SetLastError (ERROR_FILE_NOT_FOUND);
5296 retval = FALSE;
5297 goto end;
5299 TRACE("%s\n", debugstr_w(buffer));
5301 if ((ptr = strchrW(buffer, ',')) == NULL)
5303 SetLastError(ERROR_INVALID_NAME);
5304 retval = FALSE;
5305 goto end;
5308 *ptr = 0;
5309 *namesize = strlenW(buffer) + 1;
5310 if(!name || (*namesize > insize))
5312 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5313 retval = FALSE;
5314 goto end;
5316 strcpyW(name, buffer);
5318 end:
5319 HeapFree( GetProcessHeap(), 0, buffer);
5320 return retval;
5324 /******************************************************************************
5325 * GetDefaultPrinterA (WINSPOOL.@)
5327 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5329 BOOL retval = TRUE;
5330 DWORD insize = 0;
5331 WCHAR *bufferW = NULL;
5333 if (!namesize)
5335 SetLastError(ERROR_INVALID_PARAMETER);
5336 return FALSE;
5339 if(name && *namesize) {
5340 insize = *namesize;
5341 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5344 if(!GetDefaultPrinterW( bufferW, namesize)) {
5345 retval = FALSE;
5346 goto end;
5349 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5350 NULL, NULL);
5351 if (!*namesize)
5353 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5354 retval = FALSE;
5356 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5358 end:
5359 HeapFree( GetProcessHeap(), 0, bufferW);
5360 return retval;
5364 /******************************************************************************
5365 * SetDefaultPrinterW (WINSPOOL.204)
5367 * Set the Name of the Default Printer
5369 * PARAMS
5370 * pszPrinter [I] Name of the Printer or NULL
5372 * RETURNS
5373 * Success: True
5374 * Failure: FALSE
5376 * NOTES
5377 * When the Parameter is NULL or points to an Empty String and
5378 * a Default Printer was already present, then this Function changes nothing.
5379 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5380 * the First enumerated local Printer is used.
5383 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5386 TRACE("(%s)\n", debugstr_w(pszPrinter));
5388 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5389 return FALSE;
5392 /******************************************************************************
5393 * SetDefaultPrinterA (WINSPOOL.202)
5395 * See SetDefaultPrinterW.
5398 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5401 TRACE("(%s)\n", debugstr_a(pszPrinter));
5403 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5404 return FALSE;
5408 /******************************************************************************
5409 * SetPrinterDataExA (WINSPOOL.@)
5411 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5412 LPCSTR pValueName, DWORD Type,
5413 LPBYTE pData, DWORD cbData)
5415 HKEY hkeyPrinter, hkeySubkey;
5416 DWORD ret;
5418 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5419 debugstr_a(pValueName), Type, pData, cbData);
5421 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5422 != ERROR_SUCCESS)
5423 return ret;
5425 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5426 != ERROR_SUCCESS) {
5427 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5428 RegCloseKey(hkeyPrinter);
5429 return ret;
5431 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5432 RegCloseKey(hkeySubkey);
5433 RegCloseKey(hkeyPrinter);
5434 return ret;
5437 /******************************************************************************
5438 * SetPrinterDataExW (WINSPOOL.@)
5440 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5441 LPCWSTR pValueName, DWORD Type,
5442 LPBYTE pData, DWORD cbData)
5444 HKEY hkeyPrinter, hkeySubkey;
5445 DWORD ret;
5447 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5448 debugstr_w(pValueName), Type, pData, cbData);
5450 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5451 != ERROR_SUCCESS)
5452 return ret;
5454 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5455 != ERROR_SUCCESS) {
5456 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5457 RegCloseKey(hkeyPrinter);
5458 return ret;
5460 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5461 RegCloseKey(hkeySubkey);
5462 RegCloseKey(hkeyPrinter);
5463 return ret;
5466 /******************************************************************************
5467 * SetPrinterDataA (WINSPOOL.@)
5469 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5470 LPBYTE pData, DWORD cbData)
5472 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5473 pData, cbData);
5476 /******************************************************************************
5477 * SetPrinterDataW (WINSPOOL.@)
5479 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5480 LPBYTE pData, DWORD cbData)
5482 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5483 pData, cbData);
5486 /******************************************************************************
5487 * GetPrinterDataExA (WINSPOOL.@)
5489 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5490 LPCSTR pValueName, LPDWORD pType,
5491 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5493 HKEY hkeyPrinter, hkeySubkey;
5494 DWORD ret;
5496 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5497 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5498 pcbNeeded);
5500 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5501 != ERROR_SUCCESS)
5502 return ret;
5504 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5505 != ERROR_SUCCESS) {
5506 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5507 RegCloseKey(hkeyPrinter);
5508 return ret;
5510 *pcbNeeded = nSize;
5511 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5512 RegCloseKey(hkeySubkey);
5513 RegCloseKey(hkeyPrinter);
5514 return ret;
5517 /******************************************************************************
5518 * GetPrinterDataExW (WINSPOOL.@)
5520 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5521 LPCWSTR pValueName, LPDWORD pType,
5522 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5524 HKEY hkeyPrinter, hkeySubkey;
5525 DWORD ret;
5527 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5528 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5529 pcbNeeded);
5531 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5532 != ERROR_SUCCESS)
5533 return ret;
5535 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5536 != ERROR_SUCCESS) {
5537 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5538 RegCloseKey(hkeyPrinter);
5539 return ret;
5541 *pcbNeeded = nSize;
5542 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5543 RegCloseKey(hkeySubkey);
5544 RegCloseKey(hkeyPrinter);
5545 return ret;
5548 /******************************************************************************
5549 * GetPrinterDataA (WINSPOOL.@)
5551 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5552 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5554 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5555 pData, nSize, pcbNeeded);
5558 /******************************************************************************
5559 * GetPrinterDataW (WINSPOOL.@)
5561 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5562 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5564 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5565 pData, nSize, pcbNeeded);
5568 /*******************************************************************************
5569 * EnumPrinterDataExW [WINSPOOL.@]
5571 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5572 LPBYTE pEnumValues, DWORD cbEnumValues,
5573 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5575 HKEY hkPrinter, hkSubKey;
5576 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5577 cbValueNameLen, cbMaxValueLen, cbValueLen,
5578 cbBufSize, dwType;
5579 LPWSTR lpValueName;
5580 HANDLE hHeap;
5581 PBYTE lpValue;
5582 PPRINTER_ENUM_VALUESW ppev;
5584 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5586 if (pKeyName == NULL || *pKeyName == 0)
5587 return ERROR_INVALID_PARAMETER;
5589 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5590 if (ret != ERROR_SUCCESS)
5592 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5593 hPrinter, ret);
5594 return ret;
5597 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5598 if (ret != ERROR_SUCCESS)
5600 r = RegCloseKey (hkPrinter);
5601 if (r != ERROR_SUCCESS)
5602 WARN ("RegCloseKey returned %i\n", r);
5603 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5604 debugstr_w (pKeyName), ret);
5605 return ret;
5608 ret = RegCloseKey (hkPrinter);
5609 if (ret != ERROR_SUCCESS)
5611 ERR ("RegCloseKey returned %i\n", ret);
5612 r = RegCloseKey (hkSubKey);
5613 if (r != ERROR_SUCCESS)
5614 WARN ("RegCloseKey returned %i\n", r);
5615 return ret;
5618 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5619 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5620 if (ret != ERROR_SUCCESS)
5622 r = RegCloseKey (hkSubKey);
5623 if (r != ERROR_SUCCESS)
5624 WARN ("RegCloseKey returned %i\n", r);
5625 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5626 return ret;
5629 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5630 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5632 if (cValues == 0) /* empty key */
5634 r = RegCloseKey (hkSubKey);
5635 if (r != ERROR_SUCCESS)
5636 WARN ("RegCloseKey returned %i\n", r);
5637 *pcbEnumValues = *pnEnumValues = 0;
5638 return ERROR_SUCCESS;
5641 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5643 hHeap = GetProcessHeap ();
5644 if (hHeap == NULL)
5646 ERR ("GetProcessHeap failed\n");
5647 r = RegCloseKey (hkSubKey);
5648 if (r != ERROR_SUCCESS)
5649 WARN ("RegCloseKey returned %i\n", r);
5650 return ERROR_OUTOFMEMORY;
5653 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5654 if (lpValueName == NULL)
5656 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5657 r = RegCloseKey (hkSubKey);
5658 if (r != ERROR_SUCCESS)
5659 WARN ("RegCloseKey returned %i\n", r);
5660 return ERROR_OUTOFMEMORY;
5663 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5664 if (lpValue == NULL)
5666 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5667 if (HeapFree (hHeap, 0, lpValueName) == 0)
5668 WARN ("HeapFree failed with code %i\n", GetLastError ());
5669 r = RegCloseKey (hkSubKey);
5670 if (r != ERROR_SUCCESS)
5671 WARN ("RegCloseKey returned %i\n", r);
5672 return ERROR_OUTOFMEMORY;
5675 TRACE ("pass 1: calculating buffer required for all names and values\n");
5677 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5679 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5681 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5683 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5684 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5685 NULL, NULL, lpValue, &cbValueLen);
5686 if (ret != ERROR_SUCCESS)
5688 if (HeapFree (hHeap, 0, lpValue) == 0)
5689 WARN ("HeapFree failed with code %i\n", GetLastError ());
5690 if (HeapFree (hHeap, 0, lpValueName) == 0)
5691 WARN ("HeapFree failed with code %i\n", GetLastError ());
5692 r = RegCloseKey (hkSubKey);
5693 if (r != ERROR_SUCCESS)
5694 WARN ("RegCloseKey returned %i\n", r);
5695 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5696 return ret;
5699 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5700 debugstr_w (lpValueName), dwIndex,
5701 cbValueNameLen + 1, cbValueLen);
5703 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5704 cbBufSize += cbValueLen;
5707 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5709 *pcbEnumValues = cbBufSize;
5710 *pnEnumValues = cValues;
5712 if (cbEnumValues < cbBufSize) /* buffer too small */
5714 if (HeapFree (hHeap, 0, lpValue) == 0)
5715 WARN ("HeapFree failed with code %i\n", GetLastError ());
5716 if (HeapFree (hHeap, 0, lpValueName) == 0)
5717 WARN ("HeapFree failed with code %i\n", GetLastError ());
5718 r = RegCloseKey (hkSubKey);
5719 if (r != ERROR_SUCCESS)
5720 WARN ("RegCloseKey returned %i\n", r);
5721 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5722 return ERROR_MORE_DATA;
5725 TRACE ("pass 2: copying all names and values to buffer\n");
5727 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5728 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5730 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5732 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5733 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5734 NULL, &dwType, lpValue, &cbValueLen);
5735 if (ret != ERROR_SUCCESS)
5737 if (HeapFree (hHeap, 0, lpValue) == 0)
5738 WARN ("HeapFree failed with code %i\n", GetLastError ());
5739 if (HeapFree (hHeap, 0, lpValueName) == 0)
5740 WARN ("HeapFree failed with code %i\n", GetLastError ());
5741 r = RegCloseKey (hkSubKey);
5742 if (r != ERROR_SUCCESS)
5743 WARN ("RegCloseKey returned %i\n", r);
5744 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5745 return ret;
5748 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5749 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5750 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5751 pEnumValues += cbValueNameLen;
5753 /* return # of *bytes* (including trailing \0), not # of chars */
5754 ppev[dwIndex].cbValueName = cbValueNameLen;
5756 ppev[dwIndex].dwType = dwType;
5758 memcpy (pEnumValues, lpValue, cbValueLen);
5759 ppev[dwIndex].pData = pEnumValues;
5760 pEnumValues += cbValueLen;
5762 ppev[dwIndex].cbData = cbValueLen;
5764 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5765 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5768 if (HeapFree (hHeap, 0, lpValue) == 0)
5770 ret = GetLastError ();
5771 ERR ("HeapFree failed with code %i\n", ret);
5772 if (HeapFree (hHeap, 0, lpValueName) == 0)
5773 WARN ("HeapFree failed with code %i\n", GetLastError ());
5774 r = RegCloseKey (hkSubKey);
5775 if (r != ERROR_SUCCESS)
5776 WARN ("RegCloseKey returned %i\n", r);
5777 return ret;
5780 if (HeapFree (hHeap, 0, lpValueName) == 0)
5782 ret = GetLastError ();
5783 ERR ("HeapFree failed with code %i\n", ret);
5784 r = RegCloseKey (hkSubKey);
5785 if (r != ERROR_SUCCESS)
5786 WARN ("RegCloseKey returned %i\n", r);
5787 return ret;
5790 ret = RegCloseKey (hkSubKey);
5791 if (ret != ERROR_SUCCESS)
5793 ERR ("RegCloseKey returned %i\n", ret);
5794 return ret;
5797 return ERROR_SUCCESS;
5800 /*******************************************************************************
5801 * EnumPrinterDataExA [WINSPOOL.@]
5803 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5804 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5805 * what Windows 2000 SP1 does.
5808 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5809 LPBYTE pEnumValues, DWORD cbEnumValues,
5810 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5812 INT len;
5813 LPWSTR pKeyNameW;
5814 DWORD ret, dwIndex, dwBufSize;
5815 HANDLE hHeap;
5816 LPSTR pBuffer;
5818 TRACE ("%p %s\n", hPrinter, pKeyName);
5820 if (pKeyName == NULL || *pKeyName == 0)
5821 return ERROR_INVALID_PARAMETER;
5823 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5824 if (len == 0)
5826 ret = GetLastError ();
5827 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5828 return ret;
5831 hHeap = GetProcessHeap ();
5832 if (hHeap == NULL)
5834 ERR ("GetProcessHeap failed\n");
5835 return ERROR_OUTOFMEMORY;
5838 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5839 if (pKeyNameW == NULL)
5841 ERR ("Failed to allocate %i bytes from process heap\n",
5842 (LONG)(len * sizeof (WCHAR)));
5843 return ERROR_OUTOFMEMORY;
5846 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5848 ret = GetLastError ();
5849 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5850 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5851 WARN ("HeapFree failed with code %i\n", GetLastError ());
5852 return ret;
5855 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5856 pcbEnumValues, pnEnumValues);
5857 if (ret != ERROR_SUCCESS)
5859 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5860 WARN ("HeapFree failed with code %i\n", GetLastError ());
5861 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5862 return ret;
5865 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5867 ret = GetLastError ();
5868 ERR ("HeapFree failed with code %i\n", ret);
5869 return ret;
5872 if (*pnEnumValues == 0) /* empty key */
5873 return ERROR_SUCCESS;
5875 dwBufSize = 0;
5876 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5878 PPRINTER_ENUM_VALUESW ppev =
5879 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5881 if (dwBufSize < ppev->cbValueName)
5882 dwBufSize = ppev->cbValueName;
5884 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5885 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5886 dwBufSize = ppev->cbData;
5889 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5891 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5892 if (pBuffer == NULL)
5894 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5895 return ERROR_OUTOFMEMORY;
5898 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5900 PPRINTER_ENUM_VALUESW ppev =
5901 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5903 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5904 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5905 NULL);
5906 if (len == 0)
5908 ret = GetLastError ();
5909 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5910 if (HeapFree (hHeap, 0, pBuffer) == 0)
5911 WARN ("HeapFree failed with code %i\n", GetLastError ());
5912 return ret;
5915 memcpy (ppev->pValueName, pBuffer, len);
5917 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5919 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5920 ppev->dwType != REG_MULTI_SZ)
5921 continue;
5923 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5924 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5925 if (len == 0)
5927 ret = GetLastError ();
5928 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5929 if (HeapFree (hHeap, 0, pBuffer) == 0)
5930 WARN ("HeapFree failed with code %i\n", GetLastError ());
5931 return ret;
5934 memcpy (ppev->pData, pBuffer, len);
5936 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5937 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5940 if (HeapFree (hHeap, 0, pBuffer) == 0)
5942 ret = GetLastError ();
5943 ERR ("HeapFree failed with code %i\n", ret);
5944 return ret;
5947 return ERROR_SUCCESS;
5950 /******************************************************************************
5951 * AbortPrinter (WINSPOOL.@)
5953 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5955 FIXME("(%p), stub!\n", hPrinter);
5956 return TRUE;
5959 /******************************************************************************
5960 * AddPortA (WINSPOOL.@)
5962 * See AddPortW.
5965 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5967 LPWSTR nameW = NULL;
5968 LPWSTR monitorW = NULL;
5969 DWORD len;
5970 BOOL res;
5972 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
5974 if (pName) {
5975 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5976 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5977 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5980 if (pMonitorName) {
5981 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
5982 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5983 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
5985 res = AddPortW(nameW, hWnd, monitorW);
5986 HeapFree(GetProcessHeap(), 0, nameW);
5987 HeapFree(GetProcessHeap(), 0, monitorW);
5988 return res;
5991 /******************************************************************************
5992 * AddPortW (WINSPOOL.@)
5994 * Add a Port for a specific Monitor
5996 * PARAMS
5997 * pName [I] Servername or NULL (local Computer)
5998 * hWnd [I] Handle to parent Window for the Dialog-Box
5999 * pMonitorName [I] Name of the Monitor that manage the Port
6001 * RETURNS
6002 * Success: TRUE
6003 * Failure: FALSE
6006 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6008 monitor_t * pm;
6009 monitor_t * pui;
6010 DWORD res;
6012 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6014 if (pName && pName[0]) {
6015 SetLastError(ERROR_INVALID_PARAMETER);
6016 return FALSE;
6019 if (!pMonitorName) {
6020 SetLastError(RPC_X_NULL_REF_POINTER);
6021 return FALSE;
6024 /* an empty Monitorname is Invalid */
6025 if (!pMonitorName[0]) {
6026 SetLastError(ERROR_NOT_SUPPORTED);
6027 return FALSE;
6030 pm = monitor_load(pMonitorName, NULL);
6031 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6032 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6033 TRACE("got %d with %u\n", res, GetLastError());
6034 res = TRUE;
6036 else
6038 pui = monitor_loadui(pm);
6039 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6040 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6041 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6042 TRACE("got %d with %u\n", res, GetLastError());
6043 res = TRUE;
6045 else
6047 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6048 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6050 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6051 SetLastError(ERROR_NOT_SUPPORTED);
6052 res = FALSE;
6054 monitor_unload(pui);
6056 /* invalidate cached PORT_INFO_2W */
6057 monitor_flush(pm);
6059 monitor_unload(pm);
6060 TRACE("returning %d with %u\n", res, GetLastError());
6061 return res;
6064 /******************************************************************************
6065 * AddPortExA (WINSPOOL.@)
6067 * See AddPortExW.
6070 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
6072 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
6073 lpBuffer, debugstr_a(lpMonitorName));
6074 return FALSE;
6077 /******************************************************************************
6078 * AddPortExW (WINSPOOL.@)
6080 * Add a Port for a specific Monitor, without presenting a user interface
6082 * PARAMS
6083 * hMonitor [I] Handle from InitializePrintMonitor2()
6084 * pName [I] Servername or NULL (local Computer)
6085 * Level [I] Structure-Level (1 or 2) for lpBuffer
6086 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6087 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
6089 * RETURNS
6090 * Success: TRUE
6091 * Failure: FALSE
6093 * BUGS
6094 * only a Stub
6097 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
6099 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
6100 lpBuffer, debugstr_w(lpMonitorName));
6101 return FALSE;
6104 /******************************************************************************
6105 * AddPrinterConnectionA (WINSPOOL.@)
6107 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6109 FIXME("%s\n", debugstr_a(pName));
6110 return FALSE;
6113 /******************************************************************************
6114 * AddPrinterConnectionW (WINSPOOL.@)
6116 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6118 FIXME("%s\n", debugstr_w(pName));
6119 return FALSE;
6122 /******************************************************************************
6123 * AddPrinterDriverExW (WINSPOOL.@)
6125 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6126 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6128 FIXME("%s %d %p %d\n", debugstr_w(pName),
6129 Level, pDriverInfo, dwFileCopyFlags);
6130 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6131 return FALSE;
6134 /******************************************************************************
6135 * AddPrinterDriverExA (WINSPOOL.@)
6137 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6138 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6140 FIXME("%s %d %p %d\n", debugstr_a(pName),
6141 Level, pDriverInfo, dwFileCopyFlags);
6142 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6143 return FALSE;
6146 /******************************************************************************
6147 * ConfigurePortA (WINSPOOL.@)
6149 * See ConfigurePortW.
6152 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6154 LPWSTR nameW = NULL;
6155 LPWSTR portW = NULL;
6156 INT len;
6157 DWORD res;
6159 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6161 /* convert servername to unicode */
6162 if (pName) {
6163 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6164 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6165 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6168 /* convert portname to unicode */
6169 if (pPortName) {
6170 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6171 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6172 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6175 res = ConfigurePortW(nameW, hWnd, portW);
6176 HeapFree(GetProcessHeap(), 0, nameW);
6177 HeapFree(GetProcessHeap(), 0, portW);
6178 return res;
6181 /******************************************************************************
6182 * ConfigurePortW (WINSPOOL.@)
6184 * Display the Configuration-Dialog for a specific Port
6186 * PARAMS
6187 * pName [I] Servername or NULL (local Computer)
6188 * hWnd [I] Handle to parent Window for the Dialog-Box
6189 * pPortName [I] Name of the Port, that should be configured
6191 * RETURNS
6192 * Success: TRUE
6193 * Failure: FALSE
6196 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6198 monitor_t * pm;
6199 monitor_t * pui;
6200 DWORD res;
6202 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6204 if (pName && pName[0]) {
6205 SetLastError(ERROR_INVALID_PARAMETER);
6206 return FALSE;
6209 if (!pPortName) {
6210 SetLastError(RPC_X_NULL_REF_POINTER);
6211 return FALSE;
6214 /* an empty Portname is Invalid, but can popup a Dialog */
6215 if (!pPortName[0]) {
6216 SetLastError(ERROR_NOT_SUPPORTED);
6217 return FALSE;
6220 pm = monitor_load_by_port(pPortName);
6221 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6222 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6223 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6224 TRACE("got %d with %u\n", res, GetLastError());
6226 else
6228 pui = monitor_loadui(pm);
6229 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6230 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6231 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6232 TRACE("got %d with %u\n", res, GetLastError());
6234 else
6236 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6237 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6239 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6240 SetLastError(ERROR_NOT_SUPPORTED);
6241 res = FALSE;
6243 monitor_unload(pui);
6245 monitor_unload(pm);
6247 TRACE("returning %d with %u\n", res, GetLastError());
6248 return res;
6251 /******************************************************************************
6252 * ConnectToPrinterDlg (WINSPOOL.@)
6254 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6256 FIXME("%p %x\n", hWnd, Flags);
6257 return NULL;
6260 /******************************************************************************
6261 * DeletePrinterConnectionA (WINSPOOL.@)
6263 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6265 FIXME("%s\n", debugstr_a(pName));
6266 return TRUE;
6269 /******************************************************************************
6270 * DeletePrinterConnectionW (WINSPOOL.@)
6272 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6274 FIXME("%s\n", debugstr_w(pName));
6275 return TRUE;
6278 /******************************************************************************
6279 * DeletePrinterDriverExW (WINSPOOL.@)
6281 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6282 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6284 HKEY hkey_drivers;
6285 BOOL ret = FALSE;
6287 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6288 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6290 if(pName && pName[0])
6292 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6293 SetLastError(ERROR_INVALID_PARAMETER);
6294 return FALSE;
6297 if(dwDeleteFlag)
6299 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6300 SetLastError(ERROR_INVALID_PARAMETER);
6301 return FALSE;
6304 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6306 if(!hkey_drivers)
6308 ERR("Can't open drivers key\n");
6309 return FALSE;
6312 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6313 ret = TRUE;
6315 RegCloseKey(hkey_drivers);
6317 return ret;
6320 /******************************************************************************
6321 * DeletePrinterDriverExA (WINSPOOL.@)
6323 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6324 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6326 UNICODE_STRING NameW, EnvW, DriverW;
6327 BOOL ret;
6329 asciitounicode(&NameW, pName);
6330 asciitounicode(&EnvW, pEnvironment);
6331 asciitounicode(&DriverW, pDriverName);
6333 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6335 RtlFreeUnicodeString(&DriverW);
6336 RtlFreeUnicodeString(&EnvW);
6337 RtlFreeUnicodeString(&NameW);
6339 return ret;
6342 /******************************************************************************
6343 * DeletePrinterDataExW (WINSPOOL.@)
6345 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6346 LPCWSTR pValueName)
6348 FIXME("%p %s %s\n", hPrinter,
6349 debugstr_w(pKeyName), debugstr_w(pValueName));
6350 return ERROR_INVALID_PARAMETER;
6353 /******************************************************************************
6354 * DeletePrinterDataExA (WINSPOOL.@)
6356 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6357 LPCSTR pValueName)
6359 FIXME("%p %s %s\n", hPrinter,
6360 debugstr_a(pKeyName), debugstr_a(pValueName));
6361 return ERROR_INVALID_PARAMETER;
6364 /******************************************************************************
6365 * DeletePrintProcessorA (WINSPOOL.@)
6367 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6369 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6370 debugstr_a(pPrintProcessorName));
6371 return TRUE;
6374 /******************************************************************************
6375 * DeletePrintProcessorW (WINSPOOL.@)
6377 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6379 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6380 debugstr_w(pPrintProcessorName));
6381 return TRUE;
6384 /******************************************************************************
6385 * DeletePrintProvidorA (WINSPOOL.@)
6387 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6389 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6390 debugstr_a(pPrintProviderName));
6391 return TRUE;
6394 /******************************************************************************
6395 * DeletePrintProvidorW (WINSPOOL.@)
6397 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6399 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6400 debugstr_w(pPrintProviderName));
6401 return TRUE;
6404 /******************************************************************************
6405 * EnumFormsA (WINSPOOL.@)
6407 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6408 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6410 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6411 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6412 return FALSE;
6415 /******************************************************************************
6416 * EnumFormsW (WINSPOOL.@)
6418 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6419 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6421 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6422 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6423 return FALSE;
6426 /*****************************************************************************
6427 * EnumMonitorsA [WINSPOOL.@]
6429 * See EnumMonitorsW.
6432 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6433 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6435 BOOL res;
6436 LPBYTE bufferW = NULL;
6437 LPWSTR nameW = NULL;
6438 DWORD needed = 0;
6439 DWORD numentries = 0;
6440 INT len;
6442 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6443 cbBuf, pcbNeeded, pcReturned);
6445 /* convert servername to unicode */
6446 if (pName) {
6447 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6448 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6449 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6451 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6452 needed = cbBuf * sizeof(WCHAR);
6453 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6454 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6456 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6457 if (pcbNeeded) needed = *pcbNeeded;
6458 /* HeapReAlloc return NULL, when bufferW was NULL */
6459 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6460 HeapAlloc(GetProcessHeap(), 0, needed);
6462 /* Try again with the large Buffer */
6463 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6465 numentries = pcReturned ? *pcReturned : 0;
6466 needed = 0;
6468 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6469 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6471 if (res) {
6472 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
6473 DWORD entrysize = 0;
6474 DWORD index;
6475 LPSTR ptr;
6476 LPMONITOR_INFO_2W mi2w;
6477 LPMONITOR_INFO_2A mi2a;
6479 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6480 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6482 /* First pass: calculate the size for all Entries */
6483 mi2w = (LPMONITOR_INFO_2W) bufferW;
6484 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6485 index = 0;
6486 while (index < numentries) {
6487 index++;
6488 needed += entrysize; /* MONITOR_INFO_?A */
6489 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6491 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6492 NULL, 0, NULL, NULL);
6493 if (Level > 1) {
6494 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6495 NULL, 0, NULL, NULL);
6496 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6497 NULL, 0, NULL, NULL);
6499 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6500 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6501 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6504 /* check for errors and quit on failure */
6505 if (cbBuf < needed) {
6506 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6507 res = FALSE;
6508 goto emA_cleanup;
6510 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6511 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6512 cbBuf -= len ; /* free Bytes in the user-Buffer */
6513 mi2w = (LPMONITOR_INFO_2W) bufferW;
6514 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6515 index = 0;
6516 /* Second Pass: Fill the User Buffer (if we have one) */
6517 while ((index < numentries) && pMonitors) {
6518 index++;
6519 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6520 mi2a->pName = ptr;
6521 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6522 ptr, cbBuf , NULL, NULL);
6523 ptr += len;
6524 cbBuf -= len;
6525 if (Level > 1) {
6526 mi2a->pEnvironment = ptr;
6527 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6528 ptr, cbBuf, NULL, NULL);
6529 ptr += len;
6530 cbBuf -= len;
6532 mi2a->pDLLName = ptr;
6533 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6534 ptr, cbBuf, NULL, NULL);
6535 ptr += len;
6536 cbBuf -= len;
6538 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6539 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6540 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6543 emA_cleanup:
6544 if (pcbNeeded) *pcbNeeded = needed;
6545 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6547 HeapFree(GetProcessHeap(), 0, nameW);
6548 HeapFree(GetProcessHeap(), 0, bufferW);
6550 TRACE("returning %d with %d (%d byte for %d entries)\n",
6551 (res), GetLastError(), needed, numentries);
6553 return (res);
6557 /*****************************************************************************
6558 * EnumMonitorsW [WINSPOOL.@]
6560 * Enumerate available Port-Monitors
6562 * PARAMS
6563 * pName [I] Servername or NULL (local Computer)
6564 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6565 * pMonitors [O] PTR to Buffer that receives the Result
6566 * cbBuf [I] Size of Buffer at pMonitors
6567 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6568 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6570 * RETURNS
6571 * Success: TRUE
6572 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6574 * NOTES
6575 * Windows reads the Registry once and cache the Results.
6577 *| Language-Monitors are also installed in the same Registry-Location but
6578 *| they are filtered in Windows (not returned by EnumMonitors).
6579 *| We do no filtering to simplify our Code.
6582 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6583 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6585 DWORD needed = 0;
6586 DWORD numentries = 0;
6587 BOOL res = FALSE;
6589 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6590 cbBuf, pcbNeeded, pcReturned);
6592 if (pName && (lstrlenW(pName))) {
6593 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6594 SetLastError(ERROR_ACCESS_DENIED);
6595 goto emW_cleanup;
6598 /* Level is not checked in win9x */
6599 if (!Level || (Level > 2)) {
6600 WARN("level (%d) is ignored in win9x\n", Level);
6601 SetLastError(ERROR_INVALID_LEVEL);
6602 goto emW_cleanup;
6604 if (!pcbNeeded) {
6605 SetLastError(RPC_X_NULL_REF_POINTER);
6606 goto emW_cleanup;
6609 /* Scan all Monitor-Keys */
6610 numentries = 0;
6611 needed = get_local_monitors(Level, NULL, 0, &numentries);
6613 /* we calculated the needed buffersize. now do the error-checks */
6614 if (cbBuf < needed) {
6615 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6616 goto emW_cleanup;
6618 else if (!pMonitors || !pcReturned) {
6619 SetLastError(RPC_X_NULL_REF_POINTER);
6620 goto emW_cleanup;
6623 /* fill the Buffer with the Monitor-Keys */
6624 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6625 res = TRUE;
6627 emW_cleanup:
6628 if (pcbNeeded) *pcbNeeded = needed;
6629 if (pcReturned) *pcReturned = numentries;
6631 TRACE("returning %d with %d (%d byte for %d entries)\n",
6632 res, GetLastError(), needed, numentries);
6634 return (res);
6637 /******************************************************************************
6638 * XcvDataW (WINSPOOL.@)
6640 * Execute commands in the Printmonitor DLL
6642 * PARAMS
6643 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6644 * pszDataName [i] Name of the command to execute
6645 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6646 * cbInputData [i] Size in Bytes of Buffer at pInputData
6647 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6648 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6649 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6650 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6652 * RETURNS
6653 * Success: TRUE
6654 * Failure: FALSE
6656 * NOTES
6657 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6658 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6660 * Minimal List of commands, that a Printmonitor DLL should support:
6662 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6663 *| "AddPort" : Add a Port
6664 *| "DeletePort": Delete a Port
6666 * Many Printmonitors support additional commands. Examples for localspl.dll:
6667 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6668 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6671 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6672 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6673 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6675 opened_printer_t *printer;
6677 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6678 pInputData, cbInputData, pOutputData,
6679 cbOutputData, pcbOutputNeeded, pdwStatus);
6681 printer = get_opened_printer(hXcv);
6682 if (!printer || (!printer->hXcv)) {
6683 SetLastError(ERROR_INVALID_HANDLE);
6684 return FALSE;
6687 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6688 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6690 return TRUE;
6693 /*****************************************************************************
6694 * EnumPrinterDataA [WINSPOOL.@]
6697 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6698 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6699 DWORD cbData, LPDWORD pcbData )
6701 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6702 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6703 return ERROR_NO_MORE_ITEMS;
6706 /*****************************************************************************
6707 * EnumPrinterDataW [WINSPOOL.@]
6710 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6711 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6712 DWORD cbData, LPDWORD pcbData )
6714 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6715 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6716 return ERROR_NO_MORE_ITEMS;
6719 /*****************************************************************************
6720 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6723 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6724 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6725 LPDWORD pcbNeeded, LPDWORD pcReturned)
6727 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6728 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6729 pcbNeeded, pcReturned);
6730 return FALSE;
6733 /*****************************************************************************
6734 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6737 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6738 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6739 LPDWORD pcbNeeded, LPDWORD pcReturned)
6741 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6742 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6743 pcbNeeded, pcReturned);
6744 return FALSE;
6747 /*****************************************************************************
6748 * EnumPrintProcessorsA [WINSPOOL.@]
6751 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6752 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6754 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6755 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6756 return FALSE;
6759 /*****************************************************************************
6760 * EnumPrintProcessorsW [WINSPOOL.@]
6763 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6764 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6766 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6767 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6768 cbBuf, pcbNeeded, pcbReturned);
6769 return FALSE;
6772 /*****************************************************************************
6773 * ExtDeviceMode [WINSPOOL.@]
6776 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6777 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6778 DWORD fMode)
6780 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6781 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6782 debugstr_a(pProfile), fMode);
6783 return -1;
6786 /*****************************************************************************
6787 * FindClosePrinterChangeNotification [WINSPOOL.@]
6790 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6792 FIXME("Stub: %p\n", hChange);
6793 return TRUE;
6796 /*****************************************************************************
6797 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6800 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6801 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6803 FIXME("Stub: %p %x %x %p\n",
6804 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6805 return INVALID_HANDLE_VALUE;
6808 /*****************************************************************************
6809 * FindNextPrinterChangeNotification [WINSPOOL.@]
6812 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6813 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6815 FIXME("Stub: %p %p %p %p\n",
6816 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6817 return FALSE;
6820 /*****************************************************************************
6821 * FreePrinterNotifyInfo [WINSPOOL.@]
6824 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6826 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6827 return TRUE;
6830 /*****************************************************************************
6831 * string_to_buf
6833 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6834 * ansi depending on the unicode parameter.
6836 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6838 if(!str)
6840 *size = 0;
6841 return TRUE;
6844 if(unicode)
6846 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6847 if(*size <= cb)
6849 memcpy(ptr, str, *size);
6850 return TRUE;
6852 return FALSE;
6854 else
6856 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6857 if(*size <= cb)
6859 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6860 return TRUE;
6862 return FALSE;
6866 /*****************************************************************************
6867 * get_job_info_1
6869 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6870 LPDWORD pcbNeeded, BOOL unicode)
6872 DWORD size, left = cbBuf;
6873 BOOL space = (cbBuf > 0);
6874 LPBYTE ptr = buf;
6876 *pcbNeeded = 0;
6878 if(space)
6880 ji1->JobId = job->job_id;
6883 string_to_buf(job->document_title, ptr, left, &size, unicode);
6884 if(space && size <= left)
6886 ji1->pDocument = (LPWSTR)ptr;
6887 ptr += size;
6888 left -= size;
6890 else
6891 space = FALSE;
6892 *pcbNeeded += size;
6894 return space;
6897 /*****************************************************************************
6898 * get_job_info_2
6900 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6901 LPDWORD pcbNeeded, BOOL unicode)
6903 DWORD size, left = cbBuf;
6904 BOOL space = (cbBuf > 0);
6905 LPBYTE ptr = buf;
6907 *pcbNeeded = 0;
6909 if(space)
6911 ji2->JobId = job->job_id;
6914 string_to_buf(job->document_title, ptr, left, &size, unicode);
6915 if(space && size <= left)
6917 ji2->pDocument = (LPWSTR)ptr;
6918 ptr += size;
6919 left -= size;
6921 else
6922 space = FALSE;
6923 *pcbNeeded += size;
6925 return space;
6928 /*****************************************************************************
6929 * get_job_info
6931 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6932 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6934 BOOL ret = FALSE;
6935 DWORD needed = 0, size;
6936 job_t *job;
6937 LPBYTE ptr = pJob;
6939 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6941 EnterCriticalSection(&printer_handles_cs);
6942 job = get_job(hPrinter, JobId);
6943 if(!job)
6944 goto end;
6946 switch(Level)
6948 case 1:
6949 size = sizeof(JOB_INFO_1W);
6950 if(cbBuf >= size)
6952 cbBuf -= size;
6953 ptr += size;
6954 memset(pJob, 0, size);
6956 else
6957 cbBuf = 0;
6958 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6959 needed += size;
6960 break;
6962 case 2:
6963 size = sizeof(JOB_INFO_2W);
6964 if(cbBuf >= size)
6966 cbBuf -= size;
6967 ptr += size;
6968 memset(pJob, 0, size);
6970 else
6971 cbBuf = 0;
6972 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
6973 needed += size;
6974 break;
6976 case 3:
6977 size = sizeof(JOB_INFO_3);
6978 if(cbBuf >= size)
6980 cbBuf -= size;
6981 memset(pJob, 0, size);
6982 ret = TRUE;
6984 else
6985 cbBuf = 0;
6986 needed = size;
6987 break;
6989 default:
6990 SetLastError(ERROR_INVALID_LEVEL);
6991 goto end;
6993 if(pcbNeeded)
6994 *pcbNeeded = needed;
6995 end:
6996 LeaveCriticalSection(&printer_handles_cs);
6997 return ret;
7000 /*****************************************************************************
7001 * GetJobA [WINSPOOL.@]
7004 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7005 DWORD cbBuf, LPDWORD pcbNeeded)
7007 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7010 /*****************************************************************************
7011 * GetJobW [WINSPOOL.@]
7014 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7015 DWORD cbBuf, LPDWORD pcbNeeded)
7017 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7020 /*****************************************************************************
7021 * schedule_lpr
7023 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7025 char *unixname, *queue, *cmd;
7026 char fmt[] = "lpr -P%s %s";
7027 DWORD len;
7029 if(!(unixname = wine_get_unix_file_name(filename)))
7030 return FALSE;
7032 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7033 queue = HeapAlloc(GetProcessHeap(), 0, len);
7034 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7036 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7037 sprintf(cmd, fmt, queue, unixname);
7039 TRACE("printing with: %s\n", cmd);
7040 system(cmd);
7042 HeapFree(GetProcessHeap(), 0, cmd);
7043 HeapFree(GetProcessHeap(), 0, queue);
7044 HeapFree(GetProcessHeap(), 0, unixname);
7045 return TRUE;
7048 /*****************************************************************************
7049 * schedule_cups
7051 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7053 #if HAVE_CUPS_CUPS_H
7054 if(pcupsPrintFile)
7056 char *unixname, *queue, *doc_titleA;
7057 DWORD len;
7058 BOOL ret;
7060 if(!(unixname = wine_get_unix_file_name(filename)))
7061 return FALSE;
7063 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7064 queue = HeapAlloc(GetProcessHeap(), 0, len);
7065 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7067 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7068 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7069 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7071 TRACE("printing via cups\n");
7072 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7073 HeapFree(GetProcessHeap(), 0, doc_titleA);
7074 HeapFree(GetProcessHeap(), 0, queue);
7075 HeapFree(GetProcessHeap(), 0, unixname);
7076 return ret;
7078 else
7079 #endif
7081 return schedule_lpr(printer_name, filename);
7085 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7087 LPWSTR filename;
7089 switch(msg)
7091 case WM_INITDIALOG:
7092 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7093 return TRUE;
7095 case WM_COMMAND:
7096 if(HIWORD(wparam) == BN_CLICKED)
7098 if(LOWORD(wparam) == IDOK)
7100 HANDLE hf;
7101 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7102 LPWSTR *output;
7104 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7105 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7107 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7109 WCHAR caption[200], message[200];
7110 int mb_ret;
7112 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7113 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7114 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7115 if(mb_ret == IDCANCEL)
7117 HeapFree(GetProcessHeap(), 0, filename);
7118 return TRUE;
7121 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7122 if(hf == INVALID_HANDLE_VALUE)
7124 WCHAR caption[200], message[200];
7126 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7127 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7128 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7129 HeapFree(GetProcessHeap(), 0, filename);
7130 return TRUE;
7132 CloseHandle(hf);
7133 DeleteFileW(filename);
7134 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7135 *output = filename;
7136 EndDialog(hwnd, IDOK);
7137 return TRUE;
7139 if(LOWORD(wparam) == IDCANCEL)
7141 EndDialog(hwnd, IDCANCEL);
7142 return TRUE;
7145 return FALSE;
7147 return FALSE;
7150 /*****************************************************************************
7151 * get_filename
7153 static BOOL get_filename(LPWSTR *filename)
7155 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7156 file_dlg_proc, (LPARAM)filename) == IDOK;
7159 /*****************************************************************************
7160 * schedule_file
7162 static BOOL schedule_file(LPCWSTR filename)
7164 LPWSTR output = NULL;
7166 if(get_filename(&output))
7168 TRACE("copy to %s\n", debugstr_w(output));
7169 CopyFileW(filename, output, FALSE);
7170 HeapFree(GetProcessHeap(), 0, output);
7171 return TRUE;
7173 return FALSE;
7176 /*****************************************************************************
7177 * schedule_pipe
7179 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7181 #ifdef HAVE_FORK
7182 char *unixname, *cmdA;
7183 DWORD len;
7184 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7185 BOOL ret = FALSE;
7186 char buf[1024];
7188 if(!(unixname = wine_get_unix_file_name(filename)))
7189 return FALSE;
7191 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7192 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7193 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7195 TRACE("printing with: %s\n", cmdA);
7197 if((file_fd = open(unixname, O_RDONLY)) == -1)
7198 goto end;
7200 if (pipe(fds))
7202 ERR("pipe() failed!\n");
7203 goto end;
7206 if (fork() == 0)
7208 close(0);
7209 dup2(fds[0], 0);
7210 close(fds[1]);
7212 /* reset signals that we previously set to SIG_IGN */
7213 signal(SIGPIPE, SIG_DFL);
7214 signal(SIGCHLD, SIG_DFL);
7216 system(cmdA);
7217 exit(0);
7220 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7221 write(fds[1], buf, no_read);
7223 ret = TRUE;
7225 end:
7226 if(file_fd != -1) close(file_fd);
7227 if(fds[0] != -1) close(fds[0]);
7228 if(fds[1] != -1) close(fds[1]);
7230 HeapFree(GetProcessHeap(), 0, cmdA);
7231 HeapFree(GetProcessHeap(), 0, unixname);
7232 return ret;
7233 #else
7234 return FALSE;
7235 #endif
7238 /*****************************************************************************
7239 * schedule_unixfile
7241 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7243 int in_fd, out_fd, no_read;
7244 char buf[1024];
7245 BOOL ret = FALSE;
7246 char *unixname, *outputA;
7247 DWORD len;
7249 if(!(unixname = wine_get_unix_file_name(filename)))
7250 return FALSE;
7252 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7253 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7254 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7256 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7257 in_fd = open(unixname, O_RDONLY);
7258 if(out_fd == -1 || in_fd == -1)
7259 goto end;
7261 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7262 write(out_fd, buf, no_read);
7264 ret = TRUE;
7265 end:
7266 if(in_fd != -1) close(in_fd);
7267 if(out_fd != -1) close(out_fd);
7268 HeapFree(GetProcessHeap(), 0, outputA);
7269 HeapFree(GetProcessHeap(), 0, unixname);
7270 return ret;
7273 /*****************************************************************************
7274 * ScheduleJob [WINSPOOL.@]
7277 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7279 opened_printer_t *printer;
7280 BOOL ret = FALSE;
7281 struct list *cursor, *cursor2;
7283 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7284 EnterCriticalSection(&printer_handles_cs);
7285 printer = get_opened_printer(hPrinter);
7286 if(!printer)
7287 goto end;
7289 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7291 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7292 HANDLE hf;
7294 if(job->job_id != dwJobID) continue;
7296 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7297 if(hf != INVALID_HANDLE_VALUE)
7299 PRINTER_INFO_5W *pi5;
7300 DWORD needed;
7301 HKEY hkey;
7302 WCHAR output[1024];
7303 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7304 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7306 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7307 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7308 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7309 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7310 debugstr_w(pi5->pPortName));
7312 output[0] = 0;
7314 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7315 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7317 DWORD type, count = sizeof(output);
7318 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7319 RegCloseKey(hkey);
7321 if(output[0] == '|')
7323 schedule_pipe(output + 1, job->filename);
7325 else if(output[0])
7327 schedule_unixfile(output, job->filename);
7329 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7331 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7333 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7335 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7337 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7339 schedule_file(job->filename);
7341 else
7343 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7345 HeapFree(GetProcessHeap(), 0, pi5);
7346 CloseHandle(hf);
7347 DeleteFileW(job->filename);
7349 list_remove(cursor);
7350 HeapFree(GetProcessHeap(), 0, job->document_title);
7351 HeapFree(GetProcessHeap(), 0, job->filename);
7352 HeapFree(GetProcessHeap(), 0, job);
7353 ret = TRUE;
7354 break;
7356 end:
7357 LeaveCriticalSection(&printer_handles_cs);
7358 return ret;
7361 /*****************************************************************************
7362 * StartDocDlgA [WINSPOOL.@]
7364 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7366 UNICODE_STRING usBuffer;
7367 DOCINFOW docW;
7368 LPWSTR retW;
7369 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7370 LPSTR ret = NULL;
7372 docW.cbSize = sizeof(docW);
7373 if (doc->lpszDocName)
7375 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7376 if (!(docW.lpszDocName = docnameW)) return NULL;
7378 if (doc->lpszOutput)
7380 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7381 if (!(docW.lpszOutput = outputW)) return NULL;
7383 if (doc->lpszDatatype)
7385 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7386 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7388 docW.fwType = doc->fwType;
7390 retW = StartDocDlgW(hPrinter, &docW);
7392 if(retW)
7394 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7395 ret = HeapAlloc(GetProcessHeap(), 0, len);
7396 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7397 HeapFree(GetProcessHeap(), 0, retW);
7400 HeapFree(GetProcessHeap(), 0, datatypeW);
7401 HeapFree(GetProcessHeap(), 0, outputW);
7402 HeapFree(GetProcessHeap(), 0, docnameW);
7404 return ret;
7407 /*****************************************************************************
7408 * StartDocDlgW [WINSPOOL.@]
7410 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7411 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7412 * port is "FILE:". Also returns the full path if passed a relative path.
7414 * The caller should free the returned string from the process heap.
7416 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7418 LPWSTR ret = NULL;
7419 DWORD len, attr;
7421 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7423 PRINTER_INFO_5W *pi5;
7424 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7425 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7426 return NULL;
7427 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7428 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7429 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7431 HeapFree(GetProcessHeap(), 0, pi5);
7432 return NULL;
7434 HeapFree(GetProcessHeap(), 0, pi5);
7437 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7439 LPWSTR name;
7441 if (get_filename(&name))
7443 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7445 HeapFree(GetProcessHeap(), 0, name);
7446 return NULL;
7448 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7449 GetFullPathNameW(name, len, ret, NULL);
7450 HeapFree(GetProcessHeap(), 0, name);
7452 return ret;
7455 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7456 return NULL;
7458 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7459 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7461 attr = GetFileAttributesW(ret);
7462 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7464 HeapFree(GetProcessHeap(), 0, ret);
7465 ret = NULL;
7467 return ret;