winspool: Implement AddMonitor.
[wine/multimedia.git] / dlls / winspool / info.c
blobc33072b052361210a12fc57fb3179fba3e27606c
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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "config.h"
26 #include "wine/port.h"
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stddef.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <signal.h>
38 #ifdef HAVE_CUPS_CUPS_H
39 # include <cups/cups.h>
40 # ifndef SONAME_LIBCUPS
41 # define SONAME_LIBCUPS "libcups.so"
42 # endif
43 #endif
45 #define NONAMELESSUNION
46 #define NONAMELESSSTRUCT
47 #include "wine/library.h"
48 #include "windef.h"
49 #include "winbase.h"
50 #include "winuser.h"
51 #include "winerror.h"
52 #include "winreg.h"
53 #include "wingdi.h"
54 #include "winspool.h"
55 #include "winternl.h"
56 #include "wine/windef16.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "wine/list.h"
60 #include "heap.h"
61 #include "winnls.h"
63 #include "wspool.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
67 static CRITICAL_SECTION printer_handles_cs;
68 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
70 0, 0, &printer_handles_cs,
71 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
74 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
76 typedef struct {
77 DWORD job_id;
78 HANDLE hf;
79 } started_doc_t;
81 typedef struct {
82 struct list jobs;
83 LONG ref;
84 } jobqueue_t;
86 typedef struct {
87 LPWSTR name;
88 jobqueue_t *queue;
89 started_doc_t *doc;
90 } opened_printer_t;
92 typedef struct {
93 struct list entry;
94 DWORD job_id;
95 WCHAR *filename;
96 WCHAR *document_title;
97 } job_t;
100 typedef struct {
101 LPCWSTR envname;
102 LPCWSTR subdir;
103 } printenv_t;
105 /* ############################### */
107 static opened_printer_t **printer_handles;
108 static int nb_printer_handles;
109 static LONG next_job_id = 1;
111 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
112 WORD fwCapability, LPSTR lpszOutput,
113 LPDEVMODEA lpdm );
114 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
115 LPSTR lpszDevice, LPSTR lpszPort,
116 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
117 DWORD fwMode );
119 static const char Printers[] =
120 "System\\CurrentControlSet\\control\\Print\\Printers\\";
122 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
123 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
124 'c','o','n','t','r','o','l','\\',
125 'P','r','i','n','t','\\',
126 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
127 '%','s','\\','D','r','i','v','e','r','s','\\',0 };
129 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
130 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'C','o','n','t','r','o','l','\\',
132 'P','r','i','n','t','\\',
133 'M','o','n','i','t','o','r','s',0};
135 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
137 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
138 'M','i','c','r','o','s','o','f','t','\\',
139 'W','i','n','d','o','w','s',' ','N','T','\\',
140 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
141 'W','i','n','d','o','w','s',0};
143 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'D','e','v','i','c','e','s',0};
149 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
150 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
151 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
152 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
153 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
155 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
157 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
158 'i','o','n',' ','F','i','l','e',0};
159 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
160 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
161 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
162 'M','o','d','e',0};
163 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
164 'i','l','e','s',0};
165 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
166 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
167 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
168 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
169 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
170 static const WCHAR NameW[] = {'N','a','m','e',0};
171 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
172 static const WCHAR PortW[] = {'P','o','r','t',0};
173 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
174 's','s','o','r',0};
175 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
176 'v','e','r',0};
177 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
178 'v','e','r','D','a','t','a',0};
179 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
180 'i','l','e',0};
181 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
182 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
183 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
184 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
185 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
186 static const WCHAR emptyStringW[] = {0};
188 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
190 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
191 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
192 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
194 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
195 'D','o','c','u','m','e','n','t',0};
197 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
198 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
199 DWORD Level, LPBYTE pDriverInfo,
200 DWORD cbBuf, LPDWORD pcbNeeded,
201 BOOL unicode);
202 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey);
204 /******************************************************************
205 * validate the user-supplied printing-environment [internal]
207 * PARAMS
208 * env [I] PTR to Environment-String or NULL
210 * RETURNS
211 * Failure: NULL
212 * Success: PTR to printenv_t
214 * NOTES
215 * An empty string is handled the same way as NULL.
216 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
220 static const printenv_t * validate_envW(LPCWSTR env)
222 static const printenv_t env_x86 = {envname_x86W, subdir_x86W};
223 static const printenv_t env_win40 = {envname_win40W, subdir_win40W};
224 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
226 const printenv_t *result = NULL;
227 unsigned int i;
229 TRACE("testing %s\n", debugstr_w(env));
230 if (env && env[0])
232 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
234 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
236 result = all_printenv[i];
237 break;
241 if (result == NULL) {
242 FIXME("unsupported Environment: %s\n", debugstr_w(env));
243 SetLastError(ERROR_INVALID_ENVIRONMENT);
245 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
247 else
249 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
251 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
253 return result;
257 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
258 if passed a NULL string. This returns NULLs to the result.
260 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
262 if ( (src) )
264 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
265 return usBufferPtr->Buffer;
267 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
268 return NULL;
271 static LPWSTR strdupW(LPCWSTR p)
273 LPWSTR ret;
274 DWORD len;
276 if(!p) return NULL;
277 len = (strlenW(p) + 1) * sizeof(WCHAR);
278 ret = HeapAlloc(GetProcessHeap(), 0, len);
279 memcpy(ret, p, len);
280 return ret;
283 static void
284 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name,BOOL force) {
285 char qbuf[200];
287 /* If forcing, or no profile string entry for device yet, set the entry
289 * The always change entry if not WINEPS yet is discussable.
291 if (force ||
292 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
293 !strcmp(qbuf,"*") ||
294 !strstr(qbuf,"WINEPS.DRV")
296 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
297 HKEY hkey;
299 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
300 WriteProfileStringA("windows","device",buf);
301 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
302 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
303 RegCloseKey(hkey);
305 HeapFree(GetProcessHeap(),0,buf);
309 #ifdef HAVE_CUPS_CUPS_H
310 static typeof(cupsGetDests) *pcupsGetDests;
311 static typeof(cupsGetPPD) *pcupsGetPPD;
312 static typeof(cupsPrintFile) *pcupsPrintFile;
313 static void *cupshandle;
315 static BOOL CUPS_LoadPrinters(void)
317 int i, nrofdests;
318 BOOL hadprinter = FALSE;
319 cups_dest_t *dests;
320 PRINTER_INFO_2A pinfo2a;
321 char *port,*devline;
322 HKEY hkeyPrinter, hkeyPrinters, hkey;
324 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
325 if (!cupshandle)
326 return FALSE;
327 TRACE("loaded %s\n", SONAME_LIBCUPS);
329 #define DYNCUPS(x) \
330 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
331 if (!p##x) return FALSE;
333 DYNCUPS(cupsGetPPD);
334 DYNCUPS(cupsGetDests);
335 DYNCUPS(cupsPrintFile);
336 #undef DYNCUPS
338 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
339 ERROR_SUCCESS) {
340 ERR("Can't create Printers key\n");
341 return FALSE;
344 nrofdests = pcupsGetDests(&dests);
345 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
346 for (i=0;i<nrofdests;i++) {
347 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
348 sprintf(port,"LPR:%s",dests[i].name);
349 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
350 sprintf(devline,"WINEPS.DRV,%s",port);
351 WriteProfileStringA("devices",dests[i].name,devline);
352 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
353 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
354 RegCloseKey(hkey);
356 HeapFree(GetProcessHeap(),0,devline);
358 TRACE("Printer %d: %s\n", i, dests[i].name);
359 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
360 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
361 and continue */
362 TRACE("Printer already exists\n");
363 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
364 RegCloseKey(hkeyPrinter);
365 } else {
366 memset(&pinfo2a,0,sizeof(pinfo2a));
367 pinfo2a.pPrinterName = dests[i].name;
368 pinfo2a.pDatatype = "RAW";
369 pinfo2a.pPrintProcessor = "WinPrint";
370 pinfo2a.pDriverName = "PS Driver";
371 pinfo2a.pComment = "WINEPS Printer using CUPS";
372 pinfo2a.pLocation = "<physical location of printer>";
373 pinfo2a.pPortName = port;
374 pinfo2a.pParameters = "<parameters?>";
375 pinfo2a.pShareName = "<share name?>";
376 pinfo2a.pSepFile = "<sep file?>";
378 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
379 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
380 ERR("printer '%s' not added by AddPrinterA (error %ld)\n",dests[i].name,GetLastError());
383 HeapFree(GetProcessHeap(),0,port);
385 hadprinter = TRUE;
386 if (dests[i].is_default)
387 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
389 RegCloseKey(hkeyPrinters);
390 return hadprinter;
392 #endif
394 static BOOL
395 PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
396 PRINTER_INFO_2A pinfo2a;
397 char *e,*s,*name,*prettyname,*devname;
398 BOOL ret = FALSE, set_default = FALSE;
399 char *port,*devline,*env_default;
400 HKEY hkeyPrinter, hkeyPrinters, hkey;
402 while (isspace(*pent)) pent++;
403 s = strchr(pent,':');
404 if(s) *s='\0';
405 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
406 strcpy(name,pent);
407 if(s) {
408 *s=':';
409 pent = s;
410 } else
411 pent = "";
413 TRACE("name=%s entry=%s\n",name, pent);
415 if(ispunct(*name)) { /* a tc entry, not a real printer */
416 TRACE("skipping tc entry\n");
417 goto end;
420 if(strstr(pent,":server")) { /* server only version so skip */
421 TRACE("skipping server entry\n");
422 goto end;
425 /* Determine whether this is a postscript printer. */
427 ret = TRUE;
428 env_default = getenv("PRINTER");
429 prettyname = name;
430 /* Get longest name, usually the one at the right for later display. */
431 while((s=strchr(prettyname,'|'))) {
432 *s = '\0';
433 e = s;
434 while(isspace(*--e)) *e = '\0';
435 TRACE("\t%s\n", debugstr_a(prettyname));
436 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
437 for(prettyname = s+1; isspace(*prettyname); prettyname++)
440 e = prettyname + strlen(prettyname);
441 while(isspace(*--e)) *e = '\0';
442 TRACE("\t%s\n", debugstr_a(prettyname));
443 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
445 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
446 * if it is too long, we use it as comment below. */
447 devname = prettyname;
448 if (strlen(devname)>=CCHDEVICENAME-1)
449 devname = name;
450 if (strlen(devname)>=CCHDEVICENAME-1) {
451 ret = FALSE;
452 goto end;
455 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
456 sprintf(port,"LPR:%s",name);
458 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
459 sprintf(devline,"WINEPS.DRV,%s",port);
460 WriteProfileStringA("devices",devname,devline);
461 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
462 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
463 RegCloseKey(hkey);
465 HeapFree(GetProcessHeap(),0,devline);
467 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
468 ERROR_SUCCESS) {
469 ERR("Can't create Printers key\n");
470 ret = FALSE;
471 goto end;
473 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
474 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
475 and continue */
476 TRACE("Printer already exists\n");
477 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
478 RegCloseKey(hkeyPrinter);
479 } else {
480 memset(&pinfo2a,0,sizeof(pinfo2a));
481 pinfo2a.pPrinterName = devname;
482 pinfo2a.pDatatype = "RAW";
483 pinfo2a.pPrintProcessor = "WinPrint";
484 pinfo2a.pDriverName = "PS Driver";
485 pinfo2a.pComment = "WINEPS Printer using LPR";
486 pinfo2a.pLocation = prettyname;
487 pinfo2a.pPortName = port;
488 pinfo2a.pParameters = "<parameters?>";
489 pinfo2a.pShareName = "<share name?>";
490 pinfo2a.pSepFile = "<sep file?>";
492 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
493 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
494 ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
497 RegCloseKey(hkeyPrinters);
499 if (isfirst || set_default)
500 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
502 HeapFree(GetProcessHeap(), 0, port);
503 end:
504 HeapFree(GetProcessHeap(), 0, name);
505 return ret;
508 static BOOL
509 PRINTCAP_LoadPrinters(void) {
510 BOOL hadprinter = FALSE;
511 char buf[200];
512 FILE *f;
513 char *pent = NULL;
514 BOOL had_bash = FALSE;
516 f = fopen("/etc/printcap","r");
517 if (!f)
518 return FALSE;
520 while(fgets(buf,sizeof(buf),f)) {
521 char *start, *end;
523 end=strchr(buf,'\n');
524 if (end) *end='\0';
526 start = buf;
527 while(isspace(*start)) start++;
528 if(*start == '#' || *start == '\0')
529 continue;
531 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
532 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
533 HeapFree(GetProcessHeap(),0,pent);
534 pent = NULL;
537 if (end && *--end == '\\') {
538 *end = '\0';
539 had_bash = TRUE;
540 } else
541 had_bash = FALSE;
543 if (pent) {
544 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
545 strcat(pent,start);
546 } else {
547 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
548 strcpy(pent,start);
552 if(pent) {
553 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
554 HeapFree(GetProcessHeap(),0,pent);
556 fclose(f);
557 return hadprinter;
560 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
562 if (value)
563 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
564 lstrlenW(value) * sizeof(WCHAR));
565 else
566 return ERROR_FILE_NOT_FOUND;
569 void WINSPOOL_LoadSystemPrinters(void)
571 HKEY hkey, hkeyPrinters;
572 DRIVER_INFO_3A di3a;
573 HANDLE hprn;
574 DWORD needed, num, i;
575 WCHAR PrinterName[256];
576 BOOL done = FALSE;
578 di3a.cVersion = 0x400;
579 di3a.pName = "PS Driver";
580 di3a.pEnvironment = NULL; /* NULL means auto */
581 di3a.pDriverPath = "wineps16";
582 di3a.pDataFile = "<datafile?>";
583 di3a.pConfigFile = "wineps16";
584 di3a.pHelpFile = "<helpfile?>";
585 di3a.pDependentFiles = "<dependend files?>";
586 di3a.pMonitorName = "<monitor name?>";
587 di3a.pDefaultDataType = "RAW";
589 if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
590 ERR("Failed adding PS Driver (%ld)\n",GetLastError());
591 return;
594 /* This ensures that all printer entries have a valid Name value. If causes
595 problems later if they don't. If one is found to be missed we create one
596 and set it equal to the name of the key */
597 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
598 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
599 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
600 for(i = 0; i < num; i++) {
601 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
602 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
603 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
604 set_reg_szW(hkey, NameW, PrinterName);
606 RegCloseKey(hkey);
611 RegCloseKey(hkeyPrinters);
614 /* We want to avoid calling AddPrinter on printers as much as
615 possible, because on cups printers this will (eventually) lead
616 to a call to cupsGetPPD which takes forever, even with non-cups
617 printers AddPrinter takes a while. So we'll tag all printers that
618 were automatically added last time around, if they still exist
619 we'll leave them be otherwise we'll delete them. */
620 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
621 if(needed) {
622 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
623 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
624 for(i = 0; i < num; i++) {
625 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
626 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
627 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
628 DWORD dw = 1;
629 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
630 RegCloseKey(hkey);
632 ClosePrinter(hprn);
637 HeapFree(GetProcessHeap(), 0, pi);
641 #ifdef HAVE_CUPS_CUPS_H
642 done = CUPS_LoadPrinters();
643 #endif
645 if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
646 /* Check for [ppd] section in config file before parsing /etc/printcap */
647 /* @@ Wine registry key: HKCU\Software\Wine\Printing\PPD Files */
648 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\PPD Files",
649 &hkey) == ERROR_SUCCESS) {
650 RegCloseKey(hkey);
651 PRINTCAP_LoadPrinters();
655 /* Now enumerate the list again and delete any printers that a still tagged */
656 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
657 if(needed) {
658 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
659 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
660 for(i = 0; i < num; i++) {
661 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
662 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
663 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
664 DWORD dw, type, size = sizeof(dw);
665 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
666 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
667 DeletePrinter(hprn);
669 RegCloseKey(hkey);
671 ClosePrinter(hprn);
676 HeapFree(GetProcessHeap(), 0, pi);
679 return;
683 /*****************************************************************************
684 * enumerate the local monitors (INTERNAL)
686 * returns the needed size (in bytes) for pMonitors
687 * and *lpreturned is set to number of entries returned in pMonitors
690 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
692 HKEY hroot = NULL;
693 HKEY hentry = NULL;
694 LPWSTR ptr;
695 LPMONITOR_INFO_2W mi;
696 WCHAR buffer[MAX_PATH];
697 WCHAR dllname[MAX_PATH];
698 DWORD dllsize;
699 DWORD len;
700 DWORD index = 0;
701 DWORD needed = 0;
702 DWORD numentries;
703 DWORD entrysize;
705 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
707 numentries = *lpreturned; /* this is 0, when we scan the registry */
708 len = entrysize * numentries;
709 ptr = (LPWSTR) &pMonitors[len];
711 numentries = 0;
712 len = sizeof(buffer);
713 buffer[0] = '\0';
715 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
716 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
717 /* Scan all Monitor-Registry-Keys */
718 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
719 TRACE("Monitor_%ld: %s\n", numentries, debugstr_w(buffer));
720 dllsize = sizeof(dllname);
721 dllname[0] = '\0';
723 /* The Monitor must have a Driver-DLL */
724 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
725 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
726 /* We found a valid DLL for this Monitor. */
727 TRACE("using Driver: %s\n", debugstr_w(dllname));
729 RegCloseKey(hentry);
732 /* Windows returns only Port-Monitors here, but to simplify our code,
733 we do no filtering for Language-Monitors */
734 if (dllname[0]) {
735 numentries++;
736 needed += entrysize;
737 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
738 if (level > 1) {
739 /* we install and return only monitors for "Windows NT x86" */
740 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
741 needed += dllsize;
744 /* required size is calculated. Now fill the user-buffer */
745 if (pMonitors && (cbBuf >= needed)){
746 mi = (LPMONITOR_INFO_2W) pMonitors;
747 pMonitors += entrysize;
749 TRACE("%p: writing MONITOR_INFO_%ldW #%ld\n", mi, level, numentries);
750 mi->pName = ptr;
751 lstrcpyW(ptr, buffer); /* Name of the Monitor */
752 ptr += (len+1); /* len is lstrlenW(monitorname) */
753 if (level > 1) {
754 mi->pEnvironment = ptr;
755 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
756 ptr += (lstrlenW(envname_x86W)+1);
758 mi->pDLLName = ptr;
759 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
760 ptr += (dllsize / sizeof(WCHAR));
764 index++;
765 len = sizeof(buffer);
766 buffer[0] = '\0';
768 RegCloseKey(hroot);
770 *lpreturned = numentries;
771 TRACE("need %ld byte for %ld entries\n", needed, numentries);
772 return needed;
775 /******************************************************************
776 * get_opened_printer_entry
777 * Get the first place empty in the opened printer table
779 static HANDLE get_opened_printer_entry( LPCWSTR name )
781 UINT_PTR handle = nb_printer_handles, i;
782 jobqueue_t *queue = NULL;
783 opened_printer_t *printer;
785 EnterCriticalSection(&printer_handles_cs);
787 for (i = 0; i < nb_printer_handles; i++)
789 if (!printer_handles[i])
791 if(handle == nb_printer_handles)
792 handle = i;
794 else if(!queue && !strcmpW(name, printer_handles[i]->name))
795 queue = printer_handles[i]->queue;
798 if (handle >= nb_printer_handles)
800 opened_printer_t **new_array;
801 if (printer_handles)
802 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
803 (nb_printer_handles + 16) * sizeof(*new_array) );
804 else
805 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
806 (nb_printer_handles + 16) * sizeof(*new_array) );
808 if (!new_array)
810 handle = 0;
811 goto end;
813 printer_handles = new_array;
814 nb_printer_handles += 16;
817 if (!(printer = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer))))
819 handle = 0;
820 goto end;
823 printer->name = HeapAlloc(GetProcessHeap(), 0, (strlenW(name) + 1) * sizeof(WCHAR));
824 strcpyW(printer->name, name);
825 if(queue)
826 printer->queue = queue;
827 else
829 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
830 list_init(&printer->queue->jobs);
831 printer->queue->ref = 0;
833 InterlockedIncrement(&printer->queue->ref);
834 printer->doc = NULL;
836 printer_handles[handle] = printer;
837 handle++;
838 end:
839 LeaveCriticalSection(&printer_handles_cs);
841 return (HANDLE)handle;
844 /******************************************************************
845 * get_opened_printer
846 * Get the pointer to the opened printer referred by the handle
848 static opened_printer_t *get_opened_printer(HANDLE hprn)
850 UINT_PTR idx = (UINT_PTR)hprn;
851 opened_printer_t *ret = NULL;
853 EnterCriticalSection(&printer_handles_cs);
855 if ((idx <= 0) || (idx > nb_printer_handles))
856 goto end;
858 ret = printer_handles[idx - 1];
859 end:
860 LeaveCriticalSection(&printer_handles_cs);
861 return ret;
864 /******************************************************************
865 * get_opened_printer_name
866 * Get the pointer to the opened printer name referred by the handle
868 static LPCWSTR get_opened_printer_name(HANDLE hprn)
870 opened_printer_t *printer = get_opened_printer(hprn);
871 if(!printer) return NULL;
872 return printer->name;
875 /******************************************************************
876 * WINSPOOL_GetOpenedPrinterRegKey
879 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
881 LPCWSTR name = get_opened_printer_name(hPrinter);
882 DWORD ret;
883 HKEY hkeyPrinters;
885 if(!name) return ERROR_INVALID_HANDLE;
887 if((ret = RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters)) !=
888 ERROR_SUCCESS)
889 return ret;
891 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
893 ERR("Can't find opened printer %s in registry\n",
894 debugstr_w(name));
895 RegCloseKey(hkeyPrinters);
896 return ERROR_INVALID_PRINTER_NAME; /* ? */
898 RegCloseKey(hkeyPrinters);
899 return ERROR_SUCCESS;
902 /******************************************************************
903 * get_job
905 * Get the pointer to the specified job.
906 * Should hold the printer_handles_cs before calling.
908 static job_t *get_job(HANDLE hprn, DWORD JobId)
910 opened_printer_t *printer = get_opened_printer(hprn);
911 job_t *job;
913 if(!printer) return NULL;
914 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
916 if(job->job_id == JobId)
917 return job;
919 return NULL;
922 /***********************************************************
923 * DEVMODEcpyAtoW
925 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
927 BOOL Formname;
928 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
929 DWORD size;
931 Formname = (dmA->dmSize > off_formname);
932 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
933 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
934 dmW->dmDeviceName, CCHDEVICENAME);
935 if(!Formname) {
936 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
937 dmA->dmSize - CCHDEVICENAME);
938 } else {
939 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
940 off_formname - CCHDEVICENAME);
941 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
942 dmW->dmFormName, CCHFORMNAME);
943 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
944 (off_formname + CCHFORMNAME));
946 dmW->dmSize = size;
947 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
948 dmA->dmDriverExtra);
949 return dmW;
952 /***********************************************************
953 * DEVMODEdupWtoA
954 * Creates an ascii copy of supplied devmode on heap
956 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
958 LPDEVMODEA dmA;
959 DWORD size;
960 BOOL Formname;
961 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
963 if(!dmW) return NULL;
964 Formname = (dmW->dmSize > off_formname);
965 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
966 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
967 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
968 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
969 if(!Formname) {
970 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
971 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
972 } else {
973 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
974 off_formname - CCHDEVICENAME * sizeof(WCHAR));
975 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
976 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
977 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
978 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
980 dmA->dmSize = size;
981 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
982 dmW->dmDriverExtra);
983 return dmA;
986 /***********************************************************
987 * PRINTER_INFO_2AtoW
988 * Creates a unicode copy of PRINTER_INFO_2A on heap
990 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
992 LPPRINTER_INFO_2W piW;
993 UNICODE_STRING usBuffer;
995 if(!piA) return NULL;
996 piW = HeapAlloc(heap, 0, sizeof(*piW));
997 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
999 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1000 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1001 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1002 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1003 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1004 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1005 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1006 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1007 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1008 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1009 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1010 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1011 return piW;
1014 /***********************************************************
1015 * FREE_PRINTER_INFO_2W
1016 * Free PRINTER_INFO_2W and all strings
1018 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1020 if(!piW) return;
1022 HeapFree(heap,0,piW->pServerName);
1023 HeapFree(heap,0,piW->pPrinterName);
1024 HeapFree(heap,0,piW->pShareName);
1025 HeapFree(heap,0,piW->pPortName);
1026 HeapFree(heap,0,piW->pDriverName);
1027 HeapFree(heap,0,piW->pComment);
1028 HeapFree(heap,0,piW->pLocation);
1029 HeapFree(heap,0,piW->pDevMode);
1030 HeapFree(heap,0,piW->pSepFile);
1031 HeapFree(heap,0,piW->pPrintProcessor);
1032 HeapFree(heap,0,piW->pDatatype);
1033 HeapFree(heap,0,piW->pParameters);
1034 HeapFree(heap,0,piW);
1035 return;
1038 /******************************************************************
1039 * DeviceCapabilities [WINSPOOL.@]
1040 * DeviceCapabilitiesA [WINSPOOL.@]
1043 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1044 LPSTR pOutput, LPDEVMODEA lpdm)
1046 INT ret;
1048 if (!GDI_CallDeviceCapabilities16)
1050 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1051 (LPCSTR)104 );
1052 if (!GDI_CallDeviceCapabilities16) return -1;
1054 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1056 /* If DC_PAPERSIZE map POINT16s to POINTs */
1057 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1058 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1059 POINT *pt = (POINT *)pOutput;
1060 INT i;
1061 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1062 for(i = 0; i < ret; i++, pt++)
1064 pt->x = tmp[i].x;
1065 pt->y = tmp[i].y;
1067 HeapFree( GetProcessHeap(), 0, tmp );
1069 return ret;
1073 /*****************************************************************************
1074 * DeviceCapabilitiesW [WINSPOOL.@]
1076 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1079 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1080 WORD fwCapability, LPWSTR pOutput,
1081 const DEVMODEW *pDevMode)
1083 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1084 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
1085 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
1086 INT ret;
1088 if(pOutput && (fwCapability == DC_BINNAMES ||
1089 fwCapability == DC_FILEDEPENDENCIES ||
1090 fwCapability == DC_PAPERNAMES)) {
1091 /* These need A -> W translation */
1092 INT size = 0, i;
1093 LPSTR pOutputA;
1094 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1095 dmA);
1096 if(ret == -1)
1097 return ret;
1098 switch(fwCapability) {
1099 case DC_BINNAMES:
1100 size = 24;
1101 break;
1102 case DC_PAPERNAMES:
1103 case DC_FILEDEPENDENCIES:
1104 size = 64;
1105 break;
1107 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1108 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1109 dmA);
1110 for(i = 0; i < ret; i++)
1111 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1112 pOutput + (i * size), size);
1113 HeapFree(GetProcessHeap(), 0, pOutputA);
1114 } else {
1115 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1116 (LPSTR)pOutput, dmA);
1118 HeapFree(GetProcessHeap(),0,pPortA);
1119 HeapFree(GetProcessHeap(),0,pDeviceA);
1120 HeapFree(GetProcessHeap(),0,dmA);
1121 return ret;
1124 /******************************************************************
1125 * DocumentPropertiesA [WINSPOOL.@]
1127 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1129 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1130 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1131 LPDEVMODEA pDevModeInput,DWORD fMode )
1133 LPSTR lpName = pDeviceName;
1134 LONG ret;
1136 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1137 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1140 if(!pDeviceName) {
1141 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1142 if(!lpNameW) {
1143 ERR("no name from hPrinter?\n");
1144 SetLastError(ERROR_INVALID_HANDLE);
1145 return -1;
1147 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1150 if (!GDI_CallExtDeviceMode16)
1152 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1153 (LPCSTR)102 );
1154 if (!GDI_CallExtDeviceMode16) {
1155 ERR("No CallExtDeviceMode16?\n");
1156 return -1;
1159 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1160 pDevModeInput, NULL, fMode);
1162 if(!pDeviceName)
1163 HeapFree(GetProcessHeap(),0,lpName);
1164 return ret;
1168 /*****************************************************************************
1169 * DocumentPropertiesW (WINSPOOL.@)
1171 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1173 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1174 LPWSTR pDeviceName,
1175 LPDEVMODEW pDevModeOutput,
1176 LPDEVMODEW pDevModeInput, DWORD fMode)
1179 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
1180 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1181 LPDEVMODEA pDevModeOutputA = NULL;
1182 LONG ret;
1184 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
1185 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1186 fMode);
1187 if(pDevModeOutput) {
1188 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1189 if(ret < 0) return ret;
1190 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1192 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1193 pDevModeInputA, fMode);
1194 if(pDevModeOutput) {
1195 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1196 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1198 if(fMode == 0 && ret > 0)
1199 ret += (CCHDEVICENAME + CCHFORMNAME);
1200 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1201 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1202 return ret;
1205 /******************************************************************
1206 * OpenPrinterA [WINSPOOL.@]
1208 * See OpenPrinterW.
1211 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1212 LPPRINTER_DEFAULTSA pDefault)
1214 UNICODE_STRING lpPrinterNameW;
1215 UNICODE_STRING usBuffer;
1216 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1217 PWSTR pwstrPrinterNameW;
1218 BOOL ret;
1220 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1222 if(pDefault) {
1223 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1224 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1225 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1226 pDefaultW = &DefaultW;
1228 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1229 if(pDefault) {
1230 RtlFreeUnicodeString(&usBuffer);
1231 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1233 RtlFreeUnicodeString(&lpPrinterNameW);
1234 return ret;
1237 /******************************************************************
1238 * OpenPrinterW [WINSPOOL.@]
1240 * Open a Printer / Printserver or a Printer-Object
1242 * PARAMS
1243 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1244 * phPrinter [O] The resulting Handle is stored here
1245 * pDefault [I] PTR to Default Printer Settings or NULL
1247 * RETURNS
1248 * Success: TRUE
1249 * Failure: FALSE
1251 * NOTES
1252 * lpPrinterName is one of:
1253 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1254 *| Printer: "PrinterName"
1255 *| Printer-Object: "PrinterName,Job xxx"
1256 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1257 *| XcvPort: "Servername,XcvPort PortName"
1259 * BUGS
1260 *| Printserver not supported
1261 *| Printer-Object not supported
1262 *| XcvMonitor not supported
1263 *| XcvPort not supported
1264 *| pDefaults not supported
1267 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter,
1268 LPPRINTER_DEFAULTSW pDefault)
1270 HKEY hkeyPrinters, hkeyPrinter;
1272 if (!lpPrinterName) {
1273 FIXME("(printerName: NULL, pDefault %p Ret: False\n", pDefault);
1274 SetLastError(ERROR_INVALID_PARAMETER);
1275 return FALSE;
1278 TRACE("(printerName: %s, pDefault %p)\n", debugstr_w(lpPrinterName),
1279 pDefault);
1281 /* Check Printer exists */
1282 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1283 ERROR_SUCCESS) {
1284 ERR("Can't create Printers key\n");
1285 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
1286 return FALSE;
1289 if(lpPrinterName[0] == '\0' || /* explicitly exclude "" */
1290 RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter)
1291 != ERROR_SUCCESS) {
1292 TRACE("Can't find printer %s in registry\n",
1293 debugstr_w(lpPrinterName));
1294 RegCloseKey(hkeyPrinters);
1295 SetLastError(ERROR_INVALID_PRINTER_NAME);
1296 return FALSE;
1298 RegCloseKey(hkeyPrinter);
1299 RegCloseKey(hkeyPrinters);
1301 if(!phPrinter) /* This seems to be what win95 does anyway */
1302 return TRUE;
1304 /* Get the unique handle of the printer*/
1305 *phPrinter = get_opened_printer_entry( lpPrinterName );
1307 if (pDefault != NULL)
1308 FIXME("Not handling pDefault\n");
1310 return TRUE;
1313 /******************************************************************
1314 * AddMonitorA [WINSPOOL.@]
1316 * See AddMonitorW.
1319 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
1321 LPWSTR nameW = NULL;
1322 INT len;
1323 BOOL res;
1324 LPMONITOR_INFO_2A mi2a;
1325 MONITOR_INFO_2W mi2w;
1327 mi2a = (LPMONITOR_INFO_2A) pMonitors;
1328 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
1329 mi2a ? debugstr_a(mi2a->pName) : NULL,
1330 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
1331 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
1333 if (Level != 2) {
1334 SetLastError(ERROR_INVALID_LEVEL);
1335 return FALSE;
1338 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1339 if (mi2a == NULL) {
1340 return FALSE;
1343 if (pName) {
1344 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
1345 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1346 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
1349 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
1350 if (mi2a->pName) {
1351 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
1352 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1353 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
1355 if (mi2a->pEnvironment) {
1356 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
1357 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1358 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
1360 if (mi2a->pDLLName) {
1361 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
1362 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1363 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
1366 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
1368 HeapFree(GetProcessHeap(), 0, mi2w.pName);
1369 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
1370 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
1372 HeapFree(GetProcessHeap(), 0, nameW);
1373 return (res);
1376 /******************************************************************************
1377 * AddMonitorW [WINSPOOL.@]
1379 * Install a Printmonitor
1381 * PARAMS
1382 * pName [I] Servername or NULL (local Computer)
1383 * Level [I] Structure-Level (Must be 2)
1384 * pMonitors [I] PTR to MONITOR_INFO_2
1386 * RETURNS
1387 * Success: TRUE
1388 * Failure: FALSE
1390 * NOTES
1391 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1394 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1396 LPMONITOR_INFO_2W mi2w;
1397 HKEY hroot = NULL;
1398 HKEY hentry = NULL;
1399 HMODULE hdll = NULL;
1400 DWORD disposition;
1401 BOOL res = FALSE;
1403 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1404 TRACE("(%s, %ld, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1405 mi2w ? debugstr_w(mi2w->pName) : NULL,
1406 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
1407 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
1409 if (Level != 2) {
1410 SetLastError(ERROR_INVALID_LEVEL);
1411 return FALSE;
1414 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
1415 if (mi2w == NULL) {
1416 return FALSE;
1419 if (pName && (pName[0])) {
1420 FIXME("for server %s not implemented\n", debugstr_w(pName));
1421 SetLastError(ERROR_ACCESS_DENIED);
1422 return FALSE;
1426 if (!mi2w->pName || (! mi2w->pName[0])) {
1427 WARN("pName not valid : %s \n", debugstr_w(mi2w->pName));
1428 SetLastError(ERROR_INVALID_PARAMETER);
1429 return FALSE;
1431 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
1432 WARN("Environment %s requested (we support only %s)\n",
1433 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
1434 SetLastError(ERROR_INVALID_ENVIRONMENT);
1435 return FALSE;
1438 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1439 WARN("pDLLName not valid : %s \n", debugstr_w(mi2w->pDLLName));
1440 SetLastError(ERROR_INVALID_PARAMETER);
1441 return FALSE;
1444 if ((hdll = LoadLibraryW(mi2w->pDLLName)) == NULL) {
1445 return FALSE;
1447 FreeLibrary(hdll);
1449 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
1450 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
1451 return FALSE;
1454 if(RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1455 KEY_WRITE, NULL, &hentry, &disposition) == ERROR_SUCCESS) {
1457 if (disposition == REG_OPENED_EXISTING_KEY) {
1458 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1459 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
1460 9x: ERROR_ALREADY_EXISTS (183) */
1461 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1463 else
1465 INT len;
1466 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1467 res = (RegSetValueExW(hentry, DriverW, 0,
1468 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1470 RegCloseKey(hentry);
1473 RegCloseKey(hroot);
1474 return (res);
1477 /******************************************************************
1478 * DeletePrinterDriverA [WINSPOOL.@]
1481 BOOL WINAPI
1482 DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
1484 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1485 debugstr_a(pDriverName));
1486 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1487 return FALSE;
1490 /******************************************************************
1491 * DeletePrinterDriverW [WINSPOOL.@]
1494 BOOL WINAPI
1495 DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
1497 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1498 debugstr_w(pDriverName));
1499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1500 return FALSE;
1503 /******************************************************************
1504 * DeleteMonitorA [WINSPOOL.@]
1506 * See DeleteMonitorW.
1509 BOOL WINAPI
1510 DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
1512 FIXME("(%s,%s,%s):stub\n",debugstr_a(pName),debugstr_a(pEnvironment),
1513 debugstr_a(pMonitorName));
1514 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1515 return FALSE;
1518 /******************************************************************
1519 * DeleteMonitorW [WINSPOOL.@]
1521 * Delete a specific Printmonitor from a Printing-Environment
1523 * PARAMS
1524 * pName [I] Servername or NULL (local Computer)
1525 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1526 * pMonitorName [I] Name of the Monitor, that should be deleted
1528 * RETURNS
1529 * Success: TRUE
1530 * Failure: FALSE
1532 * BUGS
1533 * only a Stub
1536 BOOL WINAPI
1537 DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1539 FIXME("(%s,%s,%s):stub\n",debugstr_w(pName),debugstr_w(pEnvironment),
1540 debugstr_w(pMonitorName));
1541 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1542 return FALSE;
1545 /******************************************************************
1546 * DeletePortA [WINSPOOL.@]
1548 * See DeletePortW.
1551 BOOL WINAPI
1552 DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
1554 FIXME("(%s,%p,%s):stub\n",debugstr_a(pName),hWnd,
1555 debugstr_a(pPortName));
1556 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1557 return FALSE;
1560 /******************************************************************
1561 * DeletePortW [WINSPOOL.@]
1563 * Delete a specific Port
1565 * PARAMS
1566 * pName [I] Servername or NULL (local Computer)
1567 * hWnd [I] Handle to parent Window for the Dialog-Box
1568 * pPortName [I] Name of the Port, that should be deleted
1570 * RETURNS
1571 * Success: TRUE
1572 * Failure: FALSE
1574 * BUGS
1575 * only a Stub
1578 BOOL WINAPI
1579 DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1581 FIXME("(%s,%p,%s):stub\n",debugstr_w(pName),hWnd,
1582 debugstr_w(pPortName));
1583 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1584 return FALSE;
1587 /******************************************************************************
1588 * SetPrinterW [WINSPOOL.@]
1590 BOOL WINAPI
1591 SetPrinterW(
1592 HANDLE hPrinter,
1593 DWORD Level,
1594 LPBYTE pPrinter,
1595 DWORD Command) {
1597 FIXME("():stub\n");
1598 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1599 return FALSE;
1602 /******************************************************************************
1603 * WritePrinter [WINSPOOL.@]
1605 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
1607 opened_printer_t *printer;
1608 BOOL ret = FALSE;
1610 TRACE("(%p, %p, %ld, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1612 EnterCriticalSection(&printer_handles_cs);
1613 printer = get_opened_printer(hPrinter);
1614 if(!printer)
1616 SetLastError(ERROR_INVALID_HANDLE);
1617 goto end;
1620 if(!printer->doc)
1622 SetLastError(ERROR_SPL_NO_STARTDOC);
1623 goto end;
1626 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
1627 end:
1628 LeaveCriticalSection(&printer_handles_cs);
1629 return ret;
1632 /*****************************************************************************
1633 * AddFormA [WINSPOOL.@]
1635 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1637 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1638 return 1;
1641 /*****************************************************************************
1642 * AddFormW [WINSPOOL.@]
1644 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
1646 FIXME("(%p,%ld,%p): stub\n", hPrinter, Level, pForm);
1647 return 1;
1650 /*****************************************************************************
1651 * AddJobA [WINSPOOL.@]
1653 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1655 BOOL ret;
1656 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
1657 DWORD needed;
1659 if(Level != 1) {
1660 SetLastError(ERROR_INVALID_LEVEL);
1661 return FALSE;
1664 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
1666 if(ret) {
1667 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
1668 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
1669 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
1670 if(*pcbNeeded > cbBuf) {
1671 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1672 ret = FALSE;
1673 } else {
1674 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
1675 addjobA->JobId = addjobW->JobId;
1676 addjobA->Path = (char *)(addjobA + 1);
1677 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
1680 return ret;
1683 /*****************************************************************************
1684 * AddJobW [WINSPOOL.@]
1686 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
1688 opened_printer_t *printer;
1689 job_t *job;
1690 BOOL ret = FALSE;
1691 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
1692 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
1693 WCHAR path[MAX_PATH], filename[MAX_PATH];
1694 DWORD len;
1695 ADDJOB_INFO_1W *addjob;
1697 TRACE("(%p,%ld,%p,%ld,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
1699 EnterCriticalSection(&printer_handles_cs);
1701 printer = get_opened_printer(hPrinter);
1703 if(!printer) {
1704 SetLastError(ERROR_INVALID_HANDLE);
1705 goto end;
1708 if(Level != 1) {
1709 SetLastError(ERROR_INVALID_LEVEL);
1710 goto end;
1713 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
1714 if(!job)
1715 goto end;
1717 job->job_id = InterlockedIncrement(&next_job_id);
1719 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
1720 if(path[len - 1] != '\\')
1721 path[len++] = '\\';
1722 memcpy(path + len, spool_path, sizeof(spool_path));
1723 sprintfW(filename, fmtW, path, job->job_id);
1725 len = strlenW(filename);
1726 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1727 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
1728 job->document_title = strdupW(default_doc_title);
1729 list_add_tail(&printer->queue->jobs, &job->entry);
1731 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
1732 if(*pcbNeeded <= cbBuf) {
1733 addjob = (ADDJOB_INFO_1W*)pData;
1734 addjob->JobId = job->job_id;
1735 addjob->Path = (WCHAR *)(addjob + 1);
1736 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
1737 ret = TRUE;
1738 } else
1739 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1741 end:
1742 LeaveCriticalSection(&printer_handles_cs);
1743 return ret;
1746 /*****************************************************************************
1747 * GetPrintProcessorDirectoryA [WINSPOOL.@]
1749 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
1750 DWORD level, LPBYTE Info,
1751 DWORD cbBuf, LPDWORD needed)
1753 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_a(server), debugstr_a(env),
1754 level, Info, cbBuf);
1755 return 0;
1758 /*****************************************************************************
1759 * GetPrintProcessorDirectoryW [WINSPOOL.@]
1761 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
1762 DWORD level, LPBYTE Info,
1763 DWORD cbBuf, LPDWORD needed)
1765 FIXME("(%s,%s,%ld,%p,0x%08lx): stub\n", debugstr_w(server), debugstr_w(env),
1766 level, Info, cbBuf);
1767 return 0;
1770 /*****************************************************************************
1771 * WINSPOOL_OpenDriverReg [internal]
1773 * opens the registry for the printer drivers depending on the given input
1774 * variable pEnvironment
1776 * RETURNS:
1777 * the opened hkey on success
1778 * NULL on error
1780 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
1782 static const WCHAR WinNTW[] = { 'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0 };
1783 static const WCHAR Win40W[] = { 'W','i','n','d','o','w','s',' ','4','.','0',0 };
1784 HKEY retval;
1785 LPWSTR lpKey, buffer = NULL;
1786 LPCWSTR pEnvW;
1788 TRACE("%s\n",
1789 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment));
1791 if(pEnvironment) {
1792 if (unicode) {
1793 pEnvW = pEnvironment;
1794 } else {
1795 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
1796 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1797 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
1798 pEnvW = buffer;
1800 } else {
1801 OSVERSIONINFOW ver;
1802 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
1804 if(!GetVersionExW( &ver))
1805 return 0;
1807 switch (ver.dwPlatformId) {
1808 case VER_PLATFORM_WIN32s:
1809 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
1810 return 0;
1811 case VER_PLATFORM_WIN32_NT:
1812 pEnvW = WinNTW;
1813 break;
1814 default:
1815 pEnvW = Win40W;
1816 break;
1818 TRACE("set environment to %s\n", debugstr_w(pEnvW));
1821 lpKey = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1822 (strlenW(pEnvW) + strlenW(DriversW) + 1) * sizeof(WCHAR));
1823 wsprintfW( lpKey, DriversW, pEnvW);
1825 TRACE("%s\n", debugstr_w(lpKey));
1827 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, lpKey, &retval) != ERROR_SUCCESS)
1828 retval = 0;
1830 HeapFree( GetProcessHeap(), 0, buffer);
1831 HeapFree( GetProcessHeap(), 0, lpKey);
1833 return retval;
1836 /*****************************************************************************
1837 * AddPrinterW [WINSPOOL.@]
1839 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1841 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1842 LPDEVMODEA dmA;
1843 LPDEVMODEW dmW;
1844 HANDLE retval;
1845 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1846 LONG size;
1848 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1850 if(pName != NULL) {
1851 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1852 SetLastError(ERROR_INVALID_PARAMETER);
1853 return 0;
1855 if(Level != 2) {
1856 ERR("Level = %ld, unsupported!\n", Level);
1857 SetLastError(ERROR_INVALID_LEVEL);
1858 return 0;
1860 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1861 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1862 debugstr_w(pi->pPrinterName)
1864 SetLastError(ERROR_INVALID_LEVEL);
1865 return 0;
1867 if(!pPrinter) {
1868 SetLastError(ERROR_INVALID_PARAMETER);
1869 return 0;
1871 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1872 ERROR_SUCCESS) {
1873 ERR("Can't create Printers key\n");
1874 return 0;
1876 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
1877 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
1878 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
1879 RegCloseKey(hkeyPrinter);
1880 RegCloseKey(hkeyPrinters);
1881 return 0;
1883 RegCloseKey(hkeyPrinter);
1885 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
1886 if(!hkeyDrivers) {
1887 ERR("Can't create Drivers key\n");
1888 RegCloseKey(hkeyPrinters);
1889 return 0;
1891 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
1892 ERROR_SUCCESS) {
1893 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
1894 RegCloseKey(hkeyPrinters);
1895 RegCloseKey(hkeyDrivers);
1896 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
1897 return 0;
1899 RegCloseKey(hkeyDriver);
1900 RegCloseKey(hkeyDrivers);
1902 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
1903 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
1904 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
1905 RegCloseKey(hkeyPrinters);
1906 return 0;
1909 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
1910 ERROR_SUCCESS) {
1911 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
1912 SetLastError(ERROR_INVALID_PRINTER_NAME);
1913 RegCloseKey(hkeyPrinters);
1914 return 0;
1916 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
1917 (LPBYTE)&pi->Attributes, sizeof(DWORD));
1918 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
1920 /* See if we can load the driver. We may need the devmode structure anyway
1922 * FIXME:
1923 * Note that DocumentPropertiesW will briefly try to open the printer we
1924 * just create to find a DEVMODEA struct (it will use the WINEPS default
1925 * one in case it is not there, so we are ok).
1927 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
1929 if(size < 0) {
1930 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
1931 size = sizeof(DEVMODEW);
1933 if(pi->pDevMode)
1934 dmW = pi->pDevMode;
1935 else
1937 dmW = HeapAlloc(GetProcessHeap(), 0, size);
1938 ZeroMemory(dmW,size);
1939 dmW->dmSize = size;
1940 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
1942 WARN("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
1943 HeapFree(GetProcessHeap(),0,dmW);
1944 dmW=NULL;
1946 else
1948 /* set devmode to printer name */
1949 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
1953 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
1954 and we support these drivers. NT writes DEVMODEW so somehow
1955 we'll need to distinguish between these when we support NT
1956 drivers */
1957 if (dmW)
1959 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
1960 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY,
1961 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
1962 HeapFree(GetProcessHeap(), 0, dmA);
1963 if(!pi->pDevMode)
1964 HeapFree(GetProcessHeap(), 0, dmW);
1966 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
1967 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
1968 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
1969 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
1971 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
1972 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
1973 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
1974 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
1975 (LPBYTE)&pi->Priority, sizeof(DWORD));
1976 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
1977 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
1978 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
1979 (LPBYTE)&pi->StartTime, sizeof(DWORD));
1980 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
1981 (LPBYTE)&pi->Status, sizeof(DWORD));
1982 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
1983 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
1985 RegCloseKey(hkeyPrinter);
1986 RegCloseKey(hkeyPrinters);
1987 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
1988 ERR("OpenPrinter failing\n");
1989 return 0;
1991 return retval;
1994 /*****************************************************************************
1995 * AddPrinterA [WINSPOOL.@]
1997 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1999 UNICODE_STRING pNameW;
2000 PWSTR pwstrNameW;
2001 PRINTER_INFO_2W *piW;
2002 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2003 HANDLE ret;
2005 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2006 if(Level != 2) {
2007 ERR("Level = %ld, unsupported!\n", Level);
2008 SetLastError(ERROR_INVALID_LEVEL);
2009 return 0;
2011 pwstrNameW = asciitounicode(&pNameW,pName);
2012 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2014 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2016 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2017 RtlFreeUnicodeString(&pNameW);
2018 return ret;
2022 /*****************************************************************************
2023 * ClosePrinter [WINSPOOL.@]
2025 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2027 UINT_PTR i = (UINT_PTR)hPrinter;
2028 opened_printer_t *printer = NULL;
2029 BOOL ret = FALSE;
2031 TRACE("Handle %p\n", hPrinter);
2033 EnterCriticalSection(&printer_handles_cs);
2035 if ((i > 0) && (i <= nb_printer_handles))
2036 printer = printer_handles[i - 1];
2038 if(printer)
2040 struct list *cursor, *cursor2;
2042 if(printer->doc)
2043 EndDocPrinter(hPrinter);
2045 if(InterlockedDecrement(&printer->queue->ref) == 0)
2047 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2049 job_t *job = LIST_ENTRY(cursor, job_t, entry);
2050 ScheduleJob(hPrinter, job->job_id);
2052 HeapFree(GetProcessHeap(), 0, printer->queue);
2054 HeapFree(GetProcessHeap(), 0, printer->name);
2055 HeapFree(GetProcessHeap(), 0, printer);
2056 printer_handles[i - 1] = NULL;
2057 ret = TRUE;
2059 LeaveCriticalSection(&printer_handles_cs);
2060 return ret;
2063 /*****************************************************************************
2064 * DeleteFormA [WINSPOOL.@]
2066 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
2068 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
2069 return 1;
2072 /*****************************************************************************
2073 * DeleteFormW [WINSPOOL.@]
2075 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
2077 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
2078 return 1;
2081 /*****************************************************************************
2082 * WINSPOOL_SHRegDeleteKey
2084 * Recursively delete subkeys.
2085 * Cut & paste from shlwapi.
2088 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
2090 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
2091 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
2092 HKEY hSubKey = 0;
2094 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
2095 if(!dwRet)
2097 /* Find how many subkeys there are */
2098 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
2099 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
2100 if(!dwRet)
2102 dwMaxSubkeyLen++;
2103 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
2104 /* Name too big: alloc a buffer for it */
2105 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
2107 if(!lpszName)
2108 dwRet = ERROR_NOT_ENOUGH_MEMORY;
2109 else
2111 /* Recursively delete all the subkeys */
2112 for(i = 0; i < dwKeyCount && !dwRet; i++)
2114 dwSize = dwMaxSubkeyLen;
2115 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
2116 if(!dwRet)
2117 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
2120 if (lpszName != szNameBuf)
2121 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
2125 RegCloseKey(hSubKey);
2126 if(!dwRet)
2127 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
2129 return dwRet;
2132 /*****************************************************************************
2133 * DeletePrinter [WINSPOOL.@]
2135 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
2137 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2138 HKEY hkeyPrinters, hkey;
2140 if(!lpNameW) {
2141 SetLastError(ERROR_INVALID_HANDLE);
2142 return FALSE;
2144 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
2145 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
2146 RegCloseKey(hkeyPrinters);
2148 WriteProfileStringW(devicesW, lpNameW, NULL);
2149 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
2150 RegDeleteValueW(hkey, lpNameW);
2151 RegCloseKey(hkey);
2153 return TRUE;
2156 /*****************************************************************************
2157 * SetPrinterA [WINSPOOL.@]
2159 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2160 DWORD Command)
2162 FIXME("(%p,%ld,%p,%ld): stub\n",hPrinter,Level,pPrinter,Command);
2163 return FALSE;
2166 /*****************************************************************************
2167 * SetJobA [WINSPOOL.@]
2169 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
2170 LPBYTE pJob, DWORD Command)
2172 BOOL ret;
2173 LPBYTE JobW;
2174 UNICODE_STRING usBuffer;
2176 TRACE("(%p, %ld, %ld, %p, %ld)\n",hPrinter, JobId, Level, pJob, Command);
2178 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
2179 are all ignored by SetJob, so we don't bother copying them */
2180 switch(Level)
2182 case 0:
2183 JobW = NULL;
2184 break;
2185 case 1:
2187 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
2188 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
2190 JobW = (LPBYTE)info1W;
2191 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
2192 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
2193 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
2194 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
2195 info1W->Status = info1A->Status;
2196 info1W->Priority = info1A->Priority;
2197 info1W->Position = info1A->Position;
2198 info1W->PagesPrinted = info1A->PagesPrinted;
2199 break;
2201 case 2:
2203 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
2204 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
2206 JobW = (LPBYTE)info2W;
2207 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
2208 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
2209 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
2210 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
2211 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
2212 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
2213 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
2214 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
2215 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
2216 info2W->Status = info2A->Status;
2217 info2W->Priority = info2A->Priority;
2218 info2W->Position = info2A->Position;
2219 info2W->StartTime = info2A->StartTime;
2220 info2W->UntilTime = info2A->UntilTime;
2221 info2W->PagesPrinted = info2A->PagesPrinted;
2222 break;
2224 case 3:
2225 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
2226 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
2227 break;
2228 default:
2229 SetLastError(ERROR_INVALID_LEVEL);
2230 return FALSE;
2233 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
2235 switch(Level)
2237 case 1:
2239 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
2240 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
2241 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
2242 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
2243 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
2244 break;
2246 case 2:
2248 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
2249 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
2250 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
2251 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
2252 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
2253 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
2254 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
2255 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
2256 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
2257 break;
2260 HeapFree(GetProcessHeap(), 0, JobW);
2262 return ret;
2265 /*****************************************************************************
2266 * SetJobW [WINSPOOL.@]
2268 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
2269 LPBYTE pJob, DWORD Command)
2271 BOOL ret = FALSE;
2272 job_t *job;
2274 TRACE("(%p, %ld, %ld, %p, %ld)\n", hPrinter, JobId, Level, pJob, Command);
2275 FIXME("Ignoring everything other than document title\n");
2277 EnterCriticalSection(&printer_handles_cs);
2278 job = get_job(hPrinter, JobId);
2279 if(!job)
2280 goto end;
2282 switch(Level)
2284 case 0:
2285 break;
2286 case 1:
2288 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
2289 HeapFree(GetProcessHeap(), 0, job->document_title);
2290 job->document_title = strdupW(info1->pDocument);
2291 break;
2293 case 2:
2295 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
2296 HeapFree(GetProcessHeap(), 0, job->document_title);
2297 job->document_title = strdupW(info2->pDocument);
2298 break;
2300 case 3:
2301 break;
2302 default:
2303 SetLastError(ERROR_INVALID_LEVEL);
2304 goto end;
2306 ret = TRUE;
2307 end:
2308 LeaveCriticalSection(&printer_handles_cs);
2309 return ret;
2312 /*****************************************************************************
2313 * EndDocPrinter [WINSPOOL.@]
2315 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
2317 opened_printer_t *printer;
2318 BOOL ret = FALSE;
2319 TRACE("(%p)\n", hPrinter);
2321 EnterCriticalSection(&printer_handles_cs);
2323 printer = get_opened_printer(hPrinter);
2324 if(!printer)
2326 SetLastError(ERROR_INVALID_HANDLE);
2327 goto end;
2330 if(!printer->doc)
2332 SetLastError(ERROR_SPL_NO_STARTDOC);
2333 goto end;
2336 CloseHandle(printer->doc->hf);
2337 ScheduleJob(hPrinter, printer->doc->job_id);
2338 HeapFree(GetProcessHeap(), 0, printer->doc);
2339 printer->doc = NULL;
2340 ret = TRUE;
2341 end:
2342 LeaveCriticalSection(&printer_handles_cs);
2343 return ret;
2346 /*****************************************************************************
2347 * EndPagePrinter [WINSPOOL.@]
2349 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
2351 FIXME("(%p): stub\n", hPrinter);
2352 return TRUE;
2355 /*****************************************************************************
2356 * StartDocPrinterA [WINSPOOL.@]
2358 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2360 UNICODE_STRING usBuffer;
2361 DOC_INFO_2W doc2W;
2362 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
2363 DWORD ret;
2365 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
2366 or one (DOC_INFO_3) extra DWORDs */
2368 switch(Level) {
2369 case 2:
2370 doc2W.JobId = doc2->JobId;
2371 /* fall through */
2372 case 3:
2373 doc2W.dwMode = doc2->dwMode;
2374 /* fall through */
2375 case 1:
2376 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
2377 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
2378 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
2379 break;
2381 default:
2382 SetLastError(ERROR_INVALID_LEVEL);
2383 return FALSE;
2386 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
2388 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
2389 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
2390 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
2392 return ret;
2395 /*****************************************************************************
2396 * StartDocPrinterW [WINSPOOL.@]
2398 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
2400 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
2401 opened_printer_t *printer;
2402 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2403 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
2404 JOB_INFO_1W job_info;
2405 DWORD needed, ret = 0;
2406 HANDLE hf;
2407 WCHAR *filename;
2409 TRACE("(hPrinter = %p, Level = %ld, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
2410 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
2411 debugstr_w(doc->pDatatype));
2413 if(Level < 1 || Level > 3)
2415 SetLastError(ERROR_INVALID_LEVEL);
2416 return 0;
2419 EnterCriticalSection(&printer_handles_cs);
2420 printer = get_opened_printer(hPrinter);
2421 if(!printer)
2423 SetLastError(ERROR_INVALID_HANDLE);
2424 goto end;
2427 if(printer->doc)
2429 SetLastError(ERROR_INVALID_PRINTER_STATE);
2430 goto end;
2433 /* Even if we're printing to a file we still add a print job, we'll
2434 just ignore the spool file name */
2436 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
2438 ERR("AddJob failed gle %08lx\n", GetLastError());
2439 goto end;
2442 if(doc->pOutputFile)
2443 filename = doc->pOutputFile;
2444 else
2445 filename = addjob->Path;
2447 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2448 if(hf == INVALID_HANDLE_VALUE)
2449 goto end;
2451 memset(&job_info, 0, sizeof(job_info));
2452 job_info.pDocument = doc->pDocName;
2453 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
2455 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
2456 printer->doc->hf = hf;
2457 ret = printer->doc->job_id = addjob->JobId;
2458 end:
2459 LeaveCriticalSection(&printer_handles_cs);
2461 return ret;
2464 /*****************************************************************************
2465 * StartPagePrinter [WINSPOOL.@]
2467 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
2469 FIXME("(%p): stub\n", hPrinter);
2470 return TRUE;
2473 /*****************************************************************************
2474 * GetFormA [WINSPOOL.@]
2476 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2477 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2479 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,pFormName,
2480 Level,pForm,cbBuf,pcbNeeded);
2481 return FALSE;
2484 /*****************************************************************************
2485 * GetFormW [WINSPOOL.@]
2487 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2488 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
2490 FIXME("(%p,%s,%ld,%p,%ld,%p): stub\n",hPrinter,
2491 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
2492 return FALSE;
2495 /*****************************************************************************
2496 * SetFormA [WINSPOOL.@]
2498 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
2499 LPBYTE pForm)
2501 FIXME("(%p,%s,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2502 return FALSE;
2505 /*****************************************************************************
2506 * SetFormW [WINSPOOL.@]
2508 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
2509 LPBYTE pForm)
2511 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pFormName,Level,pForm);
2512 return FALSE;
2515 /*****************************************************************************
2516 * ReadPrinter [WINSPOOL.@]
2518 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
2519 LPDWORD pNoBytesRead)
2521 FIXME("(%p,%p,%ld,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
2522 return FALSE;
2525 /*****************************************************************************
2526 * ResetPrinterA [WINSPOOL.@]
2528 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
2530 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2531 return FALSE;
2534 /*****************************************************************************
2535 * ResetPrinterW [WINSPOOL.@]
2537 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
2539 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
2540 return FALSE;
2543 /*****************************************************************************
2544 * WINSPOOL_GetDWORDFromReg
2546 * Return DWORD associated with ValueName from hkey.
2548 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
2550 DWORD sz = sizeof(DWORD), type, value = 0;
2551 LONG ret;
2553 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
2555 if(ret != ERROR_SUCCESS) {
2556 WARN("Got ret = %ld on name %s\n", ret, ValueName);
2557 return 0;
2559 if(type != REG_DWORD) {
2560 ERR("Got type %ld\n", type);
2561 return 0;
2563 return value;
2566 /*****************************************************************************
2567 * WINSPOOL_GetStringFromReg
2569 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2570 * String is stored either as unicode or ascii.
2571 * Bit of a hack here to get the ValueName if we want ascii.
2573 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
2574 DWORD buflen, DWORD *needed,
2575 BOOL unicode)
2577 DWORD sz = buflen, type;
2578 LONG ret;
2580 if(unicode)
2581 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2582 else {
2583 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
2584 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
2585 HeapFree(GetProcessHeap(),0,ValueNameA);
2587 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
2588 WARN("Got ret = %ld\n", ret);
2589 *needed = 0;
2590 return FALSE;
2592 *needed = sz;
2593 return TRUE;
2596 /*****************************************************************************
2597 * WINSPOOL_GetDefaultDevMode
2599 * Get a default DevMode values for wineps.
2600 * FIXME - use ppd.
2603 static void WINSPOOL_GetDefaultDevMode(
2604 LPBYTE ptr,
2605 DWORD buflen, DWORD *needed,
2606 BOOL unicode)
2608 DEVMODEA dm;
2609 static const char szwps[] = "wineps.drv";
2611 /* fill default DEVMODE - should be read from ppd... */
2612 ZeroMemory( &dm, sizeof(dm) );
2613 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
2614 dm.dmSpecVersion = DM_SPECVERSION;
2615 dm.dmDriverVersion = 1;
2616 dm.dmSize = sizeof(DEVMODEA);
2617 dm.dmDriverExtra = 0;
2618 dm.dmFields =
2619 DM_ORIENTATION | DM_PAPERSIZE |
2620 DM_PAPERLENGTH | DM_PAPERWIDTH |
2621 DM_SCALE |
2622 DM_COPIES |
2623 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
2624 DM_YRESOLUTION | DM_TTOPTION;
2626 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
2627 dm.u1.s1.dmPaperSize = DMPAPER_A4;
2628 dm.u1.s1.dmPaperLength = 2970;
2629 dm.u1.s1.dmPaperWidth = 2100;
2631 dm.dmScale = 100;
2632 dm.dmCopies = 1;
2633 dm.dmDefaultSource = DMBIN_AUTO;
2634 dm.dmPrintQuality = DMRES_MEDIUM;
2635 /* dm.dmColor */
2636 /* dm.dmDuplex */
2637 dm.dmYResolution = 300; /* 300dpi */
2638 dm.dmTTOption = DMTT_BITMAP;
2639 /* dm.dmCollate */
2640 /* dm.dmFormName */
2641 /* dm.dmLogPixels */
2642 /* dm.dmBitsPerPel */
2643 /* dm.dmPelsWidth */
2644 /* dm.dmPelsHeight */
2645 /* dm.dmDisplayFlags */
2646 /* dm.dmDisplayFrequency */
2647 /* dm.dmICMMethod */
2648 /* dm.dmICMIntent */
2649 /* dm.dmMediaType */
2650 /* dm.dmDitherType */
2651 /* dm.dmReserved1 */
2652 /* dm.dmReserved2 */
2653 /* dm.dmPanningWidth */
2654 /* dm.dmPanningHeight */
2656 if(unicode) {
2657 if(buflen >= sizeof(DEVMODEW)) {
2658 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
2659 memcpy(ptr, pdmW, sizeof(DEVMODEW));
2660 HeapFree(GetProcessHeap(),0,pdmW);
2662 *needed = sizeof(DEVMODEW);
2664 else
2666 if(buflen >= sizeof(DEVMODEA)) {
2667 memcpy(ptr, &dm, sizeof(DEVMODEA));
2669 *needed = sizeof(DEVMODEA);
2673 /*****************************************************************************
2674 * WINSPOOL_GetDevModeFromReg
2676 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
2677 * DevMode is stored either as unicode or ascii.
2679 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
2680 LPBYTE ptr,
2681 DWORD buflen, DWORD *needed,
2682 BOOL unicode)
2684 DWORD sz = buflen, type;
2685 LONG ret;
2687 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
2688 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
2689 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
2690 if (sz < sizeof(DEVMODEA))
2692 TRACE("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
2693 return FALSE;
2695 /* ensures that dmSize is not erratically bogus if registry is invalid */
2696 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
2697 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
2698 if(unicode) {
2699 sz += (CCHDEVICENAME + CCHFORMNAME);
2700 if(buflen >= sz) {
2701 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
2702 memcpy(ptr, dmW, sz);
2703 HeapFree(GetProcessHeap(),0,dmW);
2706 *needed = sz;
2707 return TRUE;
2710 /*********************************************************************
2711 * WINSPOOL_GetPrinter_2
2713 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
2714 * The strings are either stored as unicode or ascii.
2716 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
2717 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2718 BOOL unicode)
2720 DWORD size, left = cbBuf;
2721 BOOL space = (cbBuf > 0);
2722 LPBYTE ptr = buf;
2724 *pcbNeeded = 0;
2726 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2727 unicode)) {
2728 if(space && size <= left) {
2729 pi2->pPrinterName = (LPWSTR)ptr;
2730 ptr += size;
2731 left -= size;
2732 } else
2733 space = FALSE;
2734 *pcbNeeded += size;
2736 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
2737 unicode)) {
2738 if(space && size <= left) {
2739 pi2->pShareName = (LPWSTR)ptr;
2740 ptr += size;
2741 left -= size;
2742 } else
2743 space = FALSE;
2744 *pcbNeeded += size;
2746 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2747 unicode)) {
2748 if(space && size <= left) {
2749 pi2->pPortName = (LPWSTR)ptr;
2750 ptr += size;
2751 left -= size;
2752 } else
2753 space = FALSE;
2754 *pcbNeeded += size;
2756 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
2757 &size, unicode)) {
2758 if(space && size <= left) {
2759 pi2->pDriverName = (LPWSTR)ptr;
2760 ptr += size;
2761 left -= size;
2762 } else
2763 space = FALSE;
2764 *pcbNeeded += size;
2766 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
2767 unicode)) {
2768 if(space && size <= left) {
2769 pi2->pComment = (LPWSTR)ptr;
2770 ptr += size;
2771 left -= size;
2772 } else
2773 space = FALSE;
2774 *pcbNeeded += size;
2776 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
2777 unicode)) {
2778 if(space && size <= left) {
2779 pi2->pLocation = (LPWSTR)ptr;
2780 ptr += size;
2781 left -= size;
2782 } else
2783 space = FALSE;
2784 *pcbNeeded += size;
2786 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
2787 &size, unicode)) {
2788 if(space && size <= left) {
2789 pi2->pDevMode = (LPDEVMODEW)ptr;
2790 ptr += size;
2791 left -= size;
2792 } else
2793 space = FALSE;
2794 *pcbNeeded += size;
2796 else
2798 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
2799 if(space && size <= left) {
2800 pi2->pDevMode = (LPDEVMODEW)ptr;
2801 ptr += size;
2802 left -= size;
2803 } else
2804 space = FALSE;
2805 *pcbNeeded += size;
2807 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
2808 &size, unicode)) {
2809 if(space && size <= left) {
2810 pi2->pSepFile = (LPWSTR)ptr;
2811 ptr += size;
2812 left -= size;
2813 } else
2814 space = FALSE;
2815 *pcbNeeded += size;
2817 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
2818 &size, unicode)) {
2819 if(space && size <= left) {
2820 pi2->pPrintProcessor = (LPWSTR)ptr;
2821 ptr += size;
2822 left -= size;
2823 } else
2824 space = FALSE;
2825 *pcbNeeded += size;
2827 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
2828 &size, unicode)) {
2829 if(space && size <= left) {
2830 pi2->pDatatype = (LPWSTR)ptr;
2831 ptr += size;
2832 left -= size;
2833 } else
2834 space = FALSE;
2835 *pcbNeeded += size;
2837 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
2838 &size, unicode)) {
2839 if(space && size <= left) {
2840 pi2->pParameters = (LPWSTR)ptr;
2841 ptr += size;
2842 left -= size;
2843 } else
2844 space = FALSE;
2845 *pcbNeeded += size;
2847 if(pi2) {
2848 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2849 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
2850 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2851 "Default Priority");
2852 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
2853 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
2856 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
2857 memset(pi2, 0, sizeof(*pi2));
2859 return space;
2862 /*********************************************************************
2863 * WINSPOOL_GetPrinter_4
2865 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
2867 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
2868 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2869 BOOL unicode)
2871 DWORD size, left = cbBuf;
2872 BOOL space = (cbBuf > 0);
2873 LPBYTE ptr = buf;
2875 *pcbNeeded = 0;
2877 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2878 unicode)) {
2879 if(space && size <= left) {
2880 pi4->pPrinterName = (LPWSTR)ptr;
2881 ptr += size;
2882 left -= size;
2883 } else
2884 space = FALSE;
2885 *pcbNeeded += size;
2887 if(pi4) {
2888 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2891 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
2892 memset(pi4, 0, sizeof(*pi4));
2894 return space;
2897 /*********************************************************************
2898 * WINSPOOL_GetPrinter_5
2900 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
2902 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
2903 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
2904 BOOL unicode)
2906 DWORD size, left = cbBuf;
2907 BOOL space = (cbBuf > 0);
2908 LPBYTE ptr = buf;
2910 *pcbNeeded = 0;
2912 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
2913 unicode)) {
2914 if(space && size <= left) {
2915 pi5->pPrinterName = (LPWSTR)ptr;
2916 ptr += size;
2917 left -= size;
2918 } else
2919 space = FALSE;
2920 *pcbNeeded += size;
2922 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
2923 unicode)) {
2924 if(space && size <= left) {
2925 pi5->pPortName = (LPWSTR)ptr;
2926 ptr += size;
2927 left -= size;
2928 } else
2929 space = FALSE;
2930 *pcbNeeded += size;
2932 if(pi5) {
2933 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
2934 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2935 "dnsTimeout");
2936 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
2937 "txTimeout");
2940 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
2941 memset(pi5, 0, sizeof(*pi5));
2943 return space;
2946 /*****************************************************************************
2947 * WINSPOOL_GetPrinter
2949 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
2950 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
2951 * just a collection of pointers to strings.
2953 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
2954 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
2956 LPCWSTR name;
2957 DWORD size, needed = 0;
2958 LPBYTE ptr = NULL;
2959 HKEY hkeyPrinter, hkeyPrinters;
2960 BOOL ret;
2962 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
2964 if (!(name = get_opened_printer_name(hPrinter))) {
2965 SetLastError(ERROR_INVALID_HANDLE);
2966 return FALSE;
2969 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2970 ERROR_SUCCESS) {
2971 ERR("Can't create Printers key\n");
2972 return FALSE;
2974 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
2976 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
2977 RegCloseKey(hkeyPrinters);
2978 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
2979 return FALSE;
2982 switch(Level) {
2983 case 2:
2985 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
2987 size = sizeof(PRINTER_INFO_2W);
2988 if(size <= cbBuf) {
2989 ptr = pPrinter + size;
2990 cbBuf -= size;
2991 memset(pPrinter, 0, size);
2992 } else {
2993 pi2 = NULL;
2994 cbBuf = 0;
2996 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
2997 unicode);
2998 needed += size;
2999 break;
3002 case 4:
3004 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3006 size = sizeof(PRINTER_INFO_4W);
3007 if(size <= cbBuf) {
3008 ptr = pPrinter + size;
3009 cbBuf -= size;
3010 memset(pPrinter, 0, size);
3011 } else {
3012 pi4 = NULL;
3013 cbBuf = 0;
3015 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3016 unicode);
3017 needed += size;
3018 break;
3022 case 5:
3024 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3026 size = sizeof(PRINTER_INFO_5W);
3027 if(size <= cbBuf) {
3028 ptr = pPrinter + size;
3029 cbBuf -= size;
3030 memset(pPrinter, 0, size);
3031 } else {
3032 pi5 = NULL;
3033 cbBuf = 0;
3036 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
3037 unicode);
3038 needed += size;
3039 break;
3042 default:
3043 FIXME("Unimplemented level %ld\n", Level);
3044 SetLastError(ERROR_INVALID_LEVEL);
3045 RegCloseKey(hkeyPrinters);
3046 RegCloseKey(hkeyPrinter);
3047 return FALSE;
3050 RegCloseKey(hkeyPrinter);
3051 RegCloseKey(hkeyPrinters);
3053 TRACE("returning %d needed = %ld\n", ret, needed);
3054 if(pcbNeeded) *pcbNeeded = needed;
3055 if(!ret)
3056 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3057 return ret;
3060 /*****************************************************************************
3061 * GetPrinterW [WINSPOOL.@]
3063 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3064 DWORD cbBuf, LPDWORD pcbNeeded)
3066 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3067 TRUE);
3070 /*****************************************************************************
3071 * GetPrinterA [WINSPOOL.@]
3073 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3074 DWORD cbBuf, LPDWORD pcbNeeded)
3076 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
3077 FALSE);
3080 /*****************************************************************************
3081 * WINSPOOL_EnumPrinters
3083 * Implementation of EnumPrintersA|W
3085 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
3086 DWORD dwLevel, LPBYTE lpbPrinters,
3087 DWORD cbBuf, LPDWORD lpdwNeeded,
3088 LPDWORD lpdwReturned, BOOL unicode)
3091 HKEY hkeyPrinters, hkeyPrinter;
3092 WCHAR PrinterName[255];
3093 DWORD needed = 0, number = 0;
3094 DWORD used, i, left;
3095 PBYTE pi, buf;
3097 if(lpbPrinters)
3098 memset(lpbPrinters, 0, cbBuf);
3099 if(lpdwReturned)
3100 *lpdwReturned = 0;
3101 if(lpdwNeeded)
3102 *lpdwNeeded = 0;
3104 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
3105 if(dwType == PRINTER_ENUM_DEFAULT)
3106 return TRUE;
3108 if (dwType & PRINTER_ENUM_CONNECTIONS) {
3109 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
3110 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
3111 if(!dwType) return TRUE;
3114 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
3115 FIXME("dwType = %08lx\n", dwType);
3116 SetLastError(ERROR_INVALID_FLAGS);
3117 return FALSE;
3120 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3121 ERROR_SUCCESS) {
3122 ERR("Can't create Printers key\n");
3123 return FALSE;
3126 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
3127 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3128 RegCloseKey(hkeyPrinters);
3129 ERR("Can't query Printers key\n");
3130 return FALSE;
3132 TRACE("Found %ld printers\n", number);
3134 switch(dwLevel) {
3135 case 1:
3136 RegCloseKey(hkeyPrinters);
3137 if (lpdwReturned)
3138 *lpdwReturned = number;
3139 return TRUE;
3141 case 2:
3142 used = number * sizeof(PRINTER_INFO_2W);
3143 break;
3144 case 4:
3145 used = number * sizeof(PRINTER_INFO_4W);
3146 break;
3147 case 5:
3148 used = number * sizeof(PRINTER_INFO_5W);
3149 break;
3151 default:
3152 SetLastError(ERROR_INVALID_LEVEL);
3153 RegCloseKey(hkeyPrinters);
3154 return FALSE;
3156 pi = (used <= cbBuf) ? lpbPrinters : NULL;
3158 for(i = 0; i < number; i++) {
3159 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
3160 ERROR_SUCCESS) {
3161 ERR("Can't enum key number %ld\n", i);
3162 RegCloseKey(hkeyPrinters);
3163 return FALSE;
3165 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
3166 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
3167 ERROR_SUCCESS) {
3168 ERR("Can't open key %s\n", debugstr_w(PrinterName));
3169 RegCloseKey(hkeyPrinters);
3170 return FALSE;
3173 if(cbBuf > used) {
3174 buf = lpbPrinters + used;
3175 left = cbBuf - used;
3176 } else {
3177 buf = NULL;
3178 left = 0;
3181 switch(dwLevel) {
3182 case 2:
3183 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
3184 left, &needed, unicode);
3185 used += needed;
3186 if(pi) pi += sizeof(PRINTER_INFO_2W);
3187 break;
3188 case 4:
3189 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
3190 left, &needed, unicode);
3191 used += needed;
3192 if(pi) pi += sizeof(PRINTER_INFO_4W);
3193 break;
3194 case 5:
3195 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
3196 left, &needed, unicode);
3197 used += needed;
3198 if(pi) pi += sizeof(PRINTER_INFO_5W);
3199 break;
3200 default:
3201 ERR("Shouldn't be here!\n");
3202 RegCloseKey(hkeyPrinter);
3203 RegCloseKey(hkeyPrinters);
3204 return FALSE;
3206 RegCloseKey(hkeyPrinter);
3208 RegCloseKey(hkeyPrinters);
3210 if(lpdwNeeded)
3211 *lpdwNeeded = used;
3213 if(used > cbBuf) {
3214 if(lpbPrinters)
3215 memset(lpbPrinters, 0, cbBuf);
3216 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3217 return FALSE;
3219 if(lpdwReturned)
3220 *lpdwReturned = number;
3221 SetLastError(ERROR_SUCCESS);
3222 return TRUE;
3226 /******************************************************************
3227 * EnumPrintersW [WINSPOOL.@]
3229 * Enumerates the available printers, print servers and print
3230 * providers, depending on the specified flags, name and level.
3232 * RETURNS:
3234 * If level is set to 1:
3235 * Not implemented yet!
3236 * Returns TRUE with an empty list.
3238 * If level is set to 2:
3239 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3240 * Returns an array of PRINTER_INFO_2 data structures in the
3241 * lpbPrinters buffer. Note that according to MSDN also an
3242 * OpenPrinter should be performed on every remote printer.
3244 * If level is set to 4 (officially WinNT only):
3245 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
3246 * Fast: Only the registry is queried to retrieve printer names,
3247 * no connection to the driver is made.
3248 * Returns an array of PRINTER_INFO_4 data structures in the
3249 * lpbPrinters buffer.
3251 * If level is set to 5 (officially WinNT4/Win9x only):
3252 * Fast: Only the registry is queried to retrieve printer names,
3253 * no connection to the driver is made.
3254 * Returns an array of PRINTER_INFO_5 data structures in the
3255 * lpbPrinters buffer.
3257 * If level set to 3 or 6+:
3258 * returns zero (failure!)
3260 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
3261 * for information.
3263 * BUGS:
3264 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
3265 * - Only levels 2, 4 and 5 are implemented at the moment.
3266 * - 16-bit printer drivers are not enumerated.
3267 * - Returned amount of bytes used/needed does not match the real Windoze
3268 * implementation (as in this implementation, all strings are part
3269 * of the buffer, whereas Win32 keeps them somewhere else)
3270 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
3272 * NOTE:
3273 * - In a regular Wine installation, no registry settings for printers
3274 * exist, which makes this function return an empty list.
3276 BOOL WINAPI EnumPrintersW(
3277 DWORD dwType, /* [in] Types of print objects to enumerate */
3278 LPWSTR lpszName, /* [in] name of objects to enumerate */
3279 DWORD dwLevel, /* [in] type of printer info structure */
3280 LPBYTE lpbPrinters, /* [out] buffer which receives info */
3281 DWORD cbBuf, /* [in] max size of buffer in bytes */
3282 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
3283 LPDWORD lpdwReturned /* [out] number of entries returned */
3286 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
3287 lpdwNeeded, lpdwReturned, TRUE);
3290 /******************************************************************
3291 * EnumPrintersA [WINSPOOL.@]
3294 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
3295 DWORD dwLevel, LPBYTE lpbPrinters,
3296 DWORD cbBuf, LPDWORD lpdwNeeded,
3297 LPDWORD lpdwReturned)
3299 BOOL ret;
3300 UNICODE_STRING lpszNameW;
3301 PWSTR pwstrNameW;
3303 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
3304 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
3305 lpdwNeeded, lpdwReturned, FALSE);
3306 RtlFreeUnicodeString(&lpszNameW);
3307 return ret;
3310 /*****************************************************************************
3311 * WINSPOOL_GetDriverInfoFromReg [internal]
3313 * Enters the information from the registry into the DRIVER_INFO struct
3315 * RETURNS
3316 * zero if the printer driver does not exist in the registry
3317 * (only if Level > 1) otherwise nonzero
3319 static BOOL WINSPOOL_GetDriverInfoFromReg(
3320 HKEY hkeyDrivers,
3321 LPWSTR DriverName,
3322 LPWSTR pEnvironment,
3323 DWORD Level,
3324 LPBYTE ptr, /* DRIVER_INFO */
3325 LPBYTE pDriverStrings, /* strings buffer */
3326 DWORD cbBuf, /* size of string buffer */
3327 LPDWORD pcbNeeded, /* space needed for str. */
3328 BOOL unicode) /* type of strings */
3329 { DWORD dw, size, tmp, type;
3330 HKEY hkeyDriver;
3331 LPBYTE strPtr = pDriverStrings;
3333 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
3334 debugstr_w(DriverName), debugstr_w(pEnvironment),
3335 Level, ptr, pDriverStrings, cbBuf, unicode);
3337 if(unicode) {
3338 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
3339 if (*pcbNeeded <= cbBuf)
3340 strcpyW((LPWSTR)strPtr, DriverName);
3341 } else {
3342 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
3343 NULL, NULL);
3344 if(*pcbNeeded <= cbBuf)
3345 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
3346 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
3348 if(Level == 1) {
3349 if(ptr)
3350 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
3351 return TRUE;
3352 } else {
3353 if(ptr)
3354 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
3355 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3358 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
3359 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
3360 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
3361 return FALSE;
3364 size = sizeof(dw);
3365 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
3366 ERROR_SUCCESS)
3367 WARN("Can't get Version\n");
3368 else if(ptr)
3369 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
3371 if(!pEnvironment)
3372 pEnvironment = (LPWSTR)DefaultEnvironmentW;
3373 if(unicode)
3374 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
3375 else
3376 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
3377 NULL, NULL);
3378 *pcbNeeded += size;
3379 if(*pcbNeeded <= cbBuf) {
3380 if(unicode)
3381 strcpyW((LPWSTR)strPtr, pEnvironment);
3382 else
3383 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
3384 (LPSTR)strPtr, size, NULL, NULL);
3385 if(ptr)
3386 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
3387 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3390 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
3391 unicode)) {
3392 *pcbNeeded += size;
3393 if(*pcbNeeded <= cbBuf)
3394 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
3395 unicode);
3396 if(ptr)
3397 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
3398 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
3401 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
3402 unicode)) {
3403 *pcbNeeded += size;
3404 if(*pcbNeeded <= cbBuf)
3405 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
3406 &tmp, unicode);
3407 if(ptr)
3408 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
3409 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3412 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3413 0, &size, unicode)) {
3414 *pcbNeeded += size;
3415 if(*pcbNeeded <= cbBuf)
3416 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
3417 size, &tmp, unicode);
3418 if(ptr)
3419 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
3420 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3423 if(Level == 2 ) {
3424 RegCloseKey(hkeyDriver);
3425 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3426 return TRUE;
3429 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
3430 unicode)) {
3431 *pcbNeeded += size;
3432 if(*pcbNeeded <= cbBuf)
3433 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
3434 size, &tmp, unicode);
3435 if(ptr)
3436 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
3437 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3440 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
3441 &size, unicode)) {
3442 *pcbNeeded += size;
3443 if(*pcbNeeded <= cbBuf)
3444 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
3445 size, &tmp, unicode);
3446 if(ptr)
3447 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
3448 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3451 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
3452 unicode)) {
3453 *pcbNeeded += size;
3454 if(*pcbNeeded <= cbBuf)
3455 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
3456 size, &tmp, unicode);
3457 if(ptr)
3458 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
3459 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3462 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
3463 unicode)) {
3464 *pcbNeeded += size;
3465 if(*pcbNeeded <= cbBuf)
3466 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
3467 size, &tmp, unicode);
3468 if(ptr)
3469 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
3470 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
3473 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
3474 RegCloseKey(hkeyDriver);
3475 return TRUE;
3478 /*****************************************************************************
3479 * WINSPOOL_GetPrinterDriver
3481 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
3482 DWORD Level, LPBYTE pDriverInfo,
3483 DWORD cbBuf, LPDWORD pcbNeeded,
3484 BOOL unicode)
3486 LPCWSTR name;
3487 WCHAR DriverName[100];
3488 DWORD ret, type, size, needed = 0;
3489 LPBYTE ptr = NULL;
3490 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
3492 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
3493 Level,pDriverInfo,cbBuf, pcbNeeded);
3495 ZeroMemory(pDriverInfo, cbBuf);
3497 if (!(name = get_opened_printer_name(hPrinter))) {
3498 SetLastError(ERROR_INVALID_HANDLE);
3499 return FALSE;
3501 if(Level < 1 || Level > 3) {
3502 SetLastError(ERROR_INVALID_LEVEL);
3503 return FALSE;
3505 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
3506 ERROR_SUCCESS) {
3507 ERR("Can't create Printers key\n");
3508 return FALSE;
3510 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
3511 != ERROR_SUCCESS) {
3512 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3513 RegCloseKey(hkeyPrinters);
3514 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3515 return FALSE;
3517 size = sizeof(DriverName);
3518 DriverName[0] = 0;
3519 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
3520 (LPBYTE)DriverName, &size);
3521 RegCloseKey(hkeyPrinter);
3522 RegCloseKey(hkeyPrinters);
3523 if(ret != ERROR_SUCCESS) {
3524 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
3525 return FALSE;
3528 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
3529 if(!hkeyDrivers) {
3530 ERR("Can't create Drivers key\n");
3531 return FALSE;
3534 switch(Level) {
3535 case 1:
3536 size = sizeof(DRIVER_INFO_1W);
3537 break;
3538 case 2:
3539 size = sizeof(DRIVER_INFO_2W);
3540 break;
3541 case 3:
3542 size = sizeof(DRIVER_INFO_3W);
3543 break;
3544 default:
3545 ERR("Invalid level\n");
3546 return FALSE;
3549 if(size <= cbBuf)
3550 ptr = pDriverInfo + size;
3552 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
3553 pEnvironment, Level, pDriverInfo,
3554 (cbBuf < size) ? NULL : ptr,
3555 (cbBuf < size) ? 0 : cbBuf - size,
3556 &needed, unicode)) {
3557 RegCloseKey(hkeyDrivers);
3558 return FALSE;
3561 RegCloseKey(hkeyDrivers);
3563 if(pcbNeeded) *pcbNeeded = size + needed;
3564 TRACE("buffer space %ld required %ld\n", cbBuf, size + needed);
3565 if(cbBuf >= needed) return TRUE;
3566 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3567 return FALSE;
3570 /*****************************************************************************
3571 * GetPrinterDriverA [WINSPOOL.@]
3573 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
3574 DWORD Level, LPBYTE pDriverInfo,
3575 DWORD cbBuf, LPDWORD pcbNeeded)
3577 BOOL ret;
3578 UNICODE_STRING pEnvW;
3579 PWSTR pwstrEnvW;
3581 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
3582 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
3583 cbBuf, pcbNeeded, FALSE);
3584 RtlFreeUnicodeString(&pEnvW);
3585 return ret;
3587 /*****************************************************************************
3588 * GetPrinterDriverW [WINSPOOL.@]
3590 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
3591 DWORD Level, LPBYTE pDriverInfo,
3592 DWORD cbBuf, LPDWORD pcbNeeded)
3594 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
3595 pDriverInfo, cbBuf, pcbNeeded, TRUE);
3598 /*****************************************************************************
3599 * GetPrinterDriverDirectoryW [WINSPOOL.@]
3601 * Return the PATH for the Printer-Drivers (UNICODE)
3603 * PARAMS
3604 * pName [I] Servername (NT only) or NULL (local Computer)
3605 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
3606 * Level [I] Structure-Level (must be 1)
3607 * pDriverDirectory [O] PTR to Buffer that receives the Result
3608 * cbBuf [I] Size of Buffer at pDriverDirectory
3609 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
3610 * required for pDriverDirectory
3612 * RETURNS
3613 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
3614 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
3615 * if cbBuf is too small
3617 * Native Values returned in pDriverDirectory on Success:
3618 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
3619 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
3620 *| win9x(Windows 4.0): "%winsysdir%"
3622 * "%winsysdir%" is the Value from GetSystemDirectoryW()
3624 * FIXME
3625 *- Only NULL or "" is supported for pName
3628 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
3629 DWORD Level, LPBYTE pDriverDirectory,
3630 DWORD cbBuf, LPDWORD pcbNeeded)
3632 DWORD needed;
3633 const printenv_t * env;
3635 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName),
3636 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3637 if(pName != NULL && pName[0]) {
3638 FIXME("pName unsupported: %s\n", debugstr_w(pName));
3639 SetLastError(ERROR_INVALID_PARAMETER);
3640 return FALSE;
3643 env = validate_envW(pEnvironment);
3644 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
3646 if(Level != 1) {
3647 WARN("(Level: %ld) is ignored in win9x\n", Level);
3648 SetLastError(ERROR_INVALID_LEVEL);
3649 return FALSE;
3652 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
3653 needed = GetSystemDirectoryW(NULL, 0);
3654 /* add the Size for the Subdirectories */
3655 needed += lstrlenW(spooldriversW);
3656 needed += lstrlenW(env->subdir);
3657 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
3659 if(pcbNeeded)
3660 *pcbNeeded = needed;
3661 TRACE("required: 0x%lx/%ld\n", needed, needed);
3662 if(needed > cbBuf) {
3663 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3664 return FALSE;
3666 if(pcbNeeded == NULL) {
3667 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
3668 SetLastError(RPC_X_NULL_REF_POINTER);
3669 return FALSE;
3671 if(pDriverDirectory == NULL) {
3672 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
3673 SetLastError(ERROR_INVALID_USER_BUFFER);
3674 return FALSE;
3677 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
3678 /* add the Subdirectories */
3679 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
3680 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
3681 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
3682 return TRUE;
3686 /*****************************************************************************
3687 * GetPrinterDriverDirectoryA [WINSPOOL.@]
3689 * Return the PATH for the Printer-Drivers (ANSI)
3691 * See GetPrinterDriverDirectoryW.
3693 * NOTES
3694 * On NT, pDriverDirectory need the same Size as the Unicode-Version
3697 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
3698 DWORD Level, LPBYTE pDriverDirectory,
3699 DWORD cbBuf, LPDWORD pcbNeeded)
3701 UNICODE_STRING nameW, environmentW;
3702 BOOL ret;
3703 DWORD pcbNeededW;
3704 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
3705 WCHAR *driverDirectoryW = NULL;
3707 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_a(pName),
3708 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
3710 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
3712 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
3713 else nameW.Buffer = NULL;
3714 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
3715 else environmentW.Buffer = NULL;
3717 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
3718 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
3719 if (ret) {
3720 DWORD needed;
3721 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
3722 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
3723 if(pcbNeeded)
3724 *pcbNeeded = needed;
3725 ret = (needed <= cbBuf) ? TRUE : FALSE;
3726 } else
3727 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
3729 TRACE("required: 0x%lx/%ld\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
3731 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
3732 RtlFreeUnicodeString(&environmentW);
3733 RtlFreeUnicodeString(&nameW);
3735 return ret;
3738 /*****************************************************************************
3739 * AddPrinterDriverA [WINSPOOL.@]
3741 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
3743 DRIVER_INFO_3A di3;
3744 HKEY hkeyDrivers, hkeyName;
3746 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
3748 if(level != 2 && level != 3) {
3749 SetLastError(ERROR_INVALID_LEVEL);
3750 return FALSE;
3752 if(pName != NULL) {
3753 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
3754 SetLastError(ERROR_INVALID_PARAMETER);
3755 return FALSE;
3757 if(!pDriverInfo) {
3758 WARN("pDriverInfo == NULL\n");
3759 SetLastError(ERROR_INVALID_PARAMETER);
3760 return FALSE;
3763 if(level == 3)
3764 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
3765 else {
3766 memset(&di3, 0, sizeof(di3));
3767 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
3770 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
3771 !di3.pDataFile) {
3772 SetLastError(ERROR_INVALID_PARAMETER);
3773 return FALSE;
3775 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
3776 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
3777 if(!di3.pHelpFile) di3.pHelpFile = "";
3778 if(!di3.pMonitorName) di3.pMonitorName = "";
3780 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
3782 if(!hkeyDrivers) {
3783 ERR("Can't create Drivers key\n");
3784 return FALSE;
3787 if(level == 2) { /* apparently can't overwrite with level2 */
3788 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
3789 RegCloseKey(hkeyName);
3790 RegCloseKey(hkeyDrivers);
3791 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
3792 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
3793 return FALSE;
3796 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
3797 RegCloseKey(hkeyDrivers);
3798 ERR("Can't create Name key\n");
3799 return FALSE;
3801 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
3803 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, 0);
3804 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, 0);
3805 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
3806 sizeof(DWORD));
3807 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, 0);
3808 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
3809 (LPBYTE) di3.pDependentFiles, 0);
3810 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, 0);
3811 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, 0);
3812 RegCloseKey(hkeyName);
3813 RegCloseKey(hkeyDrivers);
3815 return TRUE;
3818 /*****************************************************************************
3819 * AddPrinterDriverW [WINSPOOL.@]
3821 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
3822 LPBYTE pDriverInfo)
3824 FIXME("(%s,%ld,%p): stub\n",debugstr_w(printerName),
3825 level,pDriverInfo);
3826 return FALSE;
3829 /*****************************************************************************
3830 * AddPrintProcessorA [WINSPOOL.@]
3832 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
3833 LPSTR pPrintProcessorName)
3835 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
3836 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
3837 return FALSE;
3840 /*****************************************************************************
3841 * AddPrintProcessorW [WINSPOOL.@]
3843 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
3844 LPWSTR pPrintProcessorName)
3846 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
3847 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
3848 return FALSE;
3851 /*****************************************************************************
3852 * AddPrintProvidorA [WINSPOOL.@]
3854 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
3856 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
3857 return FALSE;
3860 /*****************************************************************************
3861 * AddPrintProvidorW [WINSPOOL.@]
3863 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
3865 FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
3866 return FALSE;
3869 /*****************************************************************************
3870 * AdvancedDocumentPropertiesA [WINSPOOL.@]
3872 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
3873 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
3875 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
3876 pDevModeOutput, pDevModeInput);
3877 return 0;
3880 /*****************************************************************************
3881 * AdvancedDocumentPropertiesW [WINSPOOL.@]
3883 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
3884 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
3886 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
3887 pDevModeOutput, pDevModeInput);
3888 return 0;
3891 /*****************************************************************************
3892 * PrinterProperties [WINSPOOL.@]
3894 * Displays a dialog to set the properties of the printer.
3896 * RETURNS
3897 * nonzero on success or zero on failure
3899 * BUGS
3900 * implemented as stub only
3902 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
3903 HANDLE hPrinter /* [in] handle to printer object */
3905 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
3906 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3907 return FALSE;
3910 /*****************************************************************************
3911 * EnumJobsA [WINSPOOL.@]
3914 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3915 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3916 LPDWORD pcReturned)
3918 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3919 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3921 if(pcbNeeded) *pcbNeeded = 0;
3922 if(pcReturned) *pcReturned = 0;
3923 return FALSE;
3927 /*****************************************************************************
3928 * EnumJobsW [WINSPOOL.@]
3931 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
3932 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
3933 LPDWORD pcReturned)
3935 FIXME("(%p,first=%ld,no=%ld,level=%ld,job=%p,cb=%ld,%p,%p), stub!\n",
3936 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
3938 if(pcbNeeded) *pcbNeeded = 0;
3939 if(pcReturned) *pcReturned = 0;
3940 return FALSE;
3943 /*****************************************************************************
3944 * WINSPOOL_EnumPrinterDrivers [internal]
3946 * Delivers information about all printer drivers installed on the
3947 * localhost or a given server
3949 * RETURNS
3950 * nonzero on success or zero on failure. If the buffer for the returned
3951 * information is too small the function will return an error
3953 * BUGS
3954 * - only implemented for localhost, foreign hosts will return an error
3956 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPWSTR pEnvironment,
3957 DWORD Level, LPBYTE pDriverInfo,
3958 DWORD cbBuf, LPDWORD pcbNeeded,
3959 LPDWORD pcReturned, BOOL unicode)
3961 { HKEY hkeyDrivers;
3962 DWORD i, needed, number = 0, size = 0;
3963 WCHAR DriverNameW[255];
3964 PBYTE ptr;
3966 TRACE("%s,%s,%ld,%p,%ld,%d\n",
3967 debugstr_w(pName), debugstr_w(pEnvironment),
3968 Level, pDriverInfo, cbBuf, unicode);
3970 /* check for local drivers */
3971 if(pName) {
3972 ERR("remote drivers unsupported! Current remote host is %s\n",
3973 debugstr_w(pName));
3974 return FALSE;
3977 /* check input parameter */
3978 if((Level < 1) || (Level > 3)) {
3979 ERR("unsupported level %ld\n", Level);
3980 SetLastError(ERROR_INVALID_LEVEL);
3981 return FALSE;
3984 /* initialize return values */
3985 if(pDriverInfo)
3986 memset( pDriverInfo, 0, cbBuf);
3987 *pcbNeeded = 0;
3988 *pcReturned = 0;
3990 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
3991 if(!hkeyDrivers) {
3992 ERR("Can't open Drivers key\n");
3993 return FALSE;
3996 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
3997 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
3998 RegCloseKey(hkeyDrivers);
3999 ERR("Can't query Drivers key\n");
4000 return FALSE;
4002 TRACE("Found %ld Drivers\n", number);
4004 /* get size of single struct
4005 * unicode and ascii structure have the same size
4007 switch (Level) {
4008 case 1:
4009 size = sizeof(DRIVER_INFO_1A);
4010 break;
4011 case 2:
4012 size = sizeof(DRIVER_INFO_2A);
4013 break;
4014 case 3:
4015 size = sizeof(DRIVER_INFO_3A);
4016 break;
4019 /* calculate required buffer size */
4020 *pcbNeeded = size * number;
4022 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
4023 i < number;
4024 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
4025 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
4026 != ERROR_SUCCESS) {
4027 ERR("Can't enum key number %ld\n", i);
4028 RegCloseKey(hkeyDrivers);
4029 return FALSE;
4031 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
4032 pEnvironment, Level, ptr,
4033 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
4034 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
4035 &needed, unicode)) {
4036 RegCloseKey(hkeyDrivers);
4037 return FALSE;
4039 (*pcbNeeded) += needed;
4042 RegCloseKey(hkeyDrivers);
4044 if(cbBuf < *pcbNeeded){
4045 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4046 return FALSE;
4049 *pcReturned = number;
4050 return TRUE;
4053 /*****************************************************************************
4054 * EnumPrinterDriversW [WINSPOOL.@]
4056 * see function EnumPrinterDrivers for RETURNS, BUGS
4058 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
4059 LPBYTE pDriverInfo, DWORD cbBuf,
4060 LPDWORD pcbNeeded, LPDWORD pcReturned)
4062 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
4063 cbBuf, pcbNeeded, pcReturned, TRUE);
4066 /*****************************************************************************
4067 * EnumPrinterDriversA [WINSPOOL.@]
4069 * see function EnumPrinterDrivers for RETURNS, BUGS
4071 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
4072 LPBYTE pDriverInfo, DWORD cbBuf,
4073 LPDWORD pcbNeeded, LPDWORD pcReturned)
4074 { BOOL ret;
4075 UNICODE_STRING pNameW, pEnvironmentW;
4076 PWSTR pwstrNameW, pwstrEnvironmentW;
4078 pwstrNameW = asciitounicode(&pNameW, pName);
4079 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
4081 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
4082 Level, pDriverInfo, cbBuf, pcbNeeded,
4083 pcReturned, FALSE);
4084 RtlFreeUnicodeString(&pNameW);
4085 RtlFreeUnicodeString(&pEnvironmentW);
4087 return ret;
4090 static CHAR PortMonitor[] = "Wine Port Monitor";
4091 static CHAR PortDescription[] = "Wine Port";
4093 static BOOL WINSPOOL_ComPortExists( LPCSTR name )
4095 HANDLE handle;
4097 handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
4098 NULL, OPEN_EXISTING, 0, NULL );
4099 if (handle == INVALID_HANDLE_VALUE)
4100 return FALSE;
4101 TRACE("Checking %s exists\n", name );
4102 CloseHandle( handle );
4103 return TRUE;
4106 static DWORD WINSPOOL_CountSerialPorts(void)
4108 CHAR name[6];
4109 DWORD n = 0, i;
4111 for (i=0; i<4; i++)
4113 strcpy( name, "COMx:" );
4114 name[3] = '1' + i;
4115 if (WINSPOOL_ComPortExists( name ))
4116 n++;
4119 return n;
4122 /******************************************************************************
4123 * EnumPortsA (WINSPOOL.@)
4125 * See EnumPortsW.
4127 * BUGS
4128 * ANSI-Version did not call the UNICODE-Version
4131 BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4132 LPDWORD bufneeded,LPDWORD bufreturned)
4134 CHAR portname[10];
4135 DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
4136 const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
4137 HKEY hkey_printer;
4138 BOOL retval = TRUE;
4140 TRACE("(%s,%ld,%p,%ld,%p,%p)\n",
4141 debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
4143 switch( level )
4145 case 1:
4146 info_size = sizeof (PORT_INFO_1A);
4147 break;
4148 case 2:
4149 info_size = sizeof (PORT_INFO_2A);
4150 break;
4151 default:
4152 SetLastError(ERROR_INVALID_LEVEL);
4153 return FALSE;
4156 /* see how many exist */
4158 hkey_printer = 0;
4159 serial_count = WINSPOOL_CountSerialPorts();
4160 printer_count = 0;
4162 r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
4163 if ( r == ERROR_SUCCESS )
4165 RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
4166 &printer_count, NULL, NULL, NULL, NULL);
4168 count = serial_count + printer_count;
4170 /* then fill in the structure info structure once
4171 we know the offset to the first string */
4173 memset( buffer, 0, bufsize );
4174 n = 0;
4175 ofs = info_size*count;
4176 for ( i=0; i<count; i++)
4178 DWORD vallen = sizeof(portname) - 1;
4180 /* get the serial port values, then the printer values */
4181 if ( i < serial_count )
4183 strcpy( portname, "COMx:" );
4184 portname[3] = '1' + i;
4185 if (!WINSPOOL_ComPortExists( portname ))
4186 continue;
4188 TRACE("Found %s\n", portname );
4189 vallen = strlen( portname );
4191 else
4193 r = RegEnumValueA( hkey_printer, i-serial_count,
4194 portname, &vallen, NULL, NULL, NULL, 0 );
4195 if ( r )
4196 continue;
4199 /* add a colon if necessary, and make it upper case */
4200 CharUpperBuffA(portname,vallen);
4201 if (strcasecmp(portname,"nul")!=0)
4202 if (vallen && (portname[vallen-1] != ':') )
4203 lstrcatA(portname,":");
4205 /* add the port info structure if we can fit it */
4206 if ( info_size*(n+1) < bufsize )
4208 if ( level == 1)
4210 PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
4211 info->pName = (LPSTR) &buffer[ofs];
4213 else if ( level == 2)
4215 PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
4216 info->pPortName = (LPSTR) &buffer[ofs];
4217 /* FIXME: fill in more stuff here */
4218 info->pMonitorName = PortMonitor;
4219 info->pDescription = PortDescription;
4220 info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
4223 /* add the name of the port if we can fit it */
4224 if ( ofs < bufsize )
4225 lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
4227 n++;
4229 else
4230 retval = FALSE;
4231 ofs += lstrlenA(portname)+1;
4234 RegCloseKey(hkey_printer);
4236 if(bufneeded)
4237 *bufneeded = ofs;
4239 if(bufreturned)
4240 *bufreturned = n;
4242 return retval;
4245 /******************************************************************************
4246 * EnumPortsW (WINSPOOL.@)
4248 * Enumerate available Ports
4250 * PARAMS
4251 * name [I] Servername or NULL (local Computer)
4252 * level [I] Structure-Level (1 or 2)
4253 * buffer [O] PTR to Buffer that receives the Result
4254 * bufsize [I] Size of Buffer at buffer
4255 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
4256 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
4258 * RETURNS
4259 * Success: TRUE
4260 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
4262 * BUGS
4263 * UNICODE-Version is a stub
4266 BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
4267 LPDWORD bufneeded,LPDWORD bufreturned)
4269 FIXME("(%s,%ld,%p,%ld,%p,%p) - stub\n",
4270 debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
4271 return FALSE;
4274 /******************************************************************************
4275 * GetDefaultPrinterW (WINSPOOL.@)
4277 * FIXME
4278 * This function must read the value from data 'device' of key
4279 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
4281 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
4283 BOOL retval = TRUE;
4284 DWORD insize, len;
4285 WCHAR *buffer, *ptr;
4287 if (!namesize)
4289 SetLastError(ERROR_INVALID_PARAMETER);
4290 return FALSE;
4293 /* make the buffer big enough for the stuff from the profile/registry,
4294 * the content must fit into the local buffer to compute the correct
4295 * size even if the extern buffer is too small or not given.
4296 * (20 for ,driver,port) */
4297 insize = *namesize;
4298 len = max(100, (insize + 20));
4299 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
4301 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
4303 SetLastError (ERROR_FILE_NOT_FOUND);
4304 retval = FALSE;
4305 goto end;
4307 TRACE("%s\n", debugstr_w(buffer));
4309 if ((ptr = strchrW(buffer, ',')) == NULL)
4311 SetLastError(ERROR_INVALID_NAME);
4312 retval = FALSE;
4313 goto end;
4316 *ptr = 0;
4317 *namesize = strlenW(buffer) + 1;
4318 if(!name || (*namesize > insize))
4320 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4321 retval = FALSE;
4322 goto end;
4324 strcpyW(name, buffer);
4326 end:
4327 HeapFree( GetProcessHeap(), 0, buffer);
4328 return retval;
4332 /******************************************************************************
4333 * GetDefaultPrinterA (WINSPOOL.@)
4335 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
4337 BOOL retval = TRUE;
4338 DWORD insize = 0;
4339 WCHAR *bufferW = NULL;
4341 if (!namesize)
4343 SetLastError(ERROR_INVALID_PARAMETER);
4344 return FALSE;
4347 if(name && *namesize) {
4348 insize = *namesize;
4349 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
4352 if(!GetDefaultPrinterW( bufferW, namesize)) {
4353 retval = FALSE;
4354 goto end;
4357 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
4358 NULL, NULL);
4359 if (!*namesize)
4361 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4362 retval = FALSE;
4364 TRACE("0x%08lx/0x%08lx:%s\n", *namesize, insize, debugstr_w(bufferW));
4366 end:
4367 HeapFree( GetProcessHeap(), 0, bufferW);
4368 return retval;
4372 /******************************************************************************
4373 * SetDefaultPrinterW (WINSPOOL.204)
4375 * Set the Name of the Default Printer
4377 * PARAMS
4378 * pszPrinter [I] Name of the Printer or NULL
4380 * RETURNS
4381 * Success: True
4382 * Failure: FALSE
4384 * NOTES
4385 * When the Parameter is NULL or points to an Empty String and
4386 * a Default Printer was already present, then this Function changes nothing.
4387 * Without a Default Printer and NULL (or an Empty String) as Parameter,
4388 * the First enumerated local Printer is used.
4391 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
4394 TRACE("(%s)\n", debugstr_w(pszPrinter));
4396 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4397 return FALSE;
4400 /******************************************************************************
4401 * SetDefaultPrinterA (WINSPOOL.202)
4403 * See SetDefaultPrinterW.
4406 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
4409 TRACE("(%s)\n", debugstr_a(pszPrinter));
4411 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4412 return FALSE;
4416 /******************************************************************************
4417 * SetPrinterDataExA (WINSPOOL.@)
4419 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4420 LPCSTR pValueName, DWORD Type,
4421 LPBYTE pData, DWORD cbData)
4423 HKEY hkeyPrinter, hkeySubkey;
4424 DWORD ret;
4426 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_a(pKeyName),
4427 debugstr_a(pValueName), Type, pData, cbData);
4429 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4430 != ERROR_SUCCESS)
4431 return ret;
4433 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4434 != ERROR_SUCCESS) {
4435 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
4436 RegCloseKey(hkeyPrinter);
4437 return ret;
4439 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
4440 RegCloseKey(hkeySubkey);
4441 RegCloseKey(hkeyPrinter);
4442 return ret;
4445 /******************************************************************************
4446 * SetPrinterDataExW (WINSPOOL.@)
4448 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4449 LPCWSTR pValueName, DWORD Type,
4450 LPBYTE pData, DWORD cbData)
4452 HKEY hkeyPrinter, hkeySubkey;
4453 DWORD ret;
4455 TRACE("(%p, %s, %s %08lx, %p, %08lx)\n", hPrinter, debugstr_w(pKeyName),
4456 debugstr_w(pValueName), Type, pData, cbData);
4458 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4459 != ERROR_SUCCESS)
4460 return ret;
4462 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4463 != ERROR_SUCCESS) {
4464 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
4465 RegCloseKey(hkeyPrinter);
4466 return ret;
4468 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
4469 RegCloseKey(hkeySubkey);
4470 RegCloseKey(hkeyPrinter);
4471 return ret;
4474 /******************************************************************************
4475 * SetPrinterDataA (WINSPOOL.@)
4477 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
4478 LPBYTE pData, DWORD cbData)
4480 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
4481 pData, cbData);
4484 /******************************************************************************
4485 * SetPrinterDataW (WINSPOOL.@)
4487 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
4488 LPBYTE pData, DWORD cbData)
4490 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
4491 pData, cbData);
4494 /******************************************************************************
4495 * GetPrinterDataExA (WINSPOOL.@)
4497 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4498 LPCSTR pValueName, LPDWORD pType,
4499 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4501 HKEY hkeyPrinter, hkeySubkey;
4502 DWORD ret;
4504 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4505 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
4506 pcbNeeded);
4508 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4509 != ERROR_SUCCESS)
4510 return ret;
4512 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
4513 != ERROR_SUCCESS) {
4514 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
4515 RegCloseKey(hkeyPrinter);
4516 return ret;
4518 *pcbNeeded = nSize;
4519 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4520 RegCloseKey(hkeySubkey);
4521 RegCloseKey(hkeyPrinter);
4522 return ret;
4525 /******************************************************************************
4526 * GetPrinterDataExW (WINSPOOL.@)
4528 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4529 LPCWSTR pValueName, LPDWORD pType,
4530 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4532 HKEY hkeyPrinter, hkeySubkey;
4533 DWORD ret;
4535 TRACE("(%p, %s, %s %p, %p, %08lx, %p)\n", hPrinter,
4536 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
4537 pcbNeeded);
4539 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
4540 != ERROR_SUCCESS)
4541 return ret;
4543 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
4544 != ERROR_SUCCESS) {
4545 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
4546 RegCloseKey(hkeyPrinter);
4547 return ret;
4549 *pcbNeeded = nSize;
4550 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
4551 RegCloseKey(hkeySubkey);
4552 RegCloseKey(hkeyPrinter);
4553 return ret;
4556 /******************************************************************************
4557 * GetPrinterDataA (WINSPOOL.@)
4559 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
4560 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4562 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
4563 pData, nSize, pcbNeeded);
4566 /******************************************************************************
4567 * GetPrinterDataW (WINSPOOL.@)
4569 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
4570 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
4572 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
4573 pData, nSize, pcbNeeded);
4576 /*******************************************************************************
4577 * EnumPrinterDataExW [WINSPOOL.@]
4579 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
4580 LPBYTE pEnumValues, DWORD cbEnumValues,
4581 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4583 HKEY hkPrinter, hkSubKey;
4584 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
4585 cbValueNameLen, cbMaxValueLen, cbValueLen,
4586 cbBufSize, dwType;
4587 LPWSTR lpValueName;
4588 HANDLE hHeap;
4589 PBYTE lpValue;
4590 PPRINTER_ENUM_VALUESW ppev;
4592 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
4594 if (pKeyName == NULL || *pKeyName == 0)
4595 return ERROR_INVALID_PARAMETER;
4597 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
4598 if (ret != ERROR_SUCCESS)
4600 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %li\n",
4601 hPrinter, ret);
4602 return ret;
4605 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
4606 if (ret != ERROR_SUCCESS)
4608 r = RegCloseKey (hkPrinter);
4609 if (r != ERROR_SUCCESS)
4610 WARN ("RegCloseKey returned %li\n", r);
4611 TRACE ("RegOpenKeyExW (%p, %s) returned %li\n", hPrinter,
4612 debugstr_w (pKeyName), ret);
4613 return ret;
4616 ret = RegCloseKey (hkPrinter);
4617 if (ret != ERROR_SUCCESS)
4619 ERR ("RegCloseKey returned %li\n", ret);
4620 r = RegCloseKey (hkSubKey);
4621 if (r != ERROR_SUCCESS)
4622 WARN ("RegCloseKey returned %li\n", r);
4623 return ret;
4626 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
4627 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
4628 if (ret != ERROR_SUCCESS)
4630 r = RegCloseKey (hkSubKey);
4631 if (r != ERROR_SUCCESS)
4632 WARN ("RegCloseKey returned %li\n", r);
4633 TRACE ("RegQueryInfoKeyW (%p) returned %li\n", hkSubKey, ret);
4634 return ret;
4637 TRACE ("RegQueryInfoKeyW returned cValues = %li, cbMaxValueNameLen = %li, "
4638 "cbMaxValueLen = %li\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
4640 if (cValues == 0) /* empty key */
4642 r = RegCloseKey (hkSubKey);
4643 if (r != ERROR_SUCCESS)
4644 WARN ("RegCloseKey returned %li\n", r);
4645 *pcbEnumValues = *pnEnumValues = 0;
4646 return ERROR_SUCCESS;
4649 ++cbMaxValueNameLen; /* allow for trailing '\0' */
4651 hHeap = GetProcessHeap ();
4652 if (hHeap == NULL)
4654 ERR ("GetProcessHeap failed\n");
4655 r = RegCloseKey (hkSubKey);
4656 if (r != ERROR_SUCCESS)
4657 WARN ("RegCloseKey returned %li\n", r);
4658 return ERROR_OUTOFMEMORY;
4661 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
4662 if (lpValueName == NULL)
4664 ERR ("Failed to allocate %li bytes from process heap\n",
4665 cbMaxValueNameLen * sizeof (WCHAR));
4666 r = RegCloseKey (hkSubKey);
4667 if (r != ERROR_SUCCESS)
4668 WARN ("RegCloseKey returned %li\n", r);
4669 return ERROR_OUTOFMEMORY;
4672 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
4673 if (lpValue == NULL)
4675 ERR ("Failed to allocate %li bytes from process heap\n", cbMaxValueLen);
4676 if (HeapFree (hHeap, 0, lpValueName) == 0)
4677 WARN ("HeapFree failed with code %li\n", GetLastError ());
4678 r = RegCloseKey (hkSubKey);
4679 if (r != ERROR_SUCCESS)
4680 WARN ("RegCloseKey returned %li\n", r);
4681 return ERROR_OUTOFMEMORY;
4684 TRACE ("pass 1: calculating buffer required for all names and values\n");
4686 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
4688 TRACE ("%li bytes required for %li headers\n", cbBufSize, cValues);
4690 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4692 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4693 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4694 NULL, NULL, lpValue, &cbValueLen);
4695 if (ret != ERROR_SUCCESS)
4697 if (HeapFree (hHeap, 0, lpValue) == 0)
4698 WARN ("HeapFree failed with code %li\n", GetLastError ());
4699 if (HeapFree (hHeap, 0, lpValueName) == 0)
4700 WARN ("HeapFree failed with code %li\n", GetLastError ());
4701 r = RegCloseKey (hkSubKey);
4702 if (r != ERROR_SUCCESS)
4703 WARN ("RegCloseKey returned %li\n", r);
4704 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4705 return ret;
4708 TRACE ("%s [%li]: name needs %li bytes, data needs %li bytes\n",
4709 debugstr_w (lpValueName), dwIndex,
4710 (cbValueNameLen + 1) * sizeof (WCHAR), cbValueLen);
4712 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
4713 cbBufSize += cbValueLen;
4716 TRACE ("%li bytes required for all %li values\n", cbBufSize, cValues);
4718 *pcbEnumValues = cbBufSize;
4719 *pnEnumValues = cValues;
4721 if (cbEnumValues < cbBufSize) /* buffer too small */
4723 if (HeapFree (hHeap, 0, lpValue) == 0)
4724 WARN ("HeapFree failed with code %li\n", GetLastError ());
4725 if (HeapFree (hHeap, 0, lpValueName) == 0)
4726 WARN ("HeapFree failed with code %li\n", GetLastError ());
4727 r = RegCloseKey (hkSubKey);
4728 if (r != ERROR_SUCCESS)
4729 WARN ("RegCloseKey returned %li\n", r);
4730 TRACE ("%li byte buffer is not large enough\n", cbEnumValues);
4731 return ERROR_MORE_DATA;
4734 TRACE ("pass 2: copying all names and values to buffer\n");
4736 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
4737 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
4739 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
4741 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
4742 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
4743 NULL, &dwType, lpValue, &cbValueLen);
4744 if (ret != ERROR_SUCCESS)
4746 if (HeapFree (hHeap, 0, lpValue) == 0)
4747 WARN ("HeapFree failed with code %li\n", GetLastError ());
4748 if (HeapFree (hHeap, 0, lpValueName) == 0)
4749 WARN ("HeapFree failed with code %li\n", GetLastError ());
4750 r = RegCloseKey (hkSubKey);
4751 if (r != ERROR_SUCCESS)
4752 WARN ("RegCloseKey returned %li\n", r);
4753 TRACE ("RegEnumValueW (%li) returned %li\n", dwIndex, ret);
4754 return ret;
4757 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
4758 memcpy (pEnumValues, lpValueName, cbValueNameLen);
4759 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
4760 pEnumValues += cbValueNameLen;
4762 /* return # of *bytes* (including trailing \0), not # of chars */
4763 ppev[dwIndex].cbValueName = cbValueNameLen;
4765 ppev[dwIndex].dwType = dwType;
4767 memcpy (pEnumValues, lpValue, cbValueLen);
4768 ppev[dwIndex].pData = pEnumValues;
4769 pEnumValues += cbValueLen;
4771 ppev[dwIndex].cbData = cbValueLen;
4773 TRACE ("%s [%li]: copied name (%li bytes) and data (%li bytes)\n",
4774 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
4777 if (HeapFree (hHeap, 0, lpValue) == 0)
4779 ret = GetLastError ();
4780 ERR ("HeapFree failed with code %li\n", ret);
4781 if (HeapFree (hHeap, 0, lpValueName) == 0)
4782 WARN ("HeapFree failed with code %li\n", GetLastError ());
4783 r = RegCloseKey (hkSubKey);
4784 if (r != ERROR_SUCCESS)
4785 WARN ("RegCloseKey returned %li\n", r);
4786 return ret;
4789 if (HeapFree (hHeap, 0, lpValueName) == 0)
4791 ret = GetLastError ();
4792 ERR ("HeapFree failed with code %li\n", ret);
4793 r = RegCloseKey (hkSubKey);
4794 if (r != ERROR_SUCCESS)
4795 WARN ("RegCloseKey returned %li\n", r);
4796 return ret;
4799 ret = RegCloseKey (hkSubKey);
4800 if (ret != ERROR_SUCCESS)
4802 ERR ("RegCloseKey returned %li\n", ret);
4803 return ret;
4806 return ERROR_SUCCESS;
4809 /*******************************************************************************
4810 * EnumPrinterDataExA [WINSPOOL.@]
4812 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
4813 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
4814 * what Windows 2000 SP1 does.
4817 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
4818 LPBYTE pEnumValues, DWORD cbEnumValues,
4819 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
4821 INT len;
4822 LPWSTR pKeyNameW;
4823 DWORD ret, dwIndex, dwBufSize;
4824 HANDLE hHeap;
4825 LPSTR pBuffer;
4827 TRACE ("%p %s\n", hPrinter, pKeyName);
4829 if (pKeyName == NULL || *pKeyName == 0)
4830 return ERROR_INVALID_PARAMETER;
4832 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
4833 if (len == 0)
4835 ret = GetLastError ();
4836 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4837 return ret;
4840 hHeap = GetProcessHeap ();
4841 if (hHeap == NULL)
4843 ERR ("GetProcessHeap failed\n");
4844 return ERROR_OUTOFMEMORY;
4847 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
4848 if (pKeyNameW == NULL)
4850 ERR ("Failed to allocate %li bytes from process heap\n",
4851 (LONG) len * sizeof (WCHAR));
4852 return ERROR_OUTOFMEMORY;
4855 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
4857 ret = GetLastError ();
4858 ERR ("MultiByteToWideChar failed with code %li\n", ret);
4859 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4860 WARN ("HeapFree failed with code %li\n", GetLastError ());
4861 return ret;
4864 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
4865 pcbEnumValues, pnEnumValues);
4866 if (ret != ERROR_SUCCESS)
4868 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4869 WARN ("HeapFree failed with code %li\n", GetLastError ());
4870 TRACE ("EnumPrinterDataExW returned %li\n", ret);
4871 return ret;
4874 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
4876 ret = GetLastError ();
4877 ERR ("HeapFree failed with code %li\n", ret);
4878 return ret;
4881 if (*pnEnumValues == 0) /* empty key */
4882 return ERROR_SUCCESS;
4884 dwBufSize = 0;
4885 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4887 PPRINTER_ENUM_VALUESW ppev =
4888 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4890 if (dwBufSize < ppev->cbValueName)
4891 dwBufSize = ppev->cbValueName;
4893 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
4894 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
4895 dwBufSize = ppev->cbData;
4898 TRACE ("Largest Unicode name or value is %li bytes\n", dwBufSize);
4900 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
4901 if (pBuffer == NULL)
4903 ERR ("Failed to allocate %li bytes from process heap\n", dwBufSize);
4904 return ERROR_OUTOFMEMORY;
4907 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
4909 PPRINTER_ENUM_VALUESW ppev =
4910 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
4912 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
4913 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
4914 NULL);
4915 if (len == 0)
4917 ret = GetLastError ();
4918 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4919 if (HeapFree (hHeap, 0, pBuffer) == 0)
4920 WARN ("HeapFree failed with code %li\n", GetLastError ());
4921 return ret;
4924 memcpy (ppev->pValueName, pBuffer, len);
4926 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4928 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
4929 ppev->dwType != REG_MULTI_SZ)
4930 continue;
4932 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
4933 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
4934 if (len == 0)
4936 ret = GetLastError ();
4937 ERR ("WideCharToMultiByte failed with code %li\n", ret);
4938 if (HeapFree (hHeap, 0, pBuffer) == 0)
4939 WARN ("HeapFree failed with code %li\n", GetLastError ());
4940 return ret;
4943 memcpy (ppev->pData, pBuffer, len);
4945 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
4946 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
4949 if (HeapFree (hHeap, 0, pBuffer) == 0)
4951 ret = GetLastError ();
4952 ERR ("HeapFree failed with code %li\n", ret);
4953 return ret;
4956 return ERROR_SUCCESS;
4959 /******************************************************************************
4960 * AbortPrinter (WINSPOOL.@)
4962 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
4964 FIXME("(%p), stub!\n", hPrinter);
4965 return TRUE;
4968 /******************************************************************************
4969 * AddPortA (WINSPOOL.@)
4971 * See AddPortW.
4974 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
4976 FIXME("(%s, %p, %s), stub!\n",debugstr_a(pName),hWnd,debugstr_a(pMonitorName));
4977 return FALSE;
4980 /******************************************************************************
4981 * AddPortW (WINSPOOL.@)
4983 * Add a Port for a specific Monitor
4985 * PARAMS
4986 * pName [I] Servername or NULL (local Computer)
4987 * hWnd [I] Handle to parent Window for the Dialog-Box
4988 * pMonitorName [I] Name of the Monitor that manage the Port
4990 * RETURNS
4991 * Success: TRUE
4992 * Failure: FALSE
4994 * BUGS
4995 * only a Stub
4998 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
5000 FIXME("(%s, %p, %s), stub!\n",debugstr_w(pName),hWnd,debugstr_w(pMonitorName));
5001 return FALSE;
5004 /******************************************************************************
5005 * AddPortExA (WINSPOOL.@)
5007 * See AddPortExW.
5010 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
5012 FIXME("(%p, %s, %ld, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
5013 lpBuffer, debugstr_a(lpMonitorName));
5014 return FALSE;
5017 /******************************************************************************
5018 * AddPortExW (WINSPOOL.@)
5020 * Add a Port for a specific Monitor, without presenting a user interface
5022 * PARAMS
5023 * hMonitor [I] Handle from InitializePrintMonitor2()
5024 * pName [I] Servername or NULL (local Computer)
5025 * Level [I] Structure-Level (1 or 2) for lpBuffer
5026 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
5027 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
5029 * RETURNS
5030 * Success: TRUE
5031 * Failure: FALSE
5033 * BUGS
5034 * only a Stub
5037 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
5039 FIXME("(%p, %s, %ld, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
5040 lpBuffer, debugstr_w(lpMonitorName));
5041 return FALSE;
5044 /******************************************************************************
5045 * AddPrinterConnectionA (WINSPOOL.@)
5047 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
5049 FIXME("%s\n", debugstr_a(pName));
5050 return FALSE;
5053 /******************************************************************************
5054 * AddPrinterConnectionW (WINSPOOL.@)
5056 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
5058 FIXME("%s\n", debugstr_w(pName));
5059 return FALSE;
5062 /******************************************************************************
5063 * AddPrinterDriverExW (WINSPOOL.@)
5065 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
5066 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5068 FIXME("%s %ld %p %ld\n", debugstr_w(pName),
5069 Level, pDriverInfo, dwFileCopyFlags);
5070 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5071 return FALSE;
5074 /******************************************************************************
5075 * AddPrinterDriverExA (WINSPOOL.@)
5077 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
5078 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
5080 FIXME("%s %ld %p %ld\n", debugstr_a(pName),
5081 Level, pDriverInfo, dwFileCopyFlags);
5082 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
5083 return FALSE;
5086 /******************************************************************************
5087 * ConfigurePortA (WINSPOOL.@)
5089 * See ConfigurePortW.
5092 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
5094 FIXME("%s %p %s\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
5095 return FALSE;
5098 /******************************************************************************
5099 * ConfigurePortW (WINSPOOL.@)
5101 * Display the Configuration-Dialog for a specific Port
5103 * PARAMS
5104 * pName [I] Servername or NULL (local Computer)
5105 * hWnd [I] Handle to parent Window for the Dialog-Box
5106 * pPortName [I] Name of the Port, that should be configured
5108 * RETURNS
5109 * Success: TRUE
5110 * Failure: FALSE
5112 * BUGS
5113 * only a Stub
5116 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
5118 FIXME("%s %p %s\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
5119 return FALSE;
5122 /******************************************************************************
5123 * ConnectToPrinterDlg (WINSPOOL.@)
5125 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
5127 FIXME("%p %lx\n", hWnd, Flags);
5128 return NULL;
5131 /******************************************************************************
5132 * DeletePrinterConnectionA (WINSPOOL.@)
5134 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
5136 FIXME("%s\n", debugstr_a(pName));
5137 return TRUE;
5140 /******************************************************************************
5141 * DeletePrinterConnectionW (WINSPOOL.@)
5143 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
5145 FIXME("%s\n", debugstr_w(pName));
5146 return TRUE;
5149 /******************************************************************************
5150 * DeletePrinterDriverExW (WINSPOOL.@)
5152 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
5153 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5155 FIXME("%s %s %s %lx %lx\n", debugstr_w(pName), debugstr_w(pEnvironment),
5156 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
5157 return TRUE;
5160 /******************************************************************************
5161 * DeletePrinterDriverExA (WINSPOOL.@)
5163 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
5164 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
5166 FIXME("%s %s %s %lx %lx\n", debugstr_a(pName), debugstr_a(pEnvironment),
5167 debugstr_a(pDriverName), dwDeleteFlag, dwVersionFlag);
5168 return TRUE;
5171 /******************************************************************************
5172 * DeletePrinterDataExW (WINSPOOL.@)
5174 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
5175 LPCWSTR pValueName)
5177 FIXME("%p %s %s\n", hPrinter,
5178 debugstr_w(pKeyName), debugstr_w(pValueName));
5179 return ERROR_INVALID_PARAMETER;
5182 /******************************************************************************
5183 * DeletePrinterDataExA (WINSPOOL.@)
5185 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
5186 LPCSTR pValueName)
5188 FIXME("%p %s %s\n", hPrinter,
5189 debugstr_a(pKeyName), debugstr_a(pValueName));
5190 return ERROR_INVALID_PARAMETER;
5193 /******************************************************************************
5194 * DeletePrintProcessorA (WINSPOOL.@)
5196 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
5198 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5199 debugstr_a(pPrintProcessorName));
5200 return TRUE;
5203 /******************************************************************************
5204 * DeletePrintProcessorW (WINSPOOL.@)
5206 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
5208 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5209 debugstr_w(pPrintProcessorName));
5210 return TRUE;
5213 /******************************************************************************
5214 * DeletePrintProvidorA (WINSPOOL.@)
5216 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
5218 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
5219 debugstr_a(pPrintProviderName));
5220 return TRUE;
5223 /******************************************************************************
5224 * DeletePrintProvidorW (WINSPOOL.@)
5226 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
5228 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
5229 debugstr_w(pPrintProviderName));
5230 return TRUE;
5233 /******************************************************************************
5234 * EnumFormsA (WINSPOOL.@)
5236 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5237 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5239 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5240 return FALSE;
5243 /******************************************************************************
5244 * EnumFormsW (WINSPOOL.@)
5246 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
5247 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
5249 FIXME("%p %lx %p %lx %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
5250 return FALSE;
5253 /*****************************************************************************
5254 * EnumMonitorsA [WINSPOOL.@]
5256 * See EnumMonitorsW.
5259 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
5260 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5262 BOOL res;
5263 LPBYTE bufferW = NULL;
5264 LPWSTR nameW = NULL;
5265 DWORD needed = 0;
5266 DWORD numentries = 0;
5267 INT len;
5269 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
5270 cbBuf, pcbNeeded, pcReturned);
5272 /* convert servername to unicode */
5273 if (pName) {
5274 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5275 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5276 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5278 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
5279 needed = cbBuf * sizeof(WCHAR);
5280 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5281 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5283 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5284 if (pcbNeeded) needed = *pcbNeeded;
5285 /* HeapReAlloc return NULL, when bufferW was NULL */
5286 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5287 HeapAlloc(GetProcessHeap(), 0, needed);
5289 /* Try again with the large Buffer */
5290 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5292 numentries = pcReturned ? *pcReturned : 0;
5293 needed = 0;
5295 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
5296 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5298 if (res) {
5299 /* EnumMonitorsW collected all Data. Parse them to caclulate ANSI-Size */
5300 DWORD entrysize = 0;
5301 DWORD index;
5302 LPSTR ptr;
5303 LPMONITOR_INFO_2W mi2w;
5304 LPMONITOR_INFO_2A mi2a;
5306 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
5307 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
5309 /* First pass: calculate the size for all Entries */
5310 mi2w = (LPMONITOR_INFO_2W) bufferW;
5311 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5312 index = 0;
5313 while (index < numentries) {
5314 index++;
5315 needed += entrysize; /* MONITOR_INFO_?A */
5316 TRACE("%p: parsing #%ld (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
5318 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5319 NULL, 0, NULL, NULL);
5320 if (Level > 1) {
5321 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5322 NULL, 0, NULL, NULL);
5323 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5324 NULL, 0, NULL, NULL);
5326 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5327 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5328 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5331 /* check for errors and quit on failure */
5332 if (cbBuf < needed) {
5333 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5334 res = FALSE;
5335 goto emA_cleanup;
5337 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
5338 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
5339 cbBuf -= len ; /* free Bytes in the user-Buffer */
5340 mi2w = (LPMONITOR_INFO_2W) bufferW;
5341 mi2a = (LPMONITOR_INFO_2A) pMonitors;
5342 index = 0;
5343 /* Second Pass: Fill the User Buffer (if we have one) */
5344 while ((index < numentries) && pMonitors) {
5345 index++;
5346 TRACE("%p: writing MONITOR_INFO_%ldA #%ld\n", mi2a, Level, index);
5347 mi2a->pName = ptr;
5348 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
5349 ptr, cbBuf , NULL, NULL);
5350 ptr += len;
5351 cbBuf -= len;
5352 if (Level > 1) {
5353 mi2a->pEnvironment = ptr;
5354 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
5355 ptr, cbBuf, NULL, NULL);
5356 ptr += len;
5357 cbBuf -= len;
5359 mi2a->pDLLName = ptr;
5360 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
5361 ptr, cbBuf, NULL, NULL);
5362 ptr += len;
5363 cbBuf -= len;
5365 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
5366 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
5367 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
5370 emA_cleanup:
5371 if (pcbNeeded) *pcbNeeded = needed;
5372 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5374 HeapFree(GetProcessHeap(), 0, nameW);
5375 HeapFree(GetProcessHeap(), 0, bufferW);
5377 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5378 (res), GetLastError(), needed, numentries);
5380 return (res);
5384 /*****************************************************************************
5385 * EnumMonitorsW [WINSPOOL.@]
5387 * Enumerate available Port-Monitors
5389 * PARAMS
5390 * pName [I] Servername or NULL (local Computer)
5391 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
5392 * pMonitors [O] PTR to Buffer that receives the Result
5393 * cbBuf [I] Size of Buffer at pMonitors
5394 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
5395 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
5397 * RETURNS
5398 * Success: TRUE
5399 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
5401 * NOTES
5402 * Windows reads the Registry once and cache the Results.
5404 *| Language-Monitors are also installed in the same Registry-Location but
5405 *| they are filtered in Windows (not returned by EnumMonitors).
5406 *| We do no filtering to simplify our Code.
5409 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
5410 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5412 DWORD needed = 0;
5413 DWORD numentries = 0;
5414 BOOL res = FALSE;
5416 TRACE("(%s, %ld, %p, %ld, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
5417 cbBuf, pcbNeeded, pcReturned);
5419 if (pName && (lstrlenW(pName))) {
5420 FIXME("for Server %s not implemented\n", debugstr_w(pName));
5421 SetLastError(ERROR_ACCESS_DENIED);
5422 goto emW_cleanup;
5425 /* Level is not checked in win9x */
5426 if (!Level || (Level > 2)) {
5427 WARN("level (%ld) is ignored in win9x\n", Level);
5428 SetLastError(ERROR_INVALID_LEVEL);
5429 goto emW_cleanup;
5431 if (!pcbNeeded) {
5432 SetLastError(RPC_X_NULL_REF_POINTER);
5433 goto emW_cleanup;
5436 /* Scan all Monitor-Keys */
5437 numentries = 0;
5438 needed = get_local_monitors(Level, NULL, 0, &numentries);
5440 /* we calculated the needed buffersize. now do the error-checks */
5441 if (cbBuf < needed) {
5442 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5443 goto emW_cleanup;
5445 else if (!pMonitors || !pcReturned) {
5446 SetLastError(RPC_X_NULL_REF_POINTER);
5447 goto emW_cleanup;
5450 /* fill the Buffer with the Monitor-Keys */
5451 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
5452 res = TRUE;
5454 emW_cleanup:
5455 if (pcbNeeded) *pcbNeeded = needed;
5456 if (pcReturned) *pcReturned = numentries;
5458 TRACE("returning %d with %ld (%ld byte for %ld entries)\n",
5459 res, GetLastError(), needed, numentries);
5461 return (res);
5464 /******************************************************************************
5465 * XcvDataW (WINSPOOL.@)
5467 * Notes:
5468 * There doesn't seem to be an A version...
5470 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
5471 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
5472 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
5474 FIXME("%p %s %p %ld %p %ld %p %p\n", hXcv, debugstr_w(pszDataName),
5475 pInputData, cbInputData, pOutputData,
5476 cbOutputData, pcbOutputNeeded, pdwStatus);
5477 return FALSE;
5480 /*****************************************************************************
5481 * EnumPrinterDataA [WINSPOOL.@]
5484 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
5485 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5486 DWORD cbData, LPDWORD pcbData )
5488 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5489 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5490 return ERROR_NO_MORE_ITEMS;
5493 /*****************************************************************************
5494 * EnumPrinterDataW [WINSPOOL.@]
5497 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
5498 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
5499 DWORD cbData, LPDWORD pcbData )
5501 FIXME("%p %lx %p %lx %p %p %p %lx %p\n", hPrinter, dwIndex, pValueName,
5502 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
5503 return ERROR_NO_MORE_ITEMS;
5506 /*****************************************************************************
5507 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
5510 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
5511 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5512 LPDWORD pcbNeeded, LPDWORD pcReturned)
5514 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_a(pName),
5515 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
5516 pcbNeeded, pcReturned);
5517 return FALSE;
5520 /*****************************************************************************
5521 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
5524 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
5525 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
5526 LPDWORD pcbNeeded, LPDWORD pcReturned)
5528 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5529 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
5530 pcbNeeded, pcReturned);
5531 return FALSE;
5534 /*****************************************************************************
5535 * EnumPrintProcessorsA [WINSPOOL.@]
5538 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5539 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5541 FIXME("Stub: %s %s %ld %p %ld %p %p\n", pName, pEnvironment, Level,
5542 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
5543 return FALSE;
5546 /*****************************************************************************
5547 * EnumPrintProcessorsW [WINSPOOL.@]
5550 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5551 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
5553 FIXME("Stub: %s %s %ld %p %ld %p %p\n", debugstr_w(pName),
5554 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
5555 cbBuf, pcbNeeded, pcbReturned);
5556 return FALSE;
5559 /*****************************************************************************
5560 * ExtDeviceMode [WINSPOOL.@]
5563 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
5564 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
5565 DWORD fMode)
5567 FIXME("Stub: %p %p %p %s %s %p %s %lx\n", hWnd, hInst, pDevModeOutput,
5568 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
5569 debugstr_a(pProfile), fMode);
5570 return -1;
5573 /*****************************************************************************
5574 * FindClosePrinterChangeNotification [WINSPOOL.@]
5577 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
5579 FIXME("Stub: %p\n", hChange);
5580 return TRUE;
5583 /*****************************************************************************
5584 * FindFirstPrinterChangeNotification [WINSPOOL.@]
5587 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
5588 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
5590 FIXME("Stub: %p %lx %lx %p\n",
5591 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
5592 return INVALID_HANDLE_VALUE;
5595 /*****************************************************************************
5596 * FindNextPrinterChangeNotification [WINSPOOL.@]
5599 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
5600 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
5602 FIXME("Stub: %p %p %p %p\n",
5603 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
5604 return FALSE;
5607 /*****************************************************************************
5608 * FreePrinterNotifyInfo [WINSPOOL.@]
5611 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
5613 FIXME("Stub: %p\n", pPrinterNotifyInfo);
5614 return TRUE;
5617 /*****************************************************************************
5618 * string_to_buf
5620 * Copies a unicode string into a buffer. The buffer will either contain unicode or
5621 * ansi depending on the unicode parameter.
5623 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
5625 if(!str)
5627 *size = 0;
5628 return TRUE;
5631 if(unicode)
5633 *size = (strlenW(str) + 1) * sizeof(WCHAR);
5634 if(*size <= cb)
5636 memcpy(ptr, str, *size);
5637 return TRUE;
5639 return FALSE;
5641 else
5643 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
5644 if(*size <= cb)
5646 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
5647 return TRUE;
5649 return FALSE;
5653 /*****************************************************************************
5654 * get_job_info_1
5656 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
5657 LPDWORD pcbNeeded, BOOL unicode)
5659 DWORD size, left = cbBuf;
5660 BOOL space = (cbBuf > 0);
5661 LPBYTE ptr = buf;
5663 *pcbNeeded = 0;
5665 if(space)
5667 ji1->JobId = job->job_id;
5670 string_to_buf(job->document_title, ptr, left, &size, unicode);
5671 if(space && size <= left)
5673 ji1->pDocument = (LPWSTR)ptr;
5674 ptr += size;
5675 left -= size;
5677 else
5678 space = FALSE;
5679 *pcbNeeded += size;
5681 return space;
5684 /*****************************************************************************
5685 * get_job_info_2
5687 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
5688 LPDWORD pcbNeeded, BOOL unicode)
5690 DWORD size, left = cbBuf;
5691 BOOL space = (cbBuf > 0);
5692 LPBYTE ptr = buf;
5694 *pcbNeeded = 0;
5696 if(space)
5698 ji2->JobId = job->job_id;
5701 string_to_buf(job->document_title, ptr, left, &size, unicode);
5702 if(space && size <= left)
5704 ji2->pDocument = (LPWSTR)ptr;
5705 ptr += size;
5706 left -= size;
5708 else
5709 space = FALSE;
5710 *pcbNeeded += size;
5712 return space;
5715 /*****************************************************************************
5716 * get_job_info
5718 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5719 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
5721 BOOL ret = FALSE;
5722 DWORD needed = 0, size;
5723 job_t *job;
5724 LPBYTE ptr = pJob;
5726 TRACE("%p %ld %ld %p %ld %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
5728 EnterCriticalSection(&printer_handles_cs);
5729 job = get_job(hPrinter, JobId);
5730 if(!job)
5731 goto end;
5733 switch(Level)
5735 case 1:
5736 size = sizeof(JOB_INFO_1W);
5737 if(cbBuf >= size)
5739 cbBuf -= size;
5740 ptr += size;
5741 memset(pJob, 0, size);
5743 else
5744 cbBuf = 0;
5745 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
5746 needed += size;
5747 break;
5749 case 2:
5750 size = sizeof(JOB_INFO_2W);
5751 if(cbBuf >= size)
5753 cbBuf -= size;
5754 ptr += size;
5755 memset(pJob, 0, size);
5757 else
5758 cbBuf = 0;
5759 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
5760 needed += size;
5761 break;
5763 case 3:
5764 size = sizeof(JOB_INFO_3);
5765 if(cbBuf >= size)
5767 cbBuf -= size;
5768 memset(pJob, 0, size);
5769 ret = TRUE;
5771 else
5772 cbBuf = 0;
5773 needed = size;
5774 break;
5776 default:
5777 SetLastError(ERROR_INVALID_LEVEL);
5778 goto end;
5780 if(pcbNeeded)
5781 *pcbNeeded = needed;
5782 end:
5783 LeaveCriticalSection(&printer_handles_cs);
5784 return ret;
5787 /*****************************************************************************
5788 * GetJobA [WINSPOOL.@]
5791 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5792 DWORD cbBuf, LPDWORD pcbNeeded)
5794 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
5797 /*****************************************************************************
5798 * GetJobW [WINSPOOL.@]
5801 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
5802 DWORD cbBuf, LPDWORD pcbNeeded)
5804 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
5807 /*****************************************************************************
5808 * schedule_lpr
5810 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
5812 char *unixname, *queue, *cmd;
5813 char fmt[] = "lpr -P%s %s";
5814 DWORD len;
5816 if(!(unixname = wine_get_unix_file_name(filename)))
5817 return FALSE;
5819 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5820 queue = HeapAlloc(GetProcessHeap(), 0, len);
5821 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5823 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
5824 sprintf(cmd, fmt, queue, unixname);
5826 TRACE("printing with: %s\n", cmd);
5827 system(cmd);
5829 HeapFree(GetProcessHeap(), 0, cmd);
5830 HeapFree(GetProcessHeap(), 0, queue);
5831 HeapFree(GetProcessHeap(), 0, unixname);
5832 return TRUE;
5835 /*****************************************************************************
5836 * schedule_cups
5838 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
5840 #if HAVE_CUPS_CUPS_H
5841 if(pcupsPrintFile)
5843 char *unixname, *queue, *doc_titleA;
5844 DWORD len;
5845 BOOL ret;
5847 if(!(unixname = wine_get_unix_file_name(filename)))
5848 return FALSE;
5850 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
5851 queue = HeapAlloc(GetProcessHeap(), 0, len);
5852 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
5854 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
5855 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
5856 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
5858 TRACE("printing via cups\n");
5859 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
5860 HeapFree(GetProcessHeap(), 0, doc_titleA);
5861 HeapFree(GetProcessHeap(), 0, queue);
5862 HeapFree(GetProcessHeap(), 0, unixname);
5863 return ret;
5865 else
5866 #endif
5868 return schedule_lpr(printer_name, filename);
5872 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
5874 LPWSTR filename;
5876 switch(msg)
5878 case WM_INITDIALOG:
5879 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
5880 return TRUE;
5882 case WM_COMMAND:
5883 if(HIWORD(wparam) == BN_CLICKED)
5885 if(LOWORD(wparam) == IDOK)
5887 HANDLE hf;
5888 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
5889 LPWSTR *output;
5891 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
5892 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
5894 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
5896 WCHAR caption[200], message[200];
5897 int mb_ret;
5899 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5900 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
5901 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
5902 if(mb_ret == IDCANCEL)
5904 HeapFree(GetProcessHeap(), 0, filename);
5905 return TRUE;
5908 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5909 if(hf == INVALID_HANDLE_VALUE)
5911 WCHAR caption[200], message[200];
5913 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
5914 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
5915 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
5916 HeapFree(GetProcessHeap(), 0, filename);
5917 return TRUE;
5919 CloseHandle(hf);
5920 DeleteFileW(filename);
5921 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
5922 *output = filename;
5923 EndDialog(hwnd, IDOK);
5924 return TRUE;
5926 if(LOWORD(wparam) == IDCANCEL)
5928 EndDialog(hwnd, IDCANCEL);
5929 return TRUE;
5932 return FALSE;
5934 return FALSE;
5937 /*****************************************************************************
5938 * get_filename
5940 static BOOL get_filename(LPWSTR *filename)
5942 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
5943 file_dlg_proc, (LPARAM)filename) == IDOK;
5946 /*****************************************************************************
5947 * schedule_file
5949 static BOOL schedule_file(LPCWSTR filename)
5951 LPWSTR output = NULL;
5953 if(get_filename(&output))
5955 TRACE("copy to %s\n", debugstr_w(output));
5956 CopyFileW(filename, output, FALSE);
5957 HeapFree(GetProcessHeap(), 0, output);
5958 return TRUE;
5960 return FALSE;
5963 /*****************************************************************************
5964 * schedule_pipe
5966 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
5968 #ifdef HAVE_FORK
5969 char *unixname, *cmdA;
5970 DWORD len;
5971 int fds[2] = {-1, -1}, file_fd = -1, no_read;
5972 BOOL ret = FALSE;
5973 char buf[1024];
5975 if(!(unixname = wine_get_unix_file_name(filename)))
5976 return FALSE;
5978 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
5979 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
5980 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
5982 TRACE("printing with: %s\n", cmdA);
5984 if((file_fd = open(unixname, O_RDONLY)) == -1)
5985 goto end;
5987 if (pipe(fds))
5989 ERR("pipe() failed!\n");
5990 goto end;
5993 if (fork() == 0)
5995 close(0);
5996 dup2(fds[0], 0);
5997 close(fds[1]);
5999 /* reset signals that we previously set to SIG_IGN */
6000 signal(SIGPIPE, SIG_DFL);
6001 signal(SIGCHLD, SIG_DFL);
6003 system(cmdA);
6004 exit(0);
6007 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
6008 write(fds[1], buf, no_read);
6010 ret = TRUE;
6012 end:
6013 if(file_fd != -1) close(file_fd);
6014 if(fds[0] != -1) close(fds[0]);
6015 if(fds[1] != -1) close(fds[1]);
6017 HeapFree(GetProcessHeap(), 0, cmdA);
6018 HeapFree(GetProcessHeap(), 0, unixname);
6019 return ret;
6020 #else
6021 return FALSE;
6022 #endif
6025 /*****************************************************************************
6026 * schedule_unixfile
6028 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
6030 int in_fd, out_fd, no_read;
6031 char buf[1024];
6032 BOOL ret = FALSE;
6033 char *unixname, *outputA;
6034 DWORD len;
6036 if(!(unixname = wine_get_unix_file_name(filename)))
6037 return FALSE;
6039 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
6040 outputA = HeapAlloc(GetProcessHeap(), 0, len);
6041 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
6043 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
6044 in_fd = open(unixname, O_RDONLY);
6045 if(out_fd == -1 || in_fd == -1)
6046 goto end;
6048 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
6049 write(out_fd, buf, no_read);
6051 ret = TRUE;
6052 end:
6053 if(in_fd != -1) close(in_fd);
6054 if(out_fd != -1) close(out_fd);
6055 HeapFree(GetProcessHeap(), 0, outputA);
6056 HeapFree(GetProcessHeap(), 0, unixname);
6057 return ret;
6060 /*****************************************************************************
6061 * ScheduleJob [WINSPOOL.@]
6064 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
6066 opened_printer_t *printer;
6067 BOOL ret = FALSE;
6068 struct list *cursor, *cursor2;
6070 TRACE("(%p, %lx)\n", hPrinter, dwJobID);
6071 EnterCriticalSection(&printer_handles_cs);
6072 printer = get_opened_printer(hPrinter);
6073 if(!printer)
6074 goto end;
6076 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
6078 job_t *job = LIST_ENTRY(cursor, job_t, entry);
6079 HANDLE hf;
6081 if(job->job_id != dwJobID) continue;
6083 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
6084 if(hf != INVALID_HANDLE_VALUE)
6086 PRINTER_INFO_5W *pi5;
6087 DWORD needed;
6088 HKEY hkey;
6089 WCHAR output[1024];
6090 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
6091 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
6093 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
6094 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
6095 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
6096 TRACE("need to schedule job %ld filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
6097 debugstr_w(pi5->pPortName));
6099 output[0] = 0;
6101 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
6102 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
6104 DWORD type, count = sizeof(output);
6105 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
6106 RegCloseKey(hkey);
6108 if(output[0] == '|')
6110 schedule_pipe(output + 1, job->filename);
6112 else if(output[0])
6114 schedule_unixfile(output, job->filename);
6116 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
6118 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
6120 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
6122 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
6124 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
6126 schedule_file(job->filename);
6128 else
6130 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
6132 HeapFree(GetProcessHeap(), 0, pi5);
6133 CloseHandle(hf);
6134 DeleteFileW(job->filename);
6136 list_remove(cursor);
6137 HeapFree(GetProcessHeap(), 0, job->document_title);
6138 HeapFree(GetProcessHeap(), 0, job->filename);
6139 HeapFree(GetProcessHeap(), 0, job);
6140 ret = TRUE;
6141 break;
6143 end:
6144 LeaveCriticalSection(&printer_handles_cs);
6145 return ret;
6148 /*****************************************************************************
6149 * StartDocDlgA [WINSPOOL.@]
6151 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
6153 UNICODE_STRING usBuffer;
6154 DOCINFOW docW;
6155 LPWSTR retW;
6156 LPSTR ret = NULL;
6158 docW.cbSize = sizeof(docW);
6159 docW.lpszDocName = asciitounicode(&usBuffer, doc->lpszDocName);
6160 docW.lpszOutput = asciitounicode(&usBuffer, doc->lpszOutput);
6161 docW.lpszDatatype = asciitounicode(&usBuffer, doc->lpszDatatype);
6162 docW.fwType = doc->fwType;
6164 retW = StartDocDlgW(hPrinter, &docW);
6166 if(retW)
6168 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
6169 ret = HeapAlloc(GetProcessHeap(), 0, len);
6170 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
6171 HeapFree(GetProcessHeap(), 0, retW);
6174 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDatatype);
6175 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszOutput);
6176 HeapFree(GetProcessHeap(), 0, (LPWSTR)docW.lpszDocName);
6178 return ret;
6181 /*****************************************************************************
6182 * StartDocDlgW [WINSPOOL.@]
6184 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
6185 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
6186 * port is "FILE:". Also returns the full path if passed a relative path.
6188 * The caller should free the returned string from the process heap.
6190 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
6192 LPWSTR ret = NULL;
6193 DWORD len, attr;
6195 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
6197 PRINTER_INFO_5W *pi5;
6198 GetPrinterW(hPrinter, 5, NULL, 0, &len);
6199 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
6200 return NULL;
6201 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
6202 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
6203 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
6205 HeapFree(GetProcessHeap(), 0, pi5);
6206 return NULL;
6208 HeapFree(GetProcessHeap(), 0, pi5);
6211 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
6213 LPWSTR name;
6214 get_filename(&name);
6215 if(name)
6217 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
6219 HeapFree(GetProcessHeap(), 0, name);
6220 return NULL;
6222 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6223 GetFullPathNameW(name, len, ret, NULL);
6224 HeapFree(GetProcessHeap(), 0, name);
6226 return ret;
6229 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
6230 return NULL;
6232 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6233 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
6235 attr = GetFileAttributesW(ret);
6236 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
6238 HeapFree(GetProcessHeap(), 0, ret);
6239 ret = NULL;
6241 return ret;