winex11.drv: Use display device guid managed by explorer.
[wine/wine-jacek.git] / dlls / winspool.drv / info.c
blobadb1b63da5644841b59870bbdcc819266018f502
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006, 2007 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 #endif
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winuser.h"
49 #include "winerror.h"
50 #include "winreg.h"
51 #include "wingdi.h"
52 #include "winspool.h"
53 #include "winternl.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
58 #include "winnls.h"
60 #include "ddk/winsplp.h"
61 #include "wspool.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
70 0, 0, &monitor_handles_cs,
71 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
72 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
80 0, 0, &printer_handles_cs,
81 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
86 /* ############################### */
88 typedef struct {
89 WCHAR src[MAX_PATH+MAX_PATH];
90 WCHAR dst[MAX_PATH+MAX_PATH];
91 DWORD srclen;
92 DWORD dstlen;
93 DWORD copyflags;
94 } apd_data_t;
96 typedef struct {
97 struct list entry;
98 LPWSTR name;
99 LPWSTR dllname;
100 PMONITORUI monitorUI;
101 LPMONITOR monitor;
102 HMODULE hdll;
103 DWORD refcount;
104 DWORD dwMonitorSize;
105 } monitor_t;
107 typedef struct {
108 DWORD job_id;
109 HANDLE hf;
110 } started_doc_t;
112 typedef struct {
113 struct list jobs;
114 LONG ref;
115 } jobqueue_t;
117 typedef struct {
118 LPWSTR name;
119 LPWSTR printername;
120 monitor_t *pm;
121 HANDLE hXcv;
122 jobqueue_t *queue;
123 started_doc_t *doc;
124 } opened_printer_t;
126 typedef struct {
127 struct list entry;
128 DWORD job_id;
129 WCHAR *filename;
130 WCHAR *document_title;
131 } job_t;
134 typedef struct {
135 LPCWSTR envname;
136 LPCWSTR subdir;
137 DWORD driverversion;
138 LPCWSTR versionregpath;
139 LPCWSTR versionsubdir;
140 } printenv_t;
142 /* ############################### */
144 static struct list monitor_handles = LIST_INIT( monitor_handles );
145 static monitor_t * pm_localport;
147 static opened_printer_t **printer_handles;
148 static UINT nb_printer_handles;
149 static LONG next_job_id = 1;
151 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
152 WORD fwCapability, LPSTR lpszOutput,
153 LPDEVMODEA lpdm );
154 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
155 LPSTR lpszDevice, LPSTR lpszPort,
156 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
157 DWORD fwMode );
159 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
160 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
161 'c','o','n','t','r','o','l','\\',
162 'P','r','i','n','t','\\',
163 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
164 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
166 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
167 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
168 'C','o','n','t','r','o','l','\\',
169 'P','r','i','n','t','\\',
170 'M','o','n','i','t','o','r','s','\\',0};
172 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
173 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
174 'C','o','n','t','r','o','l','\\',
175 'P','r','i','n','t','\\',
176 'P','r','i','n','t','e','r','s',0};
178 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
180 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
181 'M','i','c','r','o','s','o','f','t','\\',
182 'W','i','n','d','o','w','s',' ','N','T','\\',
183 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
184 'W','i','n','d','o','w','s',0};
186 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
187 'M','i','c','r','o','s','o','f','t','\\',
188 'W','i','n','d','o','w','s',' ','N','T','\\',
189 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
190 'D','e','v','i','c','e','s',0};
192 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
193 'M','i','c','r','o','s','o','f','t','\\',
194 'W','i','n','d','o','w','s',' ','N','T','\\',
195 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
196 'P','o','r','t','s',0};
198 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
199 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
200 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
201 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
202 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
203 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
204 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
205 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
206 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
208 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
209 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
211 static const WCHAR backslashW[] = {'\\',0};
212 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
213 'i','o','n',' ','F','i','l','e',0};
214 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
215 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
216 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
217 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
218 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
219 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
220 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
221 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
222 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
223 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
224 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
225 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
226 static const WCHAR NameW[] = {'N','a','m','e',0};
227 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
228 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
229 static const WCHAR PortW[] = {'P','o','r','t',0};
230 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
231 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
232 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
233 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
234 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
235 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW[] = {0};
244 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
247 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
249 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
250 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
251 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
253 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
256 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
257 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
258 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
259 0, sizeof(DRIVER_INFO_8W)};
261 /******************************************************************
262 * validate the user-supplied printing-environment [internal]
264 * PARAMS
265 * env [I] PTR to Environment-String or NULL
267 * RETURNS
268 * Failure: NULL
269 * Success: PTR to printenv_t
271 * NOTES
272 * An empty string is handled the same way as NULL.
273 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
277 static const printenv_t * validate_envW(LPCWSTR env)
279 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
280 3, Version3_RegPathW, Version3_SubdirW};
281 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
282 0, Version0_RegPathW, Version0_SubdirW};
284 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
286 const printenv_t *result = NULL;
287 unsigned int i;
289 TRACE("testing %s\n", debugstr_w(env));
290 if (env && env[0])
292 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
294 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
296 result = all_printenv[i];
297 break;
301 if (result == NULL) {
302 FIXME("unsupported Environment: %s\n", debugstr_w(env));
303 SetLastError(ERROR_INVALID_ENVIRONMENT);
305 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
307 else
309 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
311 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
313 return result;
317 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
318 if passed a NULL string. This returns NULLs to the result.
320 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
322 if ( (src) )
324 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
325 return usBufferPtr->Buffer;
327 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
328 return NULL;
331 static LPWSTR strdupW(LPCWSTR p)
333 LPWSTR ret;
334 DWORD len;
336 if(!p) return NULL;
337 len = (strlenW(p) + 1) * sizeof(WCHAR);
338 ret = HeapAlloc(GetProcessHeap(), 0, len);
339 memcpy(ret, p, len);
340 return ret;
343 static LPSTR strdupWtoA( LPCWSTR str )
345 LPSTR ret;
346 INT len;
348 if (!str) return NULL;
349 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
350 ret = HeapAlloc( GetProcessHeap(), 0, len );
351 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
352 return ret;
355 /******************************************************************
356 * apd_copyfile [internal]
358 * Copy a file from the driverdirectory to the versioned directory
360 * RETURNS
361 * Success: TRUE
362 * Failure: FALSE
365 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
367 LPWSTR ptr;
368 LPWSTR srcname;
369 DWORD res;
371 apd->src[apd->srclen] = '\0';
372 apd->dst[apd->dstlen] = '\0';
374 if (!filename || !filename[0]) {
375 /* nothing to copy */
376 return TRUE;
379 ptr = strrchrW(filename, '\\');
380 if (ptr) {
381 ptr++;
383 else
385 ptr = filename;
388 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
389 /* we have an absolute Path */
390 srcname = filename;
392 else
394 srcname = apd->src;
395 lstrcatW(srcname, ptr);
397 lstrcatW(apd->dst, ptr);
399 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
401 /* FIXME: handle APD_COPY_NEW_FILES */
402 res = CopyFileW(srcname, apd->dst, FALSE);
403 TRACE("got %u with %u\n", res, GetLastError());
405 /* FIXME: install of wineps.drv must be fixed, before we return the real result
406 return res;
408 return TRUE;
412 /******************************************************************
413 * Return the number of bytes for an multi_sz string.
414 * The result includes all \0s
415 * (specifically the extra \0, that is needed as multi_sz terminator).
417 static int multi_sz_lenW(const WCHAR *str)
419 const WCHAR *ptr = str;
420 if(!str) return 0;
423 ptr += lstrlenW(ptr) + 1;
424 } while(*ptr);
426 return (ptr - str + 1) * sizeof(WCHAR);
429 /* ################################ */
431 static int multi_sz_lenA(const char *str)
433 const char *ptr = str;
434 if(!str) return 0;
437 ptr += lstrlenA(ptr) + 1;
438 } while(*ptr);
440 return ptr - str + 1;
443 static void
444 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
445 char qbuf[200];
447 /* If forcing, or no profile string entry for device yet, set the entry
449 * The always change entry if not WINEPS yet is discussable.
451 if (force ||
452 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
453 !strcmp(qbuf,"*") ||
454 !strstr(qbuf,"WINEPS.DRV")
456 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
457 HKEY hkey;
459 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
460 WriteProfileStringA("windows","device",buf);
461 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
462 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
463 RegCloseKey(hkey);
465 HeapFree(GetProcessHeap(),0,buf);
469 static BOOL add_printer_driver(const char *name)
471 DRIVER_INFO_3A di3a;
473 static char driver_9x[] = "wineps16.drv",
474 driver_nt[] = "wineps.drv",
475 env_9x[] = "Windows 4.0",
476 env_nt[] = "Windows NT x86",
477 data_file[] = "generic.ppd",
478 default_data_type[] = "RAW";
480 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
481 di3a.cVersion = 3;
482 di3a.pName = (char *)name;
483 di3a.pEnvironment = env_nt;
484 di3a.pDriverPath = driver_nt;
485 di3a.pDataFile = data_file;
486 di3a.pConfigFile = driver_nt;
487 di3a.pDefaultDataType = default_data_type;
489 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
490 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
492 di3a.cVersion = 0;
493 di3a.pEnvironment = env_9x;
494 di3a.pDriverPath = driver_9x;
495 di3a.pConfigFile = driver_9x;
496 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
497 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
499 return TRUE;
502 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
503 debugstr_a(di3a.pEnvironment), GetLastError());
504 return FALSE;
507 #ifdef SONAME_LIBCUPS
508 static typeof(cupsGetDests) *pcupsGetDests;
509 static typeof(cupsGetPPD) *pcupsGetPPD;
510 static typeof(cupsPrintFile) *pcupsPrintFile;
511 static void *cupshandle;
513 static BOOL CUPS_LoadPrinters(void)
515 int i, nrofdests;
516 BOOL hadprinter = FALSE, haddefault = FALSE;
517 cups_dest_t *dests;
518 PRINTER_INFO_2A pinfo2a;
519 char *port,*devline;
520 HKEY hkeyPrinter, hkeyPrinters, hkey;
521 char loaderror[256];
523 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
524 if (!cupshandle) {
525 TRACE("%s\n", loaderror);
526 return FALSE;
528 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
530 #define DYNCUPS(x) \
531 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
532 if (!p##x) return FALSE;
534 DYNCUPS(cupsGetPPD);
535 DYNCUPS(cupsGetDests);
536 DYNCUPS(cupsPrintFile);
537 #undef DYNCUPS
539 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
540 ERROR_SUCCESS) {
541 ERR("Can't create Printers key\n");
542 return FALSE;
545 nrofdests = pcupsGetDests(&dests);
546 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
547 for (i=0;i<nrofdests;i++) {
548 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
549 sprintf(port,"LPR:%s",dests[i].name);
550 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
551 sprintf(devline,"WINEPS.DRV,%s",port);
552 WriteProfileStringA("devices",dests[i].name,devline);
553 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
554 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
555 RegCloseKey(hkey);
557 HeapFree(GetProcessHeap(),0,devline);
559 TRACE("Printer %d: %s\n", i, dests[i].name);
560 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
561 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
562 and continue */
563 TRACE("Printer already exists\n");
564 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
565 RegCloseKey(hkeyPrinter);
566 } else {
567 static CHAR data_type[] = "RAW",
568 print_proc[] = "WinPrint",
569 comment[] = "WINEPS Printer using CUPS",
570 location[] = "<physical location of printer>",
571 params[] = "<parameters?>",
572 share_name[] = "<share name?>",
573 sep_file[] = "<sep file?>";
575 add_printer_driver(dests[i].name);
577 memset(&pinfo2a,0,sizeof(pinfo2a));
578 pinfo2a.pPrinterName = dests[i].name;
579 pinfo2a.pDatatype = data_type;
580 pinfo2a.pPrintProcessor = print_proc;
581 pinfo2a.pDriverName = dests[i].name;
582 pinfo2a.pComment = comment;
583 pinfo2a.pLocation = location;
584 pinfo2a.pPortName = port;
585 pinfo2a.pParameters = params;
586 pinfo2a.pShareName = share_name;
587 pinfo2a.pSepFile = sep_file;
589 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
590 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
591 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
594 HeapFree(GetProcessHeap(),0,port);
596 hadprinter = TRUE;
597 if (dests[i].is_default) {
598 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
599 haddefault = TRUE;
602 if (hadprinter & !haddefault)
603 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
604 RegCloseKey(hkeyPrinters);
605 return hadprinter;
607 #endif
609 static BOOL
610 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
611 PRINTER_INFO_2A pinfo2a;
612 char *e,*s,*name,*prettyname,*devname;
613 BOOL ret = FALSE, set_default = FALSE;
614 char *port,*devline,*env_default;
615 HKEY hkeyPrinter, hkeyPrinters, hkey;
617 while (isspace(*pent)) pent++;
618 s = strchr(pent,':');
619 if(s) *s='\0';
620 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
621 strcpy(name,pent);
622 if(s) {
623 *s=':';
624 pent = s;
625 } else
626 pent = "";
628 TRACE("name=%s entry=%s\n",name, pent);
630 if(ispunct(*name)) { /* a tc entry, not a real printer */
631 TRACE("skipping tc entry\n");
632 goto end;
635 if(strstr(pent,":server")) { /* server only version so skip */
636 TRACE("skipping server entry\n");
637 goto end;
640 /* Determine whether this is a postscript printer. */
642 ret = TRUE;
643 env_default = getenv("PRINTER");
644 prettyname = name;
645 /* Get longest name, usually the one at the right for later display. */
646 while((s=strchr(prettyname,'|'))) {
647 *s = '\0';
648 e = s;
649 while(isspace(*--e)) *e = '\0';
650 TRACE("\t%s\n", debugstr_a(prettyname));
651 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
652 for(prettyname = s+1; isspace(*prettyname); prettyname++)
655 e = prettyname + strlen(prettyname);
656 while(isspace(*--e)) *e = '\0';
657 TRACE("\t%s\n", debugstr_a(prettyname));
658 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
660 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
661 * if it is too long, we use it as comment below. */
662 devname = prettyname;
663 if (strlen(devname)>=CCHDEVICENAME-1)
664 devname = name;
665 if (strlen(devname)>=CCHDEVICENAME-1) {
666 ret = FALSE;
667 goto end;
670 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
671 sprintf(port,"LPR:%s",name);
673 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
674 sprintf(devline,"WINEPS.DRV,%s",port);
675 WriteProfileStringA("devices",devname,devline);
676 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
677 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
678 RegCloseKey(hkey);
680 HeapFree(GetProcessHeap(),0,devline);
682 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
683 ERROR_SUCCESS) {
684 ERR("Can't create Printers key\n");
685 ret = FALSE;
686 goto end;
688 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
689 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
690 and continue */
691 TRACE("Printer already exists\n");
692 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
693 RegCloseKey(hkeyPrinter);
694 } else {
695 static CHAR data_type[] = "RAW",
696 print_proc[] = "WinPrint",
697 comment[] = "WINEPS Printer using LPR",
698 params[] = "<parameters?>",
699 share_name[] = "<share name?>",
700 sep_file[] = "<sep file?>";
702 add_printer_driver(devname);
704 memset(&pinfo2a,0,sizeof(pinfo2a));
705 pinfo2a.pPrinterName = devname;
706 pinfo2a.pDatatype = data_type;
707 pinfo2a.pPrintProcessor = print_proc;
708 pinfo2a.pDriverName = devname;
709 pinfo2a.pComment = comment;
710 pinfo2a.pLocation = prettyname;
711 pinfo2a.pPortName = port;
712 pinfo2a.pParameters = params;
713 pinfo2a.pShareName = share_name;
714 pinfo2a.pSepFile = sep_file;
716 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
717 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
718 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
721 RegCloseKey(hkeyPrinters);
723 if (isfirst || set_default)
724 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
726 HeapFree(GetProcessHeap(), 0, port);
727 end:
728 HeapFree(GetProcessHeap(), 0, name);
729 return ret;
732 static BOOL
733 PRINTCAP_LoadPrinters(void) {
734 BOOL hadprinter = FALSE;
735 char buf[200];
736 FILE *f;
737 char *pent = NULL;
738 BOOL had_bash = FALSE;
740 f = fopen("/etc/printcap","r");
741 if (!f)
742 return FALSE;
744 while(fgets(buf,sizeof(buf),f)) {
745 char *start, *end;
747 end=strchr(buf,'\n');
748 if (end) *end='\0';
750 start = buf;
751 while(isspace(*start)) start++;
752 if(*start == '#' || *start == '\0')
753 continue;
755 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
756 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
757 HeapFree(GetProcessHeap(),0,pent);
758 pent = NULL;
761 if (end && *--end == '\\') {
762 *end = '\0';
763 had_bash = TRUE;
764 } else
765 had_bash = FALSE;
767 if (pent) {
768 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
769 strcat(pent,start);
770 } else {
771 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
772 strcpy(pent,start);
776 if(pent) {
777 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
778 HeapFree(GetProcessHeap(),0,pent);
780 fclose(f);
781 return hadprinter;
784 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
786 if (value)
787 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
788 (lstrlenW(value) + 1) * sizeof(WCHAR));
789 else
790 return ERROR_FILE_NOT_FOUND;
793 /*****************************************************************************
794 * enumerate the local monitors (INTERNAL)
796 * returns the needed size (in bytes) for pMonitors
797 * and *lpreturned is set to number of entries returned in pMonitors
800 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
802 HKEY hroot = NULL;
803 HKEY hentry = NULL;
804 LPWSTR ptr;
805 LPMONITOR_INFO_2W mi;
806 WCHAR buffer[MAX_PATH];
807 WCHAR dllname[MAX_PATH];
808 DWORD dllsize;
809 DWORD len;
810 DWORD index = 0;
811 DWORD needed = 0;
812 DWORD numentries;
813 DWORD entrysize;
815 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
817 numentries = *lpreturned; /* this is 0, when we scan the registry */
818 len = entrysize * numentries;
819 ptr = (LPWSTR) &pMonitors[len];
821 numentries = 0;
822 len = sizeof(buffer);
823 buffer[0] = '\0';
825 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
826 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
827 /* Scan all Monitor-Registry-Keys */
828 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
829 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
830 dllsize = sizeof(dllname);
831 dllname[0] = '\0';
833 /* The Monitor must have a Driver-DLL */
834 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
835 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
836 /* We found a valid DLL for this Monitor. */
837 TRACE("using Driver: %s\n", debugstr_w(dllname));
839 RegCloseKey(hentry);
842 /* Windows returns only Port-Monitors here, but to simplify our code,
843 we do no filtering for Language-Monitors */
844 if (dllname[0]) {
845 numentries++;
846 needed += entrysize;
847 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
848 if (level > 1) {
849 /* we install and return only monitors for "Windows NT x86" */
850 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
851 needed += dllsize;
854 /* required size is calculated. Now fill the user-buffer */
855 if (pMonitors && (cbBuf >= needed)){
856 mi = (LPMONITOR_INFO_2W) pMonitors;
857 pMonitors += entrysize;
859 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
860 mi->pName = ptr;
861 lstrcpyW(ptr, buffer); /* Name of the Monitor */
862 ptr += (len+1); /* len is lstrlenW(monitorname) */
863 if (level > 1) {
864 mi->pEnvironment = ptr;
865 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
866 ptr += (lstrlenW(envname_x86W)+1);
868 mi->pDLLName = ptr;
869 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
870 ptr += (dllsize / sizeof(WCHAR));
874 index++;
875 len = sizeof(buffer);
876 buffer[0] = '\0';
878 RegCloseKey(hroot);
880 *lpreturned = numentries;
881 TRACE("need %d byte for %d entries\n", needed, numentries);
882 return needed;
885 /******************************************************************
886 * monitor_unload [internal]
888 * release a printmonitor and unload it from memory, when needed
891 static void monitor_unload(monitor_t * pm)
893 if (pm == NULL) return;
894 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
896 EnterCriticalSection(&monitor_handles_cs);
898 if (pm->refcount) pm->refcount--;
900 if (pm->refcount == 0) {
901 list_remove(&pm->entry);
902 FreeLibrary(pm->hdll);
903 HeapFree(GetProcessHeap(), 0, pm->name);
904 HeapFree(GetProcessHeap(), 0, pm->dllname);
905 HeapFree(GetProcessHeap(), 0, pm);
907 LeaveCriticalSection(&monitor_handles_cs);
910 /******************************************************************
911 * monitor_unloadall [internal]
913 * release all printmonitors and unload them from memory, when needed
916 static void monitor_unloadall(void)
918 monitor_t * pm;
919 monitor_t * next;
921 EnterCriticalSection(&monitor_handles_cs);
922 /* iterate through the list, with safety against removal */
923 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
925 monitor_unload(pm);
927 LeaveCriticalSection(&monitor_handles_cs);
930 /******************************************************************
931 * monitor_load [internal]
933 * load a printmonitor, get the dllname from the registry, when needed
934 * initialize the monitor and dump found function-pointers
936 * On failure, SetLastError() is called and NULL is returned
939 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
941 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
942 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
943 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
944 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
945 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
947 monitor_t * pm = NULL;
948 monitor_t * cursor;
949 LPWSTR regroot = NULL;
950 LPWSTR driver = dllname;
952 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
953 /* Is the Monitor already loaded? */
954 EnterCriticalSection(&monitor_handles_cs);
956 if (name) {
957 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
959 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
960 pm = cursor;
961 break;
966 if (pm == NULL) {
967 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
968 if (pm == NULL) goto cleanup;
969 list_add_tail(&monitor_handles, &pm->entry);
971 pm->refcount++;
973 if (pm->name == NULL) {
974 /* Load the monitor */
975 LPMONITOREX pmonitorEx;
976 DWORD len;
978 if (name) {
979 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
980 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
983 if (regroot) {
984 lstrcpyW(regroot, MonitorsW);
985 lstrcatW(regroot, name);
986 /* Get the Driver from the Registry */
987 if (driver == NULL) {
988 HKEY hroot;
989 DWORD namesize;
990 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
991 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
992 &namesize) == ERROR_SUCCESS) {
993 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
994 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
996 RegCloseKey(hroot);
1001 pm->name = strdupW(name);
1002 pm->dllname = strdupW(driver);
1004 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
1005 monitor_unload(pm);
1006 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1007 pm = NULL;
1008 goto cleanup;
1011 pm->hdll = LoadLibraryW(driver);
1012 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
1014 if (pm->hdll == NULL) {
1015 monitor_unload(pm);
1016 SetLastError(ERROR_MOD_NOT_FOUND);
1017 pm = NULL;
1018 goto cleanup;
1021 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1022 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1023 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1024 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1025 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1028 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1029 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1030 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1031 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1032 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1034 if (pInitializePrintMonitorUI != NULL) {
1035 pm->monitorUI = pInitializePrintMonitorUI();
1036 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1037 if (pm->monitorUI) {
1038 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1039 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1044 if (pInitializePrintMonitor && regroot) {
1045 pmonitorEx = pInitializePrintMonitor(regroot);
1046 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1047 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1049 if (pmonitorEx) {
1050 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1051 pm->monitor = &(pmonitorEx->Monitor);
1055 if (pm->monitor) {
1056 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1060 if (!pm->monitor && regroot) {
1061 if (pInitializePrintMonitor2 != NULL) {
1062 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1064 if (pInitializeMonitorEx != NULL) {
1065 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1067 if (pInitializeMonitor != NULL) {
1068 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1071 if (!pm->monitor && !pm->monitorUI) {
1072 monitor_unload(pm);
1073 SetLastError(ERROR_PROC_NOT_FOUND);
1074 pm = NULL;
1077 cleanup:
1078 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1079 pm->refcount++;
1080 pm_localport = pm;
1082 LeaveCriticalSection(&monitor_handles_cs);
1083 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1084 HeapFree(GetProcessHeap(), 0, regroot);
1085 TRACE("=> %p\n", pm);
1086 return pm;
1089 /******************************************************************
1090 * monitor_loadall [internal]
1092 * Load all registered monitors
1095 static DWORD monitor_loadall(void)
1097 monitor_t * pm;
1098 DWORD registered = 0;
1099 DWORD loaded = 0;
1100 HKEY hmonitors;
1101 WCHAR buffer[MAX_PATH];
1102 DWORD id = 0;
1104 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1105 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1106 NULL, NULL, NULL, NULL, NULL);
1108 TRACE("%d monitors registered\n", registered);
1110 EnterCriticalSection(&monitor_handles_cs);
1111 while (id < registered) {
1112 buffer[0] = '\0';
1113 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1114 pm = monitor_load(buffer, NULL);
1115 if (pm) loaded++;
1116 id++;
1118 LeaveCriticalSection(&monitor_handles_cs);
1119 RegCloseKey(hmonitors);
1121 TRACE("%d monitors loaded\n", loaded);
1122 return loaded;
1125 /******************************************************************
1126 * monitor_loadui [internal]
1128 * load the userinterface-dll for a given portmonitor
1130 * On failure, NULL is returned
1133 static monitor_t * monitor_loadui(monitor_t * pm)
1135 monitor_t * pui = NULL;
1136 LPWSTR buffer[MAX_PATH];
1137 HANDLE hXcv;
1138 DWORD len;
1139 DWORD res;
1141 if (pm == NULL) return NULL;
1142 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1144 /* Try the Portmonitor first; works for many monitors */
1145 if (pm->monitorUI) {
1146 EnterCriticalSection(&monitor_handles_cs);
1147 pm->refcount++;
1148 LeaveCriticalSection(&monitor_handles_cs);
1149 return pm;
1152 /* query the userinterface-dllname from the Portmonitor */
1153 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1154 /* building (",XcvMonitor %s",pm->name) not needed yet */
1155 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1156 TRACE("got %u with %p\n", res, hXcv);
1157 if (res) {
1158 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1159 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1160 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1161 pm->monitor->pfnXcvClosePort(hXcv);
1164 return pui;
1168 /******************************************************************
1169 * monitor_load_by_port [internal]
1171 * load a printmonitor for a given port
1173 * On failure, NULL is returned
1176 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1178 HKEY hroot;
1179 HKEY hport;
1180 LPWSTR buffer;
1181 monitor_t * pm = NULL;
1182 DWORD registered = 0;
1183 DWORD id = 0;
1184 DWORD len;
1186 TRACE("(%s)\n", debugstr_w(portname));
1188 /* Try the Local Monitor first */
1189 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1190 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1191 /* found the portname */
1192 RegCloseKey(hroot);
1193 return monitor_load(LocalPortW, NULL);
1195 RegCloseKey(hroot);
1198 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1199 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1200 if (buffer == NULL) return NULL;
1202 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1203 EnterCriticalSection(&monitor_handles_cs);
1204 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1206 while ((pm == NULL) && (id < registered)) {
1207 buffer[0] = '\0';
1208 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1209 TRACE("testing %s\n", debugstr_w(buffer));
1210 len = lstrlenW(buffer);
1211 lstrcatW(buffer, bs_Ports_bsW);
1212 lstrcatW(buffer, portname);
1213 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1214 RegCloseKey(hport);
1215 buffer[len] = '\0'; /* use only the Monitor-Name */
1216 pm = monitor_load(buffer, NULL);
1218 id++;
1220 LeaveCriticalSection(&monitor_handles_cs);
1221 RegCloseKey(hroot);
1223 HeapFree(GetProcessHeap(), 0, buffer);
1224 return pm;
1227 /******************************************************************
1228 * enumerate the local Ports from all loaded monitors (internal)
1230 * returns the needed size (in bytes) for pPorts
1231 * and *lpreturned is set to number of entries returned in pPorts
1234 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1236 monitor_t * pm;
1237 LPWSTR ptr;
1238 LPPORT_INFO_2W cache;
1239 LPPORT_INFO_2W out;
1240 LPBYTE pi_buffer = NULL;
1241 DWORD pi_allocated = 0;
1242 DWORD pi_needed;
1243 DWORD pi_index;
1244 DWORD pi_returned;
1245 DWORD res;
1246 DWORD outindex = 0;
1247 DWORD needed;
1248 DWORD numentries;
1249 DWORD entrysize;
1252 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1253 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1255 numentries = *lpreturned; /* this is 0, when we scan the registry */
1256 needed = entrysize * numentries;
1257 ptr = (LPWSTR) &pPorts[needed];
1259 numentries = 0;
1260 needed = 0;
1262 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1264 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1265 pi_needed = 0;
1266 pi_returned = 0;
1267 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1268 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1269 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1270 HeapFree(GetProcessHeap(), 0, pi_buffer);
1271 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1272 pi_allocated = (pi_buffer) ? pi_needed : 0;
1273 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1275 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1276 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1278 numentries += pi_returned;
1279 needed += pi_needed;
1281 /* fill the output-buffer (pPorts), if we have one */
1282 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1283 pi_index = 0;
1284 while (pi_returned > pi_index) {
1285 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1286 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1287 out->pPortName = ptr;
1288 lstrcpyW(ptr, cache->pPortName);
1289 ptr += (lstrlenW(ptr)+1);
1290 if (level > 1) {
1291 out->pMonitorName = ptr;
1292 lstrcpyW(ptr, cache->pMonitorName);
1293 ptr += (lstrlenW(ptr)+1);
1295 out->pDescription = ptr;
1296 lstrcpyW(ptr, cache->pDescription);
1297 ptr += (lstrlenW(ptr)+1);
1298 out->fPortType = cache->fPortType;
1299 out->Reserved = cache->Reserved;
1301 pi_index++;
1302 outindex++;
1307 /* the temporary portinfo-buffer is no longer needed */
1308 HeapFree(GetProcessHeap(), 0, pi_buffer);
1310 *lpreturned = numentries;
1311 TRACE("need %d byte for %d entries\n", needed, numentries);
1312 return needed;
1315 /******************************************************************
1316 * get_servername_from_name (internal)
1318 * for an external server, a copy of the serverpart from the full name is returned
1321 static LPWSTR get_servername_from_name(LPCWSTR name)
1323 LPWSTR server;
1324 LPWSTR ptr;
1325 WCHAR buffer[MAX_PATH];
1326 DWORD len;
1328 if (name == NULL) return NULL;
1329 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1331 server = strdupW(&name[2]); /* skip over both backslash */
1332 if (server == NULL) return NULL;
1334 /* strip '\' and the printername */
1335 ptr = strchrW(server, '\\');
1336 if (ptr) ptr[0] = '\0';
1338 TRACE("found %s\n", debugstr_w(server));
1340 len = sizeof(buffer)/sizeof(buffer[0]);
1341 if (GetComputerNameW(buffer, &len)) {
1342 if (lstrcmpW(buffer, server) == 0) {
1343 /* The requested Servername is our computername */
1344 HeapFree(GetProcessHeap(), 0, server);
1345 return NULL;
1348 return server;
1351 /******************************************************************
1352 * get_basename_from_name (internal)
1354 * skip over the serverpart from the full name
1357 static LPCWSTR get_basename_from_name(LPCWSTR name)
1359 if (name == NULL) return NULL;
1360 if ((name[0] == '\\') && (name[1] == '\\')) {
1361 /* skip over the servername and search for the following '\' */
1362 name = strchrW(&name[2], '\\');
1363 if ((name) && (name[1])) {
1364 /* found a separator ('\') followed by a name:
1365 skip over the separator and return the rest */
1366 name++;
1368 else
1370 /* no basename present (we found only a servername) */
1371 return NULL;
1374 return name;
1377 /******************************************************************
1378 * get_opened_printer_entry
1379 * Get the first place empty in the opened printer table
1381 * ToDo:
1382 * - pDefault is ignored
1384 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1386 UINT_PTR handle = nb_printer_handles, i;
1387 jobqueue_t *queue = NULL;
1388 opened_printer_t *printer = NULL;
1389 LPWSTR servername;
1390 LPCWSTR printername;
1391 HKEY hkeyPrinters;
1392 HKEY hkeyPrinter;
1393 DWORD len;
1395 servername = get_servername_from_name(name);
1396 if (servername) {
1397 FIXME("server %s not supported\n", debugstr_w(servername));
1398 HeapFree(GetProcessHeap(), 0, servername);
1399 SetLastError(ERROR_INVALID_PRINTER_NAME);
1400 return NULL;
1403 printername = get_basename_from_name(name);
1404 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1406 /* an empty printername is invalid */
1407 if (printername && (!printername[0])) {
1408 SetLastError(ERROR_INVALID_PARAMETER);
1409 return NULL;
1412 EnterCriticalSection(&printer_handles_cs);
1414 for (i = 0; i < nb_printer_handles; i++)
1416 if (!printer_handles[i])
1418 if(handle == nb_printer_handles)
1419 handle = i;
1421 else
1423 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1424 queue = printer_handles[i]->queue;
1428 if (handle >= nb_printer_handles)
1430 opened_printer_t **new_array;
1431 if (printer_handles)
1432 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1433 (nb_printer_handles + 16) * sizeof(*new_array) );
1434 else
1435 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1436 (nb_printer_handles + 16) * sizeof(*new_array) );
1438 if (!new_array)
1440 handle = 0;
1441 goto end;
1443 printer_handles = new_array;
1444 nb_printer_handles += 16;
1447 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1449 handle = 0;
1450 goto end;
1454 /* clone the base name. This is NULL for the printserver */
1455 printer->printername = strdupW(printername);
1457 /* clone the full name */
1458 printer->name = strdupW(name);
1459 if (name && (!printer->name)) {
1460 handle = 0;
1461 goto end;
1464 if (printername) {
1465 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1466 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1467 /* OpenPrinter(",XcvMonitor " detected */
1468 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1469 printer->pm = monitor_load(&printername[len], NULL);
1470 if (printer->pm == NULL) {
1471 SetLastError(ERROR_UNKNOWN_PORT);
1472 handle = 0;
1473 goto end;
1476 else
1478 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1479 if (strncmpW( printername, XcvPortW, len) == 0) {
1480 /* OpenPrinter(",XcvPort " detected */
1481 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1482 printer->pm = monitor_load_by_port(&printername[len]);
1483 if (printer->pm == NULL) {
1484 SetLastError(ERROR_UNKNOWN_PORT);
1485 handle = 0;
1486 goto end;
1491 if (printer->pm) {
1492 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1493 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1494 pDefault ? pDefault->DesiredAccess : 0,
1495 &printer->hXcv);
1497 if (printer->hXcv == NULL) {
1498 SetLastError(ERROR_INVALID_PARAMETER);
1499 handle = 0;
1500 goto end;
1503 else
1505 /* Does the Printer exist? */
1506 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1507 ERR("Can't create Printers key\n");
1508 handle = 0;
1509 goto end;
1511 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1512 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1513 RegCloseKey(hkeyPrinters);
1514 SetLastError(ERROR_INVALID_PRINTER_NAME);
1515 handle = 0;
1516 goto end;
1518 RegCloseKey(hkeyPrinter);
1519 RegCloseKey(hkeyPrinters);
1522 else
1524 TRACE("using the local printserver\n");
1527 if(queue)
1528 printer->queue = queue;
1529 else
1531 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1532 if (!printer->queue) {
1533 handle = 0;
1534 goto end;
1536 list_init(&printer->queue->jobs);
1537 printer->queue->ref = 0;
1539 InterlockedIncrement(&printer->queue->ref);
1541 printer_handles[handle] = printer;
1542 handle++;
1543 end:
1544 LeaveCriticalSection(&printer_handles_cs);
1545 if (!handle && printer) {
1546 /* Something failed: Free all resources */
1547 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1548 monitor_unload(printer->pm);
1549 HeapFree(GetProcessHeap(), 0, printer->printername);
1550 HeapFree(GetProcessHeap(), 0, printer->name);
1551 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1552 HeapFree(GetProcessHeap(), 0, printer);
1555 return (HANDLE)handle;
1558 /******************************************************************
1559 * get_opened_printer
1560 * Get the pointer to the opened printer referred by the handle
1562 static opened_printer_t *get_opened_printer(HANDLE hprn)
1564 UINT_PTR idx = (UINT_PTR)hprn;
1565 opened_printer_t *ret = NULL;
1567 EnterCriticalSection(&printer_handles_cs);
1569 if ((idx > 0) && (idx <= nb_printer_handles)) {
1570 ret = printer_handles[idx - 1];
1572 LeaveCriticalSection(&printer_handles_cs);
1573 return ret;
1576 /******************************************************************
1577 * get_opened_printer_name
1578 * Get the pointer to the opened printer name referred by the handle
1580 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1582 opened_printer_t *printer = get_opened_printer(hprn);
1583 if(!printer) return NULL;
1584 return printer->name;
1587 /******************************************************************
1588 * WINSPOOL_GetOpenedPrinterRegKey
1591 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1593 LPCWSTR name = get_opened_printer_name(hPrinter);
1594 DWORD ret;
1595 HKEY hkeyPrinters;
1597 if(!name) return ERROR_INVALID_HANDLE;
1599 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1600 ERROR_SUCCESS)
1601 return ret;
1603 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1605 ERR("Can't find opened printer %s in registry\n",
1606 debugstr_w(name));
1607 RegCloseKey(hkeyPrinters);
1608 return ERROR_INVALID_PRINTER_NAME; /* ? */
1610 RegCloseKey(hkeyPrinters);
1611 return ERROR_SUCCESS;
1614 void WINSPOOL_LoadSystemPrinters(void)
1616 HKEY hkey, hkeyPrinters;
1617 HANDLE hprn;
1618 DWORD needed, num, i;
1619 WCHAR PrinterName[256];
1620 BOOL done = FALSE;
1622 /* This ensures that all printer entries have a valid Name value. If causes
1623 problems later if they don't. If one is found to be missed we create one
1624 and set it equal to the name of the key */
1625 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1626 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1627 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1628 for(i = 0; i < num; i++) {
1629 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1630 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1631 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1632 set_reg_szW(hkey, NameW, PrinterName);
1634 RegCloseKey(hkey);
1639 RegCloseKey(hkeyPrinters);
1642 /* We want to avoid calling AddPrinter on printers as much as
1643 possible, because on cups printers this will (eventually) lead
1644 to a call to cupsGetPPD which takes forever, even with non-cups
1645 printers AddPrinter takes a while. So we'll tag all printers that
1646 were automatically added last time around, if they still exist
1647 we'll leave them be otherwise we'll delete them. */
1648 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1649 if(needed) {
1650 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1651 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1652 for(i = 0; i < num; i++) {
1653 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1654 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1655 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1656 DWORD dw = 1;
1657 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1658 RegCloseKey(hkey);
1660 ClosePrinter(hprn);
1665 HeapFree(GetProcessHeap(), 0, pi);
1669 #ifdef SONAME_LIBCUPS
1670 done = CUPS_LoadPrinters();
1671 #endif
1673 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1674 PRINTCAP_LoadPrinters();
1676 /* Now enumerate the list again and delete any printers that are still tagged */
1677 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1678 if(needed) {
1679 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1680 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1681 for(i = 0; i < num; i++) {
1682 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1683 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1684 BOOL delete_driver = FALSE;
1685 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1686 DWORD dw, type, size = sizeof(dw);
1687 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1688 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1689 DeletePrinter(hprn);
1690 delete_driver = TRUE;
1692 RegCloseKey(hkey);
1694 ClosePrinter(hprn);
1695 if(delete_driver)
1696 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1701 HeapFree(GetProcessHeap(), 0, pi);
1704 return;
1708 /******************************************************************
1709 * get_job
1711 * Get the pointer to the specified job.
1712 * Should hold the printer_handles_cs before calling.
1714 static job_t *get_job(HANDLE hprn, DWORD JobId)
1716 opened_printer_t *printer = get_opened_printer(hprn);
1717 job_t *job;
1719 if(!printer) return NULL;
1720 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1722 if(job->job_id == JobId)
1723 return job;
1725 return NULL;
1728 /***********************************************************
1729 * DEVMODEcpyAtoW
1731 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1733 BOOL Formname;
1734 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1735 DWORD size;
1737 Formname = (dmA->dmSize > off_formname);
1738 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1739 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1740 dmW->dmDeviceName, CCHDEVICENAME);
1741 if(!Formname) {
1742 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1743 dmA->dmSize - CCHDEVICENAME);
1744 } else {
1745 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1746 off_formname - CCHDEVICENAME);
1747 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1748 dmW->dmFormName, CCHFORMNAME);
1749 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1750 (off_formname + CCHFORMNAME));
1752 dmW->dmSize = size;
1753 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1754 dmA->dmDriverExtra);
1755 return dmW;
1758 /***********************************************************
1759 * DEVMODEdupWtoA
1760 * Creates an ascii copy of supplied devmode on heap
1762 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1764 LPDEVMODEA dmA;
1765 DWORD size;
1766 BOOL Formname;
1767 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1769 if(!dmW) return NULL;
1770 Formname = (dmW->dmSize > off_formname);
1771 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1772 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1773 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1774 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1775 if(!Formname) {
1776 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1777 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1778 } else {
1779 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1780 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1781 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1782 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1783 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1784 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1786 dmA->dmSize = size;
1787 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1788 dmW->dmDriverExtra);
1789 return dmA;
1792 /***********************************************************
1793 * PRINTER_INFO_2AtoW
1794 * Creates a unicode copy of PRINTER_INFO_2A on heap
1796 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1798 LPPRINTER_INFO_2W piW;
1799 UNICODE_STRING usBuffer;
1801 if(!piA) return NULL;
1802 piW = HeapAlloc(heap, 0, sizeof(*piW));
1803 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1805 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1806 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1807 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1808 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1809 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1810 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1811 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1812 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1813 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1814 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1815 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1816 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1817 return piW;
1820 /***********************************************************
1821 * FREE_PRINTER_INFO_2W
1822 * Free PRINTER_INFO_2W and all strings
1824 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1826 if(!piW) return;
1828 HeapFree(heap,0,piW->pServerName);
1829 HeapFree(heap,0,piW->pPrinterName);
1830 HeapFree(heap,0,piW->pShareName);
1831 HeapFree(heap,0,piW->pPortName);
1832 HeapFree(heap,0,piW->pDriverName);
1833 HeapFree(heap,0,piW->pComment);
1834 HeapFree(heap,0,piW->pLocation);
1835 HeapFree(heap,0,piW->pDevMode);
1836 HeapFree(heap,0,piW->pSepFile);
1837 HeapFree(heap,0,piW->pPrintProcessor);
1838 HeapFree(heap,0,piW->pDatatype);
1839 HeapFree(heap,0,piW->pParameters);
1840 HeapFree(heap,0,piW);
1841 return;
1844 /******************************************************************
1845 * DeviceCapabilities [WINSPOOL.@]
1846 * DeviceCapabilitiesA [WINSPOOL.@]
1849 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1850 LPSTR pOutput, LPDEVMODEA lpdm)
1852 INT ret;
1854 if (!GDI_CallDeviceCapabilities16)
1856 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1857 (LPCSTR)104 );
1858 if (!GDI_CallDeviceCapabilities16) return -1;
1860 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1862 /* If DC_PAPERSIZE map POINT16s to POINTs */
1863 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1864 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1865 POINT *pt = (POINT *)pOutput;
1866 INT i;
1867 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1868 for(i = 0; i < ret; i++, pt++)
1870 pt->x = tmp[i].x;
1871 pt->y = tmp[i].y;
1873 HeapFree( GetProcessHeap(), 0, tmp );
1875 return ret;
1879 /*****************************************************************************
1880 * DeviceCapabilitiesW [WINSPOOL.@]
1882 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1885 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1886 WORD fwCapability, LPWSTR pOutput,
1887 const DEVMODEW *pDevMode)
1889 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1890 LPSTR pDeviceA = strdupWtoA(pDevice);
1891 LPSTR pPortA = strdupWtoA(pPort);
1892 INT ret;
1894 if(pOutput && (fwCapability == DC_BINNAMES ||
1895 fwCapability == DC_FILEDEPENDENCIES ||
1896 fwCapability == DC_PAPERNAMES)) {
1897 /* These need A -> W translation */
1898 INT size = 0, i;
1899 LPSTR pOutputA;
1900 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1901 dmA);
1902 if(ret == -1)
1903 return ret;
1904 switch(fwCapability) {
1905 case DC_BINNAMES:
1906 size = 24;
1907 break;
1908 case DC_PAPERNAMES:
1909 case DC_FILEDEPENDENCIES:
1910 size = 64;
1911 break;
1913 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1914 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1915 dmA);
1916 for(i = 0; i < ret; i++)
1917 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1918 pOutput + (i * size), size);
1919 HeapFree(GetProcessHeap(), 0, pOutputA);
1920 } else {
1921 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1922 (LPSTR)pOutput, dmA);
1924 HeapFree(GetProcessHeap(),0,pPortA);
1925 HeapFree(GetProcessHeap(),0,pDeviceA);
1926 HeapFree(GetProcessHeap(),0,dmA);
1927 return ret;
1930 /******************************************************************
1931 * DocumentPropertiesA [WINSPOOL.@]
1933 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1935 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1936 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1937 LPDEVMODEA pDevModeInput,DWORD fMode )
1939 LPSTR lpName = pDeviceName;
1940 static CHAR port[] = "LPT1:";
1941 LONG ret;
1943 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1944 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1947 if(!pDeviceName) {
1948 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1949 if(!lpNameW) {
1950 ERR("no name from hPrinter?\n");
1951 SetLastError(ERROR_INVALID_HANDLE);
1952 return -1;
1954 lpName = strdupWtoA(lpNameW);
1957 if (!GDI_CallExtDeviceMode16)
1959 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1960 (LPCSTR)102 );
1961 if (!GDI_CallExtDeviceMode16) {
1962 ERR("No CallExtDeviceMode16?\n");
1963 return -1;
1966 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1967 pDevModeInput, NULL, fMode);
1969 if(!pDeviceName)
1970 HeapFree(GetProcessHeap(),0,lpName);
1971 return ret;
1975 /*****************************************************************************
1976 * DocumentPropertiesW (WINSPOOL.@)
1978 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1980 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1981 LPWSTR pDeviceName,
1982 LPDEVMODEW pDevModeOutput,
1983 LPDEVMODEW pDevModeInput, DWORD fMode)
1986 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1987 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1988 LPDEVMODEA pDevModeOutputA = NULL;
1989 LONG ret;
1991 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1992 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1993 fMode);
1994 if(pDevModeOutput) {
1995 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1996 if(ret < 0) return ret;
1997 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1999 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2000 pDevModeInputA, fMode);
2001 if(pDevModeOutput) {
2002 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2003 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2005 if(fMode == 0 && ret > 0)
2006 ret += (CCHDEVICENAME + CCHFORMNAME);
2007 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2008 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2009 return ret;
2012 /******************************************************************
2013 * OpenPrinterA [WINSPOOL.@]
2015 * See OpenPrinterW.
2018 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2019 LPPRINTER_DEFAULTSA pDefault)
2021 UNICODE_STRING lpPrinterNameW;
2022 UNICODE_STRING usBuffer;
2023 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2024 PWSTR pwstrPrinterNameW;
2025 BOOL ret;
2027 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2029 if(pDefault) {
2030 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2031 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2032 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2033 pDefaultW = &DefaultW;
2035 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2036 if(pDefault) {
2037 RtlFreeUnicodeString(&usBuffer);
2038 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2040 RtlFreeUnicodeString(&lpPrinterNameW);
2041 return ret;
2044 /******************************************************************
2045 * OpenPrinterW [WINSPOOL.@]
2047 * Open a Printer / Printserver or a Printer-Object
2049 * PARAMS
2050 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2051 * phPrinter [O] The resulting Handle is stored here
2052 * pDefault [I] PTR to Default Printer Settings or NULL
2054 * RETURNS
2055 * Success: TRUE
2056 * Failure: FALSE
2058 * NOTES
2059 * lpPrinterName is one of:
2060 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2061 *| Printer: "PrinterName"
2062 *| Printer-Object: "PrinterName,Job xxx"
2063 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2064 *| XcvPort: "Servername,XcvPort PortName"
2066 * BUGS
2067 *| Printer-Object not supported
2068 *| pDefaults is ignored
2071 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2074 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2075 if (pDefault) {
2076 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2077 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2080 if(!phPrinter) {
2081 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2082 SetLastError(ERROR_INVALID_PARAMETER);
2083 return FALSE;
2086 /* Get the unique handle of the printer or Printserver */
2087 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2088 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2089 return (*phPrinter != 0);
2092 /******************************************************************
2093 * AddMonitorA [WINSPOOL.@]
2095 * See AddMonitorW.
2098 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2100 LPWSTR nameW = NULL;
2101 INT len;
2102 BOOL res;
2103 LPMONITOR_INFO_2A mi2a;
2104 MONITOR_INFO_2W mi2w;
2106 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2107 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2108 mi2a ? debugstr_a(mi2a->pName) : NULL,
2109 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2110 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2112 if (Level != 2) {
2113 SetLastError(ERROR_INVALID_LEVEL);
2114 return FALSE;
2117 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2118 if (mi2a == NULL) {
2119 return FALSE;
2122 if (pName) {
2123 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2124 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2125 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2128 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2129 if (mi2a->pName) {
2130 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2131 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2132 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2134 if (mi2a->pEnvironment) {
2135 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2136 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2137 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2139 if (mi2a->pDLLName) {
2140 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2141 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2142 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2145 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2147 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2148 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2149 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2151 HeapFree(GetProcessHeap(), 0, nameW);
2152 return (res);
2155 /******************************************************************************
2156 * AddMonitorW [WINSPOOL.@]
2158 * Install a Printmonitor
2160 * PARAMS
2161 * pName [I] Servername or NULL (local Computer)
2162 * Level [I] Structure-Level (Must be 2)
2163 * pMonitors [I] PTR to MONITOR_INFO_2
2165 * RETURNS
2166 * Success: TRUE
2167 * Failure: FALSE
2169 * NOTES
2170 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2173 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2175 monitor_t * pm = NULL;
2176 LPMONITOR_INFO_2W mi2w;
2177 HKEY hroot = NULL;
2178 HKEY hentry = NULL;
2179 DWORD disposition;
2180 BOOL res = FALSE;
2182 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2183 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2184 mi2w ? debugstr_w(mi2w->pName) : NULL,
2185 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2186 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2188 if (Level != 2) {
2189 SetLastError(ERROR_INVALID_LEVEL);
2190 return FALSE;
2193 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2194 if (mi2w == NULL) {
2195 return FALSE;
2198 if (pName && (pName[0])) {
2199 FIXME("for server %s not implemented\n", debugstr_w(pName));
2200 SetLastError(ERROR_ACCESS_DENIED);
2201 return FALSE;
2205 if (!mi2w->pName || (! mi2w->pName[0])) {
2206 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2207 SetLastError(ERROR_INVALID_PARAMETER);
2208 return FALSE;
2210 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2211 WARN("Environment %s requested (we support only %s)\n",
2212 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2213 SetLastError(ERROR_INVALID_ENVIRONMENT);
2214 return FALSE;
2217 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2218 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2219 SetLastError(ERROR_INVALID_PARAMETER);
2220 return FALSE;
2223 /* Load and initialize the monitor. SetLastError() is called on failure */
2224 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2225 return FALSE;
2227 monitor_unload(pm);
2229 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2230 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2231 return FALSE;
2234 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2235 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2236 &disposition) == ERROR_SUCCESS) {
2238 /* Some installers set options for the port before calling AddMonitor.
2239 We query the "Driver" entry to verify that the monitor is installed,
2240 before we return an error.
2241 When a user installs two print monitors at the same time with the
2242 same name but with a different driver DLL and a task switch comes
2243 between RegQueryValueExW and RegSetValueExW, a race condition
2244 is possible but silently ignored. */
2246 DWORD namesize = 0;
2248 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2249 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2250 &namesize) == ERROR_SUCCESS)) {
2251 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2252 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2253 9x: ERROR_ALREADY_EXISTS (183) */
2254 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2256 else
2258 INT len;
2259 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2260 res = (RegSetValueExW(hentry, DriverW, 0,
2261 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2263 RegCloseKey(hentry);
2266 RegCloseKey(hroot);
2267 return (res);
2270 /******************************************************************
2271 * DeletePrinterDriverA [WINSPOOL.@]
2274 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2276 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2279 /******************************************************************
2280 * DeletePrinterDriverW [WINSPOOL.@]
2283 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2285 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2288 /******************************************************************
2289 * DeleteMonitorA [WINSPOOL.@]
2291 * See DeleteMonitorW.
2294 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2296 LPWSTR nameW = NULL;
2297 LPWSTR EnvironmentW = NULL;
2298 LPWSTR MonitorNameW = NULL;
2299 BOOL res;
2300 INT len;
2302 if (pName) {
2303 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2304 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2305 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2308 if (pEnvironment) {
2309 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2310 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2311 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2313 if (pMonitorName) {
2314 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2315 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2316 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2319 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2321 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2322 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2323 HeapFree(GetProcessHeap(), 0, nameW);
2324 return (res);
2327 /******************************************************************
2328 * DeleteMonitorW [WINSPOOL.@]
2330 * Delete a specific Printmonitor from a Printing-Environment
2332 * PARAMS
2333 * pName [I] Servername or NULL (local Computer)
2334 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2335 * pMonitorName [I] Name of the Monitor, that should be deleted
2337 * RETURNS
2338 * Success: TRUE
2339 * Failure: FALSE
2341 * NOTES
2342 * pEnvironment is ignored in Windows for the local Computer.
2346 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2348 HKEY hroot = NULL;
2350 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2351 debugstr_w(pMonitorName));
2353 if (pName && (pName[0])) {
2354 FIXME("for server %s not implemented\n", debugstr_w(pName));
2355 SetLastError(ERROR_ACCESS_DENIED);
2356 return FALSE;
2359 /* pEnvironment is ignored in Windows for the local Computer */
2361 if (!pMonitorName || !pMonitorName[0]) {
2362 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2363 SetLastError(ERROR_INVALID_PARAMETER);
2364 return FALSE;
2367 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2368 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2369 return FALSE;
2372 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2373 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2374 RegCloseKey(hroot);
2375 return TRUE;
2378 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2379 RegCloseKey(hroot);
2381 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2382 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2383 return (FALSE);
2386 /******************************************************************
2387 * DeletePortA [WINSPOOL.@]
2389 * See DeletePortW.
2392 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2394 LPWSTR nameW = NULL;
2395 LPWSTR portW = NULL;
2396 INT len;
2397 DWORD res;
2399 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2401 /* convert servername to unicode */
2402 if (pName) {
2403 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2404 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2405 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2408 /* convert portname to unicode */
2409 if (pPortName) {
2410 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2411 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2412 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2415 res = DeletePortW(nameW, hWnd, portW);
2416 HeapFree(GetProcessHeap(), 0, nameW);
2417 HeapFree(GetProcessHeap(), 0, portW);
2418 return res;
2421 /******************************************************************
2422 * DeletePortW [WINSPOOL.@]
2424 * Delete a specific Port
2426 * PARAMS
2427 * pName [I] Servername or NULL (local Computer)
2428 * hWnd [I] Handle to parent Window for the Dialog-Box
2429 * pPortName [I] Name of the Port, that should be deleted
2431 * RETURNS
2432 * Success: TRUE
2433 * Failure: FALSE
2436 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2438 monitor_t * pm;
2439 monitor_t * pui;
2440 DWORD res;
2442 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2444 if (pName && pName[0]) {
2445 SetLastError(ERROR_INVALID_PARAMETER);
2446 return FALSE;
2449 if (!pPortName) {
2450 SetLastError(RPC_X_NULL_REF_POINTER);
2451 return FALSE;
2454 /* an empty Portname is Invalid */
2455 if (!pPortName[0]) {
2456 SetLastError(ERROR_NOT_SUPPORTED);
2457 return FALSE;
2460 pm = monitor_load_by_port(pPortName);
2461 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2462 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2463 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2464 TRACE("got %d with %u\n", res, GetLastError());
2466 else
2468 pui = monitor_loadui(pm);
2469 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2470 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2471 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2472 TRACE("got %d with %u\n", res, GetLastError());
2474 else
2476 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2477 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2479 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2480 SetLastError(ERROR_NOT_SUPPORTED);
2481 res = FALSE;
2483 monitor_unload(pui);
2485 monitor_unload(pm);
2487 TRACE("returning %d with %u\n", res, GetLastError());
2488 return res;
2491 /******************************************************************************
2492 * SetPrinterW [WINSPOOL.@]
2494 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2496 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2497 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2498 return FALSE;
2501 /******************************************************************************
2502 * WritePrinter [WINSPOOL.@]
2504 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2506 opened_printer_t *printer;
2507 BOOL ret = FALSE;
2509 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2511 EnterCriticalSection(&printer_handles_cs);
2512 printer = get_opened_printer(hPrinter);
2513 if(!printer)
2515 SetLastError(ERROR_INVALID_HANDLE);
2516 goto end;
2519 if(!printer->doc)
2521 SetLastError(ERROR_SPL_NO_STARTDOC);
2522 goto end;
2525 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2526 end:
2527 LeaveCriticalSection(&printer_handles_cs);
2528 return ret;
2531 /*****************************************************************************
2532 * AddFormA [WINSPOOL.@]
2534 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2536 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2537 return 1;
2540 /*****************************************************************************
2541 * AddFormW [WINSPOOL.@]
2543 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2545 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2546 return 1;
2549 /*****************************************************************************
2550 * AddJobA [WINSPOOL.@]
2552 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2554 BOOL ret;
2555 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2556 DWORD needed;
2558 if(Level != 1) {
2559 SetLastError(ERROR_INVALID_LEVEL);
2560 return FALSE;
2563 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2565 if(ret) {
2566 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2567 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2568 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2569 if(*pcbNeeded > cbBuf) {
2570 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2571 ret = FALSE;
2572 } else {
2573 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2574 addjobA->JobId = addjobW->JobId;
2575 addjobA->Path = (char *)(addjobA + 1);
2576 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2579 return ret;
2582 /*****************************************************************************
2583 * AddJobW [WINSPOOL.@]
2585 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2587 opened_printer_t *printer;
2588 job_t *job;
2589 BOOL ret = FALSE;
2590 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2591 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2592 WCHAR path[MAX_PATH], filename[MAX_PATH];
2593 DWORD len;
2594 ADDJOB_INFO_1W *addjob;
2596 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2598 EnterCriticalSection(&printer_handles_cs);
2600 printer = get_opened_printer(hPrinter);
2602 if(!printer) {
2603 SetLastError(ERROR_INVALID_HANDLE);
2604 goto end;
2607 if(Level != 1) {
2608 SetLastError(ERROR_INVALID_LEVEL);
2609 goto end;
2612 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2613 if(!job)
2614 goto end;
2616 job->job_id = InterlockedIncrement(&next_job_id);
2618 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2619 if(path[len - 1] != '\\')
2620 path[len++] = '\\';
2621 memcpy(path + len, spool_path, sizeof(spool_path));
2622 sprintfW(filename, fmtW, path, job->job_id);
2624 len = strlenW(filename);
2625 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2626 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2627 job->document_title = strdupW(default_doc_title);
2628 list_add_tail(&printer->queue->jobs, &job->entry);
2630 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2631 if(*pcbNeeded <= cbBuf) {
2632 addjob = (ADDJOB_INFO_1W*)pData;
2633 addjob->JobId = job->job_id;
2634 addjob->Path = (WCHAR *)(addjob + 1);
2635 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2636 ret = TRUE;
2637 } else
2638 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2640 end:
2641 LeaveCriticalSection(&printer_handles_cs);
2642 return ret;
2645 /*****************************************************************************
2646 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2648 * Return the PATH for the Print-Processors
2650 * See GetPrintProcessorDirectoryW.
2654 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2655 DWORD level, LPBYTE Info,
2656 DWORD cbBuf, LPDWORD pcbNeeded)
2658 LPWSTR serverW = NULL;
2659 LPWSTR envW = NULL;
2660 BOOL ret;
2661 INT len;
2663 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2664 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2667 if (server) {
2668 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2669 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2670 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2673 if (env) {
2674 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2675 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2676 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2679 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2680 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2682 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2683 cbBuf, pcbNeeded);
2685 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2686 cbBuf, NULL, NULL) > 0;
2689 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2690 HeapFree(GetProcessHeap(), 0, envW);
2691 HeapFree(GetProcessHeap(), 0, serverW);
2692 return ret;
2695 /*****************************************************************************
2696 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2698 * Return the PATH for the Print-Processors
2700 * PARAMS
2701 * server [I] Servername (NT only) or NULL (local Computer)
2702 * env [I] Printing-Environment (see below) or NULL (Default)
2703 * level [I] Structure-Level (must be 1)
2704 * Info [O] PTR to Buffer that receives the Result
2705 * cbBuf [I] Size of Buffer at "Info"
2706 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2707 * required for the Buffer at "Info"
2709 * RETURNS
2710 * Success: TRUE and in pcbNeeded the Bytes used in Info
2711 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2712 * if cbBuf is too small
2714 * Native Values returned in Info on Success:
2715 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2716 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2717 *| win9x(Windows 4.0): "%winsysdir%"
2719 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2721 * BUGS
2722 * Only NULL or "" is supported for server
2725 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2726 DWORD level, LPBYTE Info,
2727 DWORD cbBuf, LPDWORD pcbNeeded)
2729 DWORD needed;
2730 const printenv_t * env_t;
2732 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2733 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2735 if(server != NULL && server[0]) {
2736 FIXME("server not supported: %s\n", debugstr_w(server));
2737 SetLastError(ERROR_INVALID_PARAMETER);
2738 return FALSE;
2741 env_t = validate_envW(env);
2742 if(!env_t) return FALSE; /* environment invalid or unsupported */
2744 if(level != 1) {
2745 WARN("(Level: %d) is ignored in win9x\n", level);
2746 SetLastError(ERROR_INVALID_LEVEL);
2747 return FALSE;
2750 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2751 needed = GetSystemDirectoryW(NULL, 0);
2752 /* add the Size for the Subdirectories */
2753 needed += lstrlenW(spoolprtprocsW);
2754 needed += lstrlenW(env_t->subdir);
2755 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2757 if(pcbNeeded) *pcbNeeded = needed;
2758 TRACE ("required: 0x%x/%d\n", needed, needed);
2759 if (needed > cbBuf) {
2760 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2761 return FALSE;
2763 if(pcbNeeded == NULL) {
2764 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2765 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2766 SetLastError(RPC_X_NULL_REF_POINTER);
2767 return FALSE;
2769 if(Info == NULL) {
2770 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2771 SetLastError(RPC_X_NULL_REF_POINTER);
2772 return FALSE;
2775 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2776 /* add the Subdirectories */
2777 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2778 lstrcatW((LPWSTR) Info, env_t->subdir);
2779 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2780 return TRUE;
2783 /*****************************************************************************
2784 * WINSPOOL_OpenDriverReg [internal]
2786 * opens the registry for the printer drivers depending on the given input
2787 * variable pEnvironment
2789 * RETURNS:
2790 * the opened hkey on success
2791 * NULL on error
2793 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2795 HKEY retval = NULL;
2796 LPWSTR buffer;
2797 const printenv_t * env;
2799 TRACE("(%s, %d)\n",
2800 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2802 if (!pEnvironment || unicode) {
2803 /* pEnvironment was NULL or an Unicode-String: use it direct */
2804 env = validate_envW(pEnvironment);
2806 else
2808 /* pEnvironment was an ANSI-String: convert to unicode first */
2809 LPWSTR buffer;
2810 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2811 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2812 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2813 env = validate_envW(buffer);
2814 HeapFree(GetProcessHeap(), 0, buffer);
2816 if (!env) return NULL;
2818 buffer = HeapAlloc( GetProcessHeap(), 0,
2819 (strlenW(DriversW) + strlenW(env->envname) +
2820 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2821 if(buffer) {
2822 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2823 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2824 HeapFree(GetProcessHeap(), 0, buffer);
2826 return retval;
2829 /*****************************************************************************
2830 * AddPrinterW [WINSPOOL.@]
2832 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2834 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2835 LPDEVMODEA dmA;
2836 LPDEVMODEW dmW;
2837 HANDLE retval;
2838 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2839 LONG size;
2840 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2841 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2842 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2843 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2844 statusW[] = {'S','t','a','t','u','s',0},
2845 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2847 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2849 if(pName != NULL) {
2850 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2851 SetLastError(ERROR_INVALID_PARAMETER);
2852 return 0;
2854 if(Level != 2) {
2855 ERR("Level = %d, unsupported!\n", Level);
2856 SetLastError(ERROR_INVALID_LEVEL);
2857 return 0;
2859 if(!pPrinter) {
2860 SetLastError(ERROR_INVALID_PARAMETER);
2861 return 0;
2863 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2864 ERROR_SUCCESS) {
2865 ERR("Can't create Printers key\n");
2866 return 0;
2868 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2869 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2870 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2871 RegCloseKey(hkeyPrinter);
2872 RegCloseKey(hkeyPrinters);
2873 return 0;
2875 RegCloseKey(hkeyPrinter);
2877 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2878 if(!hkeyDrivers) {
2879 ERR("Can't create Drivers key\n");
2880 RegCloseKey(hkeyPrinters);
2881 return 0;
2883 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2884 ERROR_SUCCESS) {
2885 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2886 RegCloseKey(hkeyPrinters);
2887 RegCloseKey(hkeyDrivers);
2888 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2889 return 0;
2891 RegCloseKey(hkeyDriver);
2892 RegCloseKey(hkeyDrivers);
2894 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2895 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2896 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2897 RegCloseKey(hkeyPrinters);
2898 return 0;
2901 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2902 ERROR_SUCCESS) {
2903 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2904 SetLastError(ERROR_INVALID_PRINTER_NAME);
2905 RegCloseKey(hkeyPrinters);
2906 return 0;
2908 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2909 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2910 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2912 /* See if we can load the driver. We may need the devmode structure anyway
2914 * FIXME:
2915 * Note that DocumentPropertiesW will briefly try to open the printer we
2916 * just create to find a DEVMODEA struct (it will use the WINEPS default
2917 * one in case it is not there, so we are ok).
2919 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2921 if(size < 0) {
2922 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2923 size = sizeof(DEVMODEW);
2925 if(pi->pDevMode)
2926 dmW = pi->pDevMode;
2927 else
2929 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2930 dmW->dmSize = size;
2931 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2933 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2934 HeapFree(GetProcessHeap(),0,dmW);
2935 dmW=NULL;
2937 else
2939 /* set devmode to printer name */
2940 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2944 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2945 and we support these drivers. NT writes DEVMODEW so somehow
2946 we'll need to distinguish between these when we support NT
2947 drivers */
2948 if (dmW)
2950 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2951 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2952 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2953 HeapFree(GetProcessHeap(), 0, dmA);
2954 if(!pi->pDevMode)
2955 HeapFree(GetProcessHeap(), 0, dmW);
2957 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2958 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2959 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2960 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2962 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2963 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2964 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2965 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2966 (LPBYTE)&pi->Priority, sizeof(DWORD));
2967 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2968 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2969 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2970 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2971 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2972 (LPBYTE)&pi->Status, sizeof(DWORD));
2973 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2974 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2976 RegCloseKey(hkeyPrinter);
2977 RegCloseKey(hkeyPrinters);
2978 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2979 ERR("OpenPrinter failing\n");
2980 return 0;
2982 return retval;
2985 /*****************************************************************************
2986 * AddPrinterA [WINSPOOL.@]
2988 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2990 UNICODE_STRING pNameW;
2991 PWSTR pwstrNameW;
2992 PRINTER_INFO_2W *piW;
2993 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2994 HANDLE ret;
2996 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2997 if(Level != 2) {
2998 ERR("Level = %d, unsupported!\n", Level);
2999 SetLastError(ERROR_INVALID_LEVEL);
3000 return 0;
3002 pwstrNameW = asciitounicode(&pNameW,pName);
3003 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3005 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3007 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3008 RtlFreeUnicodeString(&pNameW);
3009 return ret;
3013 /*****************************************************************************
3014 * ClosePrinter [WINSPOOL.@]
3016 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3018 UINT_PTR i = (UINT_PTR)hPrinter;
3019 opened_printer_t *printer = NULL;
3020 BOOL ret = FALSE;
3022 TRACE("(%p)\n", hPrinter);
3024 EnterCriticalSection(&printer_handles_cs);
3026 if ((i > 0) && (i <= nb_printer_handles))
3027 printer = printer_handles[i - 1];
3030 if(printer)
3032 struct list *cursor, *cursor2;
3034 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3035 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3036 printer->hXcv, debugstr_w(printer->name), printer->doc );
3038 if(printer->doc)
3039 EndDocPrinter(hPrinter);
3041 if(InterlockedDecrement(&printer->queue->ref) == 0)
3043 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3045 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3046 ScheduleJob(hPrinter, job->job_id);
3048 HeapFree(GetProcessHeap(), 0, printer->queue);
3050 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3051 monitor_unload(printer->pm);
3052 HeapFree(GetProcessHeap(), 0, printer->printername);
3053 HeapFree(GetProcessHeap(), 0, printer->name);
3054 HeapFree(GetProcessHeap(), 0, printer);
3055 printer_handles[i - 1] = NULL;
3056 ret = TRUE;
3058 LeaveCriticalSection(&printer_handles_cs);
3059 return ret;
3062 /*****************************************************************************
3063 * DeleteFormA [WINSPOOL.@]
3065 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3067 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3068 return 1;
3071 /*****************************************************************************
3072 * DeleteFormW [WINSPOOL.@]
3074 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3076 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3077 return 1;
3080 /*****************************************************************************
3081 * DeletePrinter [WINSPOOL.@]
3083 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3085 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3086 HKEY hkeyPrinters, hkey;
3088 if(!lpNameW) {
3089 SetLastError(ERROR_INVALID_HANDLE);
3090 return FALSE;
3092 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3093 RegDeleteTreeW(hkeyPrinters, lpNameW);
3094 RegCloseKey(hkeyPrinters);
3096 WriteProfileStringW(devicesW, lpNameW, NULL);
3097 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3098 RegDeleteValueW(hkey, lpNameW);
3099 RegCloseKey(hkey);
3101 return TRUE;
3104 /*****************************************************************************
3105 * SetPrinterA [WINSPOOL.@]
3107 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3108 DWORD Command)
3110 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3111 return FALSE;
3114 /*****************************************************************************
3115 * SetJobA [WINSPOOL.@]
3117 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3118 LPBYTE pJob, DWORD Command)
3120 BOOL ret;
3121 LPBYTE JobW;
3122 UNICODE_STRING usBuffer;
3124 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3126 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3127 are all ignored by SetJob, so we don't bother copying them */
3128 switch(Level)
3130 case 0:
3131 JobW = NULL;
3132 break;
3133 case 1:
3135 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3136 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3138 JobW = (LPBYTE)info1W;
3139 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3140 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3141 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3142 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3143 info1W->Status = info1A->Status;
3144 info1W->Priority = info1A->Priority;
3145 info1W->Position = info1A->Position;
3146 info1W->PagesPrinted = info1A->PagesPrinted;
3147 break;
3149 case 2:
3151 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3152 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3154 JobW = (LPBYTE)info2W;
3155 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3156 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3157 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3158 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3159 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3160 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3161 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3162 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3163 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3164 info2W->Status = info2A->Status;
3165 info2W->Priority = info2A->Priority;
3166 info2W->Position = info2A->Position;
3167 info2W->StartTime = info2A->StartTime;
3168 info2W->UntilTime = info2A->UntilTime;
3169 info2W->PagesPrinted = info2A->PagesPrinted;
3170 break;
3172 case 3:
3173 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3174 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3175 break;
3176 default:
3177 SetLastError(ERROR_INVALID_LEVEL);
3178 return FALSE;
3181 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3183 switch(Level)
3185 case 1:
3187 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3188 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3189 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3190 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3191 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3192 break;
3194 case 2:
3196 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3197 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3198 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3199 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3200 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3201 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3202 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3203 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3204 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3205 break;
3208 HeapFree(GetProcessHeap(), 0, JobW);
3210 return ret;
3213 /*****************************************************************************
3214 * SetJobW [WINSPOOL.@]
3216 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3217 LPBYTE pJob, DWORD Command)
3219 BOOL ret = FALSE;
3220 job_t *job;
3222 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3223 FIXME("Ignoring everything other than document title\n");
3225 EnterCriticalSection(&printer_handles_cs);
3226 job = get_job(hPrinter, JobId);
3227 if(!job)
3228 goto end;
3230 switch(Level)
3232 case 0:
3233 break;
3234 case 1:
3236 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3237 HeapFree(GetProcessHeap(), 0, job->document_title);
3238 job->document_title = strdupW(info1->pDocument);
3239 break;
3241 case 2:
3243 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3244 HeapFree(GetProcessHeap(), 0, job->document_title);
3245 job->document_title = strdupW(info2->pDocument);
3246 break;
3248 case 3:
3249 break;
3250 default:
3251 SetLastError(ERROR_INVALID_LEVEL);
3252 goto end;
3254 ret = TRUE;
3255 end:
3256 LeaveCriticalSection(&printer_handles_cs);
3257 return ret;
3260 /*****************************************************************************
3261 * EndDocPrinter [WINSPOOL.@]
3263 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3265 opened_printer_t *printer;
3266 BOOL ret = FALSE;
3267 TRACE("(%p)\n", hPrinter);
3269 EnterCriticalSection(&printer_handles_cs);
3271 printer = get_opened_printer(hPrinter);
3272 if(!printer)
3274 SetLastError(ERROR_INVALID_HANDLE);
3275 goto end;
3278 if(!printer->doc)
3280 SetLastError(ERROR_SPL_NO_STARTDOC);
3281 goto end;
3284 CloseHandle(printer->doc->hf);
3285 ScheduleJob(hPrinter, printer->doc->job_id);
3286 HeapFree(GetProcessHeap(), 0, printer->doc);
3287 printer->doc = NULL;
3288 ret = TRUE;
3289 end:
3290 LeaveCriticalSection(&printer_handles_cs);
3291 return ret;
3294 /*****************************************************************************
3295 * EndPagePrinter [WINSPOOL.@]
3297 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3299 FIXME("(%p): stub\n", hPrinter);
3300 return TRUE;
3303 /*****************************************************************************
3304 * StartDocPrinterA [WINSPOOL.@]
3306 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3308 UNICODE_STRING usBuffer;
3309 DOC_INFO_2W doc2W;
3310 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3311 DWORD ret;
3313 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3314 or one (DOC_INFO_3) extra DWORDs */
3316 switch(Level) {
3317 case 2:
3318 doc2W.JobId = doc2->JobId;
3319 /* fall through */
3320 case 3:
3321 doc2W.dwMode = doc2->dwMode;
3322 /* fall through */
3323 case 1:
3324 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3325 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3326 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3327 break;
3329 default:
3330 SetLastError(ERROR_INVALID_LEVEL);
3331 return FALSE;
3334 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3336 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3337 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3338 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3340 return ret;
3343 /*****************************************************************************
3344 * StartDocPrinterW [WINSPOOL.@]
3346 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3348 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3349 opened_printer_t *printer;
3350 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3351 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3352 JOB_INFO_1W job_info;
3353 DWORD needed, ret = 0;
3354 HANDLE hf;
3355 WCHAR *filename;
3357 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3358 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3359 debugstr_w(doc->pDatatype));
3361 if(Level < 1 || Level > 3)
3363 SetLastError(ERROR_INVALID_LEVEL);
3364 return 0;
3367 EnterCriticalSection(&printer_handles_cs);
3368 printer = get_opened_printer(hPrinter);
3369 if(!printer)
3371 SetLastError(ERROR_INVALID_HANDLE);
3372 goto end;
3375 if(printer->doc)
3377 SetLastError(ERROR_INVALID_PRINTER_STATE);
3378 goto end;
3381 /* Even if we're printing to a file we still add a print job, we'll
3382 just ignore the spool file name */
3384 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3386 ERR("AddJob failed gle %u\n", GetLastError());
3387 goto end;
3390 if(doc->pOutputFile)
3391 filename = doc->pOutputFile;
3392 else
3393 filename = addjob->Path;
3395 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3396 if(hf == INVALID_HANDLE_VALUE)
3397 goto end;
3399 memset(&job_info, 0, sizeof(job_info));
3400 job_info.pDocument = doc->pDocName;
3401 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3403 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3404 printer->doc->hf = hf;
3405 ret = printer->doc->job_id = addjob->JobId;
3406 end:
3407 LeaveCriticalSection(&printer_handles_cs);
3409 return ret;
3412 /*****************************************************************************
3413 * StartPagePrinter [WINSPOOL.@]
3415 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3417 FIXME("(%p): stub\n", hPrinter);
3418 return TRUE;
3421 /*****************************************************************************
3422 * GetFormA [WINSPOOL.@]
3424 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3425 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3427 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3428 Level,pForm,cbBuf,pcbNeeded);
3429 return FALSE;
3432 /*****************************************************************************
3433 * GetFormW [WINSPOOL.@]
3435 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3436 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3438 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3439 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3440 return FALSE;
3443 /*****************************************************************************
3444 * SetFormA [WINSPOOL.@]
3446 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3447 LPBYTE pForm)
3449 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3450 return FALSE;
3453 /*****************************************************************************
3454 * SetFormW [WINSPOOL.@]
3456 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3457 LPBYTE pForm)
3459 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3460 return FALSE;
3463 /*****************************************************************************
3464 * ReadPrinter [WINSPOOL.@]
3466 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3467 LPDWORD pNoBytesRead)
3469 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3470 return FALSE;
3473 /*****************************************************************************
3474 * ResetPrinterA [WINSPOOL.@]
3476 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3478 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3479 return FALSE;
3482 /*****************************************************************************
3483 * ResetPrinterW [WINSPOOL.@]
3485 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3487 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3488 return FALSE;
3491 /*****************************************************************************
3492 * WINSPOOL_GetDWORDFromReg
3494 * Return DWORD associated with ValueName from hkey.
3496 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3498 DWORD sz = sizeof(DWORD), type, value = 0;
3499 LONG ret;
3501 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3503 if(ret != ERROR_SUCCESS) {
3504 WARN("Got ret = %d on name %s\n", ret, ValueName);
3505 return 0;
3507 if(type != REG_DWORD) {
3508 ERR("Got type %d\n", type);
3509 return 0;
3511 return value;
3515 /*****************************************************************************
3516 * get_filename_from_reg [internal]
3518 * Get ValueName from hkey storing result in out
3519 * when the Value in the registry has only a filename, use driverdir as prefix
3520 * outlen is space left in out
3521 * String is stored either as unicode or ascii
3525 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3526 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3528 WCHAR filename[MAX_PATH];
3529 DWORD size;
3530 DWORD type;
3531 LONG ret;
3532 LPWSTR buffer = filename;
3533 LPWSTR ptr;
3535 *needed = 0;
3536 size = sizeof(filename);
3537 buffer[0] = '\0';
3538 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3539 if (ret == ERROR_MORE_DATA) {
3540 TRACE("need dynamic buffer: %u\n", size);
3541 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3542 if (!buffer) {
3543 /* No Memory is bad */
3544 return FALSE;
3546 buffer[0] = '\0';
3547 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3550 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3551 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3552 return FALSE;
3555 ptr = buffer;
3556 while (ptr) {
3557 /* do we have a full path ? */
3558 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3559 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3561 if (!ret) {
3562 /* we must build the full Path */
3563 *needed += dirlen;
3564 if ((out) && (outlen > dirlen)) {
3565 if (unicode) {
3566 lstrcpyW((LPWSTR)out, driverdir);
3568 else
3570 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3572 out += dirlen;
3573 outlen -= dirlen;
3575 else
3576 out = NULL;
3579 /* write the filename */
3580 if (unicode) {
3581 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3582 if ((out) && (outlen >= size)) {
3583 lstrcpyW((LPWSTR)out, ptr);
3584 out += size;
3585 outlen -= size;
3587 else
3588 out = NULL;
3590 else
3592 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3593 if ((out) && (outlen >= size)) {
3594 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3595 out += size;
3596 outlen -= size;
3598 else
3599 out = NULL;
3601 *needed += size;
3602 ptr += lstrlenW(ptr)+1;
3603 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3606 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3608 /* write the multisz-termination */
3609 if (type == REG_MULTI_SZ) {
3610 size = (unicode) ? sizeof(WCHAR) : 1;
3612 *needed += size;
3613 if (out && (outlen >= size)) {
3614 memset (out, 0, size);
3617 return TRUE;
3620 /*****************************************************************************
3621 * WINSPOOL_GetStringFromReg
3623 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3624 * String is stored either as unicode or ascii.
3625 * Bit of a hack here to get the ValueName if we want ascii.
3627 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3628 DWORD buflen, DWORD *needed,
3629 BOOL unicode)
3631 DWORD sz = buflen, type;
3632 LONG ret;
3634 if(unicode)
3635 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3636 else {
3637 LPSTR ValueNameA = strdupWtoA(ValueName);
3638 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3639 HeapFree(GetProcessHeap(),0,ValueNameA);
3641 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3642 WARN("Got ret = %d\n", ret);
3643 *needed = 0;
3644 return FALSE;
3646 /* add space for terminating '\0' */
3647 sz += unicode ? sizeof(WCHAR) : 1;
3648 *needed = sz;
3650 if (ptr)
3651 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3653 return TRUE;
3656 /*****************************************************************************
3657 * WINSPOOL_GetDefaultDevMode
3659 * Get a default DevMode values for wineps.
3660 * FIXME - use ppd.
3663 static void WINSPOOL_GetDefaultDevMode(
3664 LPBYTE ptr,
3665 DWORD buflen, DWORD *needed,
3666 BOOL unicode)
3668 DEVMODEA dm;
3669 static const char szwps[] = "wineps.drv";
3671 /* fill default DEVMODE - should be read from ppd... */
3672 ZeroMemory( &dm, sizeof(dm) );
3673 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3674 dm.dmSpecVersion = DM_SPECVERSION;
3675 dm.dmDriverVersion = 1;
3676 dm.dmSize = sizeof(DEVMODEA);
3677 dm.dmDriverExtra = 0;
3678 dm.dmFields =
3679 DM_ORIENTATION | DM_PAPERSIZE |
3680 DM_PAPERLENGTH | DM_PAPERWIDTH |
3681 DM_SCALE |
3682 DM_COPIES |
3683 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3684 DM_YRESOLUTION | DM_TTOPTION;
3686 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3687 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3688 dm.u1.s1.dmPaperLength = 2970;
3689 dm.u1.s1.dmPaperWidth = 2100;
3691 dm.u1.s1.dmScale = 100;
3692 dm.u1.s1.dmCopies = 1;
3693 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3694 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3695 /* dm.dmColor */
3696 /* dm.dmDuplex */
3697 dm.dmYResolution = 300; /* 300dpi */
3698 dm.dmTTOption = DMTT_BITMAP;
3699 /* dm.dmCollate */
3700 /* dm.dmFormName */
3701 /* dm.dmLogPixels */
3702 /* dm.dmBitsPerPel */
3703 /* dm.dmPelsWidth */
3704 /* dm.dmPelsHeight */
3705 /* dm.u2.dmDisplayFlags */
3706 /* dm.dmDisplayFrequency */
3707 /* dm.dmICMMethod */
3708 /* dm.dmICMIntent */
3709 /* dm.dmMediaType */
3710 /* dm.dmDitherType */
3711 /* dm.dmReserved1 */
3712 /* dm.dmReserved2 */
3713 /* dm.dmPanningWidth */
3714 /* dm.dmPanningHeight */
3716 if(unicode) {
3717 if(buflen >= sizeof(DEVMODEW)) {
3718 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3719 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3720 HeapFree(GetProcessHeap(),0,pdmW);
3722 *needed = sizeof(DEVMODEW);
3724 else
3726 if(buflen >= sizeof(DEVMODEA)) {
3727 memcpy(ptr, &dm, sizeof(DEVMODEA));
3729 *needed = sizeof(DEVMODEA);
3733 /*****************************************************************************
3734 * WINSPOOL_GetDevModeFromReg
3736 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3737 * DevMode is stored either as unicode or ascii.
3739 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3740 LPBYTE ptr,
3741 DWORD buflen, DWORD *needed,
3742 BOOL unicode)
3744 DWORD sz = buflen, type;
3745 LONG ret;
3747 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3748 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3749 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3750 if (sz < sizeof(DEVMODEA))
3752 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3753 return FALSE;
3755 /* ensures that dmSize is not erratically bogus if registry is invalid */
3756 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3757 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3758 if(unicode) {
3759 sz += (CCHDEVICENAME + CCHFORMNAME);
3760 if(buflen >= sz) {
3761 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3762 memcpy(ptr, dmW, sz);
3763 HeapFree(GetProcessHeap(),0,dmW);
3766 *needed = sz;
3767 return TRUE;
3770 /*********************************************************************
3771 * WINSPOOL_GetPrinter_1
3773 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3774 * The strings are either stored as unicode or ascii.
3776 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3777 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3778 BOOL unicode)
3780 DWORD size, left = cbBuf;
3781 BOOL space = (cbBuf > 0);
3782 LPBYTE ptr = buf;
3784 *pcbNeeded = 0;
3786 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3787 unicode)) {
3788 if(space && size <= left) {
3789 pi1->pName = (LPWSTR)ptr;
3790 ptr += size;
3791 left -= size;
3792 } else
3793 space = FALSE;
3794 *pcbNeeded += size;
3797 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3798 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3799 unicode)) {
3800 if(space && size <= left) {
3801 pi1->pDescription = (LPWSTR)ptr;
3802 ptr += size;
3803 left -= size;
3804 } else
3805 space = FALSE;
3806 *pcbNeeded += size;
3809 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3810 unicode)) {
3811 if(space && size <= left) {
3812 pi1->pComment = (LPWSTR)ptr;
3813 ptr += size;
3814 left -= size;
3815 } else
3816 space = FALSE;
3817 *pcbNeeded += size;
3820 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3822 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3823 memset(pi1, 0, sizeof(*pi1));
3825 return space;
3827 /*********************************************************************
3828 * WINSPOOL_GetPrinter_2
3830 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3831 * The strings are either stored as unicode or ascii.
3833 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3834 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3835 BOOL unicode)
3837 DWORD size, left = cbBuf;
3838 BOOL space = (cbBuf > 0);
3839 LPBYTE ptr = buf;
3841 *pcbNeeded = 0;
3843 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3844 unicode)) {
3845 if(space && size <= left) {
3846 pi2->pPrinterName = (LPWSTR)ptr;
3847 ptr += size;
3848 left -= size;
3849 } else
3850 space = FALSE;
3851 *pcbNeeded += size;
3853 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3854 unicode)) {
3855 if(space && size <= left) {
3856 pi2->pShareName = (LPWSTR)ptr;
3857 ptr += size;
3858 left -= size;
3859 } else
3860 space = FALSE;
3861 *pcbNeeded += size;
3863 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3864 unicode)) {
3865 if(space && size <= left) {
3866 pi2->pPortName = (LPWSTR)ptr;
3867 ptr += size;
3868 left -= size;
3869 } else
3870 space = FALSE;
3871 *pcbNeeded += size;
3873 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3874 &size, unicode)) {
3875 if(space && size <= left) {
3876 pi2->pDriverName = (LPWSTR)ptr;
3877 ptr += size;
3878 left -= size;
3879 } else
3880 space = FALSE;
3881 *pcbNeeded += size;
3883 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3884 unicode)) {
3885 if(space && size <= left) {
3886 pi2->pComment = (LPWSTR)ptr;
3887 ptr += size;
3888 left -= size;
3889 } else
3890 space = FALSE;
3891 *pcbNeeded += size;
3893 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3894 unicode)) {
3895 if(space && size <= left) {
3896 pi2->pLocation = (LPWSTR)ptr;
3897 ptr += size;
3898 left -= size;
3899 } else
3900 space = FALSE;
3901 *pcbNeeded += size;
3903 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3904 &size, unicode)) {
3905 if(space && size <= left) {
3906 pi2->pDevMode = (LPDEVMODEW)ptr;
3907 ptr += size;
3908 left -= size;
3909 } else
3910 space = FALSE;
3911 *pcbNeeded += size;
3913 else
3915 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3916 if(space && size <= left) {
3917 pi2->pDevMode = (LPDEVMODEW)ptr;
3918 ptr += size;
3919 left -= size;
3920 } else
3921 space = FALSE;
3922 *pcbNeeded += size;
3924 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3925 &size, unicode)) {
3926 if(space && size <= left) {
3927 pi2->pSepFile = (LPWSTR)ptr;
3928 ptr += size;
3929 left -= size;
3930 } else
3931 space = FALSE;
3932 *pcbNeeded += size;
3934 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3935 &size, unicode)) {
3936 if(space && size <= left) {
3937 pi2->pPrintProcessor = (LPWSTR)ptr;
3938 ptr += size;
3939 left -= size;
3940 } else
3941 space = FALSE;
3942 *pcbNeeded += size;
3944 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3945 &size, unicode)) {
3946 if(space && size <= left) {
3947 pi2->pDatatype = (LPWSTR)ptr;
3948 ptr += size;
3949 left -= size;
3950 } else
3951 space = FALSE;
3952 *pcbNeeded += size;
3954 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3955 &size, unicode)) {
3956 if(space && size <= left) {
3957 pi2->pParameters = (LPWSTR)ptr;
3958 ptr += size;
3959 left -= size;
3960 } else
3961 space = FALSE;
3962 *pcbNeeded += size;
3964 if(pi2) {
3965 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3966 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3967 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3968 "Default Priority");
3969 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3970 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3973 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3974 memset(pi2, 0, sizeof(*pi2));
3976 return space;
3979 /*********************************************************************
3980 * WINSPOOL_GetPrinter_4
3982 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3984 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3985 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3986 BOOL unicode)
3988 DWORD size, left = cbBuf;
3989 BOOL space = (cbBuf > 0);
3990 LPBYTE ptr = buf;
3992 *pcbNeeded = 0;
3994 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3995 unicode)) {
3996 if(space && size <= left) {
3997 pi4->pPrinterName = (LPWSTR)ptr;
3998 ptr += size;
3999 left -= size;
4000 } else
4001 space = FALSE;
4002 *pcbNeeded += size;
4004 if(pi4) {
4005 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4008 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4009 memset(pi4, 0, sizeof(*pi4));
4011 return space;
4014 /*********************************************************************
4015 * WINSPOOL_GetPrinter_5
4017 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4019 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4020 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4021 BOOL unicode)
4023 DWORD size, left = cbBuf;
4024 BOOL space = (cbBuf > 0);
4025 LPBYTE ptr = buf;
4027 *pcbNeeded = 0;
4029 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4030 unicode)) {
4031 if(space && size <= left) {
4032 pi5->pPrinterName = (LPWSTR)ptr;
4033 ptr += size;
4034 left -= size;
4035 } else
4036 space = FALSE;
4037 *pcbNeeded += size;
4039 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4040 unicode)) {
4041 if(space && size <= left) {
4042 pi5->pPortName = (LPWSTR)ptr;
4043 ptr += size;
4044 left -= size;
4045 } else
4046 space = FALSE;
4047 *pcbNeeded += size;
4049 if(pi5) {
4050 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4051 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4052 "dnsTimeout");
4053 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4054 "txTimeout");
4057 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4058 memset(pi5, 0, sizeof(*pi5));
4060 return space;
4063 /*****************************************************************************
4064 * WINSPOOL_GetPrinter
4066 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4067 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4068 * just a collection of pointers to strings.
4070 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4071 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4073 LPCWSTR name;
4074 DWORD size, needed = 0;
4075 LPBYTE ptr = NULL;
4076 HKEY hkeyPrinter, hkeyPrinters;
4077 BOOL ret;
4079 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4081 if (!(name = get_opened_printer_name(hPrinter))) {
4082 SetLastError(ERROR_INVALID_HANDLE);
4083 return FALSE;
4086 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4087 ERROR_SUCCESS) {
4088 ERR("Can't create Printers key\n");
4089 return FALSE;
4091 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4093 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4094 RegCloseKey(hkeyPrinters);
4095 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4096 return FALSE;
4099 switch(Level) {
4100 case 2:
4102 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4104 size = sizeof(PRINTER_INFO_2W);
4105 if(size <= cbBuf) {
4106 ptr = pPrinter + size;
4107 cbBuf -= size;
4108 memset(pPrinter, 0, size);
4109 } else {
4110 pi2 = NULL;
4111 cbBuf = 0;
4113 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4114 unicode);
4115 needed += size;
4116 break;
4119 case 4:
4121 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4123 size = sizeof(PRINTER_INFO_4W);
4124 if(size <= cbBuf) {
4125 ptr = pPrinter + size;
4126 cbBuf -= size;
4127 memset(pPrinter, 0, size);
4128 } else {
4129 pi4 = NULL;
4130 cbBuf = 0;
4132 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4133 unicode);
4134 needed += size;
4135 break;
4139 case 5:
4141 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4143 size = sizeof(PRINTER_INFO_5W);
4144 if(size <= cbBuf) {
4145 ptr = pPrinter + size;
4146 cbBuf -= size;
4147 memset(pPrinter, 0, size);
4148 } else {
4149 pi5 = NULL;
4150 cbBuf = 0;
4153 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4154 unicode);
4155 needed += size;
4156 break;
4159 default:
4160 FIXME("Unimplemented level %d\n", Level);
4161 SetLastError(ERROR_INVALID_LEVEL);
4162 RegCloseKey(hkeyPrinters);
4163 RegCloseKey(hkeyPrinter);
4164 return FALSE;
4167 RegCloseKey(hkeyPrinter);
4168 RegCloseKey(hkeyPrinters);
4170 TRACE("returning %d needed = %d\n", ret, needed);
4171 if(pcbNeeded) *pcbNeeded = needed;
4172 if(!ret)
4173 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4174 return ret;
4177 /*****************************************************************************
4178 * GetPrinterW [WINSPOOL.@]
4180 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4181 DWORD cbBuf, LPDWORD pcbNeeded)
4183 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4184 TRUE);
4187 /*****************************************************************************
4188 * GetPrinterA [WINSPOOL.@]
4190 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4191 DWORD cbBuf, LPDWORD pcbNeeded)
4193 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4194 FALSE);
4197 /*****************************************************************************
4198 * WINSPOOL_EnumPrinters
4200 * Implementation of EnumPrintersA|W
4202 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4203 DWORD dwLevel, LPBYTE lpbPrinters,
4204 DWORD cbBuf, LPDWORD lpdwNeeded,
4205 LPDWORD lpdwReturned, BOOL unicode)
4208 HKEY hkeyPrinters, hkeyPrinter;
4209 WCHAR PrinterName[255];
4210 DWORD needed = 0, number = 0;
4211 DWORD used, i, left;
4212 PBYTE pi, buf;
4214 if(lpbPrinters)
4215 memset(lpbPrinters, 0, cbBuf);
4216 if(lpdwReturned)
4217 *lpdwReturned = 0;
4218 if(lpdwNeeded)
4219 *lpdwNeeded = 0;
4221 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4222 if(dwType == PRINTER_ENUM_DEFAULT)
4223 return TRUE;
4225 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4226 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4227 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4228 if (!dwType) {
4229 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4230 *lpdwNeeded = 0;
4231 *lpdwReturned = 0;
4232 return TRUE;
4237 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4238 FIXME("dwType = %08x\n", dwType);
4239 SetLastError(ERROR_INVALID_FLAGS);
4240 return FALSE;
4243 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4244 ERROR_SUCCESS) {
4245 ERR("Can't create Printers key\n");
4246 return FALSE;
4249 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4250 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4251 RegCloseKey(hkeyPrinters);
4252 ERR("Can't query Printers key\n");
4253 return FALSE;
4255 TRACE("Found %d printers\n", number);
4257 switch(dwLevel) {
4258 case 1:
4259 used = number * sizeof(PRINTER_INFO_1W);
4260 break;
4261 case 2:
4262 used = number * sizeof(PRINTER_INFO_2W);
4263 break;
4264 case 4:
4265 used = number * sizeof(PRINTER_INFO_4W);
4266 break;
4267 case 5:
4268 used = number * sizeof(PRINTER_INFO_5W);
4269 break;
4271 default:
4272 SetLastError(ERROR_INVALID_LEVEL);
4273 RegCloseKey(hkeyPrinters);
4274 return FALSE;
4276 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4278 for(i = 0; i < number; i++) {
4279 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4280 ERROR_SUCCESS) {
4281 ERR("Can't enum key number %d\n", i);
4282 RegCloseKey(hkeyPrinters);
4283 return FALSE;
4285 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4286 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4287 ERROR_SUCCESS) {
4288 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4289 RegCloseKey(hkeyPrinters);
4290 return FALSE;
4293 if(cbBuf > used) {
4294 buf = lpbPrinters + used;
4295 left = cbBuf - used;
4296 } else {
4297 buf = NULL;
4298 left = 0;
4301 switch(dwLevel) {
4302 case 1:
4303 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4304 left, &needed, unicode);
4305 used += needed;
4306 if(pi) pi += sizeof(PRINTER_INFO_1W);
4307 break;
4308 case 2:
4309 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4310 left, &needed, unicode);
4311 used += needed;
4312 if(pi) pi += sizeof(PRINTER_INFO_2W);
4313 break;
4314 case 4:
4315 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4316 left, &needed, unicode);
4317 used += needed;
4318 if(pi) pi += sizeof(PRINTER_INFO_4W);
4319 break;
4320 case 5:
4321 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4322 left, &needed, unicode);
4323 used += needed;
4324 if(pi) pi += sizeof(PRINTER_INFO_5W);
4325 break;
4326 default:
4327 ERR("Shouldn't be here!\n");
4328 RegCloseKey(hkeyPrinter);
4329 RegCloseKey(hkeyPrinters);
4330 return FALSE;
4332 RegCloseKey(hkeyPrinter);
4334 RegCloseKey(hkeyPrinters);
4336 if(lpdwNeeded)
4337 *lpdwNeeded = used;
4339 if(used > cbBuf) {
4340 if(lpbPrinters)
4341 memset(lpbPrinters, 0, cbBuf);
4342 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4343 return FALSE;
4345 if(lpdwReturned)
4346 *lpdwReturned = number;
4347 SetLastError(ERROR_SUCCESS);
4348 return TRUE;
4352 /******************************************************************
4353 * EnumPrintersW [WINSPOOL.@]
4355 * Enumerates the available printers, print servers and print
4356 * providers, depending on the specified flags, name and level.
4358 * RETURNS:
4360 * If level is set to 1:
4361 * Returns an array of PRINTER_INFO_1 data structures in the
4362 * lpbPrinters buffer.
4364 * If level is set to 2:
4365 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4366 * Returns an array of PRINTER_INFO_2 data structures in the
4367 * lpbPrinters buffer. Note that according to MSDN also an
4368 * OpenPrinter should be performed on every remote printer.
4370 * If level is set to 4 (officially WinNT only):
4371 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4372 * Fast: Only the registry is queried to retrieve printer names,
4373 * no connection to the driver is made.
4374 * Returns an array of PRINTER_INFO_4 data structures in the
4375 * lpbPrinters buffer.
4377 * If level is set to 5 (officially WinNT4/Win9x only):
4378 * Fast: Only the registry is queried to retrieve printer names,
4379 * no connection to the driver is made.
4380 * Returns an array of PRINTER_INFO_5 data structures in the
4381 * lpbPrinters buffer.
4383 * If level set to 3 or 6+:
4384 * returns zero (failure!)
4386 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4387 * for information.
4389 * BUGS:
4390 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4391 * - Only levels 2, 4 and 5 are implemented at the moment.
4392 * - 16-bit printer drivers are not enumerated.
4393 * - Returned amount of bytes used/needed does not match the real Windoze
4394 * implementation (as in this implementation, all strings are part
4395 * of the buffer, whereas Win32 keeps them somewhere else)
4396 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4398 * NOTE:
4399 * - In a regular Wine installation, no registry settings for printers
4400 * exist, which makes this function return an empty list.
4402 BOOL WINAPI EnumPrintersW(
4403 DWORD dwType, /* [in] Types of print objects to enumerate */
4404 LPWSTR lpszName, /* [in] name of objects to enumerate */
4405 DWORD dwLevel, /* [in] type of printer info structure */
4406 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4407 DWORD cbBuf, /* [in] max size of buffer in bytes */
4408 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4409 LPDWORD lpdwReturned /* [out] number of entries returned */
4412 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4413 lpdwNeeded, lpdwReturned, TRUE);
4416 /******************************************************************
4417 * EnumPrintersA [WINSPOOL.@]
4420 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4421 DWORD dwLevel, LPBYTE lpbPrinters,
4422 DWORD cbBuf, LPDWORD lpdwNeeded,
4423 LPDWORD lpdwReturned)
4425 BOOL ret, unicode = FALSE;
4426 UNICODE_STRING lpszNameW;
4427 PWSTR pwstrNameW;
4429 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4430 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4431 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4432 lpdwNeeded, lpdwReturned, unicode);
4433 RtlFreeUnicodeString(&lpszNameW);
4434 return ret;
4437 /*****************************************************************************
4438 * WINSPOOL_GetDriverInfoFromReg [internal]
4440 * Enters the information from the registry into the DRIVER_INFO struct
4442 * RETURNS
4443 * zero if the printer driver does not exist in the registry
4444 * (only if Level > 1) otherwise nonzero
4446 static BOOL WINSPOOL_GetDriverInfoFromReg(
4447 HKEY hkeyDrivers,
4448 LPWSTR DriverName,
4449 const printenv_t * env,
4450 DWORD Level,
4451 LPBYTE ptr, /* DRIVER_INFO */
4452 LPBYTE pDriverStrings, /* strings buffer */
4453 DWORD cbBuf, /* size of string buffer */
4454 LPDWORD pcbNeeded, /* space needed for str. */
4455 BOOL unicode) /* type of strings */
4457 DWORD size, tmp;
4458 HKEY hkeyDriver;
4459 WCHAR driverdir[MAX_PATH];
4460 DWORD dirlen;
4461 LPBYTE strPtr = pDriverStrings;
4462 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4464 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4465 debugstr_w(DriverName), env,
4466 Level, di, pDriverStrings, cbBuf, unicode);
4468 if (di) ZeroMemory(di, di_sizeof[Level]);
4470 if (unicode) {
4471 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4472 if (*pcbNeeded <= cbBuf)
4473 strcpyW((LPWSTR)strPtr, DriverName);
4475 else
4477 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4478 if (*pcbNeeded <= cbBuf)
4479 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4482 /* pName for level 1 has a different offset! */
4483 if (Level == 1) {
4484 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4485 return TRUE;
4488 /* .cVersion and .pName for level > 1 */
4489 if (di) {
4490 di->cVersion = env->driverversion;
4491 di->pName = (LPWSTR) strPtr;
4492 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4495 /* Reserve Space for the largest subdir and a Backslash*/
4496 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4497 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4498 /* Should never Fail */
4499 return FALSE;
4501 lstrcatW(driverdir, env->versionsubdir);
4502 lstrcatW(driverdir, backslashW);
4504 /* dirlen must not include the terminating zero */
4505 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4506 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4508 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4509 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4510 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4511 return FALSE;
4514 /* pEnvironment */
4515 if (unicode)
4516 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4517 else
4518 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4520 *pcbNeeded += size;
4521 if (*pcbNeeded <= cbBuf) {
4522 if (unicode) {
4523 lstrcpyW((LPWSTR)strPtr, env->envname);
4525 else
4527 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4529 if (di) di->pEnvironment = (LPWSTR)strPtr;
4530 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4533 /* .pDriverPath is the Graphics rendering engine.
4534 The full Path is required to avoid a crash in some apps */
4535 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4536 *pcbNeeded += size;
4537 if (*pcbNeeded <= cbBuf)
4538 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4540 if (di) di->pDriverPath = (LPWSTR)strPtr;
4541 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4544 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4545 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4546 *pcbNeeded += size;
4547 if (*pcbNeeded <= cbBuf)
4548 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4550 if (di) di->pDataFile = (LPWSTR)strPtr;
4551 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4554 /* .pConfigFile is the Driver user Interface */
4555 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4556 *pcbNeeded += size;
4557 if (*pcbNeeded <= cbBuf)
4558 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4560 if (di) di->pConfigFile = (LPWSTR)strPtr;
4561 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4564 if (Level == 2 ) {
4565 RegCloseKey(hkeyDriver);
4566 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4567 return TRUE;
4570 if (Level == 5 ) {
4571 RegCloseKey(hkeyDriver);
4572 FIXME("level 5: incomplete\n");
4573 return TRUE;
4576 /* .pHelpFile */
4577 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4578 *pcbNeeded += size;
4579 if (*pcbNeeded <= cbBuf)
4580 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4582 if (di) di->pHelpFile = (LPWSTR)strPtr;
4583 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4586 /* .pDependentFiles */
4587 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4588 *pcbNeeded += size;
4589 if (*pcbNeeded <= cbBuf)
4590 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4592 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4593 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4595 else if (GetVersion() & 0x80000000) {
4596 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4597 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4598 *pcbNeeded += size;
4599 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4601 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4602 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4605 /* .pMonitorName is the optional Language Monitor */
4606 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4607 *pcbNeeded += size;
4608 if (*pcbNeeded <= cbBuf)
4609 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4611 if (di) di->pMonitorName = (LPWSTR)strPtr;
4612 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4615 /* .pDefaultDataType */
4616 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4617 *pcbNeeded += size;
4618 if(*pcbNeeded <= cbBuf)
4619 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4621 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4622 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4625 if (Level == 3 ) {
4626 RegCloseKey(hkeyDriver);
4627 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4628 return TRUE;
4631 /* .pszzPreviousNames */
4632 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4633 *pcbNeeded += size;
4634 if(*pcbNeeded <= cbBuf)
4635 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4637 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4638 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4641 if (Level == 4 ) {
4642 RegCloseKey(hkeyDriver);
4643 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4644 return TRUE;
4647 /* support is missing, but not important enough for a FIXME */
4648 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4650 /* .pszMfgName */
4651 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4652 *pcbNeeded += size;
4653 if(*pcbNeeded <= cbBuf)
4654 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4656 if (di) di->pszMfgName = (LPWSTR)strPtr;
4657 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4660 /* .pszOEMUrl */
4661 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4662 *pcbNeeded += size;
4663 if(*pcbNeeded <= cbBuf)
4664 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4666 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4667 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4670 /* .pszHardwareID */
4671 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4672 *pcbNeeded += size;
4673 if(*pcbNeeded <= cbBuf)
4674 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4676 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4677 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4680 /* .pszProvider */
4681 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4682 *pcbNeeded += size;
4683 if(*pcbNeeded <= cbBuf)
4684 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4686 if (di) di->pszProvider = (LPWSTR)strPtr;
4687 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4690 if (Level == 6 ) {
4691 RegCloseKey(hkeyDriver);
4692 return TRUE;
4695 /* support is missing, but not important enough for a FIXME */
4696 TRACE("level 8: incomplete\n");
4698 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4699 RegCloseKey(hkeyDriver);
4700 return TRUE;
4703 /*****************************************************************************
4704 * WINSPOOL_GetPrinterDriver
4706 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4707 DWORD Level, LPBYTE pDriverInfo,
4708 DWORD cbBuf, LPDWORD pcbNeeded,
4709 BOOL unicode)
4711 LPCWSTR name;
4712 WCHAR DriverName[100];
4713 DWORD ret, type, size, needed = 0;
4714 LPBYTE ptr = NULL;
4715 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4716 const printenv_t * env;
4718 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4719 Level,pDriverInfo,cbBuf, pcbNeeded);
4722 if (!(name = get_opened_printer_name(hPrinter))) {
4723 SetLastError(ERROR_INVALID_HANDLE);
4724 return FALSE;
4727 if (Level < 1 || Level == 7 || Level > 8) {
4728 SetLastError(ERROR_INVALID_LEVEL);
4729 return FALSE;
4732 env = validate_envW(pEnvironment);
4733 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4735 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4736 ERROR_SUCCESS) {
4737 ERR("Can't create Printers key\n");
4738 return FALSE;
4740 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4741 != ERROR_SUCCESS) {
4742 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4743 RegCloseKey(hkeyPrinters);
4744 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4745 return FALSE;
4747 size = sizeof(DriverName);
4748 DriverName[0] = 0;
4749 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4750 (LPBYTE)DriverName, &size);
4751 RegCloseKey(hkeyPrinter);
4752 RegCloseKey(hkeyPrinters);
4753 if(ret != ERROR_SUCCESS) {
4754 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4755 return FALSE;
4758 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4759 if(!hkeyDrivers) {
4760 ERR("Can't create Drivers key\n");
4761 return FALSE;
4764 size = di_sizeof[Level];
4765 if ((size <= cbBuf) && pDriverInfo)
4766 ptr = pDriverInfo + size;
4768 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4769 env, Level, pDriverInfo, ptr,
4770 (cbBuf < size) ? 0 : cbBuf - size,
4771 &needed, unicode)) {
4772 RegCloseKey(hkeyDrivers);
4773 return FALSE;
4776 RegCloseKey(hkeyDrivers);
4778 if(pcbNeeded) *pcbNeeded = size + needed;
4779 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4780 if(cbBuf >= needed) return TRUE;
4781 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4782 return FALSE;
4785 /*****************************************************************************
4786 * GetPrinterDriverA [WINSPOOL.@]
4788 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4789 DWORD Level, LPBYTE pDriverInfo,
4790 DWORD cbBuf, LPDWORD pcbNeeded)
4792 BOOL ret;
4793 UNICODE_STRING pEnvW;
4794 PWSTR pwstrEnvW;
4796 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4797 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4798 cbBuf, pcbNeeded, FALSE);
4799 RtlFreeUnicodeString(&pEnvW);
4800 return ret;
4802 /*****************************************************************************
4803 * GetPrinterDriverW [WINSPOOL.@]
4805 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4806 DWORD Level, LPBYTE pDriverInfo,
4807 DWORD cbBuf, LPDWORD pcbNeeded)
4809 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4810 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4813 /*****************************************************************************
4814 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4816 * Return the PATH for the Printer-Drivers (UNICODE)
4818 * PARAMS
4819 * pName [I] Servername (NT only) or NULL (local Computer)
4820 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4821 * Level [I] Structure-Level (must be 1)
4822 * pDriverDirectory [O] PTR to Buffer that receives the Result
4823 * cbBuf [I] Size of Buffer at pDriverDirectory
4824 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4825 * required for pDriverDirectory
4827 * RETURNS
4828 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4829 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4830 * if cbBuf is too small
4832 * Native Values returned in pDriverDirectory on Success:
4833 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4834 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4835 *| win9x(Windows 4.0): "%winsysdir%"
4837 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4839 * FIXME
4840 *- Only NULL or "" is supported for pName
4843 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4844 DWORD Level, LPBYTE pDriverDirectory,
4845 DWORD cbBuf, LPDWORD pcbNeeded)
4847 DWORD needed;
4848 const printenv_t * env;
4850 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4851 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4852 if(pName != NULL && pName[0]) {
4853 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4854 SetLastError(ERROR_INVALID_PARAMETER);
4855 return FALSE;
4858 env = validate_envW(pEnvironment);
4859 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4861 if(Level != 1) {
4862 WARN("(Level: %d) is ignored in win9x\n", Level);
4863 SetLastError(ERROR_INVALID_LEVEL);
4864 return FALSE;
4867 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4868 needed = GetSystemDirectoryW(NULL, 0);
4869 /* add the Size for the Subdirectories */
4870 needed += lstrlenW(spooldriversW);
4871 needed += lstrlenW(env->subdir);
4872 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4874 if(pcbNeeded)
4875 *pcbNeeded = needed;
4876 TRACE("required: 0x%x/%d\n", needed, needed);
4877 if(needed > cbBuf) {
4878 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4879 return FALSE;
4881 if(pcbNeeded == NULL) {
4882 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4883 SetLastError(RPC_X_NULL_REF_POINTER);
4884 return FALSE;
4886 if(pDriverDirectory == NULL) {
4887 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4888 SetLastError(ERROR_INVALID_USER_BUFFER);
4889 return FALSE;
4892 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4893 /* add the Subdirectories */
4894 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4895 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4896 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4897 return TRUE;
4901 /*****************************************************************************
4902 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4904 * Return the PATH for the Printer-Drivers (ANSI)
4906 * See GetPrinterDriverDirectoryW.
4908 * NOTES
4909 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4912 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4913 DWORD Level, LPBYTE pDriverDirectory,
4914 DWORD cbBuf, LPDWORD pcbNeeded)
4916 UNICODE_STRING nameW, environmentW;
4917 BOOL ret;
4918 DWORD pcbNeededW;
4919 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4920 WCHAR *driverDirectoryW = NULL;
4922 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4923 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4925 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4927 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4928 else nameW.Buffer = NULL;
4929 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4930 else environmentW.Buffer = NULL;
4932 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4933 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4934 if (ret) {
4935 DWORD needed;
4936 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4937 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4938 if(pcbNeeded)
4939 *pcbNeeded = needed;
4940 ret = (needed <= cbBuf) ? TRUE : FALSE;
4941 } else
4942 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4944 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4946 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4947 RtlFreeUnicodeString(&environmentW);
4948 RtlFreeUnicodeString(&nameW);
4950 return ret;
4953 /*****************************************************************************
4954 * AddPrinterDriverA [WINSPOOL.@]
4956 * See AddPrinterDriverW.
4959 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4961 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
4962 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4965 /******************************************************************************
4966 * AddPrinterDriverW (WINSPOOL.@)
4968 * Install a Printer Driver
4970 * PARAMS
4971 * pName [I] Servername or NULL (local Computer)
4972 * level [I] Level for the supplied DRIVER_INFO_*W struct
4973 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4975 * RESULTS
4976 * Success: TRUE
4977 * Failure: FALSE
4980 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
4982 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
4983 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
4986 /*****************************************************************************
4987 * AddPrintProcessorA [WINSPOOL.@]
4989 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4990 LPSTR pPrintProcessorName)
4992 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4993 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4994 return FALSE;
4997 /*****************************************************************************
4998 * AddPrintProcessorW [WINSPOOL.@]
5000 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5001 LPWSTR pPrintProcessorName)
5003 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5004 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5005 return FALSE;
5008 /*****************************************************************************
5009 * AddPrintProvidorA [WINSPOOL.@]
5011 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5013 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5014 return FALSE;
5017 /*****************************************************************************
5018 * AddPrintProvidorW [WINSPOOL.@]
5020 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5022 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5023 return FALSE;
5026 /*****************************************************************************
5027 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5029 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5030 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5032 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5033 pDevModeOutput, pDevModeInput);
5034 return 0;
5037 /*****************************************************************************
5038 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5040 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5041 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5043 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5044 pDevModeOutput, pDevModeInput);
5045 return 0;
5048 /*****************************************************************************
5049 * PrinterProperties [WINSPOOL.@]
5051 * Displays a dialog to set the properties of the printer.
5053 * RETURNS
5054 * nonzero on success or zero on failure
5056 * BUGS
5057 * implemented as stub only
5059 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5060 HANDLE hPrinter /* [in] handle to printer object */
5062 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5063 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5064 return FALSE;
5067 /*****************************************************************************
5068 * EnumJobsA [WINSPOOL.@]
5071 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5072 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5073 LPDWORD pcReturned)
5075 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5076 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5078 if(pcbNeeded) *pcbNeeded = 0;
5079 if(pcReturned) *pcReturned = 0;
5080 return FALSE;
5084 /*****************************************************************************
5085 * EnumJobsW [WINSPOOL.@]
5088 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5089 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5090 LPDWORD pcReturned)
5092 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5093 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5095 if(pcbNeeded) *pcbNeeded = 0;
5096 if(pcReturned) *pcReturned = 0;
5097 return FALSE;
5100 /*****************************************************************************
5101 * WINSPOOL_EnumPrinterDrivers [internal]
5103 * Delivers information about all printer drivers installed on the
5104 * localhost or a given server
5106 * RETURNS
5107 * nonzero on success or zero on failure. If the buffer for the returned
5108 * information is too small the function will return an error
5110 * BUGS
5111 * - only implemented for localhost, foreign hosts will return an error
5113 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5114 DWORD Level, LPBYTE pDriverInfo,
5115 DWORD cbBuf, LPDWORD pcbNeeded,
5116 LPDWORD pcReturned, BOOL unicode)
5118 { HKEY hkeyDrivers;
5119 DWORD i, needed, number = 0, size = 0;
5120 WCHAR DriverNameW[255];
5121 PBYTE ptr;
5122 const printenv_t * env;
5124 TRACE("%s,%s,%d,%p,%d,%d\n",
5125 debugstr_w(pName), debugstr_w(pEnvironment),
5126 Level, pDriverInfo, cbBuf, unicode);
5128 /* check for local drivers */
5129 if((pName) && (pName[0])) {
5130 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5131 SetLastError(ERROR_ACCESS_DENIED);
5132 return FALSE;
5135 env = validate_envW(pEnvironment);
5136 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5138 /* check input parameter */
5139 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5140 SetLastError(ERROR_INVALID_LEVEL);
5141 return FALSE;
5144 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5145 SetLastError(RPC_X_NULL_REF_POINTER);
5146 return FALSE;
5149 /* initialize return values */
5150 if(pDriverInfo)
5151 memset( pDriverInfo, 0, cbBuf);
5152 *pcbNeeded = 0;
5153 *pcReturned = 0;
5155 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5156 if(!hkeyDrivers) {
5157 ERR("Can't open Drivers key\n");
5158 return FALSE;
5161 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5162 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5163 RegCloseKey(hkeyDrivers);
5164 ERR("Can't query Drivers key\n");
5165 return FALSE;
5167 TRACE("Found %d Drivers\n", number);
5169 /* get size of single struct
5170 * unicode and ascii structure have the same size
5172 size = di_sizeof[Level];
5174 /* calculate required buffer size */
5175 *pcbNeeded = size * number;
5177 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5178 i < number;
5179 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5180 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
5181 != ERROR_SUCCESS) {
5182 ERR("Can't enum key number %d\n", i);
5183 RegCloseKey(hkeyDrivers);
5184 return FALSE;
5186 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5187 env, Level, ptr,
5188 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5189 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5190 &needed, unicode)) {
5191 RegCloseKey(hkeyDrivers);
5192 return FALSE;
5194 (*pcbNeeded) += needed;
5197 RegCloseKey(hkeyDrivers);
5199 if(cbBuf < *pcbNeeded){
5200 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5201 return FALSE;
5204 *pcReturned = number;
5205 return TRUE;
5208 /*****************************************************************************
5209 * EnumPrinterDriversW [WINSPOOL.@]
5211 * see function EnumPrinterDrivers for RETURNS, BUGS
5213 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5214 LPBYTE pDriverInfo, DWORD cbBuf,
5215 LPDWORD pcbNeeded, LPDWORD pcReturned)
5217 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5218 cbBuf, pcbNeeded, pcReturned, TRUE);
5221 /*****************************************************************************
5222 * EnumPrinterDriversA [WINSPOOL.@]
5224 * see function EnumPrinterDrivers for RETURNS, BUGS
5226 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5227 LPBYTE pDriverInfo, DWORD cbBuf,
5228 LPDWORD pcbNeeded, LPDWORD pcReturned)
5229 { BOOL ret;
5230 UNICODE_STRING pNameW, pEnvironmentW;
5231 PWSTR pwstrNameW, pwstrEnvironmentW;
5233 pwstrNameW = asciitounicode(&pNameW, pName);
5234 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5236 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5237 Level, pDriverInfo, cbBuf, pcbNeeded,
5238 pcReturned, FALSE);
5239 RtlFreeUnicodeString(&pNameW);
5240 RtlFreeUnicodeString(&pEnvironmentW);
5242 return ret;
5245 /******************************************************************************
5246 * EnumPortsA (WINSPOOL.@)
5248 * See EnumPortsW.
5251 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5252 LPDWORD pcbNeeded, LPDWORD pcReturned)
5254 BOOL res;
5255 LPBYTE bufferW = NULL;
5256 LPWSTR nameW = NULL;
5257 DWORD needed = 0;
5258 DWORD numentries = 0;
5259 INT len;
5261 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5262 cbBuf, pcbNeeded, pcReturned);
5264 /* convert servername to unicode */
5265 if (pName) {
5266 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5267 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5268 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5270 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5271 needed = cbBuf * sizeof(WCHAR);
5272 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5273 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5275 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5276 if (pcbNeeded) needed = *pcbNeeded;
5277 /* HeapReAlloc return NULL, when bufferW was NULL */
5278 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5279 HeapAlloc(GetProcessHeap(), 0, needed);
5281 /* Try again with the large Buffer */
5282 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5284 needed = pcbNeeded ? *pcbNeeded : 0;
5285 numentries = pcReturned ? *pcReturned : 0;
5288 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5289 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5291 if (res) {
5292 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5293 DWORD entrysize = 0;
5294 DWORD index;
5295 LPSTR ptr;
5296 LPPORT_INFO_2W pi2w;
5297 LPPORT_INFO_2A pi2a;
5299 needed = 0;
5300 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5302 /* First pass: calculate the size for all Entries */
5303 pi2w = (LPPORT_INFO_2W) bufferW;
5304 pi2a = (LPPORT_INFO_2A) pPorts;
5305 index = 0;
5306 while (index < numentries) {
5307 index++;
5308 needed += entrysize; /* PORT_INFO_?A */
5309 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5311 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5312 NULL, 0, NULL, NULL);
5313 if (Level > 1) {
5314 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5315 NULL, 0, NULL, NULL);
5316 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5317 NULL, 0, NULL, NULL);
5319 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5320 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5321 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5324 /* check for errors and quit on failure */
5325 if (cbBuf < needed) {
5326 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5327 res = FALSE;
5328 goto cleanup;
5330 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5331 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5332 cbBuf -= len ; /* free Bytes in the user-Buffer */
5333 pi2w = (LPPORT_INFO_2W) bufferW;
5334 pi2a = (LPPORT_INFO_2A) pPorts;
5335 index = 0;
5336 /* Second Pass: Fill the User Buffer (if we have one) */
5337 while ((index < numentries) && pPorts) {
5338 index++;
5339 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5340 pi2a->pPortName = ptr;
5341 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5342 ptr, cbBuf , NULL, NULL);
5343 ptr += len;
5344 cbBuf -= len;
5345 if (Level > 1) {
5346 pi2a->pMonitorName = ptr;
5347 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5348 ptr, cbBuf, NULL, NULL);
5349 ptr += len;
5350 cbBuf -= len;
5352 pi2a->pDescription = ptr;
5353 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5354 ptr, cbBuf, NULL, NULL);
5355 ptr += len;
5356 cbBuf -= len;
5358 pi2a->fPortType = pi2w->fPortType;
5359 pi2a->Reserved = 0; /* documented: "must be zero" */
5362 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5363 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5364 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5368 cleanup:
5369 if (pcbNeeded) *pcbNeeded = needed;
5370 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5372 HeapFree(GetProcessHeap(), 0, nameW);
5373 HeapFree(GetProcessHeap(), 0, bufferW);
5375 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5376 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5378 return (res);
5382 /******************************************************************************
5383 * EnumPortsW (WINSPOOL.@)
5385 * Enumerate available Ports
5387 * PARAMS
5388 * name [I] Servername or NULL (local Computer)
5389 * level [I] Structure-Level (1 or 2)
5390 * buffer [O] PTR to Buffer that receives the Result
5391 * bufsize [I] Size of Buffer at buffer
5392 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5393 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5395 * RETURNS
5396 * Success: TRUE
5397 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5401 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5403 DWORD needed = 0;
5404 DWORD numentries = 0;
5405 BOOL res = FALSE;
5407 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5408 cbBuf, pcbNeeded, pcReturned);
5410 if (pName && (pName[0])) {
5411 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5412 SetLastError(ERROR_ACCESS_DENIED);
5413 goto emP_cleanup;
5416 /* Level is not checked in win9x */
5417 if (!Level || (Level > 2)) {
5418 WARN("level (%d) is ignored in win9x\n", Level);
5419 SetLastError(ERROR_INVALID_LEVEL);
5420 goto emP_cleanup;
5422 if (!pcbNeeded) {
5423 SetLastError(RPC_X_NULL_REF_POINTER);
5424 goto emP_cleanup;
5427 EnterCriticalSection(&monitor_handles_cs);
5428 monitor_loadall();
5430 /* Scan all local Ports */
5431 numentries = 0;
5432 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5434 /* we calculated the needed buffersize. now do the error-checks */
5435 if (cbBuf < needed) {
5436 monitor_unloadall();
5437 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5438 goto emP_cleanup_cs;
5440 else if (!pPorts || !pcReturned) {
5441 monitor_unloadall();
5442 SetLastError(RPC_X_NULL_REF_POINTER);
5443 goto emP_cleanup_cs;
5446 /* Fill the Buffer */
5447 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5448 res = TRUE;
5449 monitor_unloadall();
5451 emP_cleanup_cs:
5452 LeaveCriticalSection(&monitor_handles_cs);
5454 emP_cleanup:
5455 if (pcbNeeded) *pcbNeeded = needed;
5456 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5458 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5459 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5461 return (res);
5464 /******************************************************************************
5465 * GetDefaultPrinterW (WINSPOOL.@)
5467 * FIXME
5468 * This function must read the value from data 'device' of key
5469 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5471 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5473 BOOL retval = TRUE;
5474 DWORD insize, len;
5475 WCHAR *buffer, *ptr;
5477 if (!namesize)
5479 SetLastError(ERROR_INVALID_PARAMETER);
5480 return FALSE;
5483 /* make the buffer big enough for the stuff from the profile/registry,
5484 * the content must fit into the local buffer to compute the correct
5485 * size even if the extern buffer is too small or not given.
5486 * (20 for ,driver,port) */
5487 insize = *namesize;
5488 len = max(100, (insize + 20));
5489 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5491 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5493 SetLastError (ERROR_FILE_NOT_FOUND);
5494 retval = FALSE;
5495 goto end;
5497 TRACE("%s\n", debugstr_w(buffer));
5499 if ((ptr = strchrW(buffer, ',')) == NULL)
5501 SetLastError(ERROR_INVALID_NAME);
5502 retval = FALSE;
5503 goto end;
5506 *ptr = 0;
5507 *namesize = strlenW(buffer) + 1;
5508 if(!name || (*namesize > insize))
5510 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5511 retval = FALSE;
5512 goto end;
5514 strcpyW(name, buffer);
5516 end:
5517 HeapFree( GetProcessHeap(), 0, buffer);
5518 return retval;
5522 /******************************************************************************
5523 * GetDefaultPrinterA (WINSPOOL.@)
5525 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5527 BOOL retval = TRUE;
5528 DWORD insize = 0;
5529 WCHAR *bufferW = NULL;
5531 if (!namesize)
5533 SetLastError(ERROR_INVALID_PARAMETER);
5534 return FALSE;
5537 if(name && *namesize) {
5538 insize = *namesize;
5539 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5542 if(!GetDefaultPrinterW( bufferW, namesize)) {
5543 retval = FALSE;
5544 goto end;
5547 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5548 NULL, NULL);
5549 if (!*namesize)
5551 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5552 retval = FALSE;
5554 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5556 end:
5557 HeapFree( GetProcessHeap(), 0, bufferW);
5558 return retval;
5562 /******************************************************************************
5563 * SetDefaultPrinterW (WINSPOOL.204)
5565 * Set the Name of the Default Printer
5567 * PARAMS
5568 * pszPrinter [I] Name of the Printer or NULL
5570 * RETURNS
5571 * Success: True
5572 * Failure: FALSE
5574 * NOTES
5575 * When the Parameter is NULL or points to an Empty String and
5576 * a Default Printer was already present, then this Function changes nothing.
5577 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5578 * the First enumerated local Printer is used.
5581 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5584 TRACE("(%s)\n", debugstr_w(pszPrinter));
5586 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5587 return FALSE;
5590 /******************************************************************************
5591 * SetDefaultPrinterA (WINSPOOL.202)
5593 * See SetDefaultPrinterW.
5596 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5599 TRACE("(%s)\n", debugstr_a(pszPrinter));
5601 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5602 return FALSE;
5606 /******************************************************************************
5607 * SetPrinterDataExA (WINSPOOL.@)
5609 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5610 LPCSTR pValueName, DWORD Type,
5611 LPBYTE pData, DWORD cbData)
5613 HKEY hkeyPrinter, hkeySubkey;
5614 DWORD ret;
5616 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5617 debugstr_a(pValueName), Type, pData, cbData);
5619 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5620 != ERROR_SUCCESS)
5621 return ret;
5623 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5624 != ERROR_SUCCESS) {
5625 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5626 RegCloseKey(hkeyPrinter);
5627 return ret;
5629 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5630 RegCloseKey(hkeySubkey);
5631 RegCloseKey(hkeyPrinter);
5632 return ret;
5635 /******************************************************************************
5636 * SetPrinterDataExW (WINSPOOL.@)
5638 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5639 LPCWSTR pValueName, DWORD Type,
5640 LPBYTE pData, DWORD cbData)
5642 HKEY hkeyPrinter, hkeySubkey;
5643 DWORD ret;
5645 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5646 debugstr_w(pValueName), Type, pData, cbData);
5648 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5649 != ERROR_SUCCESS)
5650 return ret;
5652 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5653 != ERROR_SUCCESS) {
5654 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5655 RegCloseKey(hkeyPrinter);
5656 return ret;
5658 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5659 RegCloseKey(hkeySubkey);
5660 RegCloseKey(hkeyPrinter);
5661 return ret;
5664 /******************************************************************************
5665 * SetPrinterDataA (WINSPOOL.@)
5667 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5668 LPBYTE pData, DWORD cbData)
5670 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5671 pData, cbData);
5674 /******************************************************************************
5675 * SetPrinterDataW (WINSPOOL.@)
5677 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5678 LPBYTE pData, DWORD cbData)
5680 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5681 pData, cbData);
5684 /******************************************************************************
5685 * GetPrinterDataExA (WINSPOOL.@)
5687 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5688 LPCSTR pValueName, LPDWORD pType,
5689 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5691 HKEY hkeyPrinter, hkeySubkey;
5692 DWORD ret;
5694 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5695 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5696 pcbNeeded);
5698 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5699 != ERROR_SUCCESS)
5700 return ret;
5702 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5703 != ERROR_SUCCESS) {
5704 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5705 RegCloseKey(hkeyPrinter);
5706 return ret;
5708 *pcbNeeded = nSize;
5709 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5710 RegCloseKey(hkeySubkey);
5711 RegCloseKey(hkeyPrinter);
5712 return ret;
5715 /******************************************************************************
5716 * GetPrinterDataExW (WINSPOOL.@)
5718 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5719 LPCWSTR pValueName, LPDWORD pType,
5720 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5722 HKEY hkeyPrinter, hkeySubkey;
5723 DWORD ret;
5725 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5726 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5727 pcbNeeded);
5729 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5730 != ERROR_SUCCESS)
5731 return ret;
5733 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5734 != ERROR_SUCCESS) {
5735 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5736 RegCloseKey(hkeyPrinter);
5737 return ret;
5739 *pcbNeeded = nSize;
5740 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5741 RegCloseKey(hkeySubkey);
5742 RegCloseKey(hkeyPrinter);
5743 return ret;
5746 /******************************************************************************
5747 * GetPrinterDataA (WINSPOOL.@)
5749 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5750 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5752 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5753 pData, nSize, pcbNeeded);
5756 /******************************************************************************
5757 * GetPrinterDataW (WINSPOOL.@)
5759 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5760 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5762 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5763 pData, nSize, pcbNeeded);
5766 /*******************************************************************************
5767 * EnumPrinterDataExW [WINSPOOL.@]
5769 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5770 LPBYTE pEnumValues, DWORD cbEnumValues,
5771 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5773 HKEY hkPrinter, hkSubKey;
5774 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5775 cbValueNameLen, cbMaxValueLen, cbValueLen,
5776 cbBufSize, dwType;
5777 LPWSTR lpValueName;
5778 HANDLE hHeap;
5779 PBYTE lpValue;
5780 PPRINTER_ENUM_VALUESW ppev;
5782 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5784 if (pKeyName == NULL || *pKeyName == 0)
5785 return ERROR_INVALID_PARAMETER;
5787 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5788 if (ret != ERROR_SUCCESS)
5790 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5791 hPrinter, ret);
5792 return ret;
5795 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5796 if (ret != ERROR_SUCCESS)
5798 r = RegCloseKey (hkPrinter);
5799 if (r != ERROR_SUCCESS)
5800 WARN ("RegCloseKey returned %i\n", r);
5801 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5802 debugstr_w (pKeyName), ret);
5803 return ret;
5806 ret = RegCloseKey (hkPrinter);
5807 if (ret != ERROR_SUCCESS)
5809 ERR ("RegCloseKey returned %i\n", ret);
5810 r = RegCloseKey (hkSubKey);
5811 if (r != ERROR_SUCCESS)
5812 WARN ("RegCloseKey returned %i\n", r);
5813 return ret;
5816 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5817 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5818 if (ret != ERROR_SUCCESS)
5820 r = RegCloseKey (hkSubKey);
5821 if (r != ERROR_SUCCESS)
5822 WARN ("RegCloseKey returned %i\n", r);
5823 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5824 return ret;
5827 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5828 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5830 if (cValues == 0) /* empty key */
5832 r = RegCloseKey (hkSubKey);
5833 if (r != ERROR_SUCCESS)
5834 WARN ("RegCloseKey returned %i\n", r);
5835 *pcbEnumValues = *pnEnumValues = 0;
5836 return ERROR_SUCCESS;
5839 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5841 hHeap = GetProcessHeap ();
5842 if (hHeap == NULL)
5844 ERR ("GetProcessHeap failed\n");
5845 r = RegCloseKey (hkSubKey);
5846 if (r != ERROR_SUCCESS)
5847 WARN ("RegCloseKey returned %i\n", r);
5848 return ERROR_OUTOFMEMORY;
5851 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5852 if (lpValueName == NULL)
5854 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5855 r = RegCloseKey (hkSubKey);
5856 if (r != ERROR_SUCCESS)
5857 WARN ("RegCloseKey returned %i\n", r);
5858 return ERROR_OUTOFMEMORY;
5861 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5862 if (lpValue == NULL)
5864 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5865 if (HeapFree (hHeap, 0, lpValueName) == 0)
5866 WARN ("HeapFree failed with code %i\n", GetLastError ());
5867 r = RegCloseKey (hkSubKey);
5868 if (r != ERROR_SUCCESS)
5869 WARN ("RegCloseKey returned %i\n", r);
5870 return ERROR_OUTOFMEMORY;
5873 TRACE ("pass 1: calculating buffer required for all names and values\n");
5875 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5877 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5879 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5881 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5882 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5883 NULL, NULL, lpValue, &cbValueLen);
5884 if (ret != ERROR_SUCCESS)
5886 if (HeapFree (hHeap, 0, lpValue) == 0)
5887 WARN ("HeapFree failed with code %i\n", GetLastError ());
5888 if (HeapFree (hHeap, 0, lpValueName) == 0)
5889 WARN ("HeapFree failed with code %i\n", GetLastError ());
5890 r = RegCloseKey (hkSubKey);
5891 if (r != ERROR_SUCCESS)
5892 WARN ("RegCloseKey returned %i\n", r);
5893 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5894 return ret;
5897 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5898 debugstr_w (lpValueName), dwIndex,
5899 cbValueNameLen + 1, cbValueLen);
5901 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5902 cbBufSize += cbValueLen;
5905 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5907 *pcbEnumValues = cbBufSize;
5908 *pnEnumValues = cValues;
5910 if (cbEnumValues < cbBufSize) /* buffer too small */
5912 if (HeapFree (hHeap, 0, lpValue) == 0)
5913 WARN ("HeapFree failed with code %i\n", GetLastError ());
5914 if (HeapFree (hHeap, 0, lpValueName) == 0)
5915 WARN ("HeapFree failed with code %i\n", GetLastError ());
5916 r = RegCloseKey (hkSubKey);
5917 if (r != ERROR_SUCCESS)
5918 WARN ("RegCloseKey returned %i\n", r);
5919 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5920 return ERROR_MORE_DATA;
5923 TRACE ("pass 2: copying all names and values to buffer\n");
5925 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5926 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5928 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5930 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5931 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5932 NULL, &dwType, lpValue, &cbValueLen);
5933 if (ret != ERROR_SUCCESS)
5935 if (HeapFree (hHeap, 0, lpValue) == 0)
5936 WARN ("HeapFree failed with code %i\n", GetLastError ());
5937 if (HeapFree (hHeap, 0, lpValueName) == 0)
5938 WARN ("HeapFree failed with code %i\n", GetLastError ());
5939 r = RegCloseKey (hkSubKey);
5940 if (r != ERROR_SUCCESS)
5941 WARN ("RegCloseKey returned %i\n", r);
5942 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5943 return ret;
5946 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5947 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5948 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5949 pEnumValues += cbValueNameLen;
5951 /* return # of *bytes* (including trailing \0), not # of chars */
5952 ppev[dwIndex].cbValueName = cbValueNameLen;
5954 ppev[dwIndex].dwType = dwType;
5956 memcpy (pEnumValues, lpValue, cbValueLen);
5957 ppev[dwIndex].pData = pEnumValues;
5958 pEnumValues += cbValueLen;
5960 ppev[dwIndex].cbData = cbValueLen;
5962 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5963 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5966 if (HeapFree (hHeap, 0, lpValue) == 0)
5968 ret = GetLastError ();
5969 ERR ("HeapFree failed with code %i\n", ret);
5970 if (HeapFree (hHeap, 0, lpValueName) == 0)
5971 WARN ("HeapFree failed with code %i\n", GetLastError ());
5972 r = RegCloseKey (hkSubKey);
5973 if (r != ERROR_SUCCESS)
5974 WARN ("RegCloseKey returned %i\n", r);
5975 return ret;
5978 if (HeapFree (hHeap, 0, lpValueName) == 0)
5980 ret = GetLastError ();
5981 ERR ("HeapFree failed with code %i\n", ret);
5982 r = RegCloseKey (hkSubKey);
5983 if (r != ERROR_SUCCESS)
5984 WARN ("RegCloseKey returned %i\n", r);
5985 return ret;
5988 ret = RegCloseKey (hkSubKey);
5989 if (ret != ERROR_SUCCESS)
5991 ERR ("RegCloseKey returned %i\n", ret);
5992 return ret;
5995 return ERROR_SUCCESS;
5998 /*******************************************************************************
5999 * EnumPrinterDataExA [WINSPOOL.@]
6001 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6002 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6003 * what Windows 2000 SP1 does.
6006 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6007 LPBYTE pEnumValues, DWORD cbEnumValues,
6008 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6010 INT len;
6011 LPWSTR pKeyNameW;
6012 DWORD ret, dwIndex, dwBufSize;
6013 HANDLE hHeap;
6014 LPSTR pBuffer;
6016 TRACE ("%p %s\n", hPrinter, pKeyName);
6018 if (pKeyName == NULL || *pKeyName == 0)
6019 return ERROR_INVALID_PARAMETER;
6021 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6022 if (len == 0)
6024 ret = GetLastError ();
6025 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6026 return ret;
6029 hHeap = GetProcessHeap ();
6030 if (hHeap == NULL)
6032 ERR ("GetProcessHeap failed\n");
6033 return ERROR_OUTOFMEMORY;
6036 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6037 if (pKeyNameW == NULL)
6039 ERR ("Failed to allocate %i bytes from process heap\n",
6040 (LONG)(len * sizeof (WCHAR)));
6041 return ERROR_OUTOFMEMORY;
6044 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6046 ret = GetLastError ();
6047 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6048 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6049 WARN ("HeapFree failed with code %i\n", GetLastError ());
6050 return ret;
6053 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6054 pcbEnumValues, pnEnumValues);
6055 if (ret != ERROR_SUCCESS)
6057 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6058 WARN ("HeapFree failed with code %i\n", GetLastError ());
6059 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6060 return ret;
6063 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6065 ret = GetLastError ();
6066 ERR ("HeapFree failed with code %i\n", ret);
6067 return ret;
6070 if (*pnEnumValues == 0) /* empty key */
6071 return ERROR_SUCCESS;
6073 dwBufSize = 0;
6074 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6076 PPRINTER_ENUM_VALUESW ppev =
6077 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6079 if (dwBufSize < ppev->cbValueName)
6080 dwBufSize = ppev->cbValueName;
6082 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6083 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6084 dwBufSize = ppev->cbData;
6087 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6089 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6090 if (pBuffer == NULL)
6092 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6093 return ERROR_OUTOFMEMORY;
6096 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6098 PPRINTER_ENUM_VALUESW ppev =
6099 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6101 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6102 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6103 NULL);
6104 if (len == 0)
6106 ret = GetLastError ();
6107 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6108 if (HeapFree (hHeap, 0, pBuffer) == 0)
6109 WARN ("HeapFree failed with code %i\n", GetLastError ());
6110 return ret;
6113 memcpy (ppev->pValueName, pBuffer, len);
6115 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6117 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6118 ppev->dwType != REG_MULTI_SZ)
6119 continue;
6121 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6122 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6123 if (len == 0)
6125 ret = GetLastError ();
6126 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6127 if (HeapFree (hHeap, 0, pBuffer) == 0)
6128 WARN ("HeapFree failed with code %i\n", GetLastError ());
6129 return ret;
6132 memcpy (ppev->pData, pBuffer, len);
6134 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6135 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6138 if (HeapFree (hHeap, 0, pBuffer) == 0)
6140 ret = GetLastError ();
6141 ERR ("HeapFree failed with code %i\n", ret);
6142 return ret;
6145 return ERROR_SUCCESS;
6148 /******************************************************************************
6149 * AbortPrinter (WINSPOOL.@)
6151 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6153 FIXME("(%p), stub!\n", hPrinter);
6154 return TRUE;
6157 /******************************************************************************
6158 * AddPortA (WINSPOOL.@)
6160 * See AddPortW.
6163 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6165 LPWSTR nameW = NULL;
6166 LPWSTR monitorW = NULL;
6167 DWORD len;
6168 BOOL res;
6170 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6172 if (pName) {
6173 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6174 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6175 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6178 if (pMonitorName) {
6179 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6180 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6181 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6183 res = AddPortW(nameW, hWnd, monitorW);
6184 HeapFree(GetProcessHeap(), 0, nameW);
6185 HeapFree(GetProcessHeap(), 0, monitorW);
6186 return res;
6189 /******************************************************************************
6190 * AddPortW (WINSPOOL.@)
6192 * Add a Port for a specific Monitor
6194 * PARAMS
6195 * pName [I] Servername or NULL (local Computer)
6196 * hWnd [I] Handle to parent Window for the Dialog-Box
6197 * pMonitorName [I] Name of the Monitor that manage the Port
6199 * RETURNS
6200 * Success: TRUE
6201 * Failure: FALSE
6204 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6206 monitor_t * pm;
6207 monitor_t * pui;
6208 DWORD res;
6210 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6212 if (pName && pName[0]) {
6213 SetLastError(ERROR_INVALID_PARAMETER);
6214 return FALSE;
6217 if (!pMonitorName) {
6218 SetLastError(RPC_X_NULL_REF_POINTER);
6219 return FALSE;
6222 /* an empty Monitorname is Invalid */
6223 if (!pMonitorName[0]) {
6224 SetLastError(ERROR_NOT_SUPPORTED);
6225 return FALSE;
6228 pm = monitor_load(pMonitorName, NULL);
6229 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6230 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6231 TRACE("got %d with %u\n", res, GetLastError());
6232 res = TRUE;
6234 else
6236 pui = monitor_loadui(pm);
6237 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6238 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6239 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6240 TRACE("got %d with %u\n", res, GetLastError());
6241 res = TRUE;
6243 else
6245 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6246 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6248 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6249 SetLastError(ERROR_NOT_SUPPORTED);
6250 res = FALSE;
6252 monitor_unload(pui);
6254 monitor_unload(pm);
6255 TRACE("returning %d with %u\n", res, GetLastError());
6256 return res;
6259 /******************************************************************************
6260 * AddPortExA (WINSPOOL.@)
6262 * See AddPortExW.
6265 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6267 PORT_INFO_2W pi2W;
6268 PORT_INFO_2A * pi2A;
6269 LPWSTR nameW = NULL;
6270 LPWSTR monitorW = NULL;
6271 DWORD len;
6272 BOOL res;
6274 pi2A = (PORT_INFO_2A *) pBuffer;
6276 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6277 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6279 if ((level < 1) || (level > 2)) {
6280 SetLastError(ERROR_INVALID_LEVEL);
6281 return FALSE;
6284 if (!pi2A) {
6285 SetLastError(ERROR_INVALID_PARAMETER);
6286 return FALSE;
6289 if (pName) {
6290 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6291 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6292 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6295 if (pMonitorName) {
6296 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6297 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6298 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6301 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6303 if (pi2A->pPortName) {
6304 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6305 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6306 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6309 if (level > 1) {
6310 if (pi2A->pMonitorName) {
6311 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6312 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6313 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6316 if (pi2A->pDescription) {
6317 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6318 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6319 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6321 pi2W.fPortType = pi2A->fPortType;
6322 pi2W.Reserved = pi2A->Reserved;
6325 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6327 HeapFree(GetProcessHeap(), 0, nameW);
6328 HeapFree(GetProcessHeap(), 0, monitorW);
6329 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6330 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6331 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6332 return res;
6336 /******************************************************************************
6337 * AddPortExW (WINSPOOL.@)
6339 * Add a Port for a specific Monitor, without presenting a user interface
6341 * PARAMS
6342 * pName [I] Servername or NULL (local Computer)
6343 * level [I] Structure-Level (1 or 2) for pBuffer
6344 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6345 * pMonitorName [I] Name of the Monitor that manage the Port
6347 * RETURNS
6348 * Success: TRUE
6349 * Failure: FALSE
6352 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6354 PORT_INFO_2W * pi2;
6355 monitor_t * pm;
6356 DWORD res = FALSE;
6358 pi2 = (PORT_INFO_2W *) pBuffer;
6360 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6361 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6362 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6363 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6366 if ((level < 1) || (level > 2)) {
6367 SetLastError(ERROR_INVALID_LEVEL);
6368 return FALSE;
6371 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6372 SetLastError(ERROR_INVALID_PARAMETER);
6373 return FALSE;
6376 /* load the Monitor */
6377 pm = monitor_load(pMonitorName, NULL);
6378 if (!pm) {
6379 SetLastError(ERROR_INVALID_PARAMETER);
6380 return FALSE;
6383 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6384 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6385 TRACE("got %u with %u\n", res, GetLastError());
6387 else
6389 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6391 monitor_unload(pm);
6392 return res;
6395 /******************************************************************************
6396 * AddPrinterConnectionA (WINSPOOL.@)
6398 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6400 FIXME("%s\n", debugstr_a(pName));
6401 return FALSE;
6404 /******************************************************************************
6405 * AddPrinterConnectionW (WINSPOOL.@)
6407 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6409 FIXME("%s\n", debugstr_w(pName));
6410 return FALSE;
6413 /******************************************************************************
6414 * AddPrinterDriverExW (WINSPOOL.@)
6416 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6418 * PARAMS
6419 * pName [I] Servername or NULL (local Computer)
6420 * level [I] Level for the supplied DRIVER_INFO_*W struct
6421 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6422 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6424 * RESULTS
6425 * Success: TRUE
6426 * Failure: FALSE
6429 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6431 const printenv_t *env;
6432 apd_data_t apd;
6433 DRIVER_INFO_8W di;
6434 LPWSTR ptr;
6435 HKEY hroot;
6436 HKEY hdrv;
6437 DWORD disposition;
6438 DWORD len;
6439 LONG lres;
6441 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6443 if (level < 2 || level == 5 || level == 7 || level > 8) {
6444 SetLastError(ERROR_INVALID_LEVEL);
6445 return FALSE;
6448 if (!pDriverInfo) {
6449 SetLastError(ERROR_INVALID_PARAMETER);
6450 return FALSE;
6453 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
6454 FIXME("Flags 0x%x ignored (Fallback to APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
6457 ptr = get_servername_from_name(pName);
6458 HeapFree(GetProcessHeap(), 0, ptr);
6459 if (ptr) {
6460 FIXME("not supported for server: %s\n", debugstr_w(pName));
6461 SetLastError(ERROR_ACCESS_DENIED);
6462 return FALSE;
6465 /* we need to set all entries in the Registry, independent from the Level of
6466 DRIVER_INFO, that the caller supplied */
6468 ZeroMemory(&di, sizeof(di));
6469 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
6470 memcpy(&di, pDriverInfo, di_sizeof[level]);
6473 /* dump the most used infos */
6474 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
6475 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
6476 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
6477 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
6478 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
6479 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
6480 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
6481 /* dump only the first of the additional Files */
6482 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
6485 /* check environment */
6486 env = validate_envW(di.pEnvironment);
6487 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
6489 /* fill the copy-data / get the driverdir */
6490 len = sizeof(apd.src) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
6491 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1,
6492 (LPBYTE) apd.src, len, &len)) {
6493 /* Should never Fail */
6494 return FALSE;
6496 memcpy(apd.dst, apd.src, len);
6497 lstrcatW(apd.src, backslashW);
6498 apd.srclen = lstrlenW(apd.src);
6499 lstrcatW(apd.dst, env->versionsubdir);
6500 lstrcatW(apd.dst, backslashW);
6501 apd.dstlen = lstrlenW(apd.dst);
6502 apd.copyflags = dwFileCopyFlags;
6503 CreateDirectoryW(apd.src, NULL);
6504 CreateDirectoryW(apd.dst, NULL);
6506 /* Fill the Registry for the Driver */
6507 hroot = WINSPOOL_OpenDriverReg(env->envname, TRUE);
6508 if(!hroot) {
6509 ERR("Can't create Drivers key\n");
6510 return FALSE;
6513 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
6514 KEY_WRITE | KEY_QUERY_VALUE, NULL,
6515 &hdrv, &disposition)) != ERROR_SUCCESS) {
6517 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
6518 RegCloseKey(hroot);
6519 SetLastError(lres);
6520 return FALSE;
6522 RegCloseKey(hroot);
6524 if (disposition == REG_OPENED_EXISTING_KEY) {
6525 TRACE("driver %s already installed\n", debugstr_w(di.pName));
6526 RegCloseKey(hdrv);
6527 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
6528 return FALSE;
6531 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
6532 RegSetValueExW(hdrv, VersionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
6533 sizeof(DWORD));
6535 RegSetValueExW(hdrv, DriverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
6536 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
6537 apd_copyfile(di.pDriverPath, &apd);
6539 RegSetValueExW(hdrv, Data_FileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
6540 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
6541 apd_copyfile(di.pDataFile, &apd);
6543 RegSetValueExW(hdrv, Configuration_FileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
6544 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
6545 apd_copyfile(di.pConfigFile, &apd);
6547 /* settings for level 3 */
6548 RegSetValueExW(hdrv, Help_FileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
6549 di.pHelpFile ? (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR) : 0);
6550 apd_copyfile(di.pHelpFile, &apd);
6553 ptr = di.pDependentFiles;
6554 RegSetValueExW(hdrv, Dependent_FilesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
6555 di.pDependentFiles ? multi_sz_lenW(di.pDependentFiles) : 0);
6556 while ((ptr != NULL) && (ptr[0])) {
6557 if (apd_copyfile(ptr, &apd)) {
6558 ptr += lstrlenW(ptr) + 1;
6560 else
6562 WARN("Failed to copy %s\n", debugstr_w(ptr));
6563 ptr = NULL;
6567 /* The language-Monitor was already copied to "%SystemRoot%\system32" */
6568 RegSetValueExW(hdrv, MonitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
6569 di.pMonitorName ? (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR) : 0);
6571 RegSetValueExW(hdrv, DatatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
6572 di.pDefaultDataType ? (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR) : 0);
6574 /* settings for level 4 */
6575 RegSetValueExW(hdrv, Previous_NamesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
6576 di.pszzPreviousNames ? multi_sz_lenW(di.pszzPreviousNames) : 0);
6578 if (level > 5) FIXME("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
6581 RegCloseKey(hdrv);
6582 FIXME("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
6585 TRACE("=> TRUE with %u\n", GetLastError());
6586 return TRUE;
6590 /******************************************************************************
6591 * AddPrinterDriverExA (WINSPOOL.@)
6593 * See AddPrinterDriverExW.
6596 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6598 DRIVER_INFO_8A *diA;
6599 DRIVER_INFO_8W diW;
6600 LPWSTR nameW = NULL;
6601 DWORD lenA;
6602 DWORD len;
6603 DWORD res = FALSE;
6605 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6607 diA = (DRIVER_INFO_8A *) pDriverInfo;
6608 ZeroMemory(&diW, sizeof(diW));
6610 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6611 SetLastError(ERROR_INVALID_LEVEL);
6612 return FALSE;
6615 if (diA == NULL) {
6616 SetLastError(ERROR_INVALID_PARAMETER);
6617 return FALSE;
6620 /* convert servername to unicode */
6621 if (pName) {
6622 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6623 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6624 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6627 /* common fields */
6628 diW.cVersion = diA->cVersion;
6630 if (diA->pName) {
6631 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6632 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6633 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6636 if (diA->pEnvironment) {
6637 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6638 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6639 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6642 if (diA->pDriverPath) {
6643 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6644 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6645 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6648 if (diA->pDataFile) {
6649 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6650 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6651 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6654 if (diA->pConfigFile) {
6655 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6656 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6657 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6660 if ((Level > 2) && diA->pDependentFiles) {
6661 lenA = multi_sz_lenA(diA->pDependentFiles);
6662 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6663 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6664 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6667 if ((Level > 2) && diA->pMonitorName) {
6668 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6669 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6670 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6673 if ((Level > 3) && diA->pDefaultDataType) {
6674 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6675 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6676 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6679 if ((Level > 3) && diA->pszzPreviousNames) {
6680 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6681 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6682 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6683 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6686 if ((Level > 5) && diA->pszMfgName) {
6687 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6688 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6689 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6692 if ((Level > 5) && diA->pszOEMUrl) {
6693 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6694 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6695 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6698 if ((Level > 5) && diA->pszHardwareID) {
6699 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6700 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6701 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6704 if ((Level > 5) && diA->pszProvider) {
6705 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6706 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6707 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6710 if (Level > 7) {
6711 FIXME("level %u is incomplete\n", Level);
6714 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6715 TRACE("got %u with %u\n", res, GetLastError());
6716 HeapFree(GetProcessHeap(), 0, nameW);
6717 HeapFree(GetProcessHeap(), 0, diW.pName);
6718 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6719 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6720 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6721 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6722 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6723 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6724 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6725 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6726 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6727 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6728 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6729 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6731 TRACE("=> %u with %u\n", res, GetLastError());
6732 return res;
6735 /******************************************************************************
6736 * ConfigurePortA (WINSPOOL.@)
6738 * See ConfigurePortW.
6741 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6743 LPWSTR nameW = NULL;
6744 LPWSTR portW = NULL;
6745 INT len;
6746 DWORD res;
6748 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6750 /* convert servername to unicode */
6751 if (pName) {
6752 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6753 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6754 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6757 /* convert portname to unicode */
6758 if (pPortName) {
6759 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6760 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6761 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6764 res = ConfigurePortW(nameW, hWnd, portW);
6765 HeapFree(GetProcessHeap(), 0, nameW);
6766 HeapFree(GetProcessHeap(), 0, portW);
6767 return res;
6770 /******************************************************************************
6771 * ConfigurePortW (WINSPOOL.@)
6773 * Display the Configuration-Dialog for a specific Port
6775 * PARAMS
6776 * pName [I] Servername or NULL (local Computer)
6777 * hWnd [I] Handle to parent Window for the Dialog-Box
6778 * pPortName [I] Name of the Port, that should be configured
6780 * RETURNS
6781 * Success: TRUE
6782 * Failure: FALSE
6785 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6787 monitor_t * pm;
6788 monitor_t * pui;
6789 DWORD res;
6791 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6793 if (pName && pName[0]) {
6794 SetLastError(ERROR_INVALID_PARAMETER);
6795 return FALSE;
6798 if (!pPortName) {
6799 SetLastError(RPC_X_NULL_REF_POINTER);
6800 return FALSE;
6803 /* an empty Portname is Invalid, but can popup a Dialog */
6804 if (!pPortName[0]) {
6805 SetLastError(ERROR_NOT_SUPPORTED);
6806 return FALSE;
6809 pm = monitor_load_by_port(pPortName);
6810 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6811 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6812 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6813 TRACE("got %d with %u\n", res, GetLastError());
6815 else
6817 pui = monitor_loadui(pm);
6818 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6819 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6820 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6821 TRACE("got %d with %u\n", res, GetLastError());
6823 else
6825 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6826 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6828 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6829 SetLastError(ERROR_NOT_SUPPORTED);
6830 res = FALSE;
6832 monitor_unload(pui);
6834 monitor_unload(pm);
6836 TRACE("returning %d with %u\n", res, GetLastError());
6837 return res;
6840 /******************************************************************************
6841 * ConnectToPrinterDlg (WINSPOOL.@)
6843 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6845 FIXME("%p %x\n", hWnd, Flags);
6846 return NULL;
6849 /******************************************************************************
6850 * DeletePrinterConnectionA (WINSPOOL.@)
6852 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6854 FIXME("%s\n", debugstr_a(pName));
6855 return TRUE;
6858 /******************************************************************************
6859 * DeletePrinterConnectionW (WINSPOOL.@)
6861 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6863 FIXME("%s\n", debugstr_w(pName));
6864 return TRUE;
6867 /******************************************************************************
6868 * DeletePrinterDriverExW (WINSPOOL.@)
6870 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6871 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6873 HKEY hkey_drivers;
6874 BOOL ret = FALSE;
6876 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6877 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6879 if(pName && pName[0])
6881 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6882 SetLastError(ERROR_INVALID_PARAMETER);
6883 return FALSE;
6886 if(dwDeleteFlag)
6888 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6889 SetLastError(ERROR_INVALID_PARAMETER);
6890 return FALSE;
6893 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6895 if(!hkey_drivers)
6897 ERR("Can't open drivers key\n");
6898 return FALSE;
6901 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6902 ret = TRUE;
6904 RegCloseKey(hkey_drivers);
6906 return ret;
6909 /******************************************************************************
6910 * DeletePrinterDriverExA (WINSPOOL.@)
6912 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6913 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6915 UNICODE_STRING NameW, EnvW, DriverW;
6916 BOOL ret;
6918 asciitounicode(&NameW, pName);
6919 asciitounicode(&EnvW, pEnvironment);
6920 asciitounicode(&DriverW, pDriverName);
6922 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6924 RtlFreeUnicodeString(&DriverW);
6925 RtlFreeUnicodeString(&EnvW);
6926 RtlFreeUnicodeString(&NameW);
6928 return ret;
6931 /******************************************************************************
6932 * DeletePrinterDataExW (WINSPOOL.@)
6934 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6935 LPCWSTR pValueName)
6937 FIXME("%p %s %s\n", hPrinter,
6938 debugstr_w(pKeyName), debugstr_w(pValueName));
6939 return ERROR_INVALID_PARAMETER;
6942 /******************************************************************************
6943 * DeletePrinterDataExA (WINSPOOL.@)
6945 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6946 LPCSTR pValueName)
6948 FIXME("%p %s %s\n", hPrinter,
6949 debugstr_a(pKeyName), debugstr_a(pValueName));
6950 return ERROR_INVALID_PARAMETER;
6953 /******************************************************************************
6954 * DeletePrintProcessorA (WINSPOOL.@)
6956 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6958 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6959 debugstr_a(pPrintProcessorName));
6960 return TRUE;
6963 /******************************************************************************
6964 * DeletePrintProcessorW (WINSPOOL.@)
6966 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6968 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6969 debugstr_w(pPrintProcessorName));
6970 return TRUE;
6973 /******************************************************************************
6974 * DeletePrintProvidorA (WINSPOOL.@)
6976 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6978 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6979 debugstr_a(pPrintProviderName));
6980 return TRUE;
6983 /******************************************************************************
6984 * DeletePrintProvidorW (WINSPOOL.@)
6986 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6988 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6989 debugstr_w(pPrintProviderName));
6990 return TRUE;
6993 /******************************************************************************
6994 * EnumFormsA (WINSPOOL.@)
6996 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6997 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6999 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7000 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7001 return FALSE;
7004 /******************************************************************************
7005 * EnumFormsW (WINSPOOL.@)
7007 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7008 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7010 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7011 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7012 return FALSE;
7015 /*****************************************************************************
7016 * EnumMonitorsA [WINSPOOL.@]
7018 * See EnumMonitorsW.
7021 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7022 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7024 BOOL res;
7025 LPBYTE bufferW = NULL;
7026 LPWSTR nameW = NULL;
7027 DWORD needed = 0;
7028 DWORD numentries = 0;
7029 INT len;
7031 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7032 cbBuf, pcbNeeded, pcReturned);
7034 /* convert servername to unicode */
7035 if (pName) {
7036 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7037 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7038 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7040 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7041 needed = cbBuf * sizeof(WCHAR);
7042 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7043 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7045 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7046 if (pcbNeeded) needed = *pcbNeeded;
7047 /* HeapReAlloc return NULL, when bufferW was NULL */
7048 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7049 HeapAlloc(GetProcessHeap(), 0, needed);
7051 /* Try again with the large Buffer */
7052 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7054 numentries = pcReturned ? *pcReturned : 0;
7055 needed = 0;
7057 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7058 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7060 if (res) {
7061 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7062 DWORD entrysize = 0;
7063 DWORD index;
7064 LPSTR ptr;
7065 LPMONITOR_INFO_2W mi2w;
7066 LPMONITOR_INFO_2A mi2a;
7068 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7069 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7071 /* First pass: calculate the size for all Entries */
7072 mi2w = (LPMONITOR_INFO_2W) bufferW;
7073 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7074 index = 0;
7075 while (index < numentries) {
7076 index++;
7077 needed += entrysize; /* MONITOR_INFO_?A */
7078 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7080 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7081 NULL, 0, NULL, NULL);
7082 if (Level > 1) {
7083 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7084 NULL, 0, NULL, NULL);
7085 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7086 NULL, 0, NULL, NULL);
7088 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7089 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7090 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7093 /* check for errors and quit on failure */
7094 if (cbBuf < needed) {
7095 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7096 res = FALSE;
7097 goto emA_cleanup;
7099 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7100 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7101 cbBuf -= len ; /* free Bytes in the user-Buffer */
7102 mi2w = (LPMONITOR_INFO_2W) bufferW;
7103 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7104 index = 0;
7105 /* Second Pass: Fill the User Buffer (if we have one) */
7106 while ((index < numentries) && pMonitors) {
7107 index++;
7108 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7109 mi2a->pName = ptr;
7110 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7111 ptr, cbBuf , NULL, NULL);
7112 ptr += len;
7113 cbBuf -= len;
7114 if (Level > 1) {
7115 mi2a->pEnvironment = ptr;
7116 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7117 ptr, cbBuf, NULL, NULL);
7118 ptr += len;
7119 cbBuf -= len;
7121 mi2a->pDLLName = ptr;
7122 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7123 ptr, cbBuf, NULL, NULL);
7124 ptr += len;
7125 cbBuf -= len;
7127 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7128 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7129 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7132 emA_cleanup:
7133 if (pcbNeeded) *pcbNeeded = needed;
7134 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7136 HeapFree(GetProcessHeap(), 0, nameW);
7137 HeapFree(GetProcessHeap(), 0, bufferW);
7139 TRACE("returning %d with %d (%d byte for %d entries)\n",
7140 (res), GetLastError(), needed, numentries);
7142 return (res);
7146 /*****************************************************************************
7147 * EnumMonitorsW [WINSPOOL.@]
7149 * Enumerate available Port-Monitors
7151 * PARAMS
7152 * pName [I] Servername or NULL (local Computer)
7153 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7154 * pMonitors [O] PTR to Buffer that receives the Result
7155 * cbBuf [I] Size of Buffer at pMonitors
7156 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7157 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7159 * RETURNS
7160 * Success: TRUE
7161 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7163 * NOTES
7164 * Windows reads the Registry once and cache the Results.
7166 *| Language-Monitors are also installed in the same Registry-Location but
7167 *| they are filtered in Windows (not returned by EnumMonitors).
7168 *| We do no filtering to simplify our Code.
7171 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7172 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7174 DWORD needed = 0;
7175 DWORD numentries = 0;
7176 BOOL res = FALSE;
7178 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7179 cbBuf, pcbNeeded, pcReturned);
7181 if (pName && (lstrlenW(pName))) {
7182 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7183 SetLastError(ERROR_ACCESS_DENIED);
7184 goto emW_cleanup;
7187 /* Level is not checked in win9x */
7188 if (!Level || (Level > 2)) {
7189 WARN("level (%d) is ignored in win9x\n", Level);
7190 SetLastError(ERROR_INVALID_LEVEL);
7191 goto emW_cleanup;
7193 if (!pcbNeeded) {
7194 SetLastError(RPC_X_NULL_REF_POINTER);
7195 goto emW_cleanup;
7198 /* Scan all Monitor-Keys */
7199 numentries = 0;
7200 needed = get_local_monitors(Level, NULL, 0, &numentries);
7202 /* we calculated the needed buffersize. now do the error-checks */
7203 if (cbBuf < needed) {
7204 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7205 goto emW_cleanup;
7207 else if (!pMonitors || !pcReturned) {
7208 SetLastError(RPC_X_NULL_REF_POINTER);
7209 goto emW_cleanup;
7212 /* fill the Buffer with the Monitor-Keys */
7213 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7214 res = TRUE;
7216 emW_cleanup:
7217 if (pcbNeeded) *pcbNeeded = needed;
7218 if (pcReturned) *pcReturned = numentries;
7220 TRACE("returning %d with %d (%d byte for %d entries)\n",
7221 res, GetLastError(), needed, numentries);
7223 return (res);
7226 /******************************************************************************
7227 * XcvDataW (WINSPOOL.@)
7229 * Execute commands in the Printmonitor DLL
7231 * PARAMS
7232 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7233 * pszDataName [i] Name of the command to execute
7234 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7235 * cbInputData [i] Size in Bytes of Buffer at pInputData
7236 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7237 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7238 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7239 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7241 * RETURNS
7242 * Success: TRUE
7243 * Failure: FALSE
7245 * NOTES
7246 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7247 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7249 * Minimal List of commands, that a Printmonitor DLL should support:
7251 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7252 *| "AddPort" : Add a Port
7253 *| "DeletePort": Delete a Port
7255 * Many Printmonitors support additional commands. Examples for localspl.dll:
7256 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7257 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7260 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7261 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7262 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7264 opened_printer_t *printer;
7266 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7267 pInputData, cbInputData, pOutputData,
7268 cbOutputData, pcbOutputNeeded, pdwStatus);
7270 printer = get_opened_printer(hXcv);
7271 if (!printer || (!printer->hXcv)) {
7272 SetLastError(ERROR_INVALID_HANDLE);
7273 return FALSE;
7276 if (!pcbOutputNeeded) {
7277 SetLastError(ERROR_INVALID_PARAMETER);
7278 return FALSE;
7281 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7282 SetLastError(RPC_X_NULL_REF_POINTER);
7283 return FALSE;
7286 *pcbOutputNeeded = 0;
7288 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7289 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7291 return TRUE;
7294 /*****************************************************************************
7295 * EnumPrinterDataA [WINSPOOL.@]
7298 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7299 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7300 DWORD cbData, LPDWORD pcbData )
7302 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7303 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7304 return ERROR_NO_MORE_ITEMS;
7307 /*****************************************************************************
7308 * EnumPrinterDataW [WINSPOOL.@]
7311 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7312 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7313 DWORD cbData, LPDWORD pcbData )
7315 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7316 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7317 return ERROR_NO_MORE_ITEMS;
7320 /*****************************************************************************
7321 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7324 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7325 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7326 LPDWORD pcbNeeded, LPDWORD pcReturned)
7328 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7329 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7330 pcbNeeded, pcReturned);
7331 return FALSE;
7334 /*****************************************************************************
7335 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7338 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7339 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7340 LPDWORD pcbNeeded, LPDWORD pcReturned)
7342 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7343 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7344 pcbNeeded, pcReturned);
7345 return FALSE;
7348 /*****************************************************************************
7349 * EnumPrintProcessorsA [WINSPOOL.@]
7352 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7353 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7355 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7356 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7357 return FALSE;
7360 /*****************************************************************************
7361 * EnumPrintProcessorsW [WINSPOOL.@]
7364 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7365 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7367 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7368 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7369 cbBuf, pcbNeeded, pcbReturned);
7370 return FALSE;
7373 /*****************************************************************************
7374 * ExtDeviceMode [WINSPOOL.@]
7377 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7378 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7379 DWORD fMode)
7381 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7382 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7383 debugstr_a(pProfile), fMode);
7384 return -1;
7387 /*****************************************************************************
7388 * FindClosePrinterChangeNotification [WINSPOOL.@]
7391 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7393 FIXME("Stub: %p\n", hChange);
7394 return TRUE;
7397 /*****************************************************************************
7398 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7401 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7402 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7404 FIXME("Stub: %p %x %x %p\n",
7405 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7406 return INVALID_HANDLE_VALUE;
7409 /*****************************************************************************
7410 * FindNextPrinterChangeNotification [WINSPOOL.@]
7413 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7414 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7416 FIXME("Stub: %p %p %p %p\n",
7417 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7418 return FALSE;
7421 /*****************************************************************************
7422 * FreePrinterNotifyInfo [WINSPOOL.@]
7425 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7427 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7428 return TRUE;
7431 /*****************************************************************************
7432 * string_to_buf
7434 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7435 * ansi depending on the unicode parameter.
7437 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7439 if(!str)
7441 *size = 0;
7442 return TRUE;
7445 if(unicode)
7447 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7448 if(*size <= cb)
7450 memcpy(ptr, str, *size);
7451 return TRUE;
7453 return FALSE;
7455 else
7457 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7458 if(*size <= cb)
7460 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7461 return TRUE;
7463 return FALSE;
7467 /*****************************************************************************
7468 * get_job_info_1
7470 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7471 LPDWORD pcbNeeded, BOOL unicode)
7473 DWORD size, left = cbBuf;
7474 BOOL space = (cbBuf > 0);
7475 LPBYTE ptr = buf;
7477 *pcbNeeded = 0;
7479 if(space)
7481 ji1->JobId = job->job_id;
7484 string_to_buf(job->document_title, ptr, left, &size, unicode);
7485 if(space && size <= left)
7487 ji1->pDocument = (LPWSTR)ptr;
7488 ptr += size;
7489 left -= size;
7491 else
7492 space = FALSE;
7493 *pcbNeeded += size;
7495 return space;
7498 /*****************************************************************************
7499 * get_job_info_2
7501 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7502 LPDWORD pcbNeeded, BOOL unicode)
7504 DWORD size, left = cbBuf;
7505 BOOL space = (cbBuf > 0);
7506 LPBYTE ptr = buf;
7508 *pcbNeeded = 0;
7510 if(space)
7512 ji2->JobId = job->job_id;
7515 string_to_buf(job->document_title, ptr, left, &size, unicode);
7516 if(space && size <= left)
7518 ji2->pDocument = (LPWSTR)ptr;
7519 ptr += size;
7520 left -= size;
7522 else
7523 space = FALSE;
7524 *pcbNeeded += size;
7526 return space;
7529 /*****************************************************************************
7530 * get_job_info
7532 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7533 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7535 BOOL ret = FALSE;
7536 DWORD needed = 0, size;
7537 job_t *job;
7538 LPBYTE ptr = pJob;
7540 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7542 EnterCriticalSection(&printer_handles_cs);
7543 job = get_job(hPrinter, JobId);
7544 if(!job)
7545 goto end;
7547 switch(Level)
7549 case 1:
7550 size = sizeof(JOB_INFO_1W);
7551 if(cbBuf >= size)
7553 cbBuf -= size;
7554 ptr += size;
7555 memset(pJob, 0, size);
7557 else
7558 cbBuf = 0;
7559 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7560 needed += size;
7561 break;
7563 case 2:
7564 size = sizeof(JOB_INFO_2W);
7565 if(cbBuf >= size)
7567 cbBuf -= size;
7568 ptr += size;
7569 memset(pJob, 0, size);
7571 else
7572 cbBuf = 0;
7573 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7574 needed += size;
7575 break;
7577 case 3:
7578 size = sizeof(JOB_INFO_3);
7579 if(cbBuf >= size)
7581 cbBuf -= size;
7582 memset(pJob, 0, size);
7583 ret = TRUE;
7585 else
7586 cbBuf = 0;
7587 needed = size;
7588 break;
7590 default:
7591 SetLastError(ERROR_INVALID_LEVEL);
7592 goto end;
7594 if(pcbNeeded)
7595 *pcbNeeded = needed;
7596 end:
7597 LeaveCriticalSection(&printer_handles_cs);
7598 return ret;
7601 /*****************************************************************************
7602 * GetJobA [WINSPOOL.@]
7605 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7606 DWORD cbBuf, LPDWORD pcbNeeded)
7608 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7611 /*****************************************************************************
7612 * GetJobW [WINSPOOL.@]
7615 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7616 DWORD cbBuf, LPDWORD pcbNeeded)
7618 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7621 /*****************************************************************************
7622 * schedule_lpr
7624 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7626 char *unixname, *queue, *cmd;
7627 char fmt[] = "lpr -P%s %s";
7628 DWORD len;
7630 if(!(unixname = wine_get_unix_file_name(filename)))
7631 return FALSE;
7633 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7634 queue = HeapAlloc(GetProcessHeap(), 0, len);
7635 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7637 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7638 sprintf(cmd, fmt, queue, unixname);
7640 TRACE("printing with: %s\n", cmd);
7641 system(cmd);
7643 HeapFree(GetProcessHeap(), 0, cmd);
7644 HeapFree(GetProcessHeap(), 0, queue);
7645 HeapFree(GetProcessHeap(), 0, unixname);
7646 return TRUE;
7649 /*****************************************************************************
7650 * schedule_cups
7652 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7654 #ifdef SONAME_LIBCUPS
7655 if(pcupsPrintFile)
7657 char *unixname, *queue, *doc_titleA;
7658 DWORD len;
7659 BOOL ret;
7661 if(!(unixname = wine_get_unix_file_name(filename)))
7662 return FALSE;
7664 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7665 queue = HeapAlloc(GetProcessHeap(), 0, len);
7666 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7668 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7669 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7670 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7672 TRACE("printing via cups\n");
7673 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7674 HeapFree(GetProcessHeap(), 0, doc_titleA);
7675 HeapFree(GetProcessHeap(), 0, queue);
7676 HeapFree(GetProcessHeap(), 0, unixname);
7677 return ret;
7679 else
7680 #endif
7682 return schedule_lpr(printer_name, filename);
7686 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7688 LPWSTR filename;
7690 switch(msg)
7692 case WM_INITDIALOG:
7693 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7694 return TRUE;
7696 case WM_COMMAND:
7697 if(HIWORD(wparam) == BN_CLICKED)
7699 if(LOWORD(wparam) == IDOK)
7701 HANDLE hf;
7702 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7703 LPWSTR *output;
7705 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7706 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7708 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7710 WCHAR caption[200], message[200];
7711 int mb_ret;
7713 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7714 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7715 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7716 if(mb_ret == IDCANCEL)
7718 HeapFree(GetProcessHeap(), 0, filename);
7719 return TRUE;
7722 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7723 if(hf == INVALID_HANDLE_VALUE)
7725 WCHAR caption[200], message[200];
7727 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7728 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7729 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7730 HeapFree(GetProcessHeap(), 0, filename);
7731 return TRUE;
7733 CloseHandle(hf);
7734 DeleteFileW(filename);
7735 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7736 *output = filename;
7737 EndDialog(hwnd, IDOK);
7738 return TRUE;
7740 if(LOWORD(wparam) == IDCANCEL)
7742 EndDialog(hwnd, IDCANCEL);
7743 return TRUE;
7746 return FALSE;
7748 return FALSE;
7751 /*****************************************************************************
7752 * get_filename
7754 static BOOL get_filename(LPWSTR *filename)
7756 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7757 file_dlg_proc, (LPARAM)filename) == IDOK;
7760 /*****************************************************************************
7761 * schedule_file
7763 static BOOL schedule_file(LPCWSTR filename)
7765 LPWSTR output = NULL;
7767 if(get_filename(&output))
7769 TRACE("copy to %s\n", debugstr_w(output));
7770 CopyFileW(filename, output, FALSE);
7771 HeapFree(GetProcessHeap(), 0, output);
7772 return TRUE;
7774 return FALSE;
7777 /*****************************************************************************
7778 * schedule_pipe
7780 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7782 #ifdef HAVE_FORK
7783 char *unixname, *cmdA;
7784 DWORD len;
7785 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7786 BOOL ret = FALSE;
7787 char buf[1024];
7789 if(!(unixname = wine_get_unix_file_name(filename)))
7790 return FALSE;
7792 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7793 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7794 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7796 TRACE("printing with: %s\n", cmdA);
7798 if((file_fd = open(unixname, O_RDONLY)) == -1)
7799 goto end;
7801 if (pipe(fds))
7803 ERR("pipe() failed!\n");
7804 goto end;
7807 if (fork() == 0)
7809 close(0);
7810 dup2(fds[0], 0);
7811 close(fds[1]);
7813 /* reset signals that we previously set to SIG_IGN */
7814 signal(SIGPIPE, SIG_DFL);
7815 signal(SIGCHLD, SIG_DFL);
7817 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7818 _exit(1);
7821 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7822 write(fds[1], buf, no_read);
7824 ret = TRUE;
7826 end:
7827 if(file_fd != -1) close(file_fd);
7828 if(fds[0] != -1) close(fds[0]);
7829 if(fds[1] != -1) close(fds[1]);
7831 HeapFree(GetProcessHeap(), 0, cmdA);
7832 HeapFree(GetProcessHeap(), 0, unixname);
7833 return ret;
7834 #else
7835 return FALSE;
7836 #endif
7839 /*****************************************************************************
7840 * schedule_unixfile
7842 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7844 int in_fd, out_fd, no_read;
7845 char buf[1024];
7846 BOOL ret = FALSE;
7847 char *unixname, *outputA;
7848 DWORD len;
7850 if(!(unixname = wine_get_unix_file_name(filename)))
7851 return FALSE;
7853 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7854 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7855 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7857 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7858 in_fd = open(unixname, O_RDONLY);
7859 if(out_fd == -1 || in_fd == -1)
7860 goto end;
7862 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7863 write(out_fd, buf, no_read);
7865 ret = TRUE;
7866 end:
7867 if(in_fd != -1) close(in_fd);
7868 if(out_fd != -1) close(out_fd);
7869 HeapFree(GetProcessHeap(), 0, outputA);
7870 HeapFree(GetProcessHeap(), 0, unixname);
7871 return ret;
7874 /*****************************************************************************
7875 * ScheduleJob [WINSPOOL.@]
7878 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7880 opened_printer_t *printer;
7881 BOOL ret = FALSE;
7882 struct list *cursor, *cursor2;
7884 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7885 EnterCriticalSection(&printer_handles_cs);
7886 printer = get_opened_printer(hPrinter);
7887 if(!printer)
7888 goto end;
7890 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7892 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7893 HANDLE hf;
7895 if(job->job_id != dwJobID) continue;
7897 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7898 if(hf != INVALID_HANDLE_VALUE)
7900 PRINTER_INFO_5W *pi5;
7901 DWORD needed;
7902 HKEY hkey;
7903 WCHAR output[1024];
7904 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7905 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7907 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7908 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7909 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7910 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7911 debugstr_w(pi5->pPortName));
7913 output[0] = 0;
7915 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7916 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7918 DWORD type, count = sizeof(output);
7919 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7920 RegCloseKey(hkey);
7922 if(output[0] == '|')
7924 schedule_pipe(output + 1, job->filename);
7926 else if(output[0])
7928 schedule_unixfile(output, job->filename);
7930 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7932 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7934 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7936 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7938 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7940 schedule_file(job->filename);
7942 else
7944 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7946 HeapFree(GetProcessHeap(), 0, pi5);
7947 CloseHandle(hf);
7948 DeleteFileW(job->filename);
7950 list_remove(cursor);
7951 HeapFree(GetProcessHeap(), 0, job->document_title);
7952 HeapFree(GetProcessHeap(), 0, job->filename);
7953 HeapFree(GetProcessHeap(), 0, job);
7954 ret = TRUE;
7955 break;
7957 end:
7958 LeaveCriticalSection(&printer_handles_cs);
7959 return ret;
7962 /*****************************************************************************
7963 * StartDocDlgA [WINSPOOL.@]
7965 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7967 UNICODE_STRING usBuffer;
7968 DOCINFOW docW;
7969 LPWSTR retW;
7970 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7971 LPSTR ret = NULL;
7973 docW.cbSize = sizeof(docW);
7974 if (doc->lpszDocName)
7976 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7977 if (!(docW.lpszDocName = docnameW)) return NULL;
7979 if (doc->lpszOutput)
7981 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7982 if (!(docW.lpszOutput = outputW)) return NULL;
7984 if (doc->lpszDatatype)
7986 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7987 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7989 docW.fwType = doc->fwType;
7991 retW = StartDocDlgW(hPrinter, &docW);
7993 if(retW)
7995 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7996 ret = HeapAlloc(GetProcessHeap(), 0, len);
7997 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7998 HeapFree(GetProcessHeap(), 0, retW);
8001 HeapFree(GetProcessHeap(), 0, datatypeW);
8002 HeapFree(GetProcessHeap(), 0, outputW);
8003 HeapFree(GetProcessHeap(), 0, docnameW);
8005 return ret;
8008 /*****************************************************************************
8009 * StartDocDlgW [WINSPOOL.@]
8011 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8012 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8013 * port is "FILE:". Also returns the full path if passed a relative path.
8015 * The caller should free the returned string from the process heap.
8017 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8019 LPWSTR ret = NULL;
8020 DWORD len, attr;
8022 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8024 PRINTER_INFO_5W *pi5;
8025 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8026 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8027 return NULL;
8028 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8029 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8030 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8032 HeapFree(GetProcessHeap(), 0, pi5);
8033 return NULL;
8035 HeapFree(GetProcessHeap(), 0, pi5);
8038 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8040 LPWSTR name;
8042 if (get_filename(&name))
8044 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8046 HeapFree(GetProcessHeap(), 0, name);
8047 return NULL;
8049 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8050 GetFullPathNameW(name, len, ret, NULL);
8051 HeapFree(GetProcessHeap(), 0, name);
8053 return ret;
8056 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8057 return NULL;
8059 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8060 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8062 attr = GetFileAttributesW(ret);
8063 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8065 HeapFree(GetProcessHeap(), 0, ret);
8066 ret = NULL;
8068 return ret;