push 599a9d3db769aad8dabfd10a59120f719b00f4ee
[wine/hacks.git] / dlls / winspool.drv / info.c
blobfee2210b90f09a5558f708da8576b52bdcafb048
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 int 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))
491 di3a.cVersion = 0;
492 di3a.pEnvironment = env_9x;
493 di3a.pDriverPath = driver_9x;
494 di3a.pConfigFile = driver_9x;
495 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
497 return TRUE;
500 ERR("Failed adding driver %s: %u\n", debugstr_a(di3a.pDriverPath), GetLastError());
501 return FALSE;
504 #ifdef SONAME_LIBCUPS
505 static typeof(cupsGetDests) *pcupsGetDests;
506 static typeof(cupsGetPPD) *pcupsGetPPD;
507 static typeof(cupsPrintFile) *pcupsPrintFile;
508 static void *cupshandle;
510 static BOOL CUPS_LoadPrinters(void)
512 int i, nrofdests;
513 BOOL hadprinter = FALSE, haddefault = FALSE;
514 cups_dest_t *dests;
515 PRINTER_INFO_2A pinfo2a;
516 char *port,*devline;
517 HKEY hkeyPrinter, hkeyPrinters, hkey;
518 char loaderror[256];
520 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
521 if (!cupshandle) {
522 TRACE("%s\n", loaderror);
523 return FALSE;
525 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
527 #define DYNCUPS(x) \
528 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
529 if (!p##x) return FALSE;
531 DYNCUPS(cupsGetPPD);
532 DYNCUPS(cupsGetDests);
533 DYNCUPS(cupsPrintFile);
534 #undef DYNCUPS
536 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
537 ERROR_SUCCESS) {
538 ERR("Can't create Printers key\n");
539 return FALSE;
542 nrofdests = pcupsGetDests(&dests);
543 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
544 for (i=0;i<nrofdests;i++) {
545 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
546 sprintf(port,"LPR:%s",dests[i].name);
547 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
548 sprintf(devline,"WINEPS.DRV,%s",port);
549 WriteProfileStringA("devices",dests[i].name,devline);
550 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
551 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
552 RegCloseKey(hkey);
554 HeapFree(GetProcessHeap(),0,devline);
556 TRACE("Printer %d: %s\n", i, dests[i].name);
557 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
558 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
559 and continue */
560 TRACE("Printer already exists\n");
561 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
562 RegCloseKey(hkeyPrinter);
563 } else {
564 static CHAR data_type[] = "RAW",
565 print_proc[] = "WinPrint",
566 comment[] = "WINEPS Printer using CUPS",
567 location[] = "<physical location of printer>",
568 params[] = "<parameters?>",
569 share_name[] = "<share name?>",
570 sep_file[] = "<sep file?>";
572 add_printer_driver(dests[i].name);
574 memset(&pinfo2a,0,sizeof(pinfo2a));
575 pinfo2a.pPrinterName = dests[i].name;
576 pinfo2a.pDatatype = data_type;
577 pinfo2a.pPrintProcessor = print_proc;
578 pinfo2a.pDriverName = dests[i].name;
579 pinfo2a.pComment = comment;
580 pinfo2a.pLocation = location;
581 pinfo2a.pPortName = port;
582 pinfo2a.pParameters = params;
583 pinfo2a.pShareName = share_name;
584 pinfo2a.pSepFile = sep_file;
586 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
587 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
588 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
591 HeapFree(GetProcessHeap(),0,port);
593 hadprinter = TRUE;
594 if (dests[i].is_default) {
595 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
596 haddefault = TRUE;
599 if (hadprinter & !haddefault)
600 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
601 RegCloseKey(hkeyPrinters);
602 return hadprinter;
604 #endif
606 static BOOL
607 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
608 PRINTER_INFO_2A pinfo2a;
609 char *e,*s,*name,*prettyname,*devname;
610 BOOL ret = FALSE, set_default = FALSE;
611 char *port,*devline,*env_default;
612 HKEY hkeyPrinter, hkeyPrinters, hkey;
614 while (isspace(*pent)) pent++;
615 s = strchr(pent,':');
616 if(s) *s='\0';
617 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
618 strcpy(name,pent);
619 if(s) {
620 *s=':';
621 pent = s;
622 } else
623 pent = "";
625 TRACE("name=%s entry=%s\n",name, pent);
627 if(ispunct(*name)) { /* a tc entry, not a real printer */
628 TRACE("skipping tc entry\n");
629 goto end;
632 if(strstr(pent,":server")) { /* server only version so skip */
633 TRACE("skipping server entry\n");
634 goto end;
637 /* Determine whether this is a postscript printer. */
639 ret = TRUE;
640 env_default = getenv("PRINTER");
641 prettyname = name;
642 /* Get longest name, usually the one at the right for later display. */
643 while((s=strchr(prettyname,'|'))) {
644 *s = '\0';
645 e = s;
646 while(isspace(*--e)) *e = '\0';
647 TRACE("\t%s\n", debugstr_a(prettyname));
648 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
649 for(prettyname = s+1; isspace(*prettyname); prettyname++)
652 e = prettyname + strlen(prettyname);
653 while(isspace(*--e)) *e = '\0';
654 TRACE("\t%s\n", debugstr_a(prettyname));
655 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
657 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
658 * if it is too long, we use it as comment below. */
659 devname = prettyname;
660 if (strlen(devname)>=CCHDEVICENAME-1)
661 devname = name;
662 if (strlen(devname)>=CCHDEVICENAME-1) {
663 ret = FALSE;
664 goto end;
667 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
668 sprintf(port,"LPR:%s",name);
670 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
671 sprintf(devline,"WINEPS.DRV,%s",port);
672 WriteProfileStringA("devices",devname,devline);
673 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
674 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
675 RegCloseKey(hkey);
677 HeapFree(GetProcessHeap(),0,devline);
679 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
680 ERROR_SUCCESS) {
681 ERR("Can't create Printers key\n");
682 ret = FALSE;
683 goto end;
685 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
686 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
687 and continue */
688 TRACE("Printer already exists\n");
689 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
690 RegCloseKey(hkeyPrinter);
691 } else {
692 static CHAR data_type[] = "RAW",
693 print_proc[] = "WinPrint",
694 comment[] = "WINEPS Printer using LPR",
695 params[] = "<parameters?>",
696 share_name[] = "<share name?>",
697 sep_file[] = "<sep file?>";
699 add_printer_driver(devname);
701 memset(&pinfo2a,0,sizeof(pinfo2a));
702 pinfo2a.pPrinterName = devname;
703 pinfo2a.pDatatype = data_type;
704 pinfo2a.pPrintProcessor = print_proc;
705 pinfo2a.pDriverName = devname;
706 pinfo2a.pComment = comment;
707 pinfo2a.pLocation = prettyname;
708 pinfo2a.pPortName = port;
709 pinfo2a.pParameters = params;
710 pinfo2a.pShareName = share_name;
711 pinfo2a.pSepFile = sep_file;
713 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
714 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
715 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
718 RegCloseKey(hkeyPrinters);
720 if (isfirst || set_default)
721 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
723 HeapFree(GetProcessHeap(), 0, port);
724 end:
725 HeapFree(GetProcessHeap(), 0, name);
726 return ret;
729 static BOOL
730 PRINTCAP_LoadPrinters(void) {
731 BOOL hadprinter = FALSE;
732 char buf[200];
733 FILE *f;
734 char *pent = NULL;
735 BOOL had_bash = FALSE;
737 f = fopen("/etc/printcap","r");
738 if (!f)
739 return FALSE;
741 while(fgets(buf,sizeof(buf),f)) {
742 char *start, *end;
744 end=strchr(buf,'\n');
745 if (end) *end='\0';
747 start = buf;
748 while(isspace(*start)) start++;
749 if(*start == '#' || *start == '\0')
750 continue;
752 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
753 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
754 HeapFree(GetProcessHeap(),0,pent);
755 pent = NULL;
758 if (end && *--end == '\\') {
759 *end = '\0';
760 had_bash = TRUE;
761 } else
762 had_bash = FALSE;
764 if (pent) {
765 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
766 strcat(pent,start);
767 } else {
768 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
769 strcpy(pent,start);
773 if(pent) {
774 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
775 HeapFree(GetProcessHeap(),0,pent);
777 fclose(f);
778 return hadprinter;
781 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
783 if (value)
784 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
785 (lstrlenW(value) + 1) * sizeof(WCHAR));
786 else
787 return ERROR_FILE_NOT_FOUND;
790 /*****************************************************************************
791 * enumerate the local monitors (INTERNAL)
793 * returns the needed size (in bytes) for pMonitors
794 * and *lpreturned is set to number of entries returned in pMonitors
797 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
799 HKEY hroot = NULL;
800 HKEY hentry = NULL;
801 LPWSTR ptr;
802 LPMONITOR_INFO_2W mi;
803 WCHAR buffer[MAX_PATH];
804 WCHAR dllname[MAX_PATH];
805 DWORD dllsize;
806 DWORD len;
807 DWORD index = 0;
808 DWORD needed = 0;
809 DWORD numentries;
810 DWORD entrysize;
812 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
814 numentries = *lpreturned; /* this is 0, when we scan the registry */
815 len = entrysize * numentries;
816 ptr = (LPWSTR) &pMonitors[len];
818 numentries = 0;
819 len = sizeof(buffer);
820 buffer[0] = '\0';
822 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
823 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
824 /* Scan all Monitor-Registry-Keys */
825 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
826 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
827 dllsize = sizeof(dllname);
828 dllname[0] = '\0';
830 /* The Monitor must have a Driver-DLL */
831 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
832 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
833 /* We found a valid DLL for this Monitor. */
834 TRACE("using Driver: %s\n", debugstr_w(dllname));
836 RegCloseKey(hentry);
839 /* Windows returns only Port-Monitors here, but to simplify our code,
840 we do no filtering for Language-Monitors */
841 if (dllname[0]) {
842 numentries++;
843 needed += entrysize;
844 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
845 if (level > 1) {
846 /* we install and return only monitors for "Windows NT x86" */
847 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
848 needed += dllsize;
851 /* required size is calculated. Now fill the user-buffer */
852 if (pMonitors && (cbBuf >= needed)){
853 mi = (LPMONITOR_INFO_2W) pMonitors;
854 pMonitors += entrysize;
856 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
857 mi->pName = ptr;
858 lstrcpyW(ptr, buffer); /* Name of the Monitor */
859 ptr += (len+1); /* len is lstrlenW(monitorname) */
860 if (level > 1) {
861 mi->pEnvironment = ptr;
862 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
863 ptr += (lstrlenW(envname_x86W)+1);
865 mi->pDLLName = ptr;
866 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
867 ptr += (dllsize / sizeof(WCHAR));
871 index++;
872 len = sizeof(buffer);
873 buffer[0] = '\0';
875 RegCloseKey(hroot);
877 *lpreturned = numentries;
878 TRACE("need %d byte for %d entries\n", needed, numentries);
879 return needed;
882 /******************************************************************
883 * monitor_unload [internal]
885 * release a printmonitor and unload it from memory, when needed
888 static void monitor_unload(monitor_t * pm)
890 if (pm == NULL) return;
891 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
893 EnterCriticalSection(&monitor_handles_cs);
895 if (pm->refcount) pm->refcount--;
897 if (pm->refcount == 0) {
898 list_remove(&pm->entry);
899 FreeLibrary(pm->hdll);
900 HeapFree(GetProcessHeap(), 0, pm->name);
901 HeapFree(GetProcessHeap(), 0, pm->dllname);
902 HeapFree(GetProcessHeap(), 0, pm);
904 LeaveCriticalSection(&monitor_handles_cs);
907 /******************************************************************
908 * monitor_unloadall [internal]
910 * release all printmonitors and unload them from memory, when needed
913 static void monitor_unloadall(void)
915 monitor_t * pm;
916 monitor_t * next;
918 EnterCriticalSection(&monitor_handles_cs);
919 /* iterate through the list, with safety against removal */
920 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
922 monitor_unload(pm);
924 LeaveCriticalSection(&monitor_handles_cs);
927 /******************************************************************
928 * monitor_load [internal]
930 * load a printmonitor, get the dllname from the registry, when needed
931 * initialize the monitor and dump found function-pointers
933 * On failure, SetLastError() is called and NULL is returned
936 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
938 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
939 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
940 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
941 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
942 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
944 monitor_t * pm = NULL;
945 monitor_t * cursor;
946 LPWSTR regroot = NULL;
947 LPWSTR driver = dllname;
949 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
950 /* Is the Monitor already loaded? */
951 EnterCriticalSection(&monitor_handles_cs);
953 if (name) {
954 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
956 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
957 pm = cursor;
958 break;
963 if (pm == NULL) {
964 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
965 if (pm == NULL) goto cleanup;
966 list_add_tail(&monitor_handles, &pm->entry);
968 pm->refcount++;
970 if (pm->name == NULL) {
971 /* Load the monitor */
972 LPMONITOREX pmonitorEx;
973 DWORD len;
975 if (name) {
976 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
977 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
980 if (regroot) {
981 lstrcpyW(regroot, MonitorsW);
982 lstrcatW(regroot, name);
983 /* Get the Driver from the Registry */
984 if (driver == NULL) {
985 HKEY hroot;
986 DWORD namesize;
987 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
988 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
989 &namesize) == ERROR_SUCCESS) {
990 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
991 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
993 RegCloseKey(hroot);
998 pm->name = strdupW(name);
999 pm->dllname = strdupW(driver);
1001 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
1002 monitor_unload(pm);
1003 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1004 pm = NULL;
1005 goto cleanup;
1008 pm->hdll = LoadLibraryW(driver);
1009 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
1011 if (pm->hdll == NULL) {
1012 monitor_unload(pm);
1013 SetLastError(ERROR_MOD_NOT_FOUND);
1014 pm = NULL;
1015 goto cleanup;
1018 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
1019 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
1020 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
1021 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
1022 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
1025 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
1026 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
1027 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
1028 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
1029 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
1031 if (pInitializePrintMonitorUI != NULL) {
1032 pm->monitorUI = pInitializePrintMonitorUI();
1033 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
1034 if (pm->monitorUI) {
1035 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1036 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
1041 if (pInitializePrintMonitor && regroot) {
1042 pmonitorEx = pInitializePrintMonitor(regroot);
1043 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1044 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1046 if (pmonitorEx) {
1047 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1048 pm->monitor = &(pmonitorEx->Monitor);
1052 if (pm->monitor) {
1053 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1057 if (!pm->monitor && regroot) {
1058 if (pInitializePrintMonitor2 != NULL) {
1059 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1061 if (pInitializeMonitorEx != NULL) {
1062 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1064 if (pInitializeMonitor != NULL) {
1065 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1068 if (!pm->monitor && !pm->monitorUI) {
1069 monitor_unload(pm);
1070 SetLastError(ERROR_PROC_NOT_FOUND);
1071 pm = NULL;
1074 cleanup:
1075 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1076 pm->refcount++;
1077 pm_localport = pm;
1079 LeaveCriticalSection(&monitor_handles_cs);
1080 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1081 HeapFree(GetProcessHeap(), 0, regroot);
1082 TRACE("=> %p\n", pm);
1083 return pm;
1086 /******************************************************************
1087 * monitor_loadall [internal]
1089 * Load all registered monitors
1092 static DWORD monitor_loadall(void)
1094 monitor_t * pm;
1095 DWORD registered = 0;
1096 DWORD loaded = 0;
1097 HKEY hmonitors;
1098 WCHAR buffer[MAX_PATH];
1099 DWORD id = 0;
1101 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1102 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1103 NULL, NULL, NULL, NULL, NULL);
1105 TRACE("%d monitors registered\n", registered);
1107 EnterCriticalSection(&monitor_handles_cs);
1108 while (id < registered) {
1109 buffer[0] = '\0';
1110 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1111 pm = monitor_load(buffer, NULL);
1112 if (pm) loaded++;
1113 id++;
1115 LeaveCriticalSection(&monitor_handles_cs);
1116 RegCloseKey(hmonitors);
1118 TRACE("%d monitors loaded\n", loaded);
1119 return loaded;
1122 /******************************************************************
1123 * monitor_loadui [internal]
1125 * load the userinterface-dll for a given portmonitor
1127 * On failure, NULL is returned
1130 static monitor_t * monitor_loadui(monitor_t * pm)
1132 monitor_t * pui = NULL;
1133 LPWSTR buffer[MAX_PATH];
1134 HANDLE hXcv;
1135 DWORD len;
1136 DWORD res;
1138 if (pm == NULL) return NULL;
1139 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1141 /* Try the Portmonitor first; works for many monitors */
1142 if (pm->monitorUI) {
1143 EnterCriticalSection(&monitor_handles_cs);
1144 pm->refcount++;
1145 LeaveCriticalSection(&monitor_handles_cs);
1146 return pm;
1149 /* query the userinterface-dllname from the Portmonitor */
1150 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1151 /* building (",XcvMonitor %s",pm->name) not needed yet */
1152 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1153 TRACE("got %u with %p\n", res, hXcv);
1154 if (res) {
1155 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1156 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1157 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1158 pm->monitor->pfnXcvClosePort(hXcv);
1161 return pui;
1165 /******************************************************************
1166 * monitor_load_by_port [internal]
1168 * load a printmonitor for a given port
1170 * On failure, NULL is returned
1173 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1175 HKEY hroot;
1176 HKEY hport;
1177 LPWSTR buffer;
1178 monitor_t * pm = NULL;
1179 DWORD registered = 0;
1180 DWORD id = 0;
1181 DWORD len;
1183 TRACE("(%s)\n", debugstr_w(portname));
1185 /* Try the Local Monitor first */
1186 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1187 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1188 /* found the portname */
1189 RegCloseKey(hroot);
1190 return monitor_load(LocalPortW, NULL);
1192 RegCloseKey(hroot);
1195 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1196 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1197 if (buffer == NULL) return NULL;
1199 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1200 EnterCriticalSection(&monitor_handles_cs);
1201 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1203 while ((pm == NULL) && (id < registered)) {
1204 buffer[0] = '\0';
1205 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1206 TRACE("testing %s\n", debugstr_w(buffer));
1207 len = lstrlenW(buffer);
1208 lstrcatW(buffer, bs_Ports_bsW);
1209 lstrcatW(buffer, portname);
1210 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1211 RegCloseKey(hport);
1212 buffer[len] = '\0'; /* use only the Monitor-Name */
1213 pm = monitor_load(buffer, NULL);
1215 id++;
1217 LeaveCriticalSection(&monitor_handles_cs);
1218 RegCloseKey(hroot);
1220 HeapFree(GetProcessHeap(), 0, buffer);
1221 return pm;
1224 /******************************************************************
1225 * enumerate the local Ports from all loaded monitors (internal)
1227 * returns the needed size (in bytes) for pPorts
1228 * and *lpreturned is set to number of entries returned in pPorts
1231 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1233 monitor_t * pm;
1234 LPWSTR ptr;
1235 LPPORT_INFO_2W cache;
1236 LPPORT_INFO_2W out;
1237 LPBYTE pi_buffer = NULL;
1238 DWORD pi_allocated = 0;
1239 DWORD pi_needed;
1240 DWORD pi_index;
1241 DWORD pi_returned;
1242 DWORD res;
1243 DWORD outindex = 0;
1244 DWORD needed;
1245 DWORD numentries;
1246 DWORD entrysize;
1249 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1250 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1252 numentries = *lpreturned; /* this is 0, when we scan the registry */
1253 needed = entrysize * numentries;
1254 ptr = (LPWSTR) &pPorts[needed];
1256 numentries = 0;
1257 needed = 0;
1259 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1261 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1262 pi_needed = 0;
1263 pi_returned = 0;
1264 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1265 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1266 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1267 HeapFree(GetProcessHeap(), 0, pi_buffer);
1268 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1269 pi_allocated = (pi_buffer) ? pi_needed : 0;
1270 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1272 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1273 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1275 numentries += pi_returned;
1276 needed += pi_needed;
1278 /* fill the output-buffer (pPorts), if we have one */
1279 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1280 pi_index = 0;
1281 while (pi_returned > pi_index) {
1282 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1283 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1284 out->pPortName = ptr;
1285 lstrcpyW(ptr, cache->pPortName);
1286 ptr += (lstrlenW(ptr)+1);
1287 if (level > 1) {
1288 out->pMonitorName = ptr;
1289 lstrcpyW(ptr, cache->pMonitorName);
1290 ptr += (lstrlenW(ptr)+1);
1292 out->pDescription = ptr;
1293 lstrcpyW(ptr, cache->pDescription);
1294 ptr += (lstrlenW(ptr)+1);
1295 out->fPortType = cache->fPortType;
1296 out->Reserved = cache->Reserved;
1298 pi_index++;
1299 outindex++;
1304 /* the temporary portinfo-buffer is no longer needed */
1305 HeapFree(GetProcessHeap(), 0, pi_buffer);
1307 *lpreturned = numentries;
1308 TRACE("need %d byte for %d entries\n", needed, numentries);
1309 return needed;
1312 /******************************************************************
1313 * get_servername_from_name (internal)
1315 * for an external server, a copy of the serverpart from the full name is returned
1318 static LPWSTR get_servername_from_name(LPCWSTR name)
1320 LPWSTR server;
1321 LPWSTR ptr;
1322 WCHAR buffer[MAX_PATH];
1323 DWORD len;
1325 if (name == NULL) return NULL;
1326 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1328 server = strdupW(&name[2]); /* skip over both backslash */
1329 if (server == NULL) return NULL;
1331 /* strip '\' and the printername */
1332 ptr = strchrW(server, '\\');
1333 if (ptr) ptr[0] = '\0';
1335 TRACE("found %s\n", debugstr_w(server));
1337 len = sizeof(buffer)/sizeof(buffer[0]);
1338 if (GetComputerNameW(buffer, &len)) {
1339 if (lstrcmpW(buffer, server) == 0) {
1340 /* The requested Servername is our computername */
1341 HeapFree(GetProcessHeap(), 0, server);
1342 return NULL;
1345 return server;
1348 /******************************************************************
1349 * get_basename_from_name (internal)
1351 * skip over the serverpart from the full name
1354 static LPCWSTR get_basename_from_name(LPCWSTR name)
1356 if (name == NULL) return NULL;
1357 if ((name[0] == '\\') && (name[1] == '\\')) {
1358 /* skip over the servername and search for the following '\' */
1359 name = strchrW(&name[2], '\\');
1360 if ((name) && (name[1])) {
1361 /* found a separator ('\') followed by a name:
1362 skip over the separator and return the rest */
1363 name++;
1365 else
1367 /* no basename present (we found only a servername) */
1368 return NULL;
1371 return name;
1374 /******************************************************************
1375 * get_opened_printer_entry
1376 * Get the first place empty in the opened printer table
1378 * ToDo:
1379 * - pDefault is ignored
1381 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1383 UINT_PTR handle = nb_printer_handles, i;
1384 jobqueue_t *queue = NULL;
1385 opened_printer_t *printer = NULL;
1386 LPWSTR servername;
1387 LPCWSTR printername;
1388 HKEY hkeyPrinters;
1389 HKEY hkeyPrinter;
1390 DWORD len;
1392 servername = get_servername_from_name(name);
1393 if (servername) {
1394 FIXME("server %s not supported\n", debugstr_w(servername));
1395 HeapFree(GetProcessHeap(), 0, servername);
1396 SetLastError(ERROR_INVALID_PRINTER_NAME);
1397 return NULL;
1400 printername = get_basename_from_name(name);
1401 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1403 /* an empty printername is invalid */
1404 if (printername && (!printername[0])) {
1405 SetLastError(ERROR_INVALID_PARAMETER);
1406 return NULL;
1409 EnterCriticalSection(&printer_handles_cs);
1411 for (i = 0; i < nb_printer_handles; i++)
1413 if (!printer_handles[i])
1415 if(handle == nb_printer_handles)
1416 handle = i;
1418 else
1420 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1421 queue = printer_handles[i]->queue;
1425 if (handle >= nb_printer_handles)
1427 opened_printer_t **new_array;
1428 if (printer_handles)
1429 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1430 (nb_printer_handles + 16) * sizeof(*new_array) );
1431 else
1432 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1433 (nb_printer_handles + 16) * sizeof(*new_array) );
1435 if (!new_array)
1437 handle = 0;
1438 goto end;
1440 printer_handles = new_array;
1441 nb_printer_handles += 16;
1444 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1446 handle = 0;
1447 goto end;
1451 /* clone the base name. This is NULL for the printserver */
1452 printer->printername = strdupW(printername);
1454 /* clone the full name */
1455 printer->name = strdupW(name);
1456 if (name && (!printer->name)) {
1457 handle = 0;
1458 goto end;
1461 if (printername) {
1462 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1463 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1464 /* OpenPrinter(",XcvMonitor " detected */
1465 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1466 printer->pm = monitor_load(&printername[len], NULL);
1467 if (printer->pm == NULL) {
1468 SetLastError(ERROR_UNKNOWN_PORT);
1469 handle = 0;
1470 goto end;
1473 else
1475 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1476 if (strncmpW( printername, XcvPortW, len) == 0) {
1477 /* OpenPrinter(",XcvPort " detected */
1478 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1479 printer->pm = monitor_load_by_port(&printername[len]);
1480 if (printer->pm == NULL) {
1481 SetLastError(ERROR_UNKNOWN_PORT);
1482 handle = 0;
1483 goto end;
1488 if (printer->pm) {
1489 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1490 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1491 pDefault ? pDefault->DesiredAccess : 0,
1492 &printer->hXcv);
1494 if (printer->hXcv == NULL) {
1495 SetLastError(ERROR_INVALID_PARAMETER);
1496 handle = 0;
1497 goto end;
1500 else
1502 /* Does the Printer exist? */
1503 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1504 ERR("Can't create Printers key\n");
1505 handle = 0;
1506 goto end;
1508 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1509 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1510 RegCloseKey(hkeyPrinters);
1511 SetLastError(ERROR_INVALID_PRINTER_NAME);
1512 handle = 0;
1513 goto end;
1515 RegCloseKey(hkeyPrinter);
1516 RegCloseKey(hkeyPrinters);
1519 else
1521 TRACE("using the local printserver\n");
1524 if(queue)
1525 printer->queue = queue;
1526 else
1528 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1529 if (!printer->queue) {
1530 handle = 0;
1531 goto end;
1533 list_init(&printer->queue->jobs);
1534 printer->queue->ref = 0;
1536 InterlockedIncrement(&printer->queue->ref);
1538 printer_handles[handle] = printer;
1539 handle++;
1540 end:
1541 LeaveCriticalSection(&printer_handles_cs);
1542 if (!handle && printer) {
1543 /* Something failed: Free all resources */
1544 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1545 monitor_unload(printer->pm);
1546 HeapFree(GetProcessHeap(), 0, printer->printername);
1547 HeapFree(GetProcessHeap(), 0, printer->name);
1548 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1549 HeapFree(GetProcessHeap(), 0, printer);
1552 return (HANDLE)handle;
1555 /******************************************************************
1556 * get_opened_printer
1557 * Get the pointer to the opened printer referred by the handle
1559 static opened_printer_t *get_opened_printer(HANDLE hprn)
1561 UINT_PTR idx = (UINT_PTR)hprn;
1562 opened_printer_t *ret = NULL;
1564 EnterCriticalSection(&printer_handles_cs);
1566 if ((idx <= 0) || (idx > nb_printer_handles))
1567 goto end;
1569 ret = printer_handles[idx - 1];
1570 end:
1571 LeaveCriticalSection(&printer_handles_cs);
1572 return ret;
1575 /******************************************************************
1576 * get_opened_printer_name
1577 * Get the pointer to the opened printer name referred by the handle
1579 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1581 opened_printer_t *printer = get_opened_printer(hprn);
1582 if(!printer) return NULL;
1583 return printer->name;
1586 /******************************************************************
1587 * WINSPOOL_GetOpenedPrinterRegKey
1590 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1592 LPCWSTR name = get_opened_printer_name(hPrinter);
1593 DWORD ret;
1594 HKEY hkeyPrinters;
1596 if(!name) return ERROR_INVALID_HANDLE;
1598 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1599 ERROR_SUCCESS)
1600 return ret;
1602 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1604 ERR("Can't find opened printer %s in registry\n",
1605 debugstr_w(name));
1606 RegCloseKey(hkeyPrinters);
1607 return ERROR_INVALID_PRINTER_NAME; /* ? */
1609 RegCloseKey(hkeyPrinters);
1610 return ERROR_SUCCESS;
1613 void WINSPOOL_LoadSystemPrinters(void)
1615 HKEY hkey, hkeyPrinters;
1616 HANDLE hprn;
1617 DWORD needed, num, i;
1618 WCHAR PrinterName[256];
1619 BOOL done = FALSE;
1621 /* This ensures that all printer entries have a valid Name value. If causes
1622 problems later if they don't. If one is found to be missed we create one
1623 and set it equal to the name of the key */
1624 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1625 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1626 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1627 for(i = 0; i < num; i++) {
1628 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1629 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1630 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1631 set_reg_szW(hkey, NameW, PrinterName);
1633 RegCloseKey(hkey);
1638 RegCloseKey(hkeyPrinters);
1641 /* We want to avoid calling AddPrinter on printers as much as
1642 possible, because on cups printers this will (eventually) lead
1643 to a call to cupsGetPPD which takes forever, even with non-cups
1644 printers AddPrinter takes a while. So we'll tag all printers that
1645 were automatically added last time around, if they still exist
1646 we'll leave them be otherwise we'll delete them. */
1647 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1648 if(needed) {
1649 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1650 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1651 for(i = 0; i < num; i++) {
1652 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1653 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1654 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1655 DWORD dw = 1;
1656 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1657 RegCloseKey(hkey);
1659 ClosePrinter(hprn);
1664 HeapFree(GetProcessHeap(), 0, pi);
1668 #ifdef SONAME_LIBCUPS
1669 done = CUPS_LoadPrinters();
1670 #endif
1672 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1673 PRINTCAP_LoadPrinters();
1675 /* Now enumerate the list again and delete any printers that a still tagged */
1676 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1677 if(needed) {
1678 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1679 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1680 for(i = 0; i < num; i++) {
1681 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1682 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1683 BOOL delete_driver = FALSE;
1684 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1685 DWORD dw, type, size = sizeof(dw);
1686 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1687 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1688 DeletePrinter(hprn);
1689 delete_driver = TRUE;
1691 RegCloseKey(hkey);
1693 ClosePrinter(hprn);
1694 if(delete_driver)
1695 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1700 HeapFree(GetProcessHeap(), 0, pi);
1703 return;
1707 /******************************************************************
1708 * get_job
1710 * Get the pointer to the specified job.
1711 * Should hold the printer_handles_cs before calling.
1713 static job_t *get_job(HANDLE hprn, DWORD JobId)
1715 opened_printer_t *printer = get_opened_printer(hprn);
1716 job_t *job;
1718 if(!printer) return NULL;
1719 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1721 if(job->job_id == JobId)
1722 return job;
1724 return NULL;
1727 /***********************************************************
1728 * DEVMODEcpyAtoW
1730 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1732 BOOL Formname;
1733 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1734 DWORD size;
1736 Formname = (dmA->dmSize > off_formname);
1737 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1738 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1739 dmW->dmDeviceName, CCHDEVICENAME);
1740 if(!Formname) {
1741 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1742 dmA->dmSize - CCHDEVICENAME);
1743 } else {
1744 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1745 off_formname - CCHDEVICENAME);
1746 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1747 dmW->dmFormName, CCHFORMNAME);
1748 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1749 (off_formname + CCHFORMNAME));
1751 dmW->dmSize = size;
1752 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1753 dmA->dmDriverExtra);
1754 return dmW;
1757 /***********************************************************
1758 * DEVMODEdupWtoA
1759 * Creates an ascii copy of supplied devmode on heap
1761 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1763 LPDEVMODEA dmA;
1764 DWORD size;
1765 BOOL Formname;
1766 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1768 if(!dmW) return NULL;
1769 Formname = (dmW->dmSize > off_formname);
1770 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1771 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1772 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1773 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1774 if(!Formname) {
1775 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1776 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1777 } else {
1778 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1779 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1780 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1781 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1782 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1783 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1785 dmA->dmSize = size;
1786 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1787 dmW->dmDriverExtra);
1788 return dmA;
1791 /***********************************************************
1792 * PRINTER_INFO_2AtoW
1793 * Creates a unicode copy of PRINTER_INFO_2A on heap
1795 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1797 LPPRINTER_INFO_2W piW;
1798 UNICODE_STRING usBuffer;
1800 if(!piA) return NULL;
1801 piW = HeapAlloc(heap, 0, sizeof(*piW));
1802 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1804 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1805 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1806 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1807 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1808 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1809 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1810 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1811 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1812 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1813 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1814 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1815 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1816 return piW;
1819 /***********************************************************
1820 * FREE_PRINTER_INFO_2W
1821 * Free PRINTER_INFO_2W and all strings
1823 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1825 if(!piW) return;
1827 HeapFree(heap,0,piW->pServerName);
1828 HeapFree(heap,0,piW->pPrinterName);
1829 HeapFree(heap,0,piW->pShareName);
1830 HeapFree(heap,0,piW->pPortName);
1831 HeapFree(heap,0,piW->pDriverName);
1832 HeapFree(heap,0,piW->pComment);
1833 HeapFree(heap,0,piW->pLocation);
1834 HeapFree(heap,0,piW->pDevMode);
1835 HeapFree(heap,0,piW->pSepFile);
1836 HeapFree(heap,0,piW->pPrintProcessor);
1837 HeapFree(heap,0,piW->pDatatype);
1838 HeapFree(heap,0,piW->pParameters);
1839 HeapFree(heap,0,piW);
1840 return;
1843 /******************************************************************
1844 * DeviceCapabilities [WINSPOOL.@]
1845 * DeviceCapabilitiesA [WINSPOOL.@]
1848 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1849 LPSTR pOutput, LPDEVMODEA lpdm)
1851 INT ret;
1853 if (!GDI_CallDeviceCapabilities16)
1855 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1856 (LPCSTR)104 );
1857 if (!GDI_CallDeviceCapabilities16) return -1;
1859 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1861 /* If DC_PAPERSIZE map POINT16s to POINTs */
1862 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1863 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1864 POINT *pt = (POINT *)pOutput;
1865 INT i;
1866 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1867 for(i = 0; i < ret; i++, pt++)
1869 pt->x = tmp[i].x;
1870 pt->y = tmp[i].y;
1872 HeapFree( GetProcessHeap(), 0, tmp );
1874 return ret;
1878 /*****************************************************************************
1879 * DeviceCapabilitiesW [WINSPOOL.@]
1881 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1884 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1885 WORD fwCapability, LPWSTR pOutput,
1886 const DEVMODEW *pDevMode)
1888 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1889 LPSTR pDeviceA = strdupWtoA(pDevice);
1890 LPSTR pPortA = strdupWtoA(pPort);
1891 INT ret;
1893 if(pOutput && (fwCapability == DC_BINNAMES ||
1894 fwCapability == DC_FILEDEPENDENCIES ||
1895 fwCapability == DC_PAPERNAMES)) {
1896 /* These need A -> W translation */
1897 INT size = 0, i;
1898 LPSTR pOutputA;
1899 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1900 dmA);
1901 if(ret == -1)
1902 return ret;
1903 switch(fwCapability) {
1904 case DC_BINNAMES:
1905 size = 24;
1906 break;
1907 case DC_PAPERNAMES:
1908 case DC_FILEDEPENDENCIES:
1909 size = 64;
1910 break;
1912 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1913 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1914 dmA);
1915 for(i = 0; i < ret; i++)
1916 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1917 pOutput + (i * size), size);
1918 HeapFree(GetProcessHeap(), 0, pOutputA);
1919 } else {
1920 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1921 (LPSTR)pOutput, dmA);
1923 HeapFree(GetProcessHeap(),0,pPortA);
1924 HeapFree(GetProcessHeap(),0,pDeviceA);
1925 HeapFree(GetProcessHeap(),0,dmA);
1926 return ret;
1929 /******************************************************************
1930 * DocumentPropertiesA [WINSPOOL.@]
1932 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1934 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1935 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1936 LPDEVMODEA pDevModeInput,DWORD fMode )
1938 LPSTR lpName = pDeviceName;
1939 static CHAR port[] = "LPT1:";
1940 LONG ret;
1942 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1943 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1946 if(!pDeviceName) {
1947 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1948 if(!lpNameW) {
1949 ERR("no name from hPrinter?\n");
1950 SetLastError(ERROR_INVALID_HANDLE);
1951 return -1;
1953 lpName = strdupWtoA(lpNameW);
1956 if (!GDI_CallExtDeviceMode16)
1958 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1959 (LPCSTR)102 );
1960 if (!GDI_CallExtDeviceMode16) {
1961 ERR("No CallExtDeviceMode16?\n");
1962 return -1;
1965 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1966 pDevModeInput, NULL, fMode);
1968 if(!pDeviceName)
1969 HeapFree(GetProcessHeap(),0,lpName);
1970 return ret;
1974 /*****************************************************************************
1975 * DocumentPropertiesW (WINSPOOL.@)
1977 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1979 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1980 LPWSTR pDeviceName,
1981 LPDEVMODEW pDevModeOutput,
1982 LPDEVMODEW pDevModeInput, DWORD fMode)
1985 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1986 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1987 LPDEVMODEA pDevModeOutputA = NULL;
1988 LONG ret;
1990 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1991 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1992 fMode);
1993 if(pDevModeOutput) {
1994 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1995 if(ret < 0) return ret;
1996 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1998 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1999 pDevModeInputA, fMode);
2000 if(pDevModeOutput) {
2001 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2002 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2004 if(fMode == 0 && ret > 0)
2005 ret += (CCHDEVICENAME + CCHFORMNAME);
2006 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2007 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2008 return ret;
2011 /******************************************************************
2012 * OpenPrinterA [WINSPOOL.@]
2014 * See OpenPrinterW.
2017 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2018 LPPRINTER_DEFAULTSA pDefault)
2020 UNICODE_STRING lpPrinterNameW;
2021 UNICODE_STRING usBuffer;
2022 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2023 PWSTR pwstrPrinterNameW;
2024 BOOL ret;
2026 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2028 if(pDefault) {
2029 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2030 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2031 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2032 pDefaultW = &DefaultW;
2034 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2035 if(pDefault) {
2036 RtlFreeUnicodeString(&usBuffer);
2037 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2039 RtlFreeUnicodeString(&lpPrinterNameW);
2040 return ret;
2043 /******************************************************************
2044 * OpenPrinterW [WINSPOOL.@]
2046 * Open a Printer / Printserver or a Printer-Object
2048 * PARAMS
2049 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2050 * phPrinter [O] The resulting Handle is stored here
2051 * pDefault [I] PTR to Default Printer Settings or NULL
2053 * RETURNS
2054 * Success: TRUE
2055 * Failure: FALSE
2057 * NOTES
2058 * lpPrinterName is one of:
2059 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2060 *| Printer: "PrinterName"
2061 *| Printer-Object: "PrinterName,Job xxx"
2062 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2063 *| XcvPort: "Servername,XcvPort PortName"
2065 * BUGS
2066 *| Printer-Object not supported
2067 *| pDefaults is ignored
2070 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2073 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2074 if (pDefault) {
2075 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2076 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2079 if(!phPrinter) {
2080 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2081 SetLastError(ERROR_INVALID_PARAMETER);
2082 return FALSE;
2085 /* Get the unique handle of the printer or Printserver */
2086 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2087 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2088 return (*phPrinter != 0);
2091 /******************************************************************
2092 * AddMonitorA [WINSPOOL.@]
2094 * See AddMonitorW.
2097 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2099 LPWSTR nameW = NULL;
2100 INT len;
2101 BOOL res;
2102 LPMONITOR_INFO_2A mi2a;
2103 MONITOR_INFO_2W mi2w;
2105 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2106 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2107 mi2a ? debugstr_a(mi2a->pName) : NULL,
2108 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2109 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2111 if (Level != 2) {
2112 SetLastError(ERROR_INVALID_LEVEL);
2113 return FALSE;
2116 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2117 if (mi2a == NULL) {
2118 return FALSE;
2121 if (pName) {
2122 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2123 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2124 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2127 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2128 if (mi2a->pName) {
2129 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2130 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2131 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2133 if (mi2a->pEnvironment) {
2134 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2135 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2136 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2138 if (mi2a->pDLLName) {
2139 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2140 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2141 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2144 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2146 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2147 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2148 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2150 HeapFree(GetProcessHeap(), 0, nameW);
2151 return (res);
2154 /******************************************************************************
2155 * AddMonitorW [WINSPOOL.@]
2157 * Install a Printmonitor
2159 * PARAMS
2160 * pName [I] Servername or NULL (local Computer)
2161 * Level [I] Structure-Level (Must be 2)
2162 * pMonitors [I] PTR to MONITOR_INFO_2
2164 * RETURNS
2165 * Success: TRUE
2166 * Failure: FALSE
2168 * NOTES
2169 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2172 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2174 monitor_t * pm = NULL;
2175 LPMONITOR_INFO_2W mi2w;
2176 HKEY hroot = NULL;
2177 HKEY hentry = NULL;
2178 DWORD disposition;
2179 BOOL res = FALSE;
2181 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2182 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2183 mi2w ? debugstr_w(mi2w->pName) : NULL,
2184 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2185 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2187 if (Level != 2) {
2188 SetLastError(ERROR_INVALID_LEVEL);
2189 return FALSE;
2192 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2193 if (mi2w == NULL) {
2194 return FALSE;
2197 if (pName && (pName[0])) {
2198 FIXME("for server %s not implemented\n", debugstr_w(pName));
2199 SetLastError(ERROR_ACCESS_DENIED);
2200 return FALSE;
2204 if (!mi2w->pName || (! mi2w->pName[0])) {
2205 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2206 SetLastError(ERROR_INVALID_PARAMETER);
2207 return FALSE;
2209 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2210 WARN("Environment %s requested (we support only %s)\n",
2211 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2212 SetLastError(ERROR_INVALID_ENVIRONMENT);
2213 return FALSE;
2216 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2217 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2218 SetLastError(ERROR_INVALID_PARAMETER);
2219 return FALSE;
2222 /* Load and initialize the monitor. SetLastError() is called on failure */
2223 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2224 return FALSE;
2226 monitor_unload(pm);
2228 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2229 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2230 return FALSE;
2233 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2234 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2235 &disposition) == ERROR_SUCCESS) {
2237 /* Some installers set options for the port before calling AddMonitor.
2238 We query the "Driver" entry to verify that the monitor is installed,
2239 before we return an error.
2240 When a user installs two print monitors at the same time with the
2241 same name but with a different driver DLL and a task switch comes
2242 between RegQueryValueExW and RegSetValueExW, a race condition
2243 is possible but silently ignored. */
2245 DWORD namesize = 0;
2247 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2248 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2249 &namesize) == ERROR_SUCCESS)) {
2250 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2251 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2252 9x: ERROR_ALREADY_EXISTS (183) */
2253 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2255 else
2257 INT len;
2258 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2259 res = (RegSetValueExW(hentry, DriverW, 0,
2260 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2262 RegCloseKey(hentry);
2265 RegCloseKey(hroot);
2266 return (res);
2269 /******************************************************************
2270 * DeletePrinterDriverA [WINSPOOL.@]
2273 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2275 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2278 /******************************************************************
2279 * DeletePrinterDriverW [WINSPOOL.@]
2282 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2284 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2287 /******************************************************************
2288 * DeleteMonitorA [WINSPOOL.@]
2290 * See DeleteMonitorW.
2293 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2295 LPWSTR nameW = NULL;
2296 LPWSTR EnvironmentW = NULL;
2297 LPWSTR MonitorNameW = NULL;
2298 BOOL res;
2299 INT len;
2301 if (pName) {
2302 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2303 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2304 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2307 if (pEnvironment) {
2308 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2309 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2310 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2312 if (pMonitorName) {
2313 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2314 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2315 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2318 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2320 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2321 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2322 HeapFree(GetProcessHeap(), 0, nameW);
2323 return (res);
2326 /******************************************************************
2327 * DeleteMonitorW [WINSPOOL.@]
2329 * Delete a specific Printmonitor from a Printing-Environment
2331 * PARAMS
2332 * pName [I] Servername or NULL (local Computer)
2333 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2334 * pMonitorName [I] Name of the Monitor, that should be deleted
2336 * RETURNS
2337 * Success: TRUE
2338 * Failure: FALSE
2340 * NOTES
2341 * pEnvironment is ignored in Windows for the local Computer.
2345 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2347 HKEY hroot = NULL;
2349 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2350 debugstr_w(pMonitorName));
2352 if (pName && (pName[0])) {
2353 FIXME("for server %s not implemented\n", debugstr_w(pName));
2354 SetLastError(ERROR_ACCESS_DENIED);
2355 return FALSE;
2358 /* pEnvironment is ignored in Windows for the local Computer */
2360 if (!pMonitorName || !pMonitorName[0]) {
2361 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2362 SetLastError(ERROR_INVALID_PARAMETER);
2363 return FALSE;
2366 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2367 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2368 return FALSE;
2371 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2372 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2373 RegCloseKey(hroot);
2374 return TRUE;
2377 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2378 RegCloseKey(hroot);
2380 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2381 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2382 return (FALSE);
2385 /******************************************************************
2386 * DeletePortA [WINSPOOL.@]
2388 * See DeletePortW.
2391 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2393 LPWSTR nameW = NULL;
2394 LPWSTR portW = NULL;
2395 INT len;
2396 DWORD res;
2398 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2400 /* convert servername to unicode */
2401 if (pName) {
2402 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2403 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2404 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2407 /* convert portname to unicode */
2408 if (pPortName) {
2409 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2410 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2411 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2414 res = DeletePortW(nameW, hWnd, portW);
2415 HeapFree(GetProcessHeap(), 0, nameW);
2416 HeapFree(GetProcessHeap(), 0, portW);
2417 return res;
2420 /******************************************************************
2421 * DeletePortW [WINSPOOL.@]
2423 * Delete a specific Port
2425 * PARAMS
2426 * pName [I] Servername or NULL (local Computer)
2427 * hWnd [I] Handle to parent Window for the Dialog-Box
2428 * pPortName [I] Name of the Port, that should be deleted
2430 * RETURNS
2431 * Success: TRUE
2432 * Failure: FALSE
2435 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2437 monitor_t * pm;
2438 monitor_t * pui;
2439 DWORD res;
2441 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2443 if (pName && pName[0]) {
2444 SetLastError(ERROR_INVALID_PARAMETER);
2445 return FALSE;
2448 if (!pPortName) {
2449 SetLastError(RPC_X_NULL_REF_POINTER);
2450 return FALSE;
2453 /* an empty Portname is Invalid */
2454 if (!pPortName[0]) {
2455 SetLastError(ERROR_NOT_SUPPORTED);
2456 return FALSE;
2459 pm = monitor_load_by_port(pPortName);
2460 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2461 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2462 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2463 TRACE("got %d with %u\n", res, GetLastError());
2465 else
2467 pui = monitor_loadui(pm);
2468 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2469 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2470 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2471 TRACE("got %d with %u\n", res, GetLastError());
2473 else
2475 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2476 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2478 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2479 SetLastError(ERROR_NOT_SUPPORTED);
2480 res = FALSE;
2482 monitor_unload(pui);
2484 monitor_unload(pm);
2486 TRACE("returning %d with %u\n", res, GetLastError());
2487 return res;
2490 /******************************************************************************
2491 * SetPrinterW [WINSPOOL.@]
2493 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2495 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2496 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2497 return FALSE;
2500 /******************************************************************************
2501 * WritePrinter [WINSPOOL.@]
2503 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2505 opened_printer_t *printer;
2506 BOOL ret = FALSE;
2508 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2510 EnterCriticalSection(&printer_handles_cs);
2511 printer = get_opened_printer(hPrinter);
2512 if(!printer)
2514 SetLastError(ERROR_INVALID_HANDLE);
2515 goto end;
2518 if(!printer->doc)
2520 SetLastError(ERROR_SPL_NO_STARTDOC);
2521 goto end;
2524 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2525 end:
2526 LeaveCriticalSection(&printer_handles_cs);
2527 return ret;
2530 /*****************************************************************************
2531 * AddFormA [WINSPOOL.@]
2533 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2535 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2536 return 1;
2539 /*****************************************************************************
2540 * AddFormW [WINSPOOL.@]
2542 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2544 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2545 return 1;
2548 /*****************************************************************************
2549 * AddJobA [WINSPOOL.@]
2551 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2553 BOOL ret;
2554 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2555 DWORD needed;
2557 if(Level != 1) {
2558 SetLastError(ERROR_INVALID_LEVEL);
2559 return FALSE;
2562 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2564 if(ret) {
2565 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2566 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2567 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2568 if(*pcbNeeded > cbBuf) {
2569 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2570 ret = FALSE;
2571 } else {
2572 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2573 addjobA->JobId = addjobW->JobId;
2574 addjobA->Path = (char *)(addjobA + 1);
2575 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2578 return ret;
2581 /*****************************************************************************
2582 * AddJobW [WINSPOOL.@]
2584 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2586 opened_printer_t *printer;
2587 job_t *job;
2588 BOOL ret = FALSE;
2589 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2590 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2591 WCHAR path[MAX_PATH], filename[MAX_PATH];
2592 DWORD len;
2593 ADDJOB_INFO_1W *addjob;
2595 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2597 EnterCriticalSection(&printer_handles_cs);
2599 printer = get_opened_printer(hPrinter);
2601 if(!printer) {
2602 SetLastError(ERROR_INVALID_HANDLE);
2603 goto end;
2606 if(Level != 1) {
2607 SetLastError(ERROR_INVALID_LEVEL);
2608 goto end;
2611 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2612 if(!job)
2613 goto end;
2615 job->job_id = InterlockedIncrement(&next_job_id);
2617 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2618 if(path[len - 1] != '\\')
2619 path[len++] = '\\';
2620 memcpy(path + len, spool_path, sizeof(spool_path));
2621 sprintfW(filename, fmtW, path, job->job_id);
2623 len = strlenW(filename);
2624 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2625 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2626 job->document_title = strdupW(default_doc_title);
2627 list_add_tail(&printer->queue->jobs, &job->entry);
2629 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2630 if(*pcbNeeded <= cbBuf) {
2631 addjob = (ADDJOB_INFO_1W*)pData;
2632 addjob->JobId = job->job_id;
2633 addjob->Path = (WCHAR *)(addjob + 1);
2634 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2635 ret = TRUE;
2636 } else
2637 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2639 end:
2640 LeaveCriticalSection(&printer_handles_cs);
2641 return ret;
2644 /*****************************************************************************
2645 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2647 * Return the PATH for the Print-Processors
2649 * See GetPrintProcessorDirectoryW.
2653 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2654 DWORD level, LPBYTE Info,
2655 DWORD cbBuf, LPDWORD pcbNeeded)
2657 LPWSTR serverW = NULL;
2658 LPWSTR envW = NULL;
2659 BOOL ret;
2660 INT len;
2662 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2663 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2666 if (server) {
2667 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2668 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2669 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2672 if (env) {
2673 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2674 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2675 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2678 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2679 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2681 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2682 cbBuf, pcbNeeded);
2684 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2685 cbBuf, NULL, NULL) > 0;
2688 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2689 HeapFree(GetProcessHeap(), 0, envW);
2690 HeapFree(GetProcessHeap(), 0, serverW);
2691 return ret;
2694 /*****************************************************************************
2695 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2697 * Return the PATH for the Print-Processors
2699 * PARAMS
2700 * server [I] Servername (NT only) or NULL (local Computer)
2701 * env [I] Printing-Environment (see below) or NULL (Default)
2702 * level [I] Structure-Level (must be 1)
2703 * Info [O] PTR to Buffer that receives the Result
2704 * cbBuf [I] Size of Buffer at "Info"
2705 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2706 * required for the Buffer at "Info"
2708 * RETURNS
2709 * Success: TRUE and in pcbNeeded the Bytes used in Info
2710 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2711 * if cbBuf is too small
2713 * Native Values returned in Info on Success:
2714 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2715 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2716 *| win9x(Windows 4.0): "%winsysdir%"
2718 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2720 * BUGS
2721 * Only NULL or "" is supported for server
2724 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2725 DWORD level, LPBYTE Info,
2726 DWORD cbBuf, LPDWORD pcbNeeded)
2728 DWORD needed;
2729 const printenv_t * env_t;
2731 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2732 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2734 if(server != NULL && server[0]) {
2735 FIXME("server not supported: %s\n", debugstr_w(server));
2736 SetLastError(ERROR_INVALID_PARAMETER);
2737 return FALSE;
2740 env_t = validate_envW(env);
2741 if(!env_t) return FALSE; /* environment invalid or unsupported */
2743 if(level != 1) {
2744 WARN("(Level: %d) is ignored in win9x\n", level);
2745 SetLastError(ERROR_INVALID_LEVEL);
2746 return FALSE;
2749 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2750 needed = GetSystemDirectoryW(NULL, 0);
2751 /* add the Size for the Subdirectories */
2752 needed += lstrlenW(spoolprtprocsW);
2753 needed += lstrlenW(env_t->subdir);
2754 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2756 if(pcbNeeded) *pcbNeeded = needed;
2757 TRACE ("required: 0x%x/%d\n", needed, needed);
2758 if (needed > cbBuf) {
2759 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2760 return FALSE;
2762 if(pcbNeeded == NULL) {
2763 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2764 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2765 SetLastError(RPC_X_NULL_REF_POINTER);
2766 return FALSE;
2768 if(Info == NULL) {
2769 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2770 SetLastError(RPC_X_NULL_REF_POINTER);
2771 return FALSE;
2774 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2775 /* add the Subdirectories */
2776 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2777 lstrcatW((LPWSTR) Info, env_t->subdir);
2778 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2779 return TRUE;
2782 /*****************************************************************************
2783 * WINSPOOL_OpenDriverReg [internal]
2785 * opens the registry for the printer drivers depending on the given input
2786 * variable pEnvironment
2788 * RETURNS:
2789 * the opened hkey on success
2790 * NULL on error
2792 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2794 HKEY retval = NULL;
2795 LPWSTR buffer;
2796 const printenv_t * env;
2798 TRACE("(%s, %d)\n",
2799 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2801 if (!pEnvironment || unicode) {
2802 /* pEnvironment was NULL or an Unicode-String: use it direct */
2803 env = validate_envW(pEnvironment);
2805 else
2807 /* pEnvironment was an ANSI-String: convert to unicode first */
2808 LPWSTR buffer;
2809 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2810 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2811 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2812 env = validate_envW(buffer);
2813 HeapFree(GetProcessHeap(), 0, buffer);
2815 if (!env) return NULL;
2817 buffer = HeapAlloc( GetProcessHeap(), 0,
2818 (strlenW(DriversW) + strlenW(env->envname) +
2819 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2820 if(buffer) {
2821 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2822 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2823 HeapFree(GetProcessHeap(), 0, buffer);
2825 return retval;
2828 /*****************************************************************************
2829 * AddPrinterW [WINSPOOL.@]
2831 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2833 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2834 LPDEVMODEA dmA;
2835 LPDEVMODEW dmW;
2836 HANDLE retval;
2837 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2838 LONG size;
2839 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2840 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2841 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2842 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2843 statusW[] = {'S','t','a','t','u','s',0},
2844 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2846 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2848 if(pName != NULL) {
2849 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2850 SetLastError(ERROR_INVALID_PARAMETER);
2851 return 0;
2853 if(Level != 2) {
2854 ERR("Level = %d, unsupported!\n", Level);
2855 SetLastError(ERROR_INVALID_LEVEL);
2856 return 0;
2858 if(!pPrinter) {
2859 SetLastError(ERROR_INVALID_PARAMETER);
2860 return 0;
2862 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2863 ERROR_SUCCESS) {
2864 ERR("Can't create Printers key\n");
2865 return 0;
2867 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2868 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2869 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2870 RegCloseKey(hkeyPrinter);
2871 RegCloseKey(hkeyPrinters);
2872 return 0;
2874 RegCloseKey(hkeyPrinter);
2876 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2877 if(!hkeyDrivers) {
2878 ERR("Can't create Drivers key\n");
2879 RegCloseKey(hkeyPrinters);
2880 return 0;
2882 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2883 ERROR_SUCCESS) {
2884 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2885 RegCloseKey(hkeyPrinters);
2886 RegCloseKey(hkeyDrivers);
2887 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2888 return 0;
2890 RegCloseKey(hkeyDriver);
2891 RegCloseKey(hkeyDrivers);
2893 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2894 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2895 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2896 RegCloseKey(hkeyPrinters);
2897 return 0;
2900 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2901 ERROR_SUCCESS) {
2902 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2903 SetLastError(ERROR_INVALID_PRINTER_NAME);
2904 RegCloseKey(hkeyPrinters);
2905 return 0;
2907 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2908 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2909 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2911 /* See if we can load the driver. We may need the devmode structure anyway
2913 * FIXME:
2914 * Note that DocumentPropertiesW will briefly try to open the printer we
2915 * just create to find a DEVMODEA struct (it will use the WINEPS default
2916 * one in case it is not there, so we are ok).
2918 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2920 if(size < 0) {
2921 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2922 size = sizeof(DEVMODEW);
2924 if(pi->pDevMode)
2925 dmW = pi->pDevMode;
2926 else
2928 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2929 dmW->dmSize = size;
2930 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2932 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2933 HeapFree(GetProcessHeap(),0,dmW);
2934 dmW=NULL;
2936 else
2938 /* set devmode to printer name */
2939 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2943 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2944 and we support these drivers. NT writes DEVMODEW so somehow
2945 we'll need to distinguish between these when we support NT
2946 drivers */
2947 if (dmW)
2949 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2950 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2951 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2952 HeapFree(GetProcessHeap(), 0, dmA);
2953 if(!pi->pDevMode)
2954 HeapFree(GetProcessHeap(), 0, dmW);
2956 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2957 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2958 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2959 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2961 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2962 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2963 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2964 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2965 (LPBYTE)&pi->Priority, sizeof(DWORD));
2966 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2967 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2968 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2969 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2970 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2971 (LPBYTE)&pi->Status, sizeof(DWORD));
2972 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2973 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2975 RegCloseKey(hkeyPrinter);
2976 RegCloseKey(hkeyPrinters);
2977 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2978 ERR("OpenPrinter failing\n");
2979 return 0;
2981 return retval;
2984 /*****************************************************************************
2985 * AddPrinterA [WINSPOOL.@]
2987 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2989 UNICODE_STRING pNameW;
2990 PWSTR pwstrNameW;
2991 PRINTER_INFO_2W *piW;
2992 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2993 HANDLE ret;
2995 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2996 if(Level != 2) {
2997 ERR("Level = %d, unsupported!\n", Level);
2998 SetLastError(ERROR_INVALID_LEVEL);
2999 return 0;
3001 pwstrNameW = asciitounicode(&pNameW,pName);
3002 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3004 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3006 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3007 RtlFreeUnicodeString(&pNameW);
3008 return ret;
3012 /*****************************************************************************
3013 * ClosePrinter [WINSPOOL.@]
3015 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3017 UINT_PTR i = (UINT_PTR)hPrinter;
3018 opened_printer_t *printer = NULL;
3019 BOOL ret = FALSE;
3021 TRACE("(%p)\n", hPrinter);
3023 EnterCriticalSection(&printer_handles_cs);
3025 if ((i > 0) && (i <= nb_printer_handles))
3026 printer = printer_handles[i - 1];
3029 if(printer)
3031 struct list *cursor, *cursor2;
3033 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3034 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3035 printer->hXcv, debugstr_w(printer->name), printer->doc );
3037 if(printer->doc)
3038 EndDocPrinter(hPrinter);
3040 if(InterlockedDecrement(&printer->queue->ref) == 0)
3042 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3044 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3045 ScheduleJob(hPrinter, job->job_id);
3047 HeapFree(GetProcessHeap(), 0, printer->queue);
3049 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3050 monitor_unload(printer->pm);
3051 HeapFree(GetProcessHeap(), 0, printer->printername);
3052 HeapFree(GetProcessHeap(), 0, printer->name);
3053 HeapFree(GetProcessHeap(), 0, printer);
3054 printer_handles[i - 1] = NULL;
3055 ret = TRUE;
3057 LeaveCriticalSection(&printer_handles_cs);
3058 return ret;
3061 /*****************************************************************************
3062 * DeleteFormA [WINSPOOL.@]
3064 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3066 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3067 return 1;
3070 /*****************************************************************************
3071 * DeleteFormW [WINSPOOL.@]
3073 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3075 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3076 return 1;
3079 /*****************************************************************************
3080 * DeletePrinter [WINSPOOL.@]
3082 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3084 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3085 HKEY hkeyPrinters, hkey;
3087 if(!lpNameW) {
3088 SetLastError(ERROR_INVALID_HANDLE);
3089 return FALSE;
3091 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3092 RegDeleteTreeW(hkeyPrinters, lpNameW);
3093 RegCloseKey(hkeyPrinters);
3095 WriteProfileStringW(devicesW, lpNameW, NULL);
3096 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3097 RegDeleteValueW(hkey, lpNameW);
3098 RegCloseKey(hkey);
3100 return TRUE;
3103 /*****************************************************************************
3104 * SetPrinterA [WINSPOOL.@]
3106 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3107 DWORD Command)
3109 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3110 return FALSE;
3113 /*****************************************************************************
3114 * SetJobA [WINSPOOL.@]
3116 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3117 LPBYTE pJob, DWORD Command)
3119 BOOL ret;
3120 LPBYTE JobW;
3121 UNICODE_STRING usBuffer;
3123 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3125 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3126 are all ignored by SetJob, so we don't bother copying them */
3127 switch(Level)
3129 case 0:
3130 JobW = NULL;
3131 break;
3132 case 1:
3134 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3135 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3137 JobW = (LPBYTE)info1W;
3138 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3139 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3140 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3141 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3142 info1W->Status = info1A->Status;
3143 info1W->Priority = info1A->Priority;
3144 info1W->Position = info1A->Position;
3145 info1W->PagesPrinted = info1A->PagesPrinted;
3146 break;
3148 case 2:
3150 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3151 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3153 JobW = (LPBYTE)info2W;
3154 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3155 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3156 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3157 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3158 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3159 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3160 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3161 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3162 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3163 info2W->Status = info2A->Status;
3164 info2W->Priority = info2A->Priority;
3165 info2W->Position = info2A->Position;
3166 info2W->StartTime = info2A->StartTime;
3167 info2W->UntilTime = info2A->UntilTime;
3168 info2W->PagesPrinted = info2A->PagesPrinted;
3169 break;
3171 case 3:
3172 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3173 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3174 break;
3175 default:
3176 SetLastError(ERROR_INVALID_LEVEL);
3177 return FALSE;
3180 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3182 switch(Level)
3184 case 1:
3186 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3187 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3188 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3189 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3190 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3191 break;
3193 case 2:
3195 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3196 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3197 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3198 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3199 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3200 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3201 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3202 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3203 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3204 break;
3207 HeapFree(GetProcessHeap(), 0, JobW);
3209 return ret;
3212 /*****************************************************************************
3213 * SetJobW [WINSPOOL.@]
3215 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3216 LPBYTE pJob, DWORD Command)
3218 BOOL ret = FALSE;
3219 job_t *job;
3221 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3222 FIXME("Ignoring everything other than document title\n");
3224 EnterCriticalSection(&printer_handles_cs);
3225 job = get_job(hPrinter, JobId);
3226 if(!job)
3227 goto end;
3229 switch(Level)
3231 case 0:
3232 break;
3233 case 1:
3235 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3236 HeapFree(GetProcessHeap(), 0, job->document_title);
3237 job->document_title = strdupW(info1->pDocument);
3238 break;
3240 case 2:
3242 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3243 HeapFree(GetProcessHeap(), 0, job->document_title);
3244 job->document_title = strdupW(info2->pDocument);
3245 break;
3247 case 3:
3248 break;
3249 default:
3250 SetLastError(ERROR_INVALID_LEVEL);
3251 goto end;
3253 ret = TRUE;
3254 end:
3255 LeaveCriticalSection(&printer_handles_cs);
3256 return ret;
3259 /*****************************************************************************
3260 * EndDocPrinter [WINSPOOL.@]
3262 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3264 opened_printer_t *printer;
3265 BOOL ret = FALSE;
3266 TRACE("(%p)\n", hPrinter);
3268 EnterCriticalSection(&printer_handles_cs);
3270 printer = get_opened_printer(hPrinter);
3271 if(!printer)
3273 SetLastError(ERROR_INVALID_HANDLE);
3274 goto end;
3277 if(!printer->doc)
3279 SetLastError(ERROR_SPL_NO_STARTDOC);
3280 goto end;
3283 CloseHandle(printer->doc->hf);
3284 ScheduleJob(hPrinter, printer->doc->job_id);
3285 HeapFree(GetProcessHeap(), 0, printer->doc);
3286 printer->doc = NULL;
3287 ret = TRUE;
3288 end:
3289 LeaveCriticalSection(&printer_handles_cs);
3290 return ret;
3293 /*****************************************************************************
3294 * EndPagePrinter [WINSPOOL.@]
3296 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3298 FIXME("(%p): stub\n", hPrinter);
3299 return TRUE;
3302 /*****************************************************************************
3303 * StartDocPrinterA [WINSPOOL.@]
3305 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3307 UNICODE_STRING usBuffer;
3308 DOC_INFO_2W doc2W;
3309 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3310 DWORD ret;
3312 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3313 or one (DOC_INFO_3) extra DWORDs */
3315 switch(Level) {
3316 case 2:
3317 doc2W.JobId = doc2->JobId;
3318 /* fall through */
3319 case 3:
3320 doc2W.dwMode = doc2->dwMode;
3321 /* fall through */
3322 case 1:
3323 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3324 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3325 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3326 break;
3328 default:
3329 SetLastError(ERROR_INVALID_LEVEL);
3330 return FALSE;
3333 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3335 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3336 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3337 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3339 return ret;
3342 /*****************************************************************************
3343 * StartDocPrinterW [WINSPOOL.@]
3345 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3347 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3348 opened_printer_t *printer;
3349 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3350 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3351 JOB_INFO_1W job_info;
3352 DWORD needed, ret = 0;
3353 HANDLE hf;
3354 WCHAR *filename;
3356 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3357 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3358 debugstr_w(doc->pDatatype));
3360 if(Level < 1 || Level > 3)
3362 SetLastError(ERROR_INVALID_LEVEL);
3363 return 0;
3366 EnterCriticalSection(&printer_handles_cs);
3367 printer = get_opened_printer(hPrinter);
3368 if(!printer)
3370 SetLastError(ERROR_INVALID_HANDLE);
3371 goto end;
3374 if(printer->doc)
3376 SetLastError(ERROR_INVALID_PRINTER_STATE);
3377 goto end;
3380 /* Even if we're printing to a file we still add a print job, we'll
3381 just ignore the spool file name */
3383 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3385 ERR("AddJob failed gle %u\n", GetLastError());
3386 goto end;
3389 if(doc->pOutputFile)
3390 filename = doc->pOutputFile;
3391 else
3392 filename = addjob->Path;
3394 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3395 if(hf == INVALID_HANDLE_VALUE)
3396 goto end;
3398 memset(&job_info, 0, sizeof(job_info));
3399 job_info.pDocument = doc->pDocName;
3400 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3402 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3403 printer->doc->hf = hf;
3404 ret = printer->doc->job_id = addjob->JobId;
3405 end:
3406 LeaveCriticalSection(&printer_handles_cs);
3408 return ret;
3411 /*****************************************************************************
3412 * StartPagePrinter [WINSPOOL.@]
3414 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3416 FIXME("(%p): stub\n", hPrinter);
3417 return TRUE;
3420 /*****************************************************************************
3421 * GetFormA [WINSPOOL.@]
3423 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3424 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3426 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3427 Level,pForm,cbBuf,pcbNeeded);
3428 return FALSE;
3431 /*****************************************************************************
3432 * GetFormW [WINSPOOL.@]
3434 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3435 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3437 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3438 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3439 return FALSE;
3442 /*****************************************************************************
3443 * SetFormA [WINSPOOL.@]
3445 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3446 LPBYTE pForm)
3448 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3449 return FALSE;
3452 /*****************************************************************************
3453 * SetFormW [WINSPOOL.@]
3455 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3456 LPBYTE pForm)
3458 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3459 return FALSE;
3462 /*****************************************************************************
3463 * ReadPrinter [WINSPOOL.@]
3465 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3466 LPDWORD pNoBytesRead)
3468 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3469 return FALSE;
3472 /*****************************************************************************
3473 * ResetPrinterA [WINSPOOL.@]
3475 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3477 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3478 return FALSE;
3481 /*****************************************************************************
3482 * ResetPrinterW [WINSPOOL.@]
3484 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3486 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3487 return FALSE;
3490 /*****************************************************************************
3491 * WINSPOOL_GetDWORDFromReg
3493 * Return DWORD associated with ValueName from hkey.
3495 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3497 DWORD sz = sizeof(DWORD), type, value = 0;
3498 LONG ret;
3500 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3502 if(ret != ERROR_SUCCESS) {
3503 WARN("Got ret = %d on name %s\n", ret, ValueName);
3504 return 0;
3506 if(type != REG_DWORD) {
3507 ERR("Got type %d\n", type);
3508 return 0;
3510 return value;
3514 /*****************************************************************************
3515 * get_filename_from_reg [internal]
3517 * Get ValueName from hkey storing result in out
3518 * when the Value in the registry has only a filename, use driverdir as prefix
3519 * outlen is space left in out
3520 * String is stored either as unicode or ascii
3524 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3525 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3527 WCHAR filename[MAX_PATH];
3528 DWORD size;
3529 DWORD type;
3530 LONG ret;
3531 LPWSTR buffer = filename;
3532 LPWSTR ptr;
3534 *needed = 0;
3535 size = sizeof(filename);
3536 buffer[0] = '\0';
3537 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3538 if (ret == ERROR_MORE_DATA) {
3539 TRACE("need dynamic buffer: %u\n", size);
3540 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3541 if (!buffer) {
3542 /* No Memory is bad */
3543 return FALSE;
3545 buffer[0] = '\0';
3546 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3549 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3550 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3551 return FALSE;
3554 ptr = buffer;
3555 while (ptr) {
3556 /* do we have a full path ? */
3557 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3558 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3560 if (!ret) {
3561 /* we must build the full Path */
3562 *needed += dirlen;
3563 if ((out) && (outlen > dirlen)) {
3564 if (unicode) {
3565 lstrcpyW((LPWSTR)out, driverdir);
3567 else
3569 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3571 out += dirlen;
3572 outlen -= dirlen;
3574 else
3575 out = NULL;
3578 /* write the filename */
3579 if (unicode) {
3580 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3581 if ((out) && (outlen >= size)) {
3582 lstrcpyW((LPWSTR)out, ptr);
3583 out += size;
3584 outlen -= size;
3586 else
3587 out = NULL;
3589 else
3591 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3592 if ((out) && (outlen >= size)) {
3593 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3594 out += size;
3595 outlen -= size;
3597 else
3598 out = NULL;
3600 *needed += size;
3601 ptr += lstrlenW(ptr)+1;
3602 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3605 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3607 /* write the multisz-termination */
3608 if (type == REG_MULTI_SZ) {
3609 size = (unicode) ? sizeof(WCHAR) : 1;
3611 *needed += size;
3612 if (out && (outlen >= size)) {
3613 memset (out, 0, size);
3616 return TRUE;
3619 /*****************************************************************************
3620 * WINSPOOL_GetStringFromReg
3622 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3623 * String is stored either as unicode or ascii.
3624 * Bit of a hack here to get the ValueName if we want ascii.
3626 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3627 DWORD buflen, DWORD *needed,
3628 BOOL unicode)
3630 DWORD sz = buflen, type;
3631 LONG ret;
3633 if(unicode)
3634 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3635 else {
3636 LPSTR ValueNameA = strdupWtoA(ValueName);
3637 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3638 HeapFree(GetProcessHeap(),0,ValueNameA);
3640 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3641 WARN("Got ret = %d\n", ret);
3642 *needed = 0;
3643 return FALSE;
3645 /* add space for terminating '\0' */
3646 sz += unicode ? sizeof(WCHAR) : 1;
3647 *needed = sz;
3649 if (ptr)
3650 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3652 return TRUE;
3655 /*****************************************************************************
3656 * WINSPOOL_GetDefaultDevMode
3658 * Get a default DevMode values for wineps.
3659 * FIXME - use ppd.
3662 static void WINSPOOL_GetDefaultDevMode(
3663 LPBYTE ptr,
3664 DWORD buflen, DWORD *needed,
3665 BOOL unicode)
3667 DEVMODEA dm;
3668 static const char szwps[] = "wineps.drv";
3670 /* fill default DEVMODE - should be read from ppd... */
3671 ZeroMemory( &dm, sizeof(dm) );
3672 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3673 dm.dmSpecVersion = DM_SPECVERSION;
3674 dm.dmDriverVersion = 1;
3675 dm.dmSize = sizeof(DEVMODEA);
3676 dm.dmDriverExtra = 0;
3677 dm.dmFields =
3678 DM_ORIENTATION | DM_PAPERSIZE |
3679 DM_PAPERLENGTH | DM_PAPERWIDTH |
3680 DM_SCALE |
3681 DM_COPIES |
3682 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3683 DM_YRESOLUTION | DM_TTOPTION;
3685 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3686 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3687 dm.u1.s1.dmPaperLength = 2970;
3688 dm.u1.s1.dmPaperWidth = 2100;
3690 dm.dmScale = 100;
3691 dm.dmCopies = 1;
3692 dm.dmDefaultSource = DMBIN_AUTO;
3693 dm.dmPrintQuality = DMRES_MEDIUM;
3694 /* dm.dmColor */
3695 /* dm.dmDuplex */
3696 dm.dmYResolution = 300; /* 300dpi */
3697 dm.dmTTOption = DMTT_BITMAP;
3698 /* dm.dmCollate */
3699 /* dm.dmFormName */
3700 /* dm.dmLogPixels */
3701 /* dm.dmBitsPerPel */
3702 /* dm.dmPelsWidth */
3703 /* dm.dmPelsHeight */
3704 /* dm.dmDisplayFlags */
3705 /* dm.dmDisplayFrequency */
3706 /* dm.dmICMMethod */
3707 /* dm.dmICMIntent */
3708 /* dm.dmMediaType */
3709 /* dm.dmDitherType */
3710 /* dm.dmReserved1 */
3711 /* dm.dmReserved2 */
3712 /* dm.dmPanningWidth */
3713 /* dm.dmPanningHeight */
3715 if(unicode) {
3716 if(buflen >= sizeof(DEVMODEW)) {
3717 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3718 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3719 HeapFree(GetProcessHeap(),0,pdmW);
3721 *needed = sizeof(DEVMODEW);
3723 else
3725 if(buflen >= sizeof(DEVMODEA)) {
3726 memcpy(ptr, &dm, sizeof(DEVMODEA));
3728 *needed = sizeof(DEVMODEA);
3732 /*****************************************************************************
3733 * WINSPOOL_GetDevModeFromReg
3735 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3736 * DevMode is stored either as unicode or ascii.
3738 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3739 LPBYTE ptr,
3740 DWORD buflen, DWORD *needed,
3741 BOOL unicode)
3743 DWORD sz = buflen, type;
3744 LONG ret;
3746 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3747 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3748 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3749 if (sz < sizeof(DEVMODEA))
3751 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3752 return FALSE;
3754 /* ensures that dmSize is not erratically bogus if registry is invalid */
3755 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3756 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3757 if(unicode) {
3758 sz += (CCHDEVICENAME + CCHFORMNAME);
3759 if(buflen >= sz) {
3760 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3761 memcpy(ptr, dmW, sz);
3762 HeapFree(GetProcessHeap(),0,dmW);
3765 *needed = sz;
3766 return TRUE;
3769 /*********************************************************************
3770 * WINSPOOL_GetPrinter_1
3772 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3773 * The strings are either stored as unicode or ascii.
3775 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3776 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3777 BOOL unicode)
3779 DWORD size, left = cbBuf;
3780 BOOL space = (cbBuf > 0);
3781 LPBYTE ptr = buf;
3783 *pcbNeeded = 0;
3785 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3786 unicode)) {
3787 if(space && size <= left) {
3788 pi1->pName = (LPWSTR)ptr;
3789 ptr += size;
3790 left -= size;
3791 } else
3792 space = FALSE;
3793 *pcbNeeded += size;
3796 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3797 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3798 unicode)) {
3799 if(space && size <= left) {
3800 pi1->pDescription = (LPWSTR)ptr;
3801 ptr += size;
3802 left -= size;
3803 } else
3804 space = FALSE;
3805 *pcbNeeded += size;
3808 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3809 unicode)) {
3810 if(space && size <= left) {
3811 pi1->pComment = (LPWSTR)ptr;
3812 ptr += size;
3813 left -= size;
3814 } else
3815 space = FALSE;
3816 *pcbNeeded += size;
3819 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3821 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3822 memset(pi1, 0, sizeof(*pi1));
3824 return space;
3826 /*********************************************************************
3827 * WINSPOOL_GetPrinter_2
3829 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3830 * The strings are either stored as unicode or ascii.
3832 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3833 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3834 BOOL unicode)
3836 DWORD size, left = cbBuf;
3837 BOOL space = (cbBuf > 0);
3838 LPBYTE ptr = buf;
3840 *pcbNeeded = 0;
3842 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3843 unicode)) {
3844 if(space && size <= left) {
3845 pi2->pPrinterName = (LPWSTR)ptr;
3846 ptr += size;
3847 left -= size;
3848 } else
3849 space = FALSE;
3850 *pcbNeeded += size;
3852 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3853 unicode)) {
3854 if(space && size <= left) {
3855 pi2->pShareName = (LPWSTR)ptr;
3856 ptr += size;
3857 left -= size;
3858 } else
3859 space = FALSE;
3860 *pcbNeeded += size;
3862 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3863 unicode)) {
3864 if(space && size <= left) {
3865 pi2->pPortName = (LPWSTR)ptr;
3866 ptr += size;
3867 left -= size;
3868 } else
3869 space = FALSE;
3870 *pcbNeeded += size;
3872 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3873 &size, unicode)) {
3874 if(space && size <= left) {
3875 pi2->pDriverName = (LPWSTR)ptr;
3876 ptr += size;
3877 left -= size;
3878 } else
3879 space = FALSE;
3880 *pcbNeeded += size;
3882 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3883 unicode)) {
3884 if(space && size <= left) {
3885 pi2->pComment = (LPWSTR)ptr;
3886 ptr += size;
3887 left -= size;
3888 } else
3889 space = FALSE;
3890 *pcbNeeded += size;
3892 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3893 unicode)) {
3894 if(space && size <= left) {
3895 pi2->pLocation = (LPWSTR)ptr;
3896 ptr += size;
3897 left -= size;
3898 } else
3899 space = FALSE;
3900 *pcbNeeded += size;
3902 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3903 &size, unicode)) {
3904 if(space && size <= left) {
3905 pi2->pDevMode = (LPDEVMODEW)ptr;
3906 ptr += size;
3907 left -= size;
3908 } else
3909 space = FALSE;
3910 *pcbNeeded += size;
3912 else
3914 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3915 if(space && size <= left) {
3916 pi2->pDevMode = (LPDEVMODEW)ptr;
3917 ptr += size;
3918 left -= size;
3919 } else
3920 space = FALSE;
3921 *pcbNeeded += size;
3923 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3924 &size, unicode)) {
3925 if(space && size <= left) {
3926 pi2->pSepFile = (LPWSTR)ptr;
3927 ptr += size;
3928 left -= size;
3929 } else
3930 space = FALSE;
3931 *pcbNeeded += size;
3933 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3934 &size, unicode)) {
3935 if(space && size <= left) {
3936 pi2->pPrintProcessor = (LPWSTR)ptr;
3937 ptr += size;
3938 left -= size;
3939 } else
3940 space = FALSE;
3941 *pcbNeeded += size;
3943 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3944 &size, unicode)) {
3945 if(space && size <= left) {
3946 pi2->pDatatype = (LPWSTR)ptr;
3947 ptr += size;
3948 left -= size;
3949 } else
3950 space = FALSE;
3951 *pcbNeeded += size;
3953 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3954 &size, unicode)) {
3955 if(space && size <= left) {
3956 pi2->pParameters = (LPWSTR)ptr;
3957 ptr += size;
3958 left -= size;
3959 } else
3960 space = FALSE;
3961 *pcbNeeded += size;
3963 if(pi2) {
3964 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3965 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3966 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3967 "Default Priority");
3968 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3969 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3972 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3973 memset(pi2, 0, sizeof(*pi2));
3975 return space;
3978 /*********************************************************************
3979 * WINSPOOL_GetPrinter_4
3981 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3983 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3984 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3985 BOOL unicode)
3987 DWORD size, left = cbBuf;
3988 BOOL space = (cbBuf > 0);
3989 LPBYTE ptr = buf;
3991 *pcbNeeded = 0;
3993 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3994 unicode)) {
3995 if(space && size <= left) {
3996 pi4->pPrinterName = (LPWSTR)ptr;
3997 ptr += size;
3998 left -= size;
3999 } else
4000 space = FALSE;
4001 *pcbNeeded += size;
4003 if(pi4) {
4004 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4007 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4008 memset(pi4, 0, sizeof(*pi4));
4010 return space;
4013 /*********************************************************************
4014 * WINSPOOL_GetPrinter_5
4016 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4018 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4019 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4020 BOOL unicode)
4022 DWORD size, left = cbBuf;
4023 BOOL space = (cbBuf > 0);
4024 LPBYTE ptr = buf;
4026 *pcbNeeded = 0;
4028 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4029 unicode)) {
4030 if(space && size <= left) {
4031 pi5->pPrinterName = (LPWSTR)ptr;
4032 ptr += size;
4033 left -= size;
4034 } else
4035 space = FALSE;
4036 *pcbNeeded += size;
4038 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4039 unicode)) {
4040 if(space && size <= left) {
4041 pi5->pPortName = (LPWSTR)ptr;
4042 ptr += size;
4043 left -= size;
4044 } else
4045 space = FALSE;
4046 *pcbNeeded += size;
4048 if(pi5) {
4049 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4050 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4051 "dnsTimeout");
4052 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4053 "txTimeout");
4056 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4057 memset(pi5, 0, sizeof(*pi5));
4059 return space;
4062 /*****************************************************************************
4063 * WINSPOOL_GetPrinter
4065 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4066 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4067 * just a collection of pointers to strings.
4069 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4070 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4072 LPCWSTR name;
4073 DWORD size, needed = 0;
4074 LPBYTE ptr = NULL;
4075 HKEY hkeyPrinter, hkeyPrinters;
4076 BOOL ret;
4078 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4080 if (!(name = get_opened_printer_name(hPrinter))) {
4081 SetLastError(ERROR_INVALID_HANDLE);
4082 return FALSE;
4085 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4086 ERROR_SUCCESS) {
4087 ERR("Can't create Printers key\n");
4088 return FALSE;
4090 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4092 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4093 RegCloseKey(hkeyPrinters);
4094 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4095 return FALSE;
4098 switch(Level) {
4099 case 2:
4101 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4103 size = sizeof(PRINTER_INFO_2W);
4104 if(size <= cbBuf) {
4105 ptr = pPrinter + size;
4106 cbBuf -= size;
4107 memset(pPrinter, 0, size);
4108 } else {
4109 pi2 = NULL;
4110 cbBuf = 0;
4112 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4113 unicode);
4114 needed += size;
4115 break;
4118 case 4:
4120 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4122 size = sizeof(PRINTER_INFO_4W);
4123 if(size <= cbBuf) {
4124 ptr = pPrinter + size;
4125 cbBuf -= size;
4126 memset(pPrinter, 0, size);
4127 } else {
4128 pi4 = NULL;
4129 cbBuf = 0;
4131 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4132 unicode);
4133 needed += size;
4134 break;
4138 case 5:
4140 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4142 size = sizeof(PRINTER_INFO_5W);
4143 if(size <= cbBuf) {
4144 ptr = pPrinter + size;
4145 cbBuf -= size;
4146 memset(pPrinter, 0, size);
4147 } else {
4148 pi5 = NULL;
4149 cbBuf = 0;
4152 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4153 unicode);
4154 needed += size;
4155 break;
4158 default:
4159 FIXME("Unimplemented level %d\n", Level);
4160 SetLastError(ERROR_INVALID_LEVEL);
4161 RegCloseKey(hkeyPrinters);
4162 RegCloseKey(hkeyPrinter);
4163 return FALSE;
4166 RegCloseKey(hkeyPrinter);
4167 RegCloseKey(hkeyPrinters);
4169 TRACE("returning %d needed = %d\n", ret, needed);
4170 if(pcbNeeded) *pcbNeeded = needed;
4171 if(!ret)
4172 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4173 return ret;
4176 /*****************************************************************************
4177 * GetPrinterW [WINSPOOL.@]
4179 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4180 DWORD cbBuf, LPDWORD pcbNeeded)
4182 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4183 TRUE);
4186 /*****************************************************************************
4187 * GetPrinterA [WINSPOOL.@]
4189 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4190 DWORD cbBuf, LPDWORD pcbNeeded)
4192 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4193 FALSE);
4196 /*****************************************************************************
4197 * WINSPOOL_EnumPrinters
4199 * Implementation of EnumPrintersA|W
4201 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4202 DWORD dwLevel, LPBYTE lpbPrinters,
4203 DWORD cbBuf, LPDWORD lpdwNeeded,
4204 LPDWORD lpdwReturned, BOOL unicode)
4207 HKEY hkeyPrinters, hkeyPrinter;
4208 WCHAR PrinterName[255];
4209 DWORD needed = 0, number = 0;
4210 DWORD used, i, left;
4211 PBYTE pi, buf;
4213 if(lpbPrinters)
4214 memset(lpbPrinters, 0, cbBuf);
4215 if(lpdwReturned)
4216 *lpdwReturned = 0;
4217 if(lpdwNeeded)
4218 *lpdwNeeded = 0;
4220 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4221 if(dwType == PRINTER_ENUM_DEFAULT)
4222 return TRUE;
4224 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4225 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4226 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4227 if (!dwType) {
4228 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4229 *lpdwNeeded = 0;
4230 *lpdwReturned = 0;
4231 return TRUE;
4236 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4237 FIXME("dwType = %08x\n", dwType);
4238 SetLastError(ERROR_INVALID_FLAGS);
4239 return FALSE;
4242 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4243 ERROR_SUCCESS) {
4244 ERR("Can't create Printers key\n");
4245 return FALSE;
4248 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4249 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4250 RegCloseKey(hkeyPrinters);
4251 ERR("Can't query Printers key\n");
4252 return FALSE;
4254 TRACE("Found %d printers\n", number);
4256 switch(dwLevel) {
4257 case 1:
4258 used = number * sizeof(PRINTER_INFO_1W);
4259 break;
4260 case 2:
4261 used = number * sizeof(PRINTER_INFO_2W);
4262 break;
4263 case 4:
4264 used = number * sizeof(PRINTER_INFO_4W);
4265 break;
4266 case 5:
4267 used = number * sizeof(PRINTER_INFO_5W);
4268 break;
4270 default:
4271 SetLastError(ERROR_INVALID_LEVEL);
4272 RegCloseKey(hkeyPrinters);
4273 return FALSE;
4275 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4277 for(i = 0; i < number; i++) {
4278 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4279 ERROR_SUCCESS) {
4280 ERR("Can't enum key number %d\n", i);
4281 RegCloseKey(hkeyPrinters);
4282 return FALSE;
4284 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4285 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4286 ERROR_SUCCESS) {
4287 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4288 RegCloseKey(hkeyPrinters);
4289 return FALSE;
4292 if(cbBuf > used) {
4293 buf = lpbPrinters + used;
4294 left = cbBuf - used;
4295 } else {
4296 buf = NULL;
4297 left = 0;
4300 switch(dwLevel) {
4301 case 1:
4302 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4303 left, &needed, unicode);
4304 used += needed;
4305 if(pi) pi += sizeof(PRINTER_INFO_1W);
4306 break;
4307 case 2:
4308 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4309 left, &needed, unicode);
4310 used += needed;
4311 if(pi) pi += sizeof(PRINTER_INFO_2W);
4312 break;
4313 case 4:
4314 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4315 left, &needed, unicode);
4316 used += needed;
4317 if(pi) pi += sizeof(PRINTER_INFO_4W);
4318 break;
4319 case 5:
4320 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4321 left, &needed, unicode);
4322 used += needed;
4323 if(pi) pi += sizeof(PRINTER_INFO_5W);
4324 break;
4325 default:
4326 ERR("Shouldn't be here!\n");
4327 RegCloseKey(hkeyPrinter);
4328 RegCloseKey(hkeyPrinters);
4329 return FALSE;
4331 RegCloseKey(hkeyPrinter);
4333 RegCloseKey(hkeyPrinters);
4335 if(lpdwNeeded)
4336 *lpdwNeeded = used;
4338 if(used > cbBuf) {
4339 if(lpbPrinters)
4340 memset(lpbPrinters, 0, cbBuf);
4341 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4342 return FALSE;
4344 if(lpdwReturned)
4345 *lpdwReturned = number;
4346 SetLastError(ERROR_SUCCESS);
4347 return TRUE;
4351 /******************************************************************
4352 * EnumPrintersW [WINSPOOL.@]
4354 * Enumerates the available printers, print servers and print
4355 * providers, depending on the specified flags, name and level.
4357 * RETURNS:
4359 * If level is set to 1:
4360 * Returns an array of PRINTER_INFO_1 data structures in the
4361 * lpbPrinters buffer.
4363 * If level is set to 2:
4364 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4365 * Returns an array of PRINTER_INFO_2 data structures in the
4366 * lpbPrinters buffer. Note that according to MSDN also an
4367 * OpenPrinter should be performed on every remote printer.
4369 * If level is set to 4 (officially WinNT only):
4370 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4371 * Fast: Only the registry is queried to retrieve printer names,
4372 * no connection to the driver is made.
4373 * Returns an array of PRINTER_INFO_4 data structures in the
4374 * lpbPrinters buffer.
4376 * If level is set to 5 (officially WinNT4/Win9x only):
4377 * Fast: Only the registry is queried to retrieve printer names,
4378 * no connection to the driver is made.
4379 * Returns an array of PRINTER_INFO_5 data structures in the
4380 * lpbPrinters buffer.
4382 * If level set to 3 or 6+:
4383 * returns zero (failure!)
4385 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4386 * for information.
4388 * BUGS:
4389 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4390 * - Only levels 2, 4 and 5 are implemented at the moment.
4391 * - 16-bit printer drivers are not enumerated.
4392 * - Returned amount of bytes used/needed does not match the real Windoze
4393 * implementation (as in this implementation, all strings are part
4394 * of the buffer, whereas Win32 keeps them somewhere else)
4395 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4397 * NOTE:
4398 * - In a regular Wine installation, no registry settings for printers
4399 * exist, which makes this function return an empty list.
4401 BOOL WINAPI EnumPrintersW(
4402 DWORD dwType, /* [in] Types of print objects to enumerate */
4403 LPWSTR lpszName, /* [in] name of objects to enumerate */
4404 DWORD dwLevel, /* [in] type of printer info structure */
4405 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4406 DWORD cbBuf, /* [in] max size of buffer in bytes */
4407 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4408 LPDWORD lpdwReturned /* [out] number of entries returned */
4411 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4412 lpdwNeeded, lpdwReturned, TRUE);
4415 /******************************************************************
4416 * EnumPrintersA [WINSPOOL.@]
4419 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4420 DWORD dwLevel, LPBYTE lpbPrinters,
4421 DWORD cbBuf, LPDWORD lpdwNeeded,
4422 LPDWORD lpdwReturned)
4424 BOOL ret, unicode = FALSE;
4425 UNICODE_STRING lpszNameW;
4426 PWSTR pwstrNameW;
4428 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4429 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4430 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4431 lpdwNeeded, lpdwReturned, unicode);
4432 RtlFreeUnicodeString(&lpszNameW);
4433 return ret;
4436 /*****************************************************************************
4437 * WINSPOOL_GetDriverInfoFromReg [internal]
4439 * Enters the information from the registry into the DRIVER_INFO struct
4441 * RETURNS
4442 * zero if the printer driver does not exist in the registry
4443 * (only if Level > 1) otherwise nonzero
4445 static BOOL WINSPOOL_GetDriverInfoFromReg(
4446 HKEY hkeyDrivers,
4447 LPWSTR DriverName,
4448 const printenv_t * env,
4449 DWORD Level,
4450 LPBYTE ptr, /* DRIVER_INFO */
4451 LPBYTE pDriverStrings, /* strings buffer */
4452 DWORD cbBuf, /* size of string buffer */
4453 LPDWORD pcbNeeded, /* space needed for str. */
4454 BOOL unicode) /* type of strings */
4456 DWORD size, tmp;
4457 HKEY hkeyDriver;
4458 WCHAR driverdir[MAX_PATH];
4459 DWORD dirlen;
4460 LPBYTE strPtr = pDriverStrings;
4461 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4463 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4464 debugstr_w(DriverName), env,
4465 Level, di, pDriverStrings, cbBuf, unicode);
4467 if (di) ZeroMemory(di, di_sizeof[Level]);
4469 if (unicode) {
4470 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4471 if (*pcbNeeded <= cbBuf)
4472 strcpyW((LPWSTR)strPtr, DriverName);
4474 else
4476 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4477 if (*pcbNeeded <= cbBuf)
4478 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4481 /* pName for level 1 has a different offset! */
4482 if (Level == 1) {
4483 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4484 return TRUE;
4487 /* .cVersion and .pName for level > 1 */
4488 if (di) {
4489 di->cVersion = env->driverversion;
4490 di->pName = (LPWSTR) strPtr;
4491 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4494 /* Reserve Space for the largest subdir and a Backslash*/
4495 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4496 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4497 /* Should never Fail */
4498 return FALSE;
4500 lstrcatW(driverdir, env->versionsubdir);
4501 lstrcatW(driverdir, backslashW);
4503 /* dirlen must not include the terminating zero */
4504 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4505 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4507 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4508 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4509 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4510 return FALSE;
4513 /* pEnvironment */
4514 if (unicode)
4515 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4516 else
4517 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4519 *pcbNeeded += size;
4520 if (*pcbNeeded <= cbBuf) {
4521 if (unicode) {
4522 lstrcpyW((LPWSTR)strPtr, env->envname);
4524 else
4526 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4528 if (di) di->pEnvironment = (LPWSTR)strPtr;
4529 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4532 /* .pDriverPath is the Graphics rendering engine.
4533 The full Path is required to avoid a crash in some apps */
4534 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4535 *pcbNeeded += size;
4536 if (*pcbNeeded <= cbBuf)
4537 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4539 if (di) di->pDriverPath = (LPWSTR)strPtr;
4540 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4543 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4544 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4545 *pcbNeeded += size;
4546 if (*pcbNeeded <= cbBuf)
4547 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4549 if (di) di->pDataFile = (LPWSTR)strPtr;
4550 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4553 /* .pConfigFile is the Driver user Interface */
4554 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4555 *pcbNeeded += size;
4556 if (*pcbNeeded <= cbBuf)
4557 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4559 if (di) di->pConfigFile = (LPWSTR)strPtr;
4560 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4563 if (Level == 2 ) {
4564 RegCloseKey(hkeyDriver);
4565 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4566 return TRUE;
4569 if (Level == 5 ) {
4570 RegCloseKey(hkeyDriver);
4571 FIXME("level 5: incomplete\n");
4572 return TRUE;
4575 /* .pHelpFile */
4576 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4577 *pcbNeeded += size;
4578 if (*pcbNeeded <= cbBuf)
4579 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4581 if (di) di->pHelpFile = (LPWSTR)strPtr;
4582 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4585 /* .pDependentFiles */
4586 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4587 *pcbNeeded += size;
4588 if (*pcbNeeded <= cbBuf)
4589 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4591 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4592 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4595 /* .pMonitorName is the optional Language Monitor */
4596 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4597 *pcbNeeded += size;
4598 if (*pcbNeeded <= cbBuf)
4599 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4601 if (di) di->pMonitorName = (LPWSTR)strPtr;
4602 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4605 /* .pDefaultDataType */
4606 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4607 *pcbNeeded += size;
4608 if(*pcbNeeded <= cbBuf)
4609 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4611 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4612 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4615 if (Level == 3 ) {
4616 RegCloseKey(hkeyDriver);
4617 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4618 return TRUE;
4621 /* .pszzPreviousNames */
4622 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4623 *pcbNeeded += size;
4624 if(*pcbNeeded <= cbBuf)
4625 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4627 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4628 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4631 if (Level == 4 ) {
4632 RegCloseKey(hkeyDriver);
4633 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4634 return TRUE;
4637 /* support is missing, but not important enough for a FIXME */
4638 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4640 /* .pszMfgName */
4641 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4642 *pcbNeeded += size;
4643 if(*pcbNeeded <= cbBuf)
4644 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4646 if (di) di->pszMfgName = (LPWSTR)strPtr;
4647 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4650 /* .pszOEMUrl */
4651 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4652 *pcbNeeded += size;
4653 if(*pcbNeeded <= cbBuf)
4654 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4656 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4657 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4660 /* .pszHardwareID */
4661 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4662 *pcbNeeded += size;
4663 if(*pcbNeeded <= cbBuf)
4664 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4666 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4667 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4670 /* .pszProvider */
4671 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4672 *pcbNeeded += size;
4673 if(*pcbNeeded <= cbBuf)
4674 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4676 if (di) di->pszProvider = (LPWSTR)strPtr;
4677 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4680 if (Level == 6 ) {
4681 RegCloseKey(hkeyDriver);
4682 return TRUE;
4685 /* support is missing, but not important enough for a FIXME */
4686 TRACE("level 8: incomplete\n");
4688 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4689 RegCloseKey(hkeyDriver);
4690 return TRUE;
4693 /*****************************************************************************
4694 * WINSPOOL_GetPrinterDriver
4696 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4697 DWORD Level, LPBYTE pDriverInfo,
4698 DWORD cbBuf, LPDWORD pcbNeeded,
4699 BOOL unicode)
4701 LPCWSTR name;
4702 WCHAR DriverName[100];
4703 DWORD ret, type, size, needed = 0;
4704 LPBYTE ptr = NULL;
4705 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4706 const printenv_t * env;
4708 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4709 Level,pDriverInfo,cbBuf, pcbNeeded);
4712 if (!(name = get_opened_printer_name(hPrinter))) {
4713 SetLastError(ERROR_INVALID_HANDLE);
4714 return FALSE;
4717 if (Level < 1 || Level == 7 || Level > 8) {
4718 SetLastError(ERROR_INVALID_LEVEL);
4719 return FALSE;
4722 env = validate_envW(pEnvironment);
4723 if (!env) return FALSE; /* SetLastError() is in validate_envW */
4725 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4726 ERROR_SUCCESS) {
4727 ERR("Can't create Printers key\n");
4728 return FALSE;
4730 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4731 != ERROR_SUCCESS) {
4732 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4733 RegCloseKey(hkeyPrinters);
4734 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4735 return FALSE;
4737 size = sizeof(DriverName);
4738 DriverName[0] = 0;
4739 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4740 (LPBYTE)DriverName, &size);
4741 RegCloseKey(hkeyPrinter);
4742 RegCloseKey(hkeyPrinters);
4743 if(ret != ERROR_SUCCESS) {
4744 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4745 return FALSE;
4748 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4749 if(!hkeyDrivers) {
4750 ERR("Can't create Drivers key\n");
4751 return FALSE;
4754 size = di_sizeof[Level];
4755 if ((size <= cbBuf) && pDriverInfo)
4756 ptr = pDriverInfo + size;
4758 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4759 env, Level, pDriverInfo, ptr,
4760 (cbBuf < size) ? 0 : cbBuf - size,
4761 &needed, unicode)) {
4762 RegCloseKey(hkeyDrivers);
4763 return FALSE;
4766 RegCloseKey(hkeyDrivers);
4768 if(pcbNeeded) *pcbNeeded = size + needed;
4769 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4770 if(cbBuf >= needed) return TRUE;
4771 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4772 return FALSE;
4775 /*****************************************************************************
4776 * GetPrinterDriverA [WINSPOOL.@]
4778 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4779 DWORD Level, LPBYTE pDriverInfo,
4780 DWORD cbBuf, LPDWORD pcbNeeded)
4782 BOOL ret;
4783 UNICODE_STRING pEnvW;
4784 PWSTR pwstrEnvW;
4786 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4787 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4788 cbBuf, pcbNeeded, FALSE);
4789 RtlFreeUnicodeString(&pEnvW);
4790 return ret;
4792 /*****************************************************************************
4793 * GetPrinterDriverW [WINSPOOL.@]
4795 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4796 DWORD Level, LPBYTE pDriverInfo,
4797 DWORD cbBuf, LPDWORD pcbNeeded)
4799 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4800 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4803 /*****************************************************************************
4804 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4806 * Return the PATH for the Printer-Drivers (UNICODE)
4808 * PARAMS
4809 * pName [I] Servername (NT only) or NULL (local Computer)
4810 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4811 * Level [I] Structure-Level (must be 1)
4812 * pDriverDirectory [O] PTR to Buffer that receives the Result
4813 * cbBuf [I] Size of Buffer at pDriverDirectory
4814 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4815 * required for pDriverDirectory
4817 * RETURNS
4818 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4819 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4820 * if cbBuf is too small
4822 * Native Values returned in pDriverDirectory on Success:
4823 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4824 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4825 *| win9x(Windows 4.0): "%winsysdir%"
4827 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4829 * FIXME
4830 *- Only NULL or "" is supported for pName
4833 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4834 DWORD Level, LPBYTE pDriverDirectory,
4835 DWORD cbBuf, LPDWORD pcbNeeded)
4837 DWORD needed;
4838 const printenv_t * env;
4840 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4841 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4842 if(pName != NULL && pName[0]) {
4843 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4844 SetLastError(ERROR_INVALID_PARAMETER);
4845 return FALSE;
4848 env = validate_envW(pEnvironment);
4849 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4851 if(Level != 1) {
4852 WARN("(Level: %d) is ignored in win9x\n", Level);
4853 SetLastError(ERROR_INVALID_LEVEL);
4854 return FALSE;
4857 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4858 needed = GetSystemDirectoryW(NULL, 0);
4859 /* add the Size for the Subdirectories */
4860 needed += lstrlenW(spooldriversW);
4861 needed += lstrlenW(env->subdir);
4862 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4864 if(pcbNeeded)
4865 *pcbNeeded = needed;
4866 TRACE("required: 0x%x/%d\n", needed, needed);
4867 if(needed > cbBuf) {
4868 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4869 return FALSE;
4871 if(pcbNeeded == NULL) {
4872 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4873 SetLastError(RPC_X_NULL_REF_POINTER);
4874 return FALSE;
4876 if(pDriverDirectory == NULL) {
4877 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4878 SetLastError(ERROR_INVALID_USER_BUFFER);
4879 return FALSE;
4882 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4883 /* add the Subdirectories */
4884 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4885 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4886 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4887 return TRUE;
4891 /*****************************************************************************
4892 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4894 * Return the PATH for the Printer-Drivers (ANSI)
4896 * See GetPrinterDriverDirectoryW.
4898 * NOTES
4899 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4902 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4903 DWORD Level, LPBYTE pDriverDirectory,
4904 DWORD cbBuf, LPDWORD pcbNeeded)
4906 UNICODE_STRING nameW, environmentW;
4907 BOOL ret;
4908 DWORD pcbNeededW;
4909 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4910 WCHAR *driverDirectoryW = NULL;
4912 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4913 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4915 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4917 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4918 else nameW.Buffer = NULL;
4919 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4920 else environmentW.Buffer = NULL;
4922 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4923 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4924 if (ret) {
4925 DWORD needed;
4926 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4927 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4928 if(pcbNeeded)
4929 *pcbNeeded = needed;
4930 ret = (needed <= cbBuf) ? TRUE : FALSE;
4931 } else
4932 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4934 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4936 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4937 RtlFreeUnicodeString(&environmentW);
4938 RtlFreeUnicodeString(&nameW);
4940 return ret;
4943 /*****************************************************************************
4944 * AddPrinterDriverA [WINSPOOL.@]
4946 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4948 DRIVER_INFO_3A di3;
4949 HKEY hkeyDrivers, hkeyName;
4950 static CHAR empty[] = "",
4951 nullnull[] = "\0";
4953 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4955 if(level != 2 && level != 3) {
4956 SetLastError(ERROR_INVALID_LEVEL);
4957 return FALSE;
4959 if ((pName) && (pName[0])) {
4960 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4961 SetLastError(ERROR_INVALID_PARAMETER);
4962 return FALSE;
4964 if(!pDriverInfo) {
4965 WARN("pDriverInfo == NULL\n");
4966 SetLastError(ERROR_INVALID_PARAMETER);
4967 return FALSE;
4970 if(level == 3)
4971 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4972 else {
4973 memset(&di3, 0, sizeof(di3));
4974 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4977 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4978 !di3.pDataFile) {
4979 SetLastError(ERROR_INVALID_PARAMETER);
4980 return FALSE;
4983 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4984 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4985 if(!di3.pHelpFile) di3.pHelpFile = empty;
4986 if(!di3.pMonitorName) di3.pMonitorName = empty;
4988 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4990 if(!hkeyDrivers) {
4991 ERR("Can't create Drivers key\n");
4992 return FALSE;
4995 if(level == 2) { /* apparently can't overwrite with level2 */
4996 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4997 RegCloseKey(hkeyName);
4998 RegCloseKey(hkeyDrivers);
4999 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
5000 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
5001 return FALSE;
5004 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
5005 RegCloseKey(hkeyDrivers);
5006 ERR("Can't create Name key\n");
5007 return FALSE;
5009 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
5010 lstrlenA(di3.pConfigFile) + 1);
5011 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
5012 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
5013 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
5014 sizeof(DWORD));
5015 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
5016 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
5017 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
5018 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
5019 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
5020 RegCloseKey(hkeyName);
5021 RegCloseKey(hkeyDrivers);
5023 return TRUE;
5026 /*****************************************************************************
5027 * AddPrinterDriverW [WINSPOOL.@]
5029 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
5030 LPBYTE pDriverInfo)
5032 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
5033 level,pDriverInfo);
5034 return FALSE;
5037 /*****************************************************************************
5038 * AddPrintProcessorA [WINSPOOL.@]
5040 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5041 LPSTR pPrintProcessorName)
5043 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5044 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5045 return FALSE;
5048 /*****************************************************************************
5049 * AddPrintProcessorW [WINSPOOL.@]
5051 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5052 LPWSTR pPrintProcessorName)
5054 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5055 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5056 return FALSE;
5059 /*****************************************************************************
5060 * AddPrintProvidorA [WINSPOOL.@]
5062 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5064 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5065 return FALSE;
5068 /*****************************************************************************
5069 * AddPrintProvidorW [WINSPOOL.@]
5071 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5073 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5074 return FALSE;
5077 /*****************************************************************************
5078 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5080 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5081 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5083 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5084 pDevModeOutput, pDevModeInput);
5085 return 0;
5088 /*****************************************************************************
5089 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5091 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5092 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5094 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5095 pDevModeOutput, pDevModeInput);
5096 return 0;
5099 /*****************************************************************************
5100 * PrinterProperties [WINSPOOL.@]
5102 * Displays a dialog to set the properties of the printer.
5104 * RETURNS
5105 * nonzero on success or zero on failure
5107 * BUGS
5108 * implemented as stub only
5110 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5111 HANDLE hPrinter /* [in] handle to printer object */
5113 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5114 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5115 return FALSE;
5118 /*****************************************************************************
5119 * EnumJobsA [WINSPOOL.@]
5122 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5123 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5124 LPDWORD pcReturned)
5126 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5127 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5129 if(pcbNeeded) *pcbNeeded = 0;
5130 if(pcReturned) *pcReturned = 0;
5131 return FALSE;
5135 /*****************************************************************************
5136 * EnumJobsW [WINSPOOL.@]
5139 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5140 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5141 LPDWORD pcReturned)
5143 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5144 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5146 if(pcbNeeded) *pcbNeeded = 0;
5147 if(pcReturned) *pcReturned = 0;
5148 return FALSE;
5151 /*****************************************************************************
5152 * WINSPOOL_EnumPrinterDrivers [internal]
5154 * Delivers information about all printer drivers installed on the
5155 * localhost or a given server
5157 * RETURNS
5158 * nonzero on success or zero on failure. If the buffer for the returned
5159 * information is too small the function will return an error
5161 * BUGS
5162 * - only implemented for localhost, foreign hosts will return an error
5164 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5165 DWORD Level, LPBYTE pDriverInfo,
5166 DWORD cbBuf, LPDWORD pcbNeeded,
5167 LPDWORD pcReturned, BOOL unicode)
5169 { HKEY hkeyDrivers;
5170 DWORD i, needed, number = 0, size = 0;
5171 WCHAR DriverNameW[255];
5172 PBYTE ptr;
5173 const printenv_t * env;
5175 TRACE("%s,%s,%d,%p,%d,%d\n",
5176 debugstr_w(pName), debugstr_w(pEnvironment),
5177 Level, pDriverInfo, cbBuf, unicode);
5179 /* check for local drivers */
5180 if((pName) && (pName[0])) {
5181 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5182 SetLastError(ERROR_ACCESS_DENIED);
5183 return FALSE;
5186 env = validate_envW(pEnvironment);
5187 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5189 /* check input parameter */
5190 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5191 SetLastError(ERROR_INVALID_LEVEL);
5192 return FALSE;
5195 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5196 SetLastError(RPC_X_NULL_REF_POINTER);
5197 return FALSE;
5200 /* initialize return values */
5201 if(pDriverInfo)
5202 memset( pDriverInfo, 0, cbBuf);
5203 *pcbNeeded = 0;
5204 *pcReturned = 0;
5206 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5207 if(!hkeyDrivers) {
5208 ERR("Can't open Drivers key\n");
5209 return FALSE;
5212 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5213 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5214 RegCloseKey(hkeyDrivers);
5215 ERR("Can't query Drivers key\n");
5216 return FALSE;
5218 TRACE("Found %d Drivers\n", number);
5220 /* get size of single struct
5221 * unicode and ascii structure have the same size
5223 size = di_sizeof[Level];
5225 /* calculate required buffer size */
5226 *pcbNeeded = size * number;
5228 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5229 i < number;
5230 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5231 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
5232 != ERROR_SUCCESS) {
5233 ERR("Can't enum key number %d\n", i);
5234 RegCloseKey(hkeyDrivers);
5235 return FALSE;
5237 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5238 env, Level, ptr,
5239 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5240 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5241 &needed, unicode)) {
5242 RegCloseKey(hkeyDrivers);
5243 return FALSE;
5245 (*pcbNeeded) += needed;
5248 RegCloseKey(hkeyDrivers);
5250 if(cbBuf < *pcbNeeded){
5251 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5252 return FALSE;
5255 *pcReturned = number;
5256 return TRUE;
5259 /*****************************************************************************
5260 * EnumPrinterDriversW [WINSPOOL.@]
5262 * see function EnumPrinterDrivers for RETURNS, BUGS
5264 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5265 LPBYTE pDriverInfo, DWORD cbBuf,
5266 LPDWORD pcbNeeded, LPDWORD pcReturned)
5268 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5269 cbBuf, pcbNeeded, pcReturned, TRUE);
5272 /*****************************************************************************
5273 * EnumPrinterDriversA [WINSPOOL.@]
5275 * see function EnumPrinterDrivers for RETURNS, BUGS
5277 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5278 LPBYTE pDriverInfo, DWORD cbBuf,
5279 LPDWORD pcbNeeded, LPDWORD pcReturned)
5280 { BOOL ret;
5281 UNICODE_STRING pNameW, pEnvironmentW;
5282 PWSTR pwstrNameW, pwstrEnvironmentW;
5284 pwstrNameW = asciitounicode(&pNameW, pName);
5285 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5287 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5288 Level, pDriverInfo, cbBuf, pcbNeeded,
5289 pcReturned, FALSE);
5290 RtlFreeUnicodeString(&pNameW);
5291 RtlFreeUnicodeString(&pEnvironmentW);
5293 return ret;
5296 /******************************************************************************
5297 * EnumPortsA (WINSPOOL.@)
5299 * See EnumPortsW.
5302 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5303 LPDWORD pcbNeeded, LPDWORD pcReturned)
5305 BOOL res;
5306 LPBYTE bufferW = NULL;
5307 LPWSTR nameW = NULL;
5308 DWORD needed = 0;
5309 DWORD numentries = 0;
5310 INT len;
5312 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5313 cbBuf, pcbNeeded, pcReturned);
5315 /* convert servername to unicode */
5316 if (pName) {
5317 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5318 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5319 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5321 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5322 needed = cbBuf * sizeof(WCHAR);
5323 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5324 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5326 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5327 if (pcbNeeded) needed = *pcbNeeded;
5328 /* HeapReAlloc return NULL, when bufferW was NULL */
5329 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5330 HeapAlloc(GetProcessHeap(), 0, needed);
5332 /* Try again with the large Buffer */
5333 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5335 needed = pcbNeeded ? *pcbNeeded : 0;
5336 numentries = pcReturned ? *pcReturned : 0;
5339 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5340 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5342 if (res) {
5343 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5344 DWORD entrysize = 0;
5345 DWORD index;
5346 LPSTR ptr;
5347 LPPORT_INFO_2W pi2w;
5348 LPPORT_INFO_2A pi2a;
5350 needed = 0;
5351 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5353 /* First pass: calculate the size for all Entries */
5354 pi2w = (LPPORT_INFO_2W) bufferW;
5355 pi2a = (LPPORT_INFO_2A) pPorts;
5356 index = 0;
5357 while (index < numentries) {
5358 index++;
5359 needed += entrysize; /* PORT_INFO_?A */
5360 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5362 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5363 NULL, 0, NULL, NULL);
5364 if (Level > 1) {
5365 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5366 NULL, 0, NULL, NULL);
5367 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5368 NULL, 0, NULL, NULL);
5370 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5371 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5372 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5375 /* check for errors and quit on failure */
5376 if (cbBuf < needed) {
5377 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5378 res = FALSE;
5379 goto cleanup;
5381 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5382 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5383 cbBuf -= len ; /* free Bytes in the user-Buffer */
5384 pi2w = (LPPORT_INFO_2W) bufferW;
5385 pi2a = (LPPORT_INFO_2A) pPorts;
5386 index = 0;
5387 /* Second Pass: Fill the User Buffer (if we have one) */
5388 while ((index < numentries) && pPorts) {
5389 index++;
5390 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5391 pi2a->pPortName = ptr;
5392 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5393 ptr, cbBuf , NULL, NULL);
5394 ptr += len;
5395 cbBuf -= len;
5396 if (Level > 1) {
5397 pi2a->pMonitorName = ptr;
5398 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5399 ptr, cbBuf, NULL, NULL);
5400 ptr += len;
5401 cbBuf -= len;
5403 pi2a->pDescription = ptr;
5404 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5405 ptr, cbBuf, NULL, NULL);
5406 ptr += len;
5407 cbBuf -= len;
5409 pi2a->fPortType = pi2w->fPortType;
5410 pi2a->Reserved = 0; /* documented: "must be zero" */
5413 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5414 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5415 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5419 cleanup:
5420 if (pcbNeeded) *pcbNeeded = needed;
5421 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5423 HeapFree(GetProcessHeap(), 0, nameW);
5424 HeapFree(GetProcessHeap(), 0, bufferW);
5426 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5427 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5429 return (res);
5433 /******************************************************************************
5434 * EnumPortsW (WINSPOOL.@)
5436 * Enumerate available Ports
5438 * PARAMS
5439 * name [I] Servername or NULL (local Computer)
5440 * level [I] Structure-Level (1 or 2)
5441 * buffer [O] PTR to Buffer that receives the Result
5442 * bufsize [I] Size of Buffer at buffer
5443 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5444 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5446 * RETURNS
5447 * Success: TRUE
5448 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5452 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5454 DWORD needed = 0;
5455 DWORD numentries = 0;
5456 BOOL res = FALSE;
5458 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5459 cbBuf, pcbNeeded, pcReturned);
5461 if (pName && (pName[0])) {
5462 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5463 SetLastError(ERROR_ACCESS_DENIED);
5464 goto emP_cleanup;
5467 /* Level is not checked in win9x */
5468 if (!Level || (Level > 2)) {
5469 WARN("level (%d) is ignored in win9x\n", Level);
5470 SetLastError(ERROR_INVALID_LEVEL);
5471 goto emP_cleanup;
5473 if (!pcbNeeded) {
5474 SetLastError(RPC_X_NULL_REF_POINTER);
5475 goto emP_cleanup;
5478 EnterCriticalSection(&monitor_handles_cs);
5479 monitor_loadall();
5481 /* Scan all local Ports */
5482 numentries = 0;
5483 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5485 /* we calculated the needed buffersize. now do the error-checks */
5486 if (cbBuf < needed) {
5487 monitor_unloadall();
5488 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5489 goto emP_cleanup_cs;
5491 else if (!pPorts || !pcReturned) {
5492 monitor_unloadall();
5493 SetLastError(RPC_X_NULL_REF_POINTER);
5494 goto emP_cleanup_cs;
5497 /* Fill the Buffer */
5498 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5499 res = TRUE;
5500 monitor_unloadall();
5502 emP_cleanup_cs:
5503 LeaveCriticalSection(&monitor_handles_cs);
5505 emP_cleanup:
5506 if (pcbNeeded) *pcbNeeded = needed;
5507 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5509 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5510 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5512 return (res);
5515 /******************************************************************************
5516 * GetDefaultPrinterW (WINSPOOL.@)
5518 * FIXME
5519 * This function must read the value from data 'device' of key
5520 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5522 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5524 BOOL retval = TRUE;
5525 DWORD insize, len;
5526 WCHAR *buffer, *ptr;
5528 if (!namesize)
5530 SetLastError(ERROR_INVALID_PARAMETER);
5531 return FALSE;
5534 /* make the buffer big enough for the stuff from the profile/registry,
5535 * the content must fit into the local buffer to compute the correct
5536 * size even if the extern buffer is too small or not given.
5537 * (20 for ,driver,port) */
5538 insize = *namesize;
5539 len = max(100, (insize + 20));
5540 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5542 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5544 SetLastError (ERROR_FILE_NOT_FOUND);
5545 retval = FALSE;
5546 goto end;
5548 TRACE("%s\n", debugstr_w(buffer));
5550 if ((ptr = strchrW(buffer, ',')) == NULL)
5552 SetLastError(ERROR_INVALID_NAME);
5553 retval = FALSE;
5554 goto end;
5557 *ptr = 0;
5558 *namesize = strlenW(buffer) + 1;
5559 if(!name || (*namesize > insize))
5561 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5562 retval = FALSE;
5563 goto end;
5565 strcpyW(name, buffer);
5567 end:
5568 HeapFree( GetProcessHeap(), 0, buffer);
5569 return retval;
5573 /******************************************************************************
5574 * GetDefaultPrinterA (WINSPOOL.@)
5576 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5578 BOOL retval = TRUE;
5579 DWORD insize = 0;
5580 WCHAR *bufferW = NULL;
5582 if (!namesize)
5584 SetLastError(ERROR_INVALID_PARAMETER);
5585 return FALSE;
5588 if(name && *namesize) {
5589 insize = *namesize;
5590 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5593 if(!GetDefaultPrinterW( bufferW, namesize)) {
5594 retval = FALSE;
5595 goto end;
5598 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5599 NULL, NULL);
5600 if (!*namesize)
5602 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5603 retval = FALSE;
5605 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5607 end:
5608 HeapFree( GetProcessHeap(), 0, bufferW);
5609 return retval;
5613 /******************************************************************************
5614 * SetDefaultPrinterW (WINSPOOL.204)
5616 * Set the Name of the Default Printer
5618 * PARAMS
5619 * pszPrinter [I] Name of the Printer or NULL
5621 * RETURNS
5622 * Success: True
5623 * Failure: FALSE
5625 * NOTES
5626 * When the Parameter is NULL or points to an Empty String and
5627 * a Default Printer was already present, then this Function changes nothing.
5628 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5629 * the First enumerated local Printer is used.
5632 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5635 TRACE("(%s)\n", debugstr_w(pszPrinter));
5637 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5638 return FALSE;
5641 /******************************************************************************
5642 * SetDefaultPrinterA (WINSPOOL.202)
5644 * See SetDefaultPrinterW.
5647 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5650 TRACE("(%s)\n", debugstr_a(pszPrinter));
5652 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5653 return FALSE;
5657 /******************************************************************************
5658 * SetPrinterDataExA (WINSPOOL.@)
5660 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5661 LPCSTR pValueName, DWORD Type,
5662 LPBYTE pData, DWORD cbData)
5664 HKEY hkeyPrinter, hkeySubkey;
5665 DWORD ret;
5667 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5668 debugstr_a(pValueName), Type, pData, cbData);
5670 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5671 != ERROR_SUCCESS)
5672 return ret;
5674 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5675 != ERROR_SUCCESS) {
5676 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5677 RegCloseKey(hkeyPrinter);
5678 return ret;
5680 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5681 RegCloseKey(hkeySubkey);
5682 RegCloseKey(hkeyPrinter);
5683 return ret;
5686 /******************************************************************************
5687 * SetPrinterDataExW (WINSPOOL.@)
5689 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5690 LPCWSTR pValueName, DWORD Type,
5691 LPBYTE pData, DWORD cbData)
5693 HKEY hkeyPrinter, hkeySubkey;
5694 DWORD ret;
5696 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5697 debugstr_w(pValueName), Type, pData, cbData);
5699 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5700 != ERROR_SUCCESS)
5701 return ret;
5703 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5704 != ERROR_SUCCESS) {
5705 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5706 RegCloseKey(hkeyPrinter);
5707 return ret;
5709 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5710 RegCloseKey(hkeySubkey);
5711 RegCloseKey(hkeyPrinter);
5712 return ret;
5715 /******************************************************************************
5716 * SetPrinterDataA (WINSPOOL.@)
5718 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5719 LPBYTE pData, DWORD cbData)
5721 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5722 pData, cbData);
5725 /******************************************************************************
5726 * SetPrinterDataW (WINSPOOL.@)
5728 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5729 LPBYTE pData, DWORD cbData)
5731 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5732 pData, cbData);
5735 /******************************************************************************
5736 * GetPrinterDataExA (WINSPOOL.@)
5738 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5739 LPCSTR pValueName, LPDWORD pType,
5740 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5742 HKEY hkeyPrinter, hkeySubkey;
5743 DWORD ret;
5745 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5746 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5747 pcbNeeded);
5749 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5750 != ERROR_SUCCESS)
5751 return ret;
5753 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5754 != ERROR_SUCCESS) {
5755 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5756 RegCloseKey(hkeyPrinter);
5757 return ret;
5759 *pcbNeeded = nSize;
5760 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5761 RegCloseKey(hkeySubkey);
5762 RegCloseKey(hkeyPrinter);
5763 return ret;
5766 /******************************************************************************
5767 * GetPrinterDataExW (WINSPOOL.@)
5769 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5770 LPCWSTR pValueName, LPDWORD pType,
5771 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5773 HKEY hkeyPrinter, hkeySubkey;
5774 DWORD ret;
5776 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5777 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5778 pcbNeeded);
5780 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5781 != ERROR_SUCCESS)
5782 return ret;
5784 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5785 != ERROR_SUCCESS) {
5786 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5787 RegCloseKey(hkeyPrinter);
5788 return ret;
5790 *pcbNeeded = nSize;
5791 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5792 RegCloseKey(hkeySubkey);
5793 RegCloseKey(hkeyPrinter);
5794 return ret;
5797 /******************************************************************************
5798 * GetPrinterDataA (WINSPOOL.@)
5800 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5801 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5803 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5804 pData, nSize, pcbNeeded);
5807 /******************************************************************************
5808 * GetPrinterDataW (WINSPOOL.@)
5810 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5811 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5813 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5814 pData, nSize, pcbNeeded);
5817 /*******************************************************************************
5818 * EnumPrinterDataExW [WINSPOOL.@]
5820 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5821 LPBYTE pEnumValues, DWORD cbEnumValues,
5822 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5824 HKEY hkPrinter, hkSubKey;
5825 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5826 cbValueNameLen, cbMaxValueLen, cbValueLen,
5827 cbBufSize, dwType;
5828 LPWSTR lpValueName;
5829 HANDLE hHeap;
5830 PBYTE lpValue;
5831 PPRINTER_ENUM_VALUESW ppev;
5833 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5835 if (pKeyName == NULL || *pKeyName == 0)
5836 return ERROR_INVALID_PARAMETER;
5838 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5839 if (ret != ERROR_SUCCESS)
5841 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5842 hPrinter, ret);
5843 return ret;
5846 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5847 if (ret != ERROR_SUCCESS)
5849 r = RegCloseKey (hkPrinter);
5850 if (r != ERROR_SUCCESS)
5851 WARN ("RegCloseKey returned %i\n", r);
5852 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5853 debugstr_w (pKeyName), ret);
5854 return ret;
5857 ret = RegCloseKey (hkPrinter);
5858 if (ret != ERROR_SUCCESS)
5860 ERR ("RegCloseKey returned %i\n", ret);
5861 r = RegCloseKey (hkSubKey);
5862 if (r != ERROR_SUCCESS)
5863 WARN ("RegCloseKey returned %i\n", r);
5864 return ret;
5867 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5868 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5869 if (ret != ERROR_SUCCESS)
5871 r = RegCloseKey (hkSubKey);
5872 if (r != ERROR_SUCCESS)
5873 WARN ("RegCloseKey returned %i\n", r);
5874 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5875 return ret;
5878 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5879 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5881 if (cValues == 0) /* empty key */
5883 r = RegCloseKey (hkSubKey);
5884 if (r != ERROR_SUCCESS)
5885 WARN ("RegCloseKey returned %i\n", r);
5886 *pcbEnumValues = *pnEnumValues = 0;
5887 return ERROR_SUCCESS;
5890 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5892 hHeap = GetProcessHeap ();
5893 if (hHeap == NULL)
5895 ERR ("GetProcessHeap failed\n");
5896 r = RegCloseKey (hkSubKey);
5897 if (r != ERROR_SUCCESS)
5898 WARN ("RegCloseKey returned %i\n", r);
5899 return ERROR_OUTOFMEMORY;
5902 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5903 if (lpValueName == NULL)
5905 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5906 r = RegCloseKey (hkSubKey);
5907 if (r != ERROR_SUCCESS)
5908 WARN ("RegCloseKey returned %i\n", r);
5909 return ERROR_OUTOFMEMORY;
5912 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5913 if (lpValue == NULL)
5915 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5916 if (HeapFree (hHeap, 0, lpValueName) == 0)
5917 WARN ("HeapFree failed with code %i\n", GetLastError ());
5918 r = RegCloseKey (hkSubKey);
5919 if (r != ERROR_SUCCESS)
5920 WARN ("RegCloseKey returned %i\n", r);
5921 return ERROR_OUTOFMEMORY;
5924 TRACE ("pass 1: calculating buffer required for all names and values\n");
5926 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5928 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5930 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5932 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5933 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5934 NULL, NULL, lpValue, &cbValueLen);
5935 if (ret != ERROR_SUCCESS)
5937 if (HeapFree (hHeap, 0, lpValue) == 0)
5938 WARN ("HeapFree failed with code %i\n", GetLastError ());
5939 if (HeapFree (hHeap, 0, lpValueName) == 0)
5940 WARN ("HeapFree failed with code %i\n", GetLastError ());
5941 r = RegCloseKey (hkSubKey);
5942 if (r != ERROR_SUCCESS)
5943 WARN ("RegCloseKey returned %i\n", r);
5944 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5945 return ret;
5948 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5949 debugstr_w (lpValueName), dwIndex,
5950 cbValueNameLen + 1, cbValueLen);
5952 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5953 cbBufSize += cbValueLen;
5956 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5958 *pcbEnumValues = cbBufSize;
5959 *pnEnumValues = cValues;
5961 if (cbEnumValues < cbBufSize) /* buffer too small */
5963 if (HeapFree (hHeap, 0, lpValue) == 0)
5964 WARN ("HeapFree failed with code %i\n", GetLastError ());
5965 if (HeapFree (hHeap, 0, lpValueName) == 0)
5966 WARN ("HeapFree failed with code %i\n", GetLastError ());
5967 r = RegCloseKey (hkSubKey);
5968 if (r != ERROR_SUCCESS)
5969 WARN ("RegCloseKey returned %i\n", r);
5970 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5971 return ERROR_MORE_DATA;
5974 TRACE ("pass 2: copying all names and values to buffer\n");
5976 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5977 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5979 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5981 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5982 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5983 NULL, &dwType, lpValue, &cbValueLen);
5984 if (ret != ERROR_SUCCESS)
5986 if (HeapFree (hHeap, 0, lpValue) == 0)
5987 WARN ("HeapFree failed with code %i\n", GetLastError ());
5988 if (HeapFree (hHeap, 0, lpValueName) == 0)
5989 WARN ("HeapFree failed with code %i\n", GetLastError ());
5990 r = RegCloseKey (hkSubKey);
5991 if (r != ERROR_SUCCESS)
5992 WARN ("RegCloseKey returned %i\n", r);
5993 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5994 return ret;
5997 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5998 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5999 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6000 pEnumValues += cbValueNameLen;
6002 /* return # of *bytes* (including trailing \0), not # of chars */
6003 ppev[dwIndex].cbValueName = cbValueNameLen;
6005 ppev[dwIndex].dwType = dwType;
6007 memcpy (pEnumValues, lpValue, cbValueLen);
6008 ppev[dwIndex].pData = pEnumValues;
6009 pEnumValues += cbValueLen;
6011 ppev[dwIndex].cbData = cbValueLen;
6013 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6014 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6017 if (HeapFree (hHeap, 0, lpValue) == 0)
6019 ret = GetLastError ();
6020 ERR ("HeapFree failed with code %i\n", ret);
6021 if (HeapFree (hHeap, 0, lpValueName) == 0)
6022 WARN ("HeapFree failed with code %i\n", GetLastError ());
6023 r = RegCloseKey (hkSubKey);
6024 if (r != ERROR_SUCCESS)
6025 WARN ("RegCloseKey returned %i\n", r);
6026 return ret;
6029 if (HeapFree (hHeap, 0, lpValueName) == 0)
6031 ret = GetLastError ();
6032 ERR ("HeapFree failed with code %i\n", ret);
6033 r = RegCloseKey (hkSubKey);
6034 if (r != ERROR_SUCCESS)
6035 WARN ("RegCloseKey returned %i\n", r);
6036 return ret;
6039 ret = RegCloseKey (hkSubKey);
6040 if (ret != ERROR_SUCCESS)
6042 ERR ("RegCloseKey returned %i\n", ret);
6043 return ret;
6046 return ERROR_SUCCESS;
6049 /*******************************************************************************
6050 * EnumPrinterDataExA [WINSPOOL.@]
6052 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6053 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6054 * what Windows 2000 SP1 does.
6057 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6058 LPBYTE pEnumValues, DWORD cbEnumValues,
6059 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6061 INT len;
6062 LPWSTR pKeyNameW;
6063 DWORD ret, dwIndex, dwBufSize;
6064 HANDLE hHeap;
6065 LPSTR pBuffer;
6067 TRACE ("%p %s\n", hPrinter, pKeyName);
6069 if (pKeyName == NULL || *pKeyName == 0)
6070 return ERROR_INVALID_PARAMETER;
6072 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6073 if (len == 0)
6075 ret = GetLastError ();
6076 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6077 return ret;
6080 hHeap = GetProcessHeap ();
6081 if (hHeap == NULL)
6083 ERR ("GetProcessHeap failed\n");
6084 return ERROR_OUTOFMEMORY;
6087 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6088 if (pKeyNameW == NULL)
6090 ERR ("Failed to allocate %i bytes from process heap\n",
6091 (LONG)(len * sizeof (WCHAR)));
6092 return ERROR_OUTOFMEMORY;
6095 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6097 ret = GetLastError ();
6098 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6099 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6100 WARN ("HeapFree failed with code %i\n", GetLastError ());
6101 return ret;
6104 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6105 pcbEnumValues, pnEnumValues);
6106 if (ret != ERROR_SUCCESS)
6108 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6109 WARN ("HeapFree failed with code %i\n", GetLastError ());
6110 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6111 return ret;
6114 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6116 ret = GetLastError ();
6117 ERR ("HeapFree failed with code %i\n", ret);
6118 return ret;
6121 if (*pnEnumValues == 0) /* empty key */
6122 return ERROR_SUCCESS;
6124 dwBufSize = 0;
6125 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6127 PPRINTER_ENUM_VALUESW ppev =
6128 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6130 if (dwBufSize < ppev->cbValueName)
6131 dwBufSize = ppev->cbValueName;
6133 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6134 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6135 dwBufSize = ppev->cbData;
6138 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6140 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6141 if (pBuffer == NULL)
6143 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6144 return ERROR_OUTOFMEMORY;
6147 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6149 PPRINTER_ENUM_VALUESW ppev =
6150 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6152 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6153 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6154 NULL);
6155 if (len == 0)
6157 ret = GetLastError ();
6158 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6159 if (HeapFree (hHeap, 0, pBuffer) == 0)
6160 WARN ("HeapFree failed with code %i\n", GetLastError ());
6161 return ret;
6164 memcpy (ppev->pValueName, pBuffer, len);
6166 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6168 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6169 ppev->dwType != REG_MULTI_SZ)
6170 continue;
6172 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6173 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6174 if (len == 0)
6176 ret = GetLastError ();
6177 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6178 if (HeapFree (hHeap, 0, pBuffer) == 0)
6179 WARN ("HeapFree failed with code %i\n", GetLastError ());
6180 return ret;
6183 memcpy (ppev->pData, pBuffer, len);
6185 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6186 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6189 if (HeapFree (hHeap, 0, pBuffer) == 0)
6191 ret = GetLastError ();
6192 ERR ("HeapFree failed with code %i\n", ret);
6193 return ret;
6196 return ERROR_SUCCESS;
6199 /******************************************************************************
6200 * AbortPrinter (WINSPOOL.@)
6202 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6204 FIXME("(%p), stub!\n", hPrinter);
6205 return TRUE;
6208 /******************************************************************************
6209 * AddPortA (WINSPOOL.@)
6211 * See AddPortW.
6214 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6216 LPWSTR nameW = NULL;
6217 LPWSTR monitorW = NULL;
6218 DWORD len;
6219 BOOL res;
6221 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6223 if (pName) {
6224 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6225 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6226 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6229 if (pMonitorName) {
6230 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6231 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6232 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6234 res = AddPortW(nameW, hWnd, monitorW);
6235 HeapFree(GetProcessHeap(), 0, nameW);
6236 HeapFree(GetProcessHeap(), 0, monitorW);
6237 return res;
6240 /******************************************************************************
6241 * AddPortW (WINSPOOL.@)
6243 * Add a Port for a specific Monitor
6245 * PARAMS
6246 * pName [I] Servername or NULL (local Computer)
6247 * hWnd [I] Handle to parent Window for the Dialog-Box
6248 * pMonitorName [I] Name of the Monitor that manage the Port
6250 * RETURNS
6251 * Success: TRUE
6252 * Failure: FALSE
6255 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6257 monitor_t * pm;
6258 monitor_t * pui;
6259 DWORD res;
6261 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6263 if (pName && pName[0]) {
6264 SetLastError(ERROR_INVALID_PARAMETER);
6265 return FALSE;
6268 if (!pMonitorName) {
6269 SetLastError(RPC_X_NULL_REF_POINTER);
6270 return FALSE;
6273 /* an empty Monitorname is Invalid */
6274 if (!pMonitorName[0]) {
6275 SetLastError(ERROR_NOT_SUPPORTED);
6276 return FALSE;
6279 pm = monitor_load(pMonitorName, NULL);
6280 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6281 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6282 TRACE("got %d with %u\n", res, GetLastError());
6283 res = TRUE;
6285 else
6287 pui = monitor_loadui(pm);
6288 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6289 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6290 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6291 TRACE("got %d with %u\n", res, GetLastError());
6292 res = TRUE;
6294 else
6296 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6297 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6299 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6300 SetLastError(ERROR_NOT_SUPPORTED);
6301 res = FALSE;
6303 monitor_unload(pui);
6305 monitor_unload(pm);
6306 TRACE("returning %d with %u\n", res, GetLastError());
6307 return res;
6310 /******************************************************************************
6311 * AddPortExA (WINSPOOL.@)
6313 * See AddPortExW.
6316 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6318 PORT_INFO_2W pi2W;
6319 PORT_INFO_2A * pi2A;
6320 LPWSTR nameW = NULL;
6321 LPWSTR monitorW = NULL;
6322 DWORD len;
6323 BOOL res;
6325 pi2A = (PORT_INFO_2A *) pBuffer;
6327 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6328 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6330 if ((level < 1) || (level > 2)) {
6331 SetLastError(ERROR_INVALID_LEVEL);
6332 return FALSE;
6335 if (!pi2A) {
6336 SetLastError(ERROR_INVALID_PARAMETER);
6337 return FALSE;
6340 if (pName) {
6341 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6342 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6343 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6346 if (pMonitorName) {
6347 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6348 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6349 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6352 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6354 if (pi2A->pPortName) {
6355 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6356 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6357 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6360 if (level > 1) {
6361 if (pi2A->pMonitorName) {
6362 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6363 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6364 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6367 if (pi2A->pDescription) {
6368 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6369 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6370 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6372 pi2W.fPortType = pi2A->fPortType;
6373 pi2W.Reserved = pi2A->Reserved;
6376 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6378 HeapFree(GetProcessHeap(), 0, nameW);
6379 HeapFree(GetProcessHeap(), 0, monitorW);
6380 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6381 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6382 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6383 return res;
6387 /******************************************************************************
6388 * AddPortExW (WINSPOOL.@)
6390 * Add a Port for a specific Monitor, without presenting a user interface
6392 * PARAMS
6393 * pName [I] Servername or NULL (local Computer)
6394 * level [I] Structure-Level (1 or 2) for pBuffer
6395 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6396 * pMonitorName [I] Name of the Monitor that manage the Port
6398 * RETURNS
6399 * Success: TRUE
6400 * Failure: FALSE
6403 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6405 PORT_INFO_2W * pi2;
6406 monitor_t * pm;
6407 DWORD res = FALSE;
6409 pi2 = (PORT_INFO_2W *) pBuffer;
6411 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6412 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6413 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6414 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6417 if ((level < 1) || (level > 2)) {
6418 SetLastError(ERROR_INVALID_LEVEL);
6419 return FALSE;
6422 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6423 SetLastError(ERROR_INVALID_PARAMETER);
6424 return FALSE;
6427 /* load the Monitor */
6428 pm = monitor_load(pMonitorName, NULL);
6429 if (!pm) {
6430 SetLastError(ERROR_INVALID_PARAMETER);
6431 return FALSE;
6434 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6435 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6436 TRACE("got %u with %u\n", res, GetLastError());
6438 else
6440 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6442 monitor_unload(pm);
6443 return res;
6446 /******************************************************************************
6447 * AddPrinterConnectionA (WINSPOOL.@)
6449 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6451 FIXME("%s\n", debugstr_a(pName));
6452 return FALSE;
6455 /******************************************************************************
6456 * AddPrinterConnectionW (WINSPOOL.@)
6458 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6460 FIXME("%s\n", debugstr_w(pName));
6461 return FALSE;
6464 /******************************************************************************
6465 * AddPrinterDriverExW (WINSPOOL.@)
6467 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6469 * PARAMS
6470 * pName [I] Servername or NULL (local Computer)
6471 * level [I] Level for the supplied DRIVER_INFO_*W struct
6472 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6473 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6475 * RESULTS
6476 * Success: TRUE
6477 * Failure: FALSE
6480 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6482 const printenv_t *env;
6483 apd_data_t apd;
6484 DRIVER_INFO_8W di;
6485 LPWSTR ptr;
6486 HKEY hroot;
6487 HKEY hdrv;
6488 DWORD disposition;
6489 DWORD len;
6490 LONG lres;
6492 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6494 if (level < 2 || level == 5 || level == 7 || level > 8) {
6495 SetLastError(ERROR_INVALID_LEVEL);
6496 return FALSE;
6499 if (!pDriverInfo) {
6500 SetLastError(ERROR_INVALID_PARAMETER);
6501 return FALSE;
6504 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
6505 FIXME("Flags 0x%x ignored (Fallback to APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
6508 ptr = get_servername_from_name(pName);
6509 HeapFree(GetProcessHeap(), 0, ptr);
6510 if (ptr) {
6511 FIXME("not suported for server: %s\n", debugstr_w(pName));
6512 SetLastError(ERROR_ACCESS_DENIED);
6513 return FALSE;
6516 /* we need to set all entries in the Registry, independent from the Level of
6517 DRIVER_INFO, that the caller supplied */
6519 ZeroMemory(&di, sizeof(di));
6520 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
6521 memcpy(&di, pDriverInfo, di_sizeof[level]);
6524 /* dump the most used infos */
6525 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
6526 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
6527 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
6528 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
6529 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
6530 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
6531 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
6532 /* dump only the first of the additional Files */
6533 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
6536 /* check environment */
6537 env = validate_envW(di.pEnvironment);
6538 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
6540 /* fill the copy-data / get the driverdir */
6541 len = sizeof(apd.src) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
6542 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1,
6543 (LPBYTE) apd.src, len, &len)) {
6544 /* Should never Fail */
6545 return FALSE;
6547 memcpy(apd.dst, apd.src, len);
6548 lstrcatW(apd.src, backslashW);
6549 apd.srclen = lstrlenW(apd.src);
6550 lstrcatW(apd.dst, env->versionsubdir);
6551 lstrcatW(apd.dst, backslashW);
6552 apd.dstlen = lstrlenW(apd.dst);
6553 apd.copyflags = dwFileCopyFlags;
6554 CreateDirectoryW(apd.src, NULL);
6555 CreateDirectoryW(apd.dst, NULL);
6557 /* Fill the Registry for the Driver */
6558 hroot = WINSPOOL_OpenDriverReg(env->envname, TRUE);
6559 if(!hroot) {
6560 ERR("Can't create Drivers key\n");
6561 return FALSE;
6564 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
6565 KEY_WRITE | KEY_QUERY_VALUE, NULL,
6566 &hdrv, &disposition)) != ERROR_SUCCESS) {
6568 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
6569 RegCloseKey(hroot);
6570 SetLastError(lres);
6571 return FALSE;
6573 RegCloseKey(hroot);
6575 if (disposition == REG_OPENED_EXISTING_KEY) {
6576 TRACE("driver %s already installed\n", debugstr_w(di.pName));
6577 RegCloseKey(hdrv);
6578 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
6579 return FALSE;
6582 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
6583 RegSetValueExW(hdrv, VersionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
6584 sizeof(DWORD));
6586 RegSetValueExW(hdrv, DriverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
6587 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
6588 apd_copyfile(di.pDriverPath, &apd);
6590 RegSetValueExW(hdrv, Data_FileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
6591 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
6592 apd_copyfile(di.pDataFile, &apd);
6594 RegSetValueExW(hdrv, Configuration_FileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
6595 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
6596 apd_copyfile(di.pConfigFile, &apd);
6598 /* settings for level 3 */
6599 RegSetValueExW(hdrv, Help_FileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
6600 di.pHelpFile ? (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR) : 0);
6601 apd_copyfile(di.pHelpFile, &apd);
6604 ptr = di.pDependentFiles;
6605 RegSetValueExW(hdrv, Dependent_FilesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
6606 di.pDependentFiles ? multi_sz_lenW(di.pDependentFiles) : 0);
6607 while ((ptr != NULL) && (ptr[0])) {
6608 if (apd_copyfile(ptr, &apd)) {
6609 ptr += lstrlenW(ptr) + 1;
6611 else
6613 WARN("Failed to copy %s\n", debugstr_w(ptr));
6614 ptr = NULL;
6618 /* The language-Monitor was already copied to "%SystemRoot%\system32" */
6619 RegSetValueExW(hdrv, MonitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
6620 di.pMonitorName ? (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR) : 0);
6622 RegSetValueExW(hdrv, DatatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
6623 di.pDefaultDataType ? (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR) : 0);
6625 /* settings for level 4 */
6626 RegSetValueExW(hdrv, Previous_NamesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
6627 di.pszzPreviousNames ? multi_sz_lenW(di.pszzPreviousNames) : 0);
6629 if (level > 5) FIXME("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
6632 RegCloseKey(hdrv);
6633 FIXME("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
6636 TRACE("=> TRUE with %u\n", GetLastError());
6637 return TRUE;
6641 /******************************************************************************
6642 * AddPrinterDriverExA (WINSPOOL.@)
6644 * See AddPrinterDriverExW.
6647 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6649 DRIVER_INFO_8A *diA;
6650 DRIVER_INFO_8W diW;
6651 LPWSTR nameW = NULL;
6652 DWORD lenA;
6653 DWORD len;
6654 DWORD res = FALSE;
6656 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6658 diA = (DRIVER_INFO_8A *) pDriverInfo;
6659 ZeroMemory(&diW, sizeof(diW));
6661 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6662 SetLastError(ERROR_INVALID_LEVEL);
6663 return FALSE;
6666 if (diA == NULL) {
6667 SetLastError(ERROR_INVALID_PARAMETER);
6668 return FALSE;
6671 /* convert servername to unicode */
6672 if (pName) {
6673 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6674 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6675 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6678 /* common fields */
6679 diW.cVersion = diA->cVersion;
6681 if (diA->pName) {
6682 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6683 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6684 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6687 if (diA->pEnvironment) {
6688 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6689 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6690 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6693 if (diA->pDriverPath) {
6694 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6695 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6696 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6699 if (diA->pDataFile) {
6700 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6701 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6702 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6705 if (diA->pConfigFile) {
6706 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6707 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6708 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6711 if ((Level > 2) && diA->pDependentFiles) {
6712 lenA = multi_sz_lenA(diA->pDependentFiles);
6713 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6714 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6715 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6718 if ((Level > 2) && diA->pMonitorName) {
6719 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6720 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6721 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6724 if ((Level > 3) && diA->pDefaultDataType) {
6725 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6726 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6727 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6730 if ((Level > 3) && diA->pszzPreviousNames) {
6731 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6732 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6733 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6734 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6737 if ((Level > 5) && diA->pszMfgName) {
6738 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6739 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6740 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6743 if ((Level > 5) && diA->pszOEMUrl) {
6744 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6745 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6746 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6749 if ((Level > 5) && diA->pszHardwareID) {
6750 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6751 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6752 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6755 if ((Level > 5) && diA->pszProvider) {
6756 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6757 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6758 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6761 if (Level > 7) {
6762 FIXME("level %u is incomplete\n", Level);
6765 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6766 TRACE("got %u with %u\n", res, GetLastError());
6767 HeapFree(GetProcessHeap(), 0, nameW);
6768 HeapFree(GetProcessHeap(), 0, diW.pName);
6769 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6770 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6771 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6772 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6773 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6774 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6775 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6776 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6777 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6778 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6779 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6780 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6782 TRACE("=> %u with %u\n", res, GetLastError());
6783 return res;
6786 /******************************************************************************
6787 * ConfigurePortA (WINSPOOL.@)
6789 * See ConfigurePortW.
6792 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6794 LPWSTR nameW = NULL;
6795 LPWSTR portW = NULL;
6796 INT len;
6797 DWORD res;
6799 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6801 /* convert servername to unicode */
6802 if (pName) {
6803 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6804 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6805 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6808 /* convert portname to unicode */
6809 if (pPortName) {
6810 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6811 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6812 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6815 res = ConfigurePortW(nameW, hWnd, portW);
6816 HeapFree(GetProcessHeap(), 0, nameW);
6817 HeapFree(GetProcessHeap(), 0, portW);
6818 return res;
6821 /******************************************************************************
6822 * ConfigurePortW (WINSPOOL.@)
6824 * Display the Configuration-Dialog for a specific Port
6826 * PARAMS
6827 * pName [I] Servername or NULL (local Computer)
6828 * hWnd [I] Handle to parent Window for the Dialog-Box
6829 * pPortName [I] Name of the Port, that should be configured
6831 * RETURNS
6832 * Success: TRUE
6833 * Failure: FALSE
6836 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6838 monitor_t * pm;
6839 monitor_t * pui;
6840 DWORD res;
6842 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6844 if (pName && pName[0]) {
6845 SetLastError(ERROR_INVALID_PARAMETER);
6846 return FALSE;
6849 if (!pPortName) {
6850 SetLastError(RPC_X_NULL_REF_POINTER);
6851 return FALSE;
6854 /* an empty Portname is Invalid, but can popup a Dialog */
6855 if (!pPortName[0]) {
6856 SetLastError(ERROR_NOT_SUPPORTED);
6857 return FALSE;
6860 pm = monitor_load_by_port(pPortName);
6861 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6862 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6863 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6864 TRACE("got %d with %u\n", res, GetLastError());
6866 else
6868 pui = monitor_loadui(pm);
6869 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6870 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6871 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6872 TRACE("got %d with %u\n", res, GetLastError());
6874 else
6876 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6877 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6879 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6880 SetLastError(ERROR_NOT_SUPPORTED);
6881 res = FALSE;
6883 monitor_unload(pui);
6885 monitor_unload(pm);
6887 TRACE("returning %d with %u\n", res, GetLastError());
6888 return res;
6891 /******************************************************************************
6892 * ConnectToPrinterDlg (WINSPOOL.@)
6894 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6896 FIXME("%p %x\n", hWnd, Flags);
6897 return NULL;
6900 /******************************************************************************
6901 * DeletePrinterConnectionA (WINSPOOL.@)
6903 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6905 FIXME("%s\n", debugstr_a(pName));
6906 return TRUE;
6909 /******************************************************************************
6910 * DeletePrinterConnectionW (WINSPOOL.@)
6912 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6914 FIXME("%s\n", debugstr_w(pName));
6915 return TRUE;
6918 /******************************************************************************
6919 * DeletePrinterDriverExW (WINSPOOL.@)
6921 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6922 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6924 HKEY hkey_drivers;
6925 BOOL ret = FALSE;
6927 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6928 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6930 if(pName && pName[0])
6932 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6933 SetLastError(ERROR_INVALID_PARAMETER);
6934 return FALSE;
6937 if(dwDeleteFlag)
6939 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6940 SetLastError(ERROR_INVALID_PARAMETER);
6941 return FALSE;
6944 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6946 if(!hkey_drivers)
6948 ERR("Can't open drivers key\n");
6949 return FALSE;
6952 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6953 ret = TRUE;
6955 RegCloseKey(hkey_drivers);
6957 return ret;
6960 /******************************************************************************
6961 * DeletePrinterDriverExA (WINSPOOL.@)
6963 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6964 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6966 UNICODE_STRING NameW, EnvW, DriverW;
6967 BOOL ret;
6969 asciitounicode(&NameW, pName);
6970 asciitounicode(&EnvW, pEnvironment);
6971 asciitounicode(&DriverW, pDriverName);
6973 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6975 RtlFreeUnicodeString(&DriverW);
6976 RtlFreeUnicodeString(&EnvW);
6977 RtlFreeUnicodeString(&NameW);
6979 return ret;
6982 /******************************************************************************
6983 * DeletePrinterDataExW (WINSPOOL.@)
6985 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6986 LPCWSTR pValueName)
6988 FIXME("%p %s %s\n", hPrinter,
6989 debugstr_w(pKeyName), debugstr_w(pValueName));
6990 return ERROR_INVALID_PARAMETER;
6993 /******************************************************************************
6994 * DeletePrinterDataExA (WINSPOOL.@)
6996 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6997 LPCSTR pValueName)
6999 FIXME("%p %s %s\n", hPrinter,
7000 debugstr_a(pKeyName), debugstr_a(pValueName));
7001 return ERROR_INVALID_PARAMETER;
7004 /******************************************************************************
7005 * DeletePrintProcessorA (WINSPOOL.@)
7007 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7009 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7010 debugstr_a(pPrintProcessorName));
7011 return TRUE;
7014 /******************************************************************************
7015 * DeletePrintProcessorW (WINSPOOL.@)
7017 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7019 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7020 debugstr_w(pPrintProcessorName));
7021 return TRUE;
7024 /******************************************************************************
7025 * DeletePrintProvidorA (WINSPOOL.@)
7027 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7029 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7030 debugstr_a(pPrintProviderName));
7031 return TRUE;
7034 /******************************************************************************
7035 * DeletePrintProvidorW (WINSPOOL.@)
7037 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7039 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7040 debugstr_w(pPrintProviderName));
7041 return TRUE;
7044 /******************************************************************************
7045 * EnumFormsA (WINSPOOL.@)
7047 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7048 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7050 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7051 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7052 return FALSE;
7055 /******************************************************************************
7056 * EnumFormsW (WINSPOOL.@)
7058 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7059 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7061 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7062 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7063 return FALSE;
7066 /*****************************************************************************
7067 * EnumMonitorsA [WINSPOOL.@]
7069 * See EnumMonitorsW.
7072 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7073 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7075 BOOL res;
7076 LPBYTE bufferW = NULL;
7077 LPWSTR nameW = NULL;
7078 DWORD needed = 0;
7079 DWORD numentries = 0;
7080 INT len;
7082 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7083 cbBuf, pcbNeeded, pcReturned);
7085 /* convert servername to unicode */
7086 if (pName) {
7087 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7088 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7089 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7091 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7092 needed = cbBuf * sizeof(WCHAR);
7093 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7094 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7096 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7097 if (pcbNeeded) needed = *pcbNeeded;
7098 /* HeapReAlloc return NULL, when bufferW was NULL */
7099 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7100 HeapAlloc(GetProcessHeap(), 0, needed);
7102 /* Try again with the large Buffer */
7103 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7105 numentries = pcReturned ? *pcReturned : 0;
7106 needed = 0;
7108 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7109 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7111 if (res) {
7112 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7113 DWORD entrysize = 0;
7114 DWORD index;
7115 LPSTR ptr;
7116 LPMONITOR_INFO_2W mi2w;
7117 LPMONITOR_INFO_2A mi2a;
7119 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7120 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7122 /* First pass: calculate the size for all Entries */
7123 mi2w = (LPMONITOR_INFO_2W) bufferW;
7124 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7125 index = 0;
7126 while (index < numentries) {
7127 index++;
7128 needed += entrysize; /* MONITOR_INFO_?A */
7129 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7131 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7132 NULL, 0, NULL, NULL);
7133 if (Level > 1) {
7134 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7135 NULL, 0, NULL, NULL);
7136 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7137 NULL, 0, NULL, NULL);
7139 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7140 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7141 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7144 /* check for errors and quit on failure */
7145 if (cbBuf < needed) {
7146 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7147 res = FALSE;
7148 goto emA_cleanup;
7150 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7151 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7152 cbBuf -= len ; /* free Bytes in the user-Buffer */
7153 mi2w = (LPMONITOR_INFO_2W) bufferW;
7154 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7155 index = 0;
7156 /* Second Pass: Fill the User Buffer (if we have one) */
7157 while ((index < numentries) && pMonitors) {
7158 index++;
7159 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7160 mi2a->pName = ptr;
7161 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7162 ptr, cbBuf , NULL, NULL);
7163 ptr += len;
7164 cbBuf -= len;
7165 if (Level > 1) {
7166 mi2a->pEnvironment = ptr;
7167 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7168 ptr, cbBuf, NULL, NULL);
7169 ptr += len;
7170 cbBuf -= len;
7172 mi2a->pDLLName = ptr;
7173 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7174 ptr, cbBuf, NULL, NULL);
7175 ptr += len;
7176 cbBuf -= len;
7178 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7179 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7180 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7183 emA_cleanup:
7184 if (pcbNeeded) *pcbNeeded = needed;
7185 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7187 HeapFree(GetProcessHeap(), 0, nameW);
7188 HeapFree(GetProcessHeap(), 0, bufferW);
7190 TRACE("returning %d with %d (%d byte for %d entries)\n",
7191 (res), GetLastError(), needed, numentries);
7193 return (res);
7197 /*****************************************************************************
7198 * EnumMonitorsW [WINSPOOL.@]
7200 * Enumerate available Port-Monitors
7202 * PARAMS
7203 * pName [I] Servername or NULL (local Computer)
7204 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7205 * pMonitors [O] PTR to Buffer that receives the Result
7206 * cbBuf [I] Size of Buffer at pMonitors
7207 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7208 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7210 * RETURNS
7211 * Success: TRUE
7212 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7214 * NOTES
7215 * Windows reads the Registry once and cache the Results.
7217 *| Language-Monitors are also installed in the same Registry-Location but
7218 *| they are filtered in Windows (not returned by EnumMonitors).
7219 *| We do no filtering to simplify our Code.
7222 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7223 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7225 DWORD needed = 0;
7226 DWORD numentries = 0;
7227 BOOL res = FALSE;
7229 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7230 cbBuf, pcbNeeded, pcReturned);
7232 if (pName && (lstrlenW(pName))) {
7233 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7234 SetLastError(ERROR_ACCESS_DENIED);
7235 goto emW_cleanup;
7238 /* Level is not checked in win9x */
7239 if (!Level || (Level > 2)) {
7240 WARN("level (%d) is ignored in win9x\n", Level);
7241 SetLastError(ERROR_INVALID_LEVEL);
7242 goto emW_cleanup;
7244 if (!pcbNeeded) {
7245 SetLastError(RPC_X_NULL_REF_POINTER);
7246 goto emW_cleanup;
7249 /* Scan all Monitor-Keys */
7250 numentries = 0;
7251 needed = get_local_monitors(Level, NULL, 0, &numentries);
7253 /* we calculated the needed buffersize. now do the error-checks */
7254 if (cbBuf < needed) {
7255 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7256 goto emW_cleanup;
7258 else if (!pMonitors || !pcReturned) {
7259 SetLastError(RPC_X_NULL_REF_POINTER);
7260 goto emW_cleanup;
7263 /* fill the Buffer with the Monitor-Keys */
7264 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7265 res = TRUE;
7267 emW_cleanup:
7268 if (pcbNeeded) *pcbNeeded = needed;
7269 if (pcReturned) *pcReturned = numentries;
7271 TRACE("returning %d with %d (%d byte for %d entries)\n",
7272 res, GetLastError(), needed, numentries);
7274 return (res);
7277 /******************************************************************************
7278 * XcvDataW (WINSPOOL.@)
7280 * Execute commands in the Printmonitor DLL
7282 * PARAMS
7283 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7284 * pszDataName [i] Name of the command to execute
7285 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7286 * cbInputData [i] Size in Bytes of Buffer at pInputData
7287 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7288 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7289 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7290 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7292 * RETURNS
7293 * Success: TRUE
7294 * Failure: FALSE
7296 * NOTES
7297 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7298 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7300 * Minimal List of commands, that a Printmonitor DLL should support:
7302 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7303 *| "AddPort" : Add a Port
7304 *| "DeletePort": Delete a Port
7306 * Many Printmonitors support additional commands. Examples for localspl.dll:
7307 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7308 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7311 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7312 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7313 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7315 opened_printer_t *printer;
7317 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7318 pInputData, cbInputData, pOutputData,
7319 cbOutputData, pcbOutputNeeded, pdwStatus);
7321 printer = get_opened_printer(hXcv);
7322 if (!printer || (!printer->hXcv)) {
7323 SetLastError(ERROR_INVALID_HANDLE);
7324 return FALSE;
7327 if (!pcbOutputNeeded) {
7328 SetLastError(ERROR_INVALID_PARAMETER);
7329 return FALSE;
7332 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7333 SetLastError(RPC_X_NULL_REF_POINTER);
7334 return FALSE;
7337 *pcbOutputNeeded = 0;
7339 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7340 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7342 return TRUE;
7345 /*****************************************************************************
7346 * EnumPrinterDataA [WINSPOOL.@]
7349 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7350 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7351 DWORD cbData, LPDWORD pcbData )
7353 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7354 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7355 return ERROR_NO_MORE_ITEMS;
7358 /*****************************************************************************
7359 * EnumPrinterDataW [WINSPOOL.@]
7362 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7363 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7364 DWORD cbData, LPDWORD pcbData )
7366 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7367 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7368 return ERROR_NO_MORE_ITEMS;
7371 /*****************************************************************************
7372 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7375 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7376 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7377 LPDWORD pcbNeeded, LPDWORD pcReturned)
7379 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7380 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7381 pcbNeeded, pcReturned);
7382 return FALSE;
7385 /*****************************************************************************
7386 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7389 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7390 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7391 LPDWORD pcbNeeded, LPDWORD pcReturned)
7393 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7394 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7395 pcbNeeded, pcReturned);
7396 return FALSE;
7399 /*****************************************************************************
7400 * EnumPrintProcessorsA [WINSPOOL.@]
7403 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7404 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7406 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7407 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7408 return FALSE;
7411 /*****************************************************************************
7412 * EnumPrintProcessorsW [WINSPOOL.@]
7415 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7416 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7418 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7419 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7420 cbBuf, pcbNeeded, pcbReturned);
7421 return FALSE;
7424 /*****************************************************************************
7425 * ExtDeviceMode [WINSPOOL.@]
7428 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7429 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7430 DWORD fMode)
7432 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7433 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7434 debugstr_a(pProfile), fMode);
7435 return -1;
7438 /*****************************************************************************
7439 * FindClosePrinterChangeNotification [WINSPOOL.@]
7442 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7444 FIXME("Stub: %p\n", hChange);
7445 return TRUE;
7448 /*****************************************************************************
7449 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7452 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7453 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7455 FIXME("Stub: %p %x %x %p\n",
7456 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7457 return INVALID_HANDLE_VALUE;
7460 /*****************************************************************************
7461 * FindNextPrinterChangeNotification [WINSPOOL.@]
7464 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7465 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7467 FIXME("Stub: %p %p %p %p\n",
7468 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7469 return FALSE;
7472 /*****************************************************************************
7473 * FreePrinterNotifyInfo [WINSPOOL.@]
7476 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7478 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7479 return TRUE;
7482 /*****************************************************************************
7483 * string_to_buf
7485 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7486 * ansi depending on the unicode parameter.
7488 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7490 if(!str)
7492 *size = 0;
7493 return TRUE;
7496 if(unicode)
7498 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7499 if(*size <= cb)
7501 memcpy(ptr, str, *size);
7502 return TRUE;
7504 return FALSE;
7506 else
7508 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7509 if(*size <= cb)
7511 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7512 return TRUE;
7514 return FALSE;
7518 /*****************************************************************************
7519 * get_job_info_1
7521 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7522 LPDWORD pcbNeeded, BOOL unicode)
7524 DWORD size, left = cbBuf;
7525 BOOL space = (cbBuf > 0);
7526 LPBYTE ptr = buf;
7528 *pcbNeeded = 0;
7530 if(space)
7532 ji1->JobId = job->job_id;
7535 string_to_buf(job->document_title, ptr, left, &size, unicode);
7536 if(space && size <= left)
7538 ji1->pDocument = (LPWSTR)ptr;
7539 ptr += size;
7540 left -= size;
7542 else
7543 space = FALSE;
7544 *pcbNeeded += size;
7546 return space;
7549 /*****************************************************************************
7550 * get_job_info_2
7552 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7553 LPDWORD pcbNeeded, BOOL unicode)
7555 DWORD size, left = cbBuf;
7556 BOOL space = (cbBuf > 0);
7557 LPBYTE ptr = buf;
7559 *pcbNeeded = 0;
7561 if(space)
7563 ji2->JobId = job->job_id;
7566 string_to_buf(job->document_title, ptr, left, &size, unicode);
7567 if(space && size <= left)
7569 ji2->pDocument = (LPWSTR)ptr;
7570 ptr += size;
7571 left -= size;
7573 else
7574 space = FALSE;
7575 *pcbNeeded += size;
7577 return space;
7580 /*****************************************************************************
7581 * get_job_info
7583 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7584 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7586 BOOL ret = FALSE;
7587 DWORD needed = 0, size;
7588 job_t *job;
7589 LPBYTE ptr = pJob;
7591 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7593 EnterCriticalSection(&printer_handles_cs);
7594 job = get_job(hPrinter, JobId);
7595 if(!job)
7596 goto end;
7598 switch(Level)
7600 case 1:
7601 size = sizeof(JOB_INFO_1W);
7602 if(cbBuf >= size)
7604 cbBuf -= size;
7605 ptr += size;
7606 memset(pJob, 0, size);
7608 else
7609 cbBuf = 0;
7610 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7611 needed += size;
7612 break;
7614 case 2:
7615 size = sizeof(JOB_INFO_2W);
7616 if(cbBuf >= size)
7618 cbBuf -= size;
7619 ptr += size;
7620 memset(pJob, 0, size);
7622 else
7623 cbBuf = 0;
7624 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7625 needed += size;
7626 break;
7628 case 3:
7629 size = sizeof(JOB_INFO_3);
7630 if(cbBuf >= size)
7632 cbBuf -= size;
7633 memset(pJob, 0, size);
7634 ret = TRUE;
7636 else
7637 cbBuf = 0;
7638 needed = size;
7639 break;
7641 default:
7642 SetLastError(ERROR_INVALID_LEVEL);
7643 goto end;
7645 if(pcbNeeded)
7646 *pcbNeeded = needed;
7647 end:
7648 LeaveCriticalSection(&printer_handles_cs);
7649 return ret;
7652 /*****************************************************************************
7653 * GetJobA [WINSPOOL.@]
7656 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7657 DWORD cbBuf, LPDWORD pcbNeeded)
7659 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7662 /*****************************************************************************
7663 * GetJobW [WINSPOOL.@]
7666 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7667 DWORD cbBuf, LPDWORD pcbNeeded)
7669 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7672 /*****************************************************************************
7673 * schedule_lpr
7675 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7677 char *unixname, *queue, *cmd;
7678 char fmt[] = "lpr -P%s %s";
7679 DWORD len;
7681 if(!(unixname = wine_get_unix_file_name(filename)))
7682 return FALSE;
7684 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7685 queue = HeapAlloc(GetProcessHeap(), 0, len);
7686 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7688 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7689 sprintf(cmd, fmt, queue, unixname);
7691 TRACE("printing with: %s\n", cmd);
7692 system(cmd);
7694 HeapFree(GetProcessHeap(), 0, cmd);
7695 HeapFree(GetProcessHeap(), 0, queue);
7696 HeapFree(GetProcessHeap(), 0, unixname);
7697 return TRUE;
7700 /*****************************************************************************
7701 * schedule_cups
7703 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7705 #ifdef SONAME_LIBCUPS
7706 if(pcupsPrintFile)
7708 char *unixname, *queue, *doc_titleA;
7709 DWORD len;
7710 BOOL ret;
7712 if(!(unixname = wine_get_unix_file_name(filename)))
7713 return FALSE;
7715 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7716 queue = HeapAlloc(GetProcessHeap(), 0, len);
7717 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7719 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7720 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7721 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7723 TRACE("printing via cups\n");
7724 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7725 HeapFree(GetProcessHeap(), 0, doc_titleA);
7726 HeapFree(GetProcessHeap(), 0, queue);
7727 HeapFree(GetProcessHeap(), 0, unixname);
7728 return ret;
7730 else
7731 #endif
7733 return schedule_lpr(printer_name, filename);
7737 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7739 LPWSTR filename;
7741 switch(msg)
7743 case WM_INITDIALOG:
7744 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7745 return TRUE;
7747 case WM_COMMAND:
7748 if(HIWORD(wparam) == BN_CLICKED)
7750 if(LOWORD(wparam) == IDOK)
7752 HANDLE hf;
7753 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7754 LPWSTR *output;
7756 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7757 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7759 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7761 WCHAR caption[200], message[200];
7762 int mb_ret;
7764 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7765 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7766 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7767 if(mb_ret == IDCANCEL)
7769 HeapFree(GetProcessHeap(), 0, filename);
7770 return TRUE;
7773 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7774 if(hf == INVALID_HANDLE_VALUE)
7776 WCHAR caption[200], message[200];
7778 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7779 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7780 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7781 HeapFree(GetProcessHeap(), 0, filename);
7782 return TRUE;
7784 CloseHandle(hf);
7785 DeleteFileW(filename);
7786 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7787 *output = filename;
7788 EndDialog(hwnd, IDOK);
7789 return TRUE;
7791 if(LOWORD(wparam) == IDCANCEL)
7793 EndDialog(hwnd, IDCANCEL);
7794 return TRUE;
7797 return FALSE;
7799 return FALSE;
7802 /*****************************************************************************
7803 * get_filename
7805 static BOOL get_filename(LPWSTR *filename)
7807 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7808 file_dlg_proc, (LPARAM)filename) == IDOK;
7811 /*****************************************************************************
7812 * schedule_file
7814 static BOOL schedule_file(LPCWSTR filename)
7816 LPWSTR output = NULL;
7818 if(get_filename(&output))
7820 TRACE("copy to %s\n", debugstr_w(output));
7821 CopyFileW(filename, output, FALSE);
7822 HeapFree(GetProcessHeap(), 0, output);
7823 return TRUE;
7825 return FALSE;
7828 /*****************************************************************************
7829 * schedule_pipe
7831 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7833 #ifdef HAVE_FORK
7834 char *unixname, *cmdA;
7835 DWORD len;
7836 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7837 BOOL ret = FALSE;
7838 char buf[1024];
7840 if(!(unixname = wine_get_unix_file_name(filename)))
7841 return FALSE;
7843 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7844 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7845 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7847 TRACE("printing with: %s\n", cmdA);
7849 if((file_fd = open(unixname, O_RDONLY)) == -1)
7850 goto end;
7852 if (pipe(fds))
7854 ERR("pipe() failed!\n");
7855 goto end;
7858 if (fork() == 0)
7860 close(0);
7861 dup2(fds[0], 0);
7862 close(fds[1]);
7864 /* reset signals that we previously set to SIG_IGN */
7865 signal(SIGPIPE, SIG_DFL);
7866 signal(SIGCHLD, SIG_DFL);
7868 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7869 _exit(1);
7872 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7873 write(fds[1], buf, no_read);
7875 ret = TRUE;
7877 end:
7878 if(file_fd != -1) close(file_fd);
7879 if(fds[0] != -1) close(fds[0]);
7880 if(fds[1] != -1) close(fds[1]);
7882 HeapFree(GetProcessHeap(), 0, cmdA);
7883 HeapFree(GetProcessHeap(), 0, unixname);
7884 return ret;
7885 #else
7886 return FALSE;
7887 #endif
7890 /*****************************************************************************
7891 * schedule_unixfile
7893 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7895 int in_fd, out_fd, no_read;
7896 char buf[1024];
7897 BOOL ret = FALSE;
7898 char *unixname, *outputA;
7899 DWORD len;
7901 if(!(unixname = wine_get_unix_file_name(filename)))
7902 return FALSE;
7904 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7905 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7906 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7908 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7909 in_fd = open(unixname, O_RDONLY);
7910 if(out_fd == -1 || in_fd == -1)
7911 goto end;
7913 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7914 write(out_fd, buf, no_read);
7916 ret = TRUE;
7917 end:
7918 if(in_fd != -1) close(in_fd);
7919 if(out_fd != -1) close(out_fd);
7920 HeapFree(GetProcessHeap(), 0, outputA);
7921 HeapFree(GetProcessHeap(), 0, unixname);
7922 return ret;
7925 /*****************************************************************************
7926 * ScheduleJob [WINSPOOL.@]
7929 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7931 opened_printer_t *printer;
7932 BOOL ret = FALSE;
7933 struct list *cursor, *cursor2;
7935 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7936 EnterCriticalSection(&printer_handles_cs);
7937 printer = get_opened_printer(hPrinter);
7938 if(!printer)
7939 goto end;
7941 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7943 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7944 HANDLE hf;
7946 if(job->job_id != dwJobID) continue;
7948 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7949 if(hf != INVALID_HANDLE_VALUE)
7951 PRINTER_INFO_5W *pi5;
7952 DWORD needed;
7953 HKEY hkey;
7954 WCHAR output[1024];
7955 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7956 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7958 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7959 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7960 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7961 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7962 debugstr_w(pi5->pPortName));
7964 output[0] = 0;
7966 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7967 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7969 DWORD type, count = sizeof(output);
7970 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7971 RegCloseKey(hkey);
7973 if(output[0] == '|')
7975 schedule_pipe(output + 1, job->filename);
7977 else if(output[0])
7979 schedule_unixfile(output, job->filename);
7981 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7983 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7985 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7987 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7989 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7991 schedule_file(job->filename);
7993 else
7995 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7997 HeapFree(GetProcessHeap(), 0, pi5);
7998 CloseHandle(hf);
7999 DeleteFileW(job->filename);
8001 list_remove(cursor);
8002 HeapFree(GetProcessHeap(), 0, job->document_title);
8003 HeapFree(GetProcessHeap(), 0, job->filename);
8004 HeapFree(GetProcessHeap(), 0, job);
8005 ret = TRUE;
8006 break;
8008 end:
8009 LeaveCriticalSection(&printer_handles_cs);
8010 return ret;
8013 /*****************************************************************************
8014 * StartDocDlgA [WINSPOOL.@]
8016 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8018 UNICODE_STRING usBuffer;
8019 DOCINFOW docW;
8020 LPWSTR retW;
8021 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8022 LPSTR ret = NULL;
8024 docW.cbSize = sizeof(docW);
8025 if (doc->lpszDocName)
8027 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8028 if (!(docW.lpszDocName = docnameW)) return NULL;
8030 if (doc->lpszOutput)
8032 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8033 if (!(docW.lpszOutput = outputW)) return NULL;
8035 if (doc->lpszDatatype)
8037 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8038 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8040 docW.fwType = doc->fwType;
8042 retW = StartDocDlgW(hPrinter, &docW);
8044 if(retW)
8046 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8047 ret = HeapAlloc(GetProcessHeap(), 0, len);
8048 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8049 HeapFree(GetProcessHeap(), 0, retW);
8052 HeapFree(GetProcessHeap(), 0, datatypeW);
8053 HeapFree(GetProcessHeap(), 0, outputW);
8054 HeapFree(GetProcessHeap(), 0, docnameW);
8056 return ret;
8059 /*****************************************************************************
8060 * StartDocDlgW [WINSPOOL.@]
8062 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8063 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8064 * port is "FILE:". Also returns the full path if passed a relative path.
8066 * The caller should free the returned string from the process heap.
8068 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8070 LPWSTR ret = NULL;
8071 DWORD len, attr;
8073 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8075 PRINTER_INFO_5W *pi5;
8076 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8077 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8078 return NULL;
8079 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8080 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8081 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8083 HeapFree(GetProcessHeap(), 0, pi5);
8084 return NULL;
8086 HeapFree(GetProcessHeap(), 0, pi5);
8089 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8091 LPWSTR name;
8093 if (get_filename(&name))
8095 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8097 HeapFree(GetProcessHeap(), 0, name);
8098 return NULL;
8100 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8101 GetFullPathNameW(name, len, ret, NULL);
8102 HeapFree(GetProcessHeap(), 0, name);
8104 return ret;
8107 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8108 return NULL;
8110 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8111 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8113 attr = GetFileAttributesW(ret);
8114 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8116 HeapFree(GetProcessHeap(), 0, ret);
8117 ret = NULL;
8119 return ret;