winspool: Forward EnumPrintersA to EnumPrintersW.
[wine/wine64.git] / dlls / winspool.drv / info.c
blobdadc61ff92bd7b0c7f0ea79499e462f6a1ba3da6
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-2008 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 struct list entry;
90 LPWSTR name;
91 LPWSTR dllname;
92 PMONITORUI monitorUI;
93 LPMONITOR monitor;
94 HMODULE hdll;
95 DWORD refcount;
96 DWORD dwMonitorSize;
97 } monitor_t;
99 typedef struct {
100 DWORD job_id;
101 HANDLE hf;
102 } started_doc_t;
104 typedef struct {
105 struct list jobs;
106 LONG ref;
107 } jobqueue_t;
109 typedef struct {
110 LPWSTR name;
111 LPWSTR printername;
112 monitor_t *pm;
113 HANDLE hXcv;
114 jobqueue_t *queue;
115 started_doc_t *doc;
116 } opened_printer_t;
118 typedef struct {
119 struct list entry;
120 DWORD job_id;
121 WCHAR *filename;
122 WCHAR *document_title;
123 } job_t;
126 typedef struct {
127 LPCWSTR envname;
128 LPCWSTR subdir;
129 DWORD driverversion;
130 LPCWSTR versionregpath;
131 LPCWSTR versionsubdir;
132 } printenv_t;
134 /* ############################### */
136 static struct list monitor_handles = LIST_INIT( monitor_handles );
137 static monitor_t * pm_localport;
139 static opened_printer_t **printer_handles;
140 static UINT nb_printer_handles;
141 static LONG next_job_id = 1;
143 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
144 WORD fwCapability, LPSTR lpszOutput,
145 LPDEVMODEA lpdm );
146 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
147 LPSTR lpszDevice, LPSTR lpszPort,
148 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
149 DWORD fwMode );
151 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
152 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
153 'c','o','n','t','r','o','l','\\',
154 'P','r','i','n','t','\\',
155 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
156 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
158 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
159 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
160 'C','o','n','t','r','o','l','\\',
161 'P','r','i','n','t','\\',
162 'M','o','n','i','t','o','r','s','\\',0};
164 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
165 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
166 'C','o','n','t','r','o','l','\\',
167 'P','r','i','n','t','\\',
168 'P','r','i','n','t','e','r','s',0};
170 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
172 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
173 'M','i','c','r','o','s','o','f','t','\\',
174 'W','i','n','d','o','w','s',' ','N','T','\\',
175 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
176 'W','i','n','d','o','w','s',0};
178 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
179 'M','i','c','r','o','s','o','f','t','\\',
180 'W','i','n','d','o','w','s',' ','N','T','\\',
181 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
182 'D','e','v','i','c','e','s',0};
184 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
185 'M','i','c','r','o','s','o','f','t','\\',
186 'W','i','n','d','o','w','s',' ','N','T','\\',
187 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
188 'P','o','r','t','s',0};
190 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
191 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
192 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
193 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
194 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
195 static const WCHAR Version0_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
196 static const WCHAR Version0_SubdirW[] = {'\\','0',0};
197 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
198 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
200 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
201 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
203 static const WCHAR backslashW[] = {'\\',0};
204 static const WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
205 'i','o','n',' ','F','i','l','e',0};
206 static const WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
207 static const WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
208 static const WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
209 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
210 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
211 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
212 static const WCHAR HardwareIDW[] = {'H','a','r','d','w','a','r','e','I','D',0};
213 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
214 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
215 static const WCHAR ManufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
216 static const WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
217 static const WCHAR MonitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
218 static const WCHAR NameW[] = {'N','a','m','e',0};
219 static const WCHAR ObjectGUIDW[] = {'O','b','j','e','c','t','G','U','I','D',0};
220 static const WCHAR OEM_UrlW[] = {'O','E','M',' ','U','r','l',0};
221 static const WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
222 static const WCHAR PortW[] = {'P','o','r','t',0};
223 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
224 static const WCHAR Previous_NamesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
225 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
226 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
227 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
228 static const WCHAR ProviderW[] = {'P','r','o','v','i','d','e','r',0};
229 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
230 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0};
232 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
233 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
234 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
235 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
236 static const WCHAR emptyStringW[] = {0};
237 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
238 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
240 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
242 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
243 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
244 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
246 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
247 'D','o','c','u','m','e','n','t',0};
249 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
250 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
251 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
252 0, sizeof(DRIVER_INFO_8W)};
255 static const DWORD pi_sizeof[] = {0, sizeof(PRINTER_INFO_1W), sizeof(PRINTER_INFO_2W),
256 sizeof(PRINTER_INFO_3), sizeof(PRINTER_INFO_4W),
257 sizeof(PRINTER_INFO_5W), sizeof(PRINTER_INFO_6),
258 sizeof(PRINTER_INFO_7W), sizeof(PRINTER_INFO_8W),
259 sizeof(PRINTER_INFO_9W)};
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 * Return the number of bytes for an multi_sz string.
357 * The result includes all \0s
358 * (specifically the extra \0, that is needed as multi_sz terminator).
360 #if 0
361 static int multi_sz_lenW(const WCHAR *str)
363 const WCHAR *ptr = str;
364 if(!str) return 0;
367 ptr += lstrlenW(ptr) + 1;
368 } while(*ptr);
370 return (ptr - str + 1) * sizeof(WCHAR);
372 #endif
373 /* ################################ */
375 static int multi_sz_lenA(const char *str)
377 const char *ptr = str;
378 if(!str) return 0;
381 ptr += lstrlenA(ptr) + 1;
382 } while(*ptr);
384 return ptr - str + 1;
387 static void
388 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
389 char qbuf[200];
391 /* If forcing, or no profile string entry for device yet, set the entry
393 * The always change entry if not WINEPS yet is discussable.
395 if (force ||
396 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
397 !strcmp(qbuf,"*") ||
398 !strstr(qbuf,"WINEPS.DRV")
400 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
401 HKEY hkey;
403 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
404 WriteProfileStringA("windows","device",buf);
405 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
406 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
407 RegCloseKey(hkey);
409 HeapFree(GetProcessHeap(),0,buf);
413 static BOOL add_printer_driver(const char *name)
415 DRIVER_INFO_3A di3a;
417 static char driver_9x[] = "wineps16.drv",
418 driver_nt[] = "wineps.drv",
419 env_9x[] = "Windows 4.0",
420 env_nt[] = "Windows NT x86",
421 data_file[] = "generic.ppd",
422 default_data_type[] = "RAW";
424 ZeroMemory(&di3a, sizeof(DRIVER_INFO_3A));
425 di3a.cVersion = 3;
426 di3a.pName = (char *)name;
427 di3a.pEnvironment = env_nt;
428 di3a.pDriverPath = driver_nt;
429 di3a.pDataFile = data_file;
430 di3a.pConfigFile = driver_nt;
431 di3a.pDefaultDataType = default_data_type;
433 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
434 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
436 di3a.cVersion = 0;
437 di3a.pEnvironment = env_9x;
438 di3a.pDriverPath = driver_9x;
439 di3a.pConfigFile = driver_9x;
440 if (AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a) ||
441 (GetLastError() == ERROR_PRINTER_DRIVER_ALREADY_INSTALLED ))
443 return TRUE;
446 ERR("Failed adding driver %s (%s): %u\n", debugstr_a(di3a.pDriverPath),
447 debugstr_a(di3a.pEnvironment), GetLastError());
448 return FALSE;
451 #ifdef SONAME_LIBCUPS
452 static typeof(cupsGetDests) *pcupsGetDests;
453 static typeof(cupsGetPPD) *pcupsGetPPD;
454 static typeof(cupsPrintFile) *pcupsPrintFile;
455 static void *cupshandle;
457 static BOOL CUPS_LoadPrinters(void)
459 int i, nrofdests;
460 BOOL hadprinter = FALSE, haddefault = FALSE;
461 cups_dest_t *dests;
462 PRINTER_INFO_2A pinfo2a;
463 char *port,*devline;
464 HKEY hkeyPrinter, hkeyPrinters, hkey;
465 char loaderror[256];
467 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, loaderror, sizeof(loaderror));
468 if (!cupshandle) {
469 TRACE("%s\n", loaderror);
470 return FALSE;
472 TRACE("%p: %s loaded\n", cupshandle, SONAME_LIBCUPS);
474 #define DYNCUPS(x) \
475 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
476 if (!p##x) return FALSE;
478 DYNCUPS(cupsGetPPD);
479 DYNCUPS(cupsGetDests);
480 DYNCUPS(cupsPrintFile);
481 #undef DYNCUPS
483 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
484 ERROR_SUCCESS) {
485 ERR("Can't create Printers key\n");
486 return FALSE;
489 nrofdests = pcupsGetDests(&dests);
490 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
491 for (i=0;i<nrofdests;i++) {
492 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
493 sprintf(port,"LPR:%s",dests[i].name);
494 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
495 sprintf(devline,"WINEPS.DRV,%s",port);
496 WriteProfileStringA("devices",dests[i].name,devline);
497 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
498 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
499 RegCloseKey(hkey);
501 HeapFree(GetProcessHeap(),0,devline);
503 TRACE("Printer %d: %s\n", i, dests[i].name);
504 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
505 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
506 and continue */
507 TRACE("Printer already exists\n");
508 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
509 RegCloseKey(hkeyPrinter);
510 } else {
511 static CHAR data_type[] = "RAW",
512 print_proc[] = "WinPrint",
513 comment[] = "WINEPS Printer using CUPS",
514 location[] = "<physical location of printer>",
515 params[] = "<parameters?>",
516 share_name[] = "<share name?>",
517 sep_file[] = "<sep file?>";
519 add_printer_driver(dests[i].name);
521 memset(&pinfo2a,0,sizeof(pinfo2a));
522 pinfo2a.pPrinterName = dests[i].name;
523 pinfo2a.pDatatype = data_type;
524 pinfo2a.pPrintProcessor = print_proc;
525 pinfo2a.pDriverName = dests[i].name;
526 pinfo2a.pComment = comment;
527 pinfo2a.pLocation = location;
528 pinfo2a.pPortName = port;
529 pinfo2a.pParameters = params;
530 pinfo2a.pShareName = share_name;
531 pinfo2a.pSepFile = sep_file;
533 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
534 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
535 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
538 HeapFree(GetProcessHeap(),0,port);
540 hadprinter = TRUE;
541 if (dests[i].is_default) {
542 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
543 haddefault = TRUE;
546 if (hadprinter & !haddefault)
547 WINSPOOL_SetDefaultPrinter(dests[0].name, dests[0].name, TRUE);
548 RegCloseKey(hkeyPrinters);
549 return hadprinter;
551 #endif
553 static BOOL
554 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
555 PRINTER_INFO_2A pinfo2a;
556 char *e,*s,*name,*prettyname,*devname;
557 BOOL ret = FALSE, set_default = FALSE;
558 char *port = NULL, *devline,*env_default;
559 HKEY hkeyPrinter, hkeyPrinters, hkey;
561 while (isspace(*pent)) pent++;
562 s = strchr(pent,':');
563 if(s) *s='\0';
564 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
565 strcpy(name,pent);
566 if(s) {
567 *s=':';
568 pent = s;
569 } else
570 pent = "";
572 TRACE("name=%s entry=%s\n",name, pent);
574 if(ispunct(*name)) { /* a tc entry, not a real printer */
575 TRACE("skipping tc entry\n");
576 goto end;
579 if(strstr(pent,":server")) { /* server only version so skip */
580 TRACE("skipping server entry\n");
581 goto end;
584 /* Determine whether this is a postscript printer. */
586 ret = TRUE;
587 env_default = getenv("PRINTER");
588 prettyname = name;
589 /* Get longest name, usually the one at the right for later display. */
590 while((s=strchr(prettyname,'|'))) {
591 *s = '\0';
592 e = s;
593 while(isspace(*--e)) *e = '\0';
594 TRACE("\t%s\n", debugstr_a(prettyname));
595 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
596 for(prettyname = s+1; isspace(*prettyname); prettyname++)
599 e = prettyname + strlen(prettyname);
600 while(isspace(*--e)) *e = '\0';
601 TRACE("\t%s\n", debugstr_a(prettyname));
602 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
604 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
605 * if it is too long, we use it as comment below. */
606 devname = prettyname;
607 if (strlen(devname)>=CCHDEVICENAME-1)
608 devname = name;
609 if (strlen(devname)>=CCHDEVICENAME-1) {
610 ret = FALSE;
611 goto end;
614 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
615 sprintf(port,"LPR:%s",name);
617 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
618 sprintf(devline,"WINEPS.DRV,%s",port);
619 WriteProfileStringA("devices",devname,devline);
620 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
621 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
622 RegCloseKey(hkey);
624 HeapFree(GetProcessHeap(),0,devline);
626 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
627 ERROR_SUCCESS) {
628 ERR("Can't create Printers key\n");
629 ret = FALSE;
630 goto end;
632 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
633 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
634 and continue */
635 TRACE("Printer already exists\n");
636 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
637 RegCloseKey(hkeyPrinter);
638 } else {
639 static CHAR data_type[] = "RAW",
640 print_proc[] = "WinPrint",
641 comment[] = "WINEPS Printer using LPR",
642 params[] = "<parameters?>",
643 share_name[] = "<share name?>",
644 sep_file[] = "<sep file?>";
646 add_printer_driver(devname);
648 memset(&pinfo2a,0,sizeof(pinfo2a));
649 pinfo2a.pPrinterName = devname;
650 pinfo2a.pDatatype = data_type;
651 pinfo2a.pPrintProcessor = print_proc;
652 pinfo2a.pDriverName = devname;
653 pinfo2a.pComment = comment;
654 pinfo2a.pLocation = prettyname;
655 pinfo2a.pPortName = port;
656 pinfo2a.pParameters = params;
657 pinfo2a.pShareName = share_name;
658 pinfo2a.pSepFile = sep_file;
660 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
661 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
662 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
665 RegCloseKey(hkeyPrinters);
667 if (isfirst || set_default)
668 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
670 end:
671 HeapFree(GetProcessHeap(), 0, port);
672 HeapFree(GetProcessHeap(), 0, name);
673 return ret;
676 static BOOL
677 PRINTCAP_LoadPrinters(void) {
678 BOOL hadprinter = FALSE;
679 char buf[200];
680 FILE *f;
681 char *pent = NULL;
682 BOOL had_bash = FALSE;
684 f = fopen("/etc/printcap","r");
685 if (!f)
686 return FALSE;
688 while(fgets(buf,sizeof(buf),f)) {
689 char *start, *end;
691 end=strchr(buf,'\n');
692 if (end) *end='\0';
694 start = buf;
695 while(isspace(*start)) start++;
696 if(*start == '#' || *start == '\0')
697 continue;
699 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
700 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
701 HeapFree(GetProcessHeap(),0,pent);
702 pent = NULL;
705 if (end && *--end == '\\') {
706 *end = '\0';
707 had_bash = TRUE;
708 } else
709 had_bash = FALSE;
711 if (pent) {
712 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
713 strcat(pent,start);
714 } else {
715 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
716 strcpy(pent,start);
720 if(pent) {
721 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
722 HeapFree(GetProcessHeap(),0,pent);
724 fclose(f);
725 return hadprinter;
728 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
730 if (value)
731 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
732 (lstrlenW(value) + 1) * sizeof(WCHAR));
733 else
734 return ERROR_FILE_NOT_FOUND;
737 /*****************************************************************************
738 * enumerate the local monitors (INTERNAL)
740 * returns the needed size (in bytes) for pMonitors
741 * and *lpreturned is set to number of entries returned in pMonitors
744 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
746 HKEY hroot = NULL;
747 HKEY hentry = NULL;
748 LPWSTR ptr;
749 LPMONITOR_INFO_2W mi;
750 WCHAR buffer[MAX_PATH];
751 WCHAR dllname[MAX_PATH];
752 DWORD dllsize;
753 DWORD len;
754 DWORD index = 0;
755 DWORD needed = 0;
756 DWORD numentries;
757 DWORD entrysize;
759 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
761 numentries = *lpreturned; /* this is 0, when we scan the registry */
762 len = entrysize * numentries;
763 ptr = (LPWSTR) &pMonitors[len];
765 numentries = 0;
766 len = sizeof(buffer)/sizeof(buffer[0]);
767 buffer[0] = '\0';
769 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
770 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
771 /* Scan all Monitor-Registry-Keys */
772 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
773 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
774 dllsize = sizeof(dllname);
775 dllname[0] = '\0';
777 /* The Monitor must have a Driver-DLL */
778 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
779 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
780 /* We found a valid DLL for this Monitor. */
781 TRACE("using Driver: %s\n", debugstr_w(dllname));
783 RegCloseKey(hentry);
786 /* Windows returns only Port-Monitors here, but to simplify our code,
787 we do no filtering for Language-Monitors */
788 if (dllname[0]) {
789 numentries++;
790 needed += entrysize;
791 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
792 if (level > 1) {
793 /* we install and return only monitors for "Windows NT x86" */
794 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
795 needed += dllsize;
798 /* required size is calculated. Now fill the user-buffer */
799 if (pMonitors && (cbBuf >= needed)){
800 mi = (LPMONITOR_INFO_2W) pMonitors;
801 pMonitors += entrysize;
803 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
804 mi->pName = ptr;
805 lstrcpyW(ptr, buffer); /* Name of the Monitor */
806 ptr += (len+1); /* len is lstrlenW(monitorname) */
807 if (level > 1) {
808 mi->pEnvironment = ptr;
809 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
810 ptr += (lstrlenW(envname_x86W)+1);
812 mi->pDLLName = ptr;
813 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
814 ptr += (dllsize / sizeof(WCHAR));
818 index++;
819 len = sizeof(buffer)/sizeof(buffer[0]);
820 buffer[0] = '\0';
822 RegCloseKey(hroot);
824 *lpreturned = numentries;
825 TRACE("need %d byte for %d entries\n", needed, numentries);
826 return needed;
829 /******************************************************************
830 * monitor_unload [internal]
832 * release a printmonitor and unload it from memory, when needed
835 static void monitor_unload(monitor_t * pm)
837 if (pm == NULL) return;
838 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
840 EnterCriticalSection(&monitor_handles_cs);
842 if (pm->refcount) pm->refcount--;
844 if (pm->refcount == 0) {
845 list_remove(&pm->entry);
846 FreeLibrary(pm->hdll);
847 HeapFree(GetProcessHeap(), 0, pm->name);
848 HeapFree(GetProcessHeap(), 0, pm->dllname);
849 HeapFree(GetProcessHeap(), 0, pm);
851 LeaveCriticalSection(&monitor_handles_cs);
854 /******************************************************************
855 * monitor_unloadall [internal]
857 * release all printmonitors and unload them from memory, when needed
860 static void monitor_unloadall(void)
862 monitor_t * pm;
863 monitor_t * next;
865 EnterCriticalSection(&monitor_handles_cs);
866 /* iterate through the list, with safety against removal */
867 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
869 monitor_unload(pm);
871 LeaveCriticalSection(&monitor_handles_cs);
874 /******************************************************************
875 * monitor_load [internal]
877 * load a printmonitor, get the dllname from the registry, when needed
878 * initialize the monitor and dump found function-pointers
880 * On failure, SetLastError() is called and NULL is returned
883 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
885 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
886 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
887 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
888 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
889 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
891 monitor_t * pm = NULL;
892 monitor_t * cursor;
893 LPWSTR regroot = NULL;
894 LPWSTR driver = dllname;
896 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
897 /* Is the Monitor already loaded? */
898 EnterCriticalSection(&monitor_handles_cs);
900 if (name) {
901 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
903 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
904 pm = cursor;
905 break;
910 if (pm == NULL) {
911 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
912 if (pm == NULL) goto cleanup;
913 list_add_tail(&monitor_handles, &pm->entry);
915 pm->refcount++;
917 if (pm->name == NULL) {
918 /* Load the monitor */
919 LPMONITOREX pmonitorEx;
920 DWORD len;
922 if (name) {
923 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
924 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
927 if (regroot) {
928 lstrcpyW(regroot, MonitorsW);
929 lstrcatW(regroot, name);
930 /* Get the Driver from the Registry */
931 if (driver == NULL) {
932 HKEY hroot;
933 DWORD namesize;
934 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
935 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
936 &namesize) == ERROR_SUCCESS) {
937 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
938 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
940 RegCloseKey(hroot);
945 pm->name = strdupW(name);
946 pm->dllname = strdupW(driver);
948 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
949 monitor_unload(pm);
950 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
951 pm = NULL;
952 goto cleanup;
955 pm->hdll = LoadLibraryW(driver);
956 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
958 if (pm->hdll == NULL) {
959 monitor_unload(pm);
960 SetLastError(ERROR_MOD_NOT_FOUND);
961 pm = NULL;
962 goto cleanup;
965 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
966 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
967 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
968 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
969 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
972 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
973 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
974 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
975 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
976 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
978 if (pInitializePrintMonitorUI != NULL) {
979 pm->monitorUI = pInitializePrintMonitorUI();
980 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
981 if (pm->monitorUI) {
982 TRACE( "0x%08x: dwMonitorSize (%d)\n",
983 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
988 if (pInitializePrintMonitor && regroot) {
989 pmonitorEx = pInitializePrintMonitor(regroot);
990 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
991 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
993 if (pmonitorEx) {
994 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
995 pm->monitor = &(pmonitorEx->Monitor);
999 if (pm->monitor) {
1000 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1004 if (!pm->monitor && regroot) {
1005 if (pInitializePrintMonitor2 != NULL) {
1006 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1008 if (pInitializeMonitorEx != NULL) {
1009 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1011 if (pInitializeMonitor != NULL) {
1012 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1015 if (!pm->monitor && !pm->monitorUI) {
1016 monitor_unload(pm);
1017 SetLastError(ERROR_PROC_NOT_FOUND);
1018 pm = NULL;
1021 cleanup:
1022 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1023 pm->refcount++;
1024 pm_localport = pm;
1026 LeaveCriticalSection(&monitor_handles_cs);
1027 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1028 HeapFree(GetProcessHeap(), 0, regroot);
1029 TRACE("=> %p\n", pm);
1030 return pm;
1033 /******************************************************************
1034 * monitor_loadall [internal]
1036 * Load all registered monitors
1039 static DWORD monitor_loadall(void)
1041 monitor_t * pm;
1042 DWORD registered = 0;
1043 DWORD loaded = 0;
1044 HKEY hmonitors;
1045 WCHAR buffer[MAX_PATH];
1046 DWORD id = 0;
1048 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1049 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1050 NULL, NULL, NULL, NULL, NULL);
1052 TRACE("%d monitors registered\n", registered);
1054 EnterCriticalSection(&monitor_handles_cs);
1055 while (id < registered) {
1056 buffer[0] = '\0';
1057 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1058 pm = monitor_load(buffer, NULL);
1059 if (pm) loaded++;
1060 id++;
1062 LeaveCriticalSection(&monitor_handles_cs);
1063 RegCloseKey(hmonitors);
1065 TRACE("%d monitors loaded\n", loaded);
1066 return loaded;
1069 /******************************************************************
1070 * monitor_loadui [internal]
1072 * load the userinterface-dll for a given portmonitor
1074 * On failure, NULL is returned
1077 static monitor_t * monitor_loadui(monitor_t * pm)
1079 monitor_t * pui = NULL;
1080 LPWSTR buffer[MAX_PATH];
1081 HANDLE hXcv;
1082 DWORD len;
1083 DWORD res;
1085 if (pm == NULL) return NULL;
1086 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1088 /* Try the Portmonitor first; works for many monitors */
1089 if (pm->monitorUI) {
1090 EnterCriticalSection(&monitor_handles_cs);
1091 pm->refcount++;
1092 LeaveCriticalSection(&monitor_handles_cs);
1093 return pm;
1096 /* query the userinterface-dllname from the Portmonitor */
1097 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1098 /* building (",XcvMonitor %s",pm->name) not needed yet */
1099 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1100 TRACE("got %u with %p\n", res, hXcv);
1101 if (res) {
1102 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1103 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1104 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1105 pm->monitor->pfnXcvClosePort(hXcv);
1108 return pui;
1112 /******************************************************************
1113 * monitor_load_by_port [internal]
1115 * load a printmonitor for a given port
1117 * On failure, NULL is returned
1120 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1122 HKEY hroot;
1123 HKEY hport;
1124 LPWSTR buffer;
1125 monitor_t * pm = NULL;
1126 DWORD registered = 0;
1127 DWORD id = 0;
1128 DWORD len;
1130 TRACE("(%s)\n", debugstr_w(portname));
1132 /* Try the Local Monitor first */
1133 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1134 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1135 /* found the portname */
1136 RegCloseKey(hroot);
1137 return monitor_load(LocalPortW, NULL);
1139 RegCloseKey(hroot);
1142 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1143 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1144 if (buffer == NULL) return NULL;
1146 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1147 EnterCriticalSection(&monitor_handles_cs);
1148 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1150 while ((pm == NULL) && (id < registered)) {
1151 buffer[0] = '\0';
1152 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1153 TRACE("testing %s\n", debugstr_w(buffer));
1154 len = lstrlenW(buffer);
1155 lstrcatW(buffer, bs_Ports_bsW);
1156 lstrcatW(buffer, portname);
1157 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1158 RegCloseKey(hport);
1159 buffer[len] = '\0'; /* use only the Monitor-Name */
1160 pm = monitor_load(buffer, NULL);
1162 id++;
1164 LeaveCriticalSection(&monitor_handles_cs);
1165 RegCloseKey(hroot);
1167 HeapFree(GetProcessHeap(), 0, buffer);
1168 return pm;
1171 /******************************************************************
1172 * enumerate the local Ports from all loaded monitors (internal)
1174 * returns the needed size (in bytes) for pPorts
1175 * and *lpreturned is set to number of entries returned in pPorts
1178 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1180 monitor_t * pm;
1181 LPWSTR ptr;
1182 LPPORT_INFO_2W cache;
1183 LPPORT_INFO_2W out;
1184 LPBYTE pi_buffer = NULL;
1185 DWORD pi_allocated = 0;
1186 DWORD pi_needed;
1187 DWORD pi_index;
1188 DWORD pi_returned;
1189 DWORD res;
1190 DWORD outindex = 0;
1191 DWORD needed;
1192 DWORD numentries;
1193 DWORD entrysize;
1196 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1197 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1199 numentries = *lpreturned; /* this is 0, when we scan the registry */
1200 needed = entrysize * numentries;
1201 ptr = (LPWSTR) &pPorts[needed];
1203 numentries = 0;
1204 needed = 0;
1206 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1208 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1209 pi_needed = 0;
1210 pi_returned = 0;
1211 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1212 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1213 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1214 HeapFree(GetProcessHeap(), 0, pi_buffer);
1215 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1216 pi_allocated = (pi_buffer) ? pi_needed : 0;
1217 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1219 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1220 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1222 numentries += pi_returned;
1223 needed += pi_needed;
1225 /* fill the output-buffer (pPorts), if we have one */
1226 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1227 pi_index = 0;
1228 while (pi_returned > pi_index) {
1229 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1230 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1231 out->pPortName = ptr;
1232 lstrcpyW(ptr, cache->pPortName);
1233 ptr += (lstrlenW(ptr)+1);
1234 if (level > 1) {
1235 out->pMonitorName = ptr;
1236 lstrcpyW(ptr, cache->pMonitorName);
1237 ptr += (lstrlenW(ptr)+1);
1239 out->pDescription = ptr;
1240 lstrcpyW(ptr, cache->pDescription);
1241 ptr += (lstrlenW(ptr)+1);
1242 out->fPortType = cache->fPortType;
1243 out->Reserved = cache->Reserved;
1245 pi_index++;
1246 outindex++;
1251 /* the temporary portinfo-buffer is no longer needed */
1252 HeapFree(GetProcessHeap(), 0, pi_buffer);
1254 *lpreturned = numentries;
1255 TRACE("need %d byte for %d entries\n", needed, numentries);
1256 return needed;
1259 /******************************************************************
1260 * get_servername_from_name (internal)
1262 * for an external server, a copy of the serverpart from the full name is returned
1265 static LPWSTR get_servername_from_name(LPCWSTR name)
1267 LPWSTR server;
1268 LPWSTR ptr;
1269 WCHAR buffer[MAX_PATH];
1270 DWORD len;
1272 if (name == NULL) return NULL;
1273 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1275 server = strdupW(&name[2]); /* skip over both backslash */
1276 if (server == NULL) return NULL;
1278 /* strip '\' and the printername */
1279 ptr = strchrW(server, '\\');
1280 if (ptr) ptr[0] = '\0';
1282 TRACE("found %s\n", debugstr_w(server));
1284 len = sizeof(buffer)/sizeof(buffer[0]);
1285 if (GetComputerNameW(buffer, &len)) {
1286 if (lstrcmpW(buffer, server) == 0) {
1287 /* The requested Servername is our computername */
1288 HeapFree(GetProcessHeap(), 0, server);
1289 return NULL;
1292 return server;
1295 /******************************************************************
1296 * get_basename_from_name (internal)
1298 * skip over the serverpart from the full name
1301 static LPCWSTR get_basename_from_name(LPCWSTR name)
1303 if (name == NULL) return NULL;
1304 if ((name[0] == '\\') && (name[1] == '\\')) {
1305 /* skip over the servername and search for the following '\' */
1306 name = strchrW(&name[2], '\\');
1307 if ((name) && (name[1])) {
1308 /* found a separator ('\') followed by a name:
1309 skip over the separator and return the rest */
1310 name++;
1312 else
1314 /* no basename present (we found only a servername) */
1315 return NULL;
1318 return name;
1321 /******************************************************************
1322 * get_opened_printer_entry
1323 * Get the first place empty in the opened printer table
1325 * ToDo:
1326 * - pDefault is ignored
1328 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1330 UINT_PTR handle = nb_printer_handles, i;
1331 jobqueue_t *queue = NULL;
1332 opened_printer_t *printer = NULL;
1333 LPWSTR servername;
1334 LPCWSTR printername;
1335 HKEY hkeyPrinters;
1336 HKEY hkeyPrinter;
1337 DWORD len;
1339 servername = get_servername_from_name(name);
1340 if (servername) {
1341 FIXME("server %s not supported\n", debugstr_w(servername));
1342 HeapFree(GetProcessHeap(), 0, servername);
1343 SetLastError(ERROR_INVALID_PRINTER_NAME);
1344 return NULL;
1347 printername = get_basename_from_name(name);
1348 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1350 /* an empty printername is invalid */
1351 if (printername && (!printername[0])) {
1352 SetLastError(ERROR_INVALID_PARAMETER);
1353 return NULL;
1356 EnterCriticalSection(&printer_handles_cs);
1358 for (i = 0; i < nb_printer_handles; i++)
1360 if (!printer_handles[i])
1362 if(handle == nb_printer_handles)
1363 handle = i;
1365 else
1367 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1368 queue = printer_handles[i]->queue;
1372 if (handle >= nb_printer_handles)
1374 opened_printer_t **new_array;
1375 if (printer_handles)
1376 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1377 (nb_printer_handles + 16) * sizeof(*new_array) );
1378 else
1379 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1380 (nb_printer_handles + 16) * sizeof(*new_array) );
1382 if (!new_array)
1384 handle = 0;
1385 goto end;
1387 printer_handles = new_array;
1388 nb_printer_handles += 16;
1391 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1393 handle = 0;
1394 goto end;
1398 /* clone the base name. This is NULL for the printserver */
1399 printer->printername = strdupW(printername);
1401 /* clone the full name */
1402 printer->name = strdupW(name);
1403 if (name && (!printer->name)) {
1404 handle = 0;
1405 goto end;
1408 if (printername) {
1409 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1410 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1411 /* OpenPrinter(",XcvMonitor " detected */
1412 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1413 printer->pm = monitor_load(&printername[len], NULL);
1414 if (printer->pm == NULL) {
1415 SetLastError(ERROR_UNKNOWN_PORT);
1416 handle = 0;
1417 goto end;
1420 else
1422 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1423 if (strncmpW( printername, XcvPortW, len) == 0) {
1424 /* OpenPrinter(",XcvPort " detected */
1425 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1426 printer->pm = monitor_load_by_port(&printername[len]);
1427 if (printer->pm == NULL) {
1428 SetLastError(ERROR_UNKNOWN_PORT);
1429 handle = 0;
1430 goto end;
1435 if (printer->pm) {
1436 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1437 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1438 pDefault ? pDefault->DesiredAccess : 0,
1439 &printer->hXcv);
1441 if (printer->hXcv == NULL) {
1442 SetLastError(ERROR_INVALID_PARAMETER);
1443 handle = 0;
1444 goto end;
1447 else
1449 /* Does the Printer exist? */
1450 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1451 ERR("Can't create Printers key\n");
1452 handle = 0;
1453 goto end;
1455 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1456 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1457 RegCloseKey(hkeyPrinters);
1458 SetLastError(ERROR_INVALID_PRINTER_NAME);
1459 handle = 0;
1460 goto end;
1462 RegCloseKey(hkeyPrinter);
1463 RegCloseKey(hkeyPrinters);
1466 else
1468 TRACE("using the local printserver\n");
1471 if(queue)
1472 printer->queue = queue;
1473 else
1475 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1476 if (!printer->queue) {
1477 handle = 0;
1478 goto end;
1480 list_init(&printer->queue->jobs);
1481 printer->queue->ref = 0;
1483 InterlockedIncrement(&printer->queue->ref);
1485 printer_handles[handle] = printer;
1486 handle++;
1487 end:
1488 LeaveCriticalSection(&printer_handles_cs);
1489 if (!handle && printer) {
1490 /* Something failed: Free all resources */
1491 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1492 monitor_unload(printer->pm);
1493 HeapFree(GetProcessHeap(), 0, printer->printername);
1494 HeapFree(GetProcessHeap(), 0, printer->name);
1495 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1496 HeapFree(GetProcessHeap(), 0, printer);
1499 return (HANDLE)handle;
1502 /******************************************************************
1503 * get_opened_printer
1504 * Get the pointer to the opened printer referred by the handle
1506 static opened_printer_t *get_opened_printer(HANDLE hprn)
1508 UINT_PTR idx = (UINT_PTR)hprn;
1509 opened_printer_t *ret = NULL;
1511 EnterCriticalSection(&printer_handles_cs);
1513 if ((idx > 0) && (idx <= nb_printer_handles)) {
1514 ret = printer_handles[idx - 1];
1516 LeaveCriticalSection(&printer_handles_cs);
1517 return ret;
1520 /******************************************************************
1521 * get_opened_printer_name
1522 * Get the pointer to the opened printer name referred by the handle
1524 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1526 opened_printer_t *printer = get_opened_printer(hprn);
1527 if(!printer) return NULL;
1528 return printer->name;
1531 /******************************************************************
1532 * WINSPOOL_GetOpenedPrinterRegKey
1535 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1537 LPCWSTR name = get_opened_printer_name(hPrinter);
1538 DWORD ret;
1539 HKEY hkeyPrinters;
1541 if(!name) return ERROR_INVALID_HANDLE;
1543 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1544 ERROR_SUCCESS)
1545 return ret;
1547 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1549 ERR("Can't find opened printer %s in registry\n",
1550 debugstr_w(name));
1551 RegCloseKey(hkeyPrinters);
1552 return ERROR_INVALID_PRINTER_NAME; /* ? */
1554 RegCloseKey(hkeyPrinters);
1555 return ERROR_SUCCESS;
1558 void WINSPOOL_LoadSystemPrinters(void)
1560 HKEY hkey, hkeyPrinters;
1561 HANDLE hprn;
1562 DWORD needed, num, i;
1563 WCHAR PrinterName[256];
1564 BOOL done = FALSE;
1566 /* This ensures that all printer entries have a valid Name value. If causes
1567 problems later if they don't. If one is found to be missed we create one
1568 and set it equal to the name of the key */
1569 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1570 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1571 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1572 for(i = 0; i < num; i++) {
1573 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) == ERROR_SUCCESS) {
1574 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1575 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1576 set_reg_szW(hkey, NameW, PrinterName);
1578 RegCloseKey(hkey);
1583 RegCloseKey(hkeyPrinters);
1586 /* We want to avoid calling AddPrinter on printers as much as
1587 possible, because on cups printers this will (eventually) lead
1588 to a call to cupsGetPPD which takes forever, even with non-cups
1589 printers AddPrinter takes a while. So we'll tag all printers that
1590 were automatically added last time around, if they still exist
1591 we'll leave them be otherwise we'll delete them. */
1592 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1593 if(needed) {
1594 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1595 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1596 for(i = 0; i < num; i++) {
1597 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1598 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1599 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1600 DWORD dw = 1;
1601 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1602 RegCloseKey(hkey);
1604 ClosePrinter(hprn);
1609 HeapFree(GetProcessHeap(), 0, pi);
1613 #ifdef SONAME_LIBCUPS
1614 done = CUPS_LoadPrinters();
1615 #endif
1617 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1618 PRINTCAP_LoadPrinters();
1620 /* Now enumerate the list again and delete any printers that are still tagged */
1621 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1622 if(needed) {
1623 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1624 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1625 for(i = 0; i < num; i++) {
1626 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1627 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1628 BOOL delete_driver = FALSE;
1629 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1630 DWORD dw, type, size = sizeof(dw);
1631 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1632 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1633 DeletePrinter(hprn);
1634 delete_driver = TRUE;
1636 RegCloseKey(hkey);
1638 ClosePrinter(hprn);
1639 if(delete_driver)
1640 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1645 HeapFree(GetProcessHeap(), 0, pi);
1648 return;
1652 /******************************************************************
1653 * get_job
1655 * Get the pointer to the specified job.
1656 * Should hold the printer_handles_cs before calling.
1658 static job_t *get_job(HANDLE hprn, DWORD JobId)
1660 opened_printer_t *printer = get_opened_printer(hprn);
1661 job_t *job;
1663 if(!printer) return NULL;
1664 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1666 if(job->job_id == JobId)
1667 return job;
1669 return NULL;
1672 /***********************************************************
1673 * DEVMODEcpyAtoW
1675 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1677 BOOL Formname;
1678 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1679 DWORD size;
1681 Formname = (dmA->dmSize > off_formname);
1682 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1683 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1684 dmW->dmDeviceName, CCHDEVICENAME);
1685 if(!Formname) {
1686 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1687 dmA->dmSize - CCHDEVICENAME);
1688 } else {
1689 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1690 off_formname - CCHDEVICENAME);
1691 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1692 dmW->dmFormName, CCHFORMNAME);
1693 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1694 (off_formname + CCHFORMNAME));
1696 dmW->dmSize = size;
1697 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1698 dmA->dmDriverExtra);
1699 return dmW;
1702 /***********************************************************
1703 * DEVMODEdupWtoA
1704 * Creates an ansi copy of supplied devmode
1706 static LPDEVMODEA DEVMODEdupWtoA(const DEVMODEW *dmW)
1708 LPDEVMODEA dmA;
1709 DWORD size;
1711 if (!dmW) return NULL;
1712 size = dmW->dmSize - CCHDEVICENAME -
1713 ((dmW->dmSize > FIELD_OFFSET(DEVMODEW, dmFormName)) ? CCHFORMNAME : 0);
1715 dmA = HeapAlloc(GetProcessHeap(), 0, size + dmW->dmDriverExtra);
1716 if (!dmA) return NULL;
1718 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1719 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1721 if (FIELD_OFFSET(DEVMODEW, dmFormName) >= dmW->dmSize) {
1722 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1723 dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1725 else
1727 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1728 FIELD_OFFSET(DEVMODEW, dmFormName) - FIELD_OFFSET(DEVMODEW, dmSpecVersion));
1729 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1730 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1732 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize - FIELD_OFFSET(DEVMODEW, dmLogPixels));
1735 dmA->dmSize = size;
1736 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize, dmW->dmDriverExtra);
1737 return dmA;
1740 /******************************************************************
1741 * convert_printerinfo_W_to_A [internal]
1744 static void convert_printerinfo_W_to_A(LPBYTE out, LPBYTE pPrintersW,
1745 DWORD level, DWORD outlen, DWORD numentries)
1747 DWORD id = 0;
1748 LPSTR ptr;
1749 INT len;
1751 TRACE("(%p, %p, %d, %u, %u)\n", out, pPrintersW, level, outlen, numentries);
1753 len = pi_sizeof[level] * numentries;
1754 ptr = (LPSTR) out + len;
1755 outlen -= len;
1757 /* copy the numbers of all PRINTER_INFO_* first */
1758 memcpy(out, pPrintersW, len);
1760 while (id < numentries) {
1761 switch (level) {
1762 case 1:
1764 PRINTER_INFO_1W * piW = (PRINTER_INFO_1W *) pPrintersW;
1765 PRINTER_INFO_1A * piA = (PRINTER_INFO_1A *) out;
1767 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pName));
1768 if (piW->pDescription) {
1769 piA->pDescription = ptr;
1770 len = WideCharToMultiByte(CP_ACP, 0, piW->pDescription, -1,
1771 ptr, outlen, NULL, NULL);
1772 ptr += len;
1773 outlen -= len;
1775 if (piW->pName) {
1776 piA->pName = ptr;
1777 len = WideCharToMultiByte(CP_ACP, 0, piW->pName, -1,
1778 ptr, outlen, NULL, NULL);
1779 ptr += len;
1780 outlen -= len;
1782 if (piW->pComment) {
1783 piA->pComment = ptr;
1784 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1785 ptr, outlen, NULL, NULL);
1786 ptr += len;
1787 outlen -= len;
1789 break;
1792 case 2:
1794 PRINTER_INFO_2W * piW = (PRINTER_INFO_2W *) pPrintersW;
1795 PRINTER_INFO_2A * piA = (PRINTER_INFO_2A *) out;
1796 LPDEVMODEA dmA;
1798 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1799 if (piW->pServerName) {
1800 piA->pServerName = ptr;
1801 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1802 ptr, outlen, NULL, NULL);
1803 ptr += len;
1804 outlen -= len;
1806 if (piW->pPrinterName) {
1807 piA->pPrinterName = ptr;
1808 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1809 ptr, outlen, NULL, NULL);
1810 ptr += len;
1811 outlen -= len;
1813 if (piW->pShareName) {
1814 piA->pShareName = ptr;
1815 len = WideCharToMultiByte(CP_ACP, 0, piW->pShareName, -1,
1816 ptr, outlen, NULL, NULL);
1817 ptr += len;
1818 outlen -= len;
1820 if (piW->pPortName) {
1821 piA->pPortName = ptr;
1822 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1823 ptr, outlen, NULL, NULL);
1824 ptr += len;
1825 outlen -= len;
1827 if (piW->pDriverName) {
1828 piA->pDriverName = ptr;
1829 len = WideCharToMultiByte(CP_ACP, 0, piW->pDriverName, -1,
1830 ptr, outlen, NULL, NULL);
1831 ptr += len;
1832 outlen -= len;
1834 if (piW->pComment) {
1835 piA->pComment = ptr;
1836 len = WideCharToMultiByte(CP_ACP, 0, piW->pComment, -1,
1837 ptr, outlen, NULL, NULL);
1838 ptr += len;
1839 outlen -= len;
1841 if (piW->pLocation) {
1842 piA->pLocation = ptr;
1843 len = WideCharToMultiByte(CP_ACP, 0, piW->pLocation, -1,
1844 ptr, outlen, NULL, NULL);
1845 ptr += len;
1846 outlen -= len;
1849 dmA = DEVMODEdupWtoA(piW->pDevMode);
1850 if (dmA) {
1851 /* align DEVMODEA to a DWORD boundary */
1852 len = (4 - ( (DWORD_PTR) ptr & 3)) & 3;
1853 ptr += len;
1854 outlen -= len;
1856 piA->pDevMode = (LPDEVMODEA) ptr;
1857 len = dmA->dmSize + dmA->dmDriverExtra;
1858 memcpy(ptr, dmA, len);
1859 HeapFree(GetProcessHeap(), 0, dmA);
1861 ptr += len;
1862 outlen -= len;
1865 if (piW->pSepFile) {
1866 piA->pSepFile = ptr;
1867 len = WideCharToMultiByte(CP_ACP, 0, piW->pSepFile, -1,
1868 ptr, outlen, NULL, NULL);
1869 ptr += len;
1870 outlen -= len;
1872 if (piW->pPrintProcessor) {
1873 piA->pPrintProcessor = ptr;
1874 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrintProcessor, -1,
1875 ptr, outlen, NULL, NULL);
1876 ptr += len;
1877 outlen -= len;
1879 if (piW->pDatatype) {
1880 piA->pDatatype = ptr;
1881 len = WideCharToMultiByte(CP_ACP, 0, piW->pDatatype, -1,
1882 ptr, outlen, NULL, NULL);
1883 ptr += len;
1884 outlen -= len;
1886 if (piW->pParameters) {
1887 piA->pParameters = ptr;
1888 len = WideCharToMultiByte(CP_ACP, 0, piW->pParameters, -1,
1889 ptr, outlen, NULL, NULL);
1890 ptr += len;
1891 outlen -= len;
1893 if (piW->pSecurityDescriptor) {
1894 piA->pSecurityDescriptor = NULL;
1895 FIXME("pSecurityDescriptor ignored: %s\n", debugstr_w(piW->pPrinterName));
1897 break;
1900 case 4:
1902 PRINTER_INFO_4W * piW = (PRINTER_INFO_4W *) pPrintersW;
1903 PRINTER_INFO_4A * piA = (PRINTER_INFO_4A *) out;
1905 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1907 if (piW->pPrinterName) {
1908 piA->pPrinterName = ptr;
1909 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1910 ptr, outlen, NULL, NULL);
1911 ptr += len;
1912 outlen -= len;
1914 if (piW->pServerName) {
1915 piA->pServerName = ptr;
1916 len = WideCharToMultiByte(CP_ACP, 0, piW->pServerName, -1,
1917 ptr, outlen, NULL, NULL);
1918 ptr += len;
1919 outlen -= len;
1921 break;
1924 case 5:
1926 PRINTER_INFO_5W * piW = (PRINTER_INFO_5W *) pPrintersW;
1927 PRINTER_INFO_5A * piA = (PRINTER_INFO_5A *) out;
1929 TRACE("(%u) #%u: %s\n", level, id, debugstr_w(piW->pPrinterName));
1931 if (piW->pPrinterName) {
1932 piA->pPrinterName = ptr;
1933 len = WideCharToMultiByte(CP_ACP, 0, piW->pPrinterName, -1,
1934 ptr, outlen, NULL, NULL);
1935 ptr += len;
1936 outlen -= len;
1938 if (piW->pPortName) {
1939 piA->pPortName = ptr;
1940 len = WideCharToMultiByte(CP_ACP, 0, piW->pPortName, -1,
1941 ptr, outlen, NULL, NULL);
1942 ptr += len;
1943 outlen -= len;
1945 break;
1948 default:
1949 FIXME("for level %u\n", level);
1951 pPrintersW += pi_sizeof[level];
1952 out += pi_sizeof[level];
1953 id++;
1957 /***********************************************************
1958 * PRINTER_INFO_2AtoW
1959 * Creates a unicode copy of PRINTER_INFO_2A on heap
1961 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1963 LPPRINTER_INFO_2W piW;
1964 UNICODE_STRING usBuffer;
1966 if(!piA) return NULL;
1967 piW = HeapAlloc(heap, 0, sizeof(*piW));
1968 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1970 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1971 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1972 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1973 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1974 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1975 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1976 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1977 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1978 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1979 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1980 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1981 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1982 return piW;
1985 /***********************************************************
1986 * FREE_PRINTER_INFO_2W
1987 * Free PRINTER_INFO_2W and all strings
1989 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1991 if(!piW) return;
1993 HeapFree(heap,0,piW->pServerName);
1994 HeapFree(heap,0,piW->pPrinterName);
1995 HeapFree(heap,0,piW->pShareName);
1996 HeapFree(heap,0,piW->pPortName);
1997 HeapFree(heap,0,piW->pDriverName);
1998 HeapFree(heap,0,piW->pComment);
1999 HeapFree(heap,0,piW->pLocation);
2000 HeapFree(heap,0,piW->pDevMode);
2001 HeapFree(heap,0,piW->pSepFile);
2002 HeapFree(heap,0,piW->pPrintProcessor);
2003 HeapFree(heap,0,piW->pDatatype);
2004 HeapFree(heap,0,piW->pParameters);
2005 HeapFree(heap,0,piW);
2006 return;
2009 /******************************************************************
2010 * DeviceCapabilities [WINSPOOL.@]
2011 * DeviceCapabilitiesA [WINSPOOL.@]
2014 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
2015 LPSTR pOutput, LPDEVMODEA lpdm)
2017 INT ret;
2019 if (!GDI_CallDeviceCapabilities16)
2021 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2022 (LPCSTR)104 );
2023 if (!GDI_CallDeviceCapabilities16) return -1;
2025 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
2027 /* If DC_PAPERSIZE map POINT16s to POINTs */
2028 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
2029 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
2030 POINT *pt = (POINT *)pOutput;
2031 INT i;
2032 memcpy(tmp, pOutput, ret * sizeof(POINT16));
2033 for(i = 0; i < ret; i++, pt++)
2035 pt->x = tmp[i].x;
2036 pt->y = tmp[i].y;
2038 HeapFree( GetProcessHeap(), 0, tmp );
2040 return ret;
2044 /*****************************************************************************
2045 * DeviceCapabilitiesW [WINSPOOL.@]
2047 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2050 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2051 WORD fwCapability, LPWSTR pOutput,
2052 const DEVMODEW *pDevMode)
2054 LPDEVMODEA dmA = DEVMODEdupWtoA(pDevMode);
2055 LPSTR pDeviceA = strdupWtoA(pDevice);
2056 LPSTR pPortA = strdupWtoA(pPort);
2057 INT ret;
2059 if(pOutput && (fwCapability == DC_BINNAMES ||
2060 fwCapability == DC_FILEDEPENDENCIES ||
2061 fwCapability == DC_PAPERNAMES)) {
2062 /* These need A -> W translation */
2063 INT size = 0, i;
2064 LPSTR pOutputA;
2065 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2066 dmA);
2067 if(ret == -1)
2068 return ret;
2069 switch(fwCapability) {
2070 case DC_BINNAMES:
2071 size = 24;
2072 break;
2073 case DC_PAPERNAMES:
2074 case DC_FILEDEPENDENCIES:
2075 size = 64;
2076 break;
2078 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
2079 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2080 dmA);
2081 for(i = 0; i < ret; i++)
2082 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2083 pOutput + (i * size), size);
2084 HeapFree(GetProcessHeap(), 0, pOutputA);
2085 } else {
2086 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2087 (LPSTR)pOutput, dmA);
2089 HeapFree(GetProcessHeap(),0,pPortA);
2090 HeapFree(GetProcessHeap(),0,pDeviceA);
2091 HeapFree(GetProcessHeap(),0,dmA);
2092 return ret;
2095 /******************************************************************
2096 * DocumentPropertiesA [WINSPOOL.@]
2098 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2100 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
2101 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
2102 LPDEVMODEA pDevModeInput,DWORD fMode )
2104 LPSTR lpName = pDeviceName;
2105 static CHAR port[] = "LPT1:";
2106 LONG ret;
2108 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2109 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
2112 if(!pDeviceName) {
2113 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
2114 if(!lpNameW) {
2115 ERR("no name from hPrinter?\n");
2116 SetLastError(ERROR_INVALID_HANDLE);
2117 return -1;
2119 lpName = strdupWtoA(lpNameW);
2122 if (!GDI_CallExtDeviceMode16)
2124 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
2125 (LPCSTR)102 );
2126 if (!GDI_CallExtDeviceMode16) {
2127 ERR("No CallExtDeviceMode16?\n");
2128 return -1;
2131 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
2132 pDevModeInput, NULL, fMode);
2134 if(!pDeviceName)
2135 HeapFree(GetProcessHeap(),0,lpName);
2136 return ret;
2140 /*****************************************************************************
2141 * DocumentPropertiesW (WINSPOOL.@)
2143 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
2145 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
2146 LPWSTR pDeviceName,
2147 LPDEVMODEW pDevModeOutput,
2148 LPDEVMODEW pDevModeInput, DWORD fMode)
2151 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
2152 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(pDevModeInput);
2153 LPDEVMODEA pDevModeOutputA = NULL;
2154 LONG ret;
2156 TRACE("(%p,%p,%s,%p,%p,%d)\n",
2157 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2158 fMode);
2159 if(pDevModeOutput) {
2160 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2161 if(ret < 0) return ret;
2162 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
2164 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2165 pDevModeInputA, fMode);
2166 if(pDevModeOutput) {
2167 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2168 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2170 if(fMode == 0 && ret > 0)
2171 ret += (CCHDEVICENAME + CCHFORMNAME);
2172 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2173 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2174 return ret;
2177 /******************************************************************
2178 * OpenPrinterA [WINSPOOL.@]
2180 * See OpenPrinterW.
2183 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
2184 LPPRINTER_DEFAULTSA pDefault)
2186 UNICODE_STRING lpPrinterNameW;
2187 UNICODE_STRING usBuffer;
2188 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
2189 PWSTR pwstrPrinterNameW;
2190 BOOL ret;
2192 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
2194 if(pDefault) {
2195 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
2196 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
2197 DefaultW.DesiredAccess = pDefault->DesiredAccess;
2198 pDefaultW = &DefaultW;
2200 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
2201 if(pDefault) {
2202 RtlFreeUnicodeString(&usBuffer);
2203 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
2205 RtlFreeUnicodeString(&lpPrinterNameW);
2206 return ret;
2209 /******************************************************************
2210 * OpenPrinterW [WINSPOOL.@]
2212 * Open a Printer / Printserver or a Printer-Object
2214 * PARAMS
2215 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2216 * phPrinter [O] The resulting Handle is stored here
2217 * pDefault [I] PTR to Default Printer Settings or NULL
2219 * RETURNS
2220 * Success: TRUE
2221 * Failure: FALSE
2223 * NOTES
2224 * lpPrinterName is one of:
2225 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2226 *| Printer: "PrinterName"
2227 *| Printer-Object: "PrinterName,Job xxx"
2228 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2229 *| XcvPort: "Servername,XcvPort PortName"
2231 * BUGS
2232 *| Printer-Object not supported
2233 *| pDefaults is ignored
2236 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2239 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2240 if (pDefault) {
2241 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2242 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2245 if(!phPrinter) {
2246 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2247 SetLastError(ERROR_INVALID_PARAMETER);
2248 return FALSE;
2251 /* Get the unique handle of the printer or Printserver */
2252 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2253 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2254 return (*phPrinter != 0);
2257 /******************************************************************
2258 * AddMonitorA [WINSPOOL.@]
2260 * See AddMonitorW.
2263 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2265 LPWSTR nameW = NULL;
2266 INT len;
2267 BOOL res;
2268 LPMONITOR_INFO_2A mi2a;
2269 MONITOR_INFO_2W mi2w;
2271 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2272 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2273 mi2a ? debugstr_a(mi2a->pName) : NULL,
2274 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2275 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2277 if (Level != 2) {
2278 SetLastError(ERROR_INVALID_LEVEL);
2279 return FALSE;
2282 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2283 if (mi2a == NULL) {
2284 return FALSE;
2287 if (pName) {
2288 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2289 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2290 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2293 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2294 if (mi2a->pName) {
2295 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2296 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2297 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2299 if (mi2a->pEnvironment) {
2300 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2301 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2302 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2304 if (mi2a->pDLLName) {
2305 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2306 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2307 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2310 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2312 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2313 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2314 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2316 HeapFree(GetProcessHeap(), 0, nameW);
2317 return (res);
2320 /******************************************************************************
2321 * AddMonitorW [WINSPOOL.@]
2323 * Install a Printmonitor
2325 * PARAMS
2326 * pName [I] Servername or NULL (local Computer)
2327 * Level [I] Structure-Level (Must be 2)
2328 * pMonitors [I] PTR to MONITOR_INFO_2
2330 * RETURNS
2331 * Success: TRUE
2332 * Failure: FALSE
2334 * NOTES
2335 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2338 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2340 monitor_t * pm = NULL;
2341 LPMONITOR_INFO_2W mi2w;
2342 HKEY hroot = NULL;
2343 HKEY hentry = NULL;
2344 DWORD disposition;
2345 BOOL res = FALSE;
2347 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2348 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2349 mi2w ? debugstr_w(mi2w->pName) : NULL,
2350 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2351 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2353 if (Level != 2) {
2354 SetLastError(ERROR_INVALID_LEVEL);
2355 return FALSE;
2358 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2359 if (mi2w == NULL) {
2360 return FALSE;
2363 if (pName && (pName[0])) {
2364 FIXME("for server %s not implemented\n", debugstr_w(pName));
2365 SetLastError(ERROR_ACCESS_DENIED);
2366 return FALSE;
2370 if (!mi2w->pName || (! mi2w->pName[0])) {
2371 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2372 SetLastError(ERROR_INVALID_PARAMETER);
2373 return FALSE;
2375 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2376 WARN("Environment %s requested (we support only %s)\n",
2377 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2378 SetLastError(ERROR_INVALID_ENVIRONMENT);
2379 return FALSE;
2382 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2383 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2384 SetLastError(ERROR_INVALID_PARAMETER);
2385 return FALSE;
2388 /* Load and initialize the monitor. SetLastError() is called on failure */
2389 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2390 return FALSE;
2392 monitor_unload(pm);
2394 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2395 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2396 return FALSE;
2399 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2400 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2401 &disposition) == ERROR_SUCCESS) {
2403 /* Some installers set options for the port before calling AddMonitor.
2404 We query the "Driver" entry to verify that the monitor is installed,
2405 before we return an error.
2406 When a user installs two print monitors at the same time with the
2407 same name but with a different driver DLL and a task switch comes
2408 between RegQueryValueExW and RegSetValueExW, a race condition
2409 is possible but silently ignored. */
2411 DWORD namesize = 0;
2413 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2414 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2415 &namesize) == ERROR_SUCCESS)) {
2416 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2417 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2418 9x: ERROR_ALREADY_EXISTS (183) */
2419 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2421 else
2423 INT len;
2424 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2425 res = (RegSetValueExW(hentry, DriverW, 0,
2426 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2428 RegCloseKey(hentry);
2431 RegCloseKey(hroot);
2432 return (res);
2435 /******************************************************************
2436 * DeletePrinterDriverA [WINSPOOL.@]
2439 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2441 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2444 /******************************************************************
2445 * DeletePrinterDriverW [WINSPOOL.@]
2448 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2450 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2453 /******************************************************************
2454 * DeleteMonitorA [WINSPOOL.@]
2456 * See DeleteMonitorW.
2459 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2461 LPWSTR nameW = NULL;
2462 LPWSTR EnvironmentW = NULL;
2463 LPWSTR MonitorNameW = NULL;
2464 BOOL res;
2465 INT len;
2467 if (pName) {
2468 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2469 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2470 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2473 if (pEnvironment) {
2474 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2475 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2476 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2478 if (pMonitorName) {
2479 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2480 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2481 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2484 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2486 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2487 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2488 HeapFree(GetProcessHeap(), 0, nameW);
2489 return (res);
2492 /******************************************************************
2493 * DeleteMonitorW [WINSPOOL.@]
2495 * Delete a specific Printmonitor from a Printing-Environment
2497 * PARAMS
2498 * pName [I] Servername or NULL (local Computer)
2499 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2500 * pMonitorName [I] Name of the Monitor, that should be deleted
2502 * RETURNS
2503 * Success: TRUE
2504 * Failure: FALSE
2506 * NOTES
2507 * pEnvironment is ignored in Windows for the local Computer.
2511 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2513 HKEY hroot = NULL;
2515 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2516 debugstr_w(pMonitorName));
2518 if (pName && (pName[0])) {
2519 FIXME("for server %s not implemented\n", debugstr_w(pName));
2520 SetLastError(ERROR_ACCESS_DENIED);
2521 return FALSE;
2524 /* pEnvironment is ignored in Windows for the local Computer */
2526 if (!pMonitorName || !pMonitorName[0]) {
2527 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2528 SetLastError(ERROR_INVALID_PARAMETER);
2529 return FALSE;
2532 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2533 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2534 return FALSE;
2537 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
2538 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2539 RegCloseKey(hroot);
2540 return TRUE;
2543 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2544 RegCloseKey(hroot);
2546 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2547 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2548 return (FALSE);
2551 /******************************************************************
2552 * DeletePortA [WINSPOOL.@]
2554 * See DeletePortW.
2557 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2559 LPWSTR nameW = NULL;
2560 LPWSTR portW = NULL;
2561 INT len;
2562 DWORD res;
2564 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2566 /* convert servername to unicode */
2567 if (pName) {
2568 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2569 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2570 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2573 /* convert portname to unicode */
2574 if (pPortName) {
2575 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2576 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2577 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2580 res = DeletePortW(nameW, hWnd, portW);
2581 HeapFree(GetProcessHeap(), 0, nameW);
2582 HeapFree(GetProcessHeap(), 0, portW);
2583 return res;
2586 /******************************************************************
2587 * DeletePortW [WINSPOOL.@]
2589 * Delete a specific Port
2591 * PARAMS
2592 * pName [I] Servername or NULL (local Computer)
2593 * hWnd [I] Handle to parent Window for the Dialog-Box
2594 * pPortName [I] Name of the Port, that should be deleted
2596 * RETURNS
2597 * Success: TRUE
2598 * Failure: FALSE
2601 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2603 monitor_t * pm;
2604 monitor_t * pui;
2605 DWORD res;
2607 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2609 if (pName && pName[0]) {
2610 SetLastError(ERROR_INVALID_PARAMETER);
2611 return FALSE;
2614 if (!pPortName) {
2615 SetLastError(RPC_X_NULL_REF_POINTER);
2616 return FALSE;
2619 /* an empty Portname is Invalid */
2620 if (!pPortName[0]) {
2621 SetLastError(ERROR_NOT_SUPPORTED);
2622 return FALSE;
2625 pm = monitor_load_by_port(pPortName);
2626 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2627 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2628 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2629 TRACE("got %d with %u\n", res, GetLastError());
2631 else
2633 pui = monitor_loadui(pm);
2634 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2635 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2636 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2637 TRACE("got %d with %u\n", res, GetLastError());
2639 else
2641 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2642 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2644 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2645 SetLastError(ERROR_NOT_SUPPORTED);
2646 res = FALSE;
2648 monitor_unload(pui);
2650 monitor_unload(pm);
2652 TRACE("returning %d with %u\n", res, GetLastError());
2653 return res;
2656 /******************************************************************************
2657 * SetPrinterW [WINSPOOL.@]
2659 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2661 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2662 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2663 return FALSE;
2666 /******************************************************************************
2667 * WritePrinter [WINSPOOL.@]
2669 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2671 opened_printer_t *printer;
2672 BOOL ret = FALSE;
2674 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2676 EnterCriticalSection(&printer_handles_cs);
2677 printer = get_opened_printer(hPrinter);
2678 if(!printer)
2680 SetLastError(ERROR_INVALID_HANDLE);
2681 goto end;
2684 if(!printer->doc)
2686 SetLastError(ERROR_SPL_NO_STARTDOC);
2687 goto end;
2690 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2691 end:
2692 LeaveCriticalSection(&printer_handles_cs);
2693 return ret;
2696 /*****************************************************************************
2697 * AddFormA [WINSPOOL.@]
2699 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2701 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2702 return 1;
2705 /*****************************************************************************
2706 * AddFormW [WINSPOOL.@]
2708 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2710 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2711 return 1;
2714 /*****************************************************************************
2715 * AddJobA [WINSPOOL.@]
2717 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2719 BOOL ret;
2720 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2721 DWORD needed;
2723 if(Level != 1) {
2724 SetLastError(ERROR_INVALID_LEVEL);
2725 return FALSE;
2728 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2730 if(ret) {
2731 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2732 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2733 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2734 if(*pcbNeeded > cbBuf) {
2735 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2736 ret = FALSE;
2737 } else {
2738 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2739 addjobA->JobId = addjobW->JobId;
2740 addjobA->Path = (char *)(addjobA + 1);
2741 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2744 return ret;
2747 /*****************************************************************************
2748 * AddJobW [WINSPOOL.@]
2750 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2752 opened_printer_t *printer;
2753 job_t *job;
2754 BOOL ret = FALSE;
2755 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2756 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2757 WCHAR path[MAX_PATH], filename[MAX_PATH];
2758 DWORD len;
2759 ADDJOB_INFO_1W *addjob;
2761 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2763 EnterCriticalSection(&printer_handles_cs);
2765 printer = get_opened_printer(hPrinter);
2767 if(!printer) {
2768 SetLastError(ERROR_INVALID_HANDLE);
2769 goto end;
2772 if(Level != 1) {
2773 SetLastError(ERROR_INVALID_LEVEL);
2774 goto end;
2777 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2778 if(!job)
2779 goto end;
2781 job->job_id = InterlockedIncrement(&next_job_id);
2783 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2784 if(path[len - 1] != '\\')
2785 path[len++] = '\\';
2786 memcpy(path + len, spool_path, sizeof(spool_path));
2787 sprintfW(filename, fmtW, path, job->job_id);
2789 len = strlenW(filename);
2790 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2791 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2792 job->document_title = strdupW(default_doc_title);
2793 list_add_tail(&printer->queue->jobs, &job->entry);
2795 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2796 if(*pcbNeeded <= cbBuf) {
2797 addjob = (ADDJOB_INFO_1W*)pData;
2798 addjob->JobId = job->job_id;
2799 addjob->Path = (WCHAR *)(addjob + 1);
2800 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2801 ret = TRUE;
2802 } else
2803 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2805 end:
2806 LeaveCriticalSection(&printer_handles_cs);
2807 return ret;
2810 /*****************************************************************************
2811 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2813 * Return the PATH for the Print-Processors
2815 * See GetPrintProcessorDirectoryW.
2819 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2820 DWORD level, LPBYTE Info,
2821 DWORD cbBuf, LPDWORD pcbNeeded)
2823 LPWSTR serverW = NULL;
2824 LPWSTR envW = NULL;
2825 BOOL ret;
2826 INT len;
2828 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2829 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2832 if (server) {
2833 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2834 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2835 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2838 if (env) {
2839 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2840 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2841 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2844 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2845 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2847 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2848 cbBuf, pcbNeeded);
2850 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2851 cbBuf, NULL, NULL) > 0;
2854 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2855 HeapFree(GetProcessHeap(), 0, envW);
2856 HeapFree(GetProcessHeap(), 0, serverW);
2857 return ret;
2860 /*****************************************************************************
2861 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2863 * Return the PATH for the Print-Processors
2865 * PARAMS
2866 * server [I] Servername (NT only) or NULL (local Computer)
2867 * env [I] Printing-Environment (see below) or NULL (Default)
2868 * level [I] Structure-Level (must be 1)
2869 * Info [O] PTR to Buffer that receives the Result
2870 * cbBuf [I] Size of Buffer at "Info"
2871 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2872 * required for the Buffer at "Info"
2874 * RETURNS
2875 * Success: TRUE and in pcbNeeded the Bytes used in Info
2876 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2877 * if cbBuf is too small
2879 * Native Values returned in Info on Success:
2880 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2881 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2882 *| win9x(Windows 4.0): "%winsysdir%"
2884 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2886 * BUGS
2887 * Only NULL or "" is supported for server
2890 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2891 DWORD level, LPBYTE Info,
2892 DWORD cbBuf, LPDWORD pcbNeeded)
2894 DWORD needed;
2895 const printenv_t * env_t;
2897 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2898 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2900 if(server != NULL && server[0]) {
2901 FIXME("server not supported: %s\n", debugstr_w(server));
2902 SetLastError(ERROR_INVALID_PARAMETER);
2903 return FALSE;
2906 env_t = validate_envW(env);
2907 if(!env_t) return FALSE; /* environment invalid or unsupported */
2909 if(level != 1) {
2910 WARN("(Level: %d) is ignored in win9x\n", level);
2911 SetLastError(ERROR_INVALID_LEVEL);
2912 return FALSE;
2915 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2916 needed = GetSystemDirectoryW(NULL, 0);
2917 /* add the Size for the Subdirectories */
2918 needed += lstrlenW(spoolprtprocsW);
2919 needed += lstrlenW(env_t->subdir);
2920 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2922 if(pcbNeeded) *pcbNeeded = needed;
2923 TRACE ("required: 0x%x/%d\n", needed, needed);
2924 if (needed > cbBuf) {
2925 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2926 return FALSE;
2928 if(pcbNeeded == NULL) {
2929 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2930 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2931 SetLastError(RPC_X_NULL_REF_POINTER);
2932 return FALSE;
2934 if(Info == NULL) {
2935 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2936 SetLastError(RPC_X_NULL_REF_POINTER);
2937 return FALSE;
2940 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2941 /* add the Subdirectories */
2942 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2943 lstrcatW((LPWSTR) Info, env_t->subdir);
2944 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2945 return TRUE;
2948 /*****************************************************************************
2949 * WINSPOOL_OpenDriverReg [internal]
2951 * opens the registry for the printer drivers depending on the given input
2952 * variable pEnvironment
2954 * RETURNS:
2955 * the opened hkey on success
2956 * NULL on error
2958 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2960 HKEY retval = NULL;
2961 LPWSTR buffer;
2962 const printenv_t * env;
2964 TRACE("(%s, %d)\n",
2965 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2967 if (!pEnvironment || unicode) {
2968 /* pEnvironment was NULL or an Unicode-String: use it direct */
2969 env = validate_envW(pEnvironment);
2971 else
2973 /* pEnvironment was an ANSI-String: convert to unicode first */
2974 LPWSTR buffer;
2975 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2976 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2977 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2978 env = validate_envW(buffer);
2979 HeapFree(GetProcessHeap(), 0, buffer);
2981 if (!env) return NULL;
2983 buffer = HeapAlloc( GetProcessHeap(), 0,
2984 (strlenW(DriversW) + strlenW(env->envname) +
2985 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2986 if(buffer) {
2987 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2988 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2989 HeapFree(GetProcessHeap(), 0, buffer);
2991 return retval;
2994 /*****************************************************************************
2995 * AddPrinterW [WINSPOOL.@]
2997 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2999 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
3000 LPDEVMODEA dmA;
3001 LPDEVMODEW dmW;
3002 HANDLE retval;
3003 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
3004 LONG size;
3005 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
3006 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
3007 priorityW[] = {'P','r','i','o','r','i','t','y',0},
3008 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
3009 statusW[] = {'S','t','a','t','u','s',0},
3010 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
3012 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
3014 if(pName != NULL) {
3015 ERR("pName = %s - unsupported\n", debugstr_w(pName));
3016 SetLastError(ERROR_INVALID_PARAMETER);
3017 return 0;
3019 if(Level != 2) {
3020 ERR("Level = %d, unsupported!\n", Level);
3021 SetLastError(ERROR_INVALID_LEVEL);
3022 return 0;
3024 if(!pPrinter) {
3025 SetLastError(ERROR_INVALID_PARAMETER);
3026 return 0;
3028 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3029 ERROR_SUCCESS) {
3030 ERR("Can't create Printers key\n");
3031 return 0;
3033 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
3034 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
3035 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
3036 RegCloseKey(hkeyPrinter);
3037 RegCloseKey(hkeyPrinters);
3038 return 0;
3040 RegCloseKey(hkeyPrinter);
3042 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
3043 if(!hkeyDrivers) {
3044 ERR("Can't create Drivers key\n");
3045 RegCloseKey(hkeyPrinters);
3046 return 0;
3048 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
3049 ERROR_SUCCESS) {
3050 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
3051 RegCloseKey(hkeyPrinters);
3052 RegCloseKey(hkeyDrivers);
3053 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
3054 return 0;
3056 RegCloseKey(hkeyDriver);
3057 RegCloseKey(hkeyDrivers);
3059 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
3060 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
3061 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
3062 RegCloseKey(hkeyPrinters);
3063 return 0;
3066 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
3067 ERROR_SUCCESS) {
3068 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
3069 SetLastError(ERROR_INVALID_PRINTER_NAME);
3070 RegCloseKey(hkeyPrinters);
3071 return 0;
3073 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
3074 (LPBYTE)&pi->Attributes, sizeof(DWORD));
3075 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
3077 /* See if we can load the driver. We may need the devmode structure anyway
3079 * FIXME:
3080 * Note that DocumentPropertiesW will briefly try to open the printer we
3081 * just create to find a DEVMODEA struct (it will use the WINEPS default
3082 * one in case it is not there, so we are ok).
3084 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
3086 if(size < 0) {
3087 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
3088 size = sizeof(DEVMODEW);
3090 if(pi->pDevMode)
3091 dmW = pi->pDevMode;
3092 else
3094 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
3095 dmW->dmSize = size;
3096 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
3098 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
3099 HeapFree(GetProcessHeap(),0,dmW);
3100 dmW=NULL;
3102 else
3104 /* set devmode to printer name */
3105 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
3109 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
3110 and we support these drivers. NT writes DEVMODEW so somehow
3111 we'll need to distinguish between these when we support NT
3112 drivers */
3113 if (dmW)
3115 dmA = DEVMODEdupWtoA(dmW);
3116 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
3117 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
3118 HeapFree(GetProcessHeap(), 0, dmA);
3119 if(!pi->pDevMode)
3120 HeapFree(GetProcessHeap(), 0, dmW);
3122 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
3123 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
3124 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
3125 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
3127 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
3128 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
3129 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
3130 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
3131 (LPBYTE)&pi->Priority, sizeof(DWORD));
3132 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
3133 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
3134 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
3135 (LPBYTE)&pi->StartTime, sizeof(DWORD));
3136 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
3137 (LPBYTE)&pi->Status, sizeof(DWORD));
3138 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
3139 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
3141 RegCloseKey(hkeyPrinter);
3142 RegCloseKey(hkeyPrinters);
3143 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
3144 ERR("OpenPrinter failing\n");
3145 return 0;
3147 return retval;
3150 /*****************************************************************************
3151 * AddPrinterA [WINSPOOL.@]
3153 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
3155 UNICODE_STRING pNameW;
3156 PWSTR pwstrNameW;
3157 PRINTER_INFO_2W *piW;
3158 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
3159 HANDLE ret;
3161 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
3162 if(Level != 2) {
3163 ERR("Level = %d, unsupported!\n", Level);
3164 SetLastError(ERROR_INVALID_LEVEL);
3165 return 0;
3167 pwstrNameW = asciitounicode(&pNameW,pName);
3168 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
3170 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
3172 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
3173 RtlFreeUnicodeString(&pNameW);
3174 return ret;
3178 /*****************************************************************************
3179 * ClosePrinter [WINSPOOL.@]
3181 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
3183 UINT_PTR i = (UINT_PTR)hPrinter;
3184 opened_printer_t *printer = NULL;
3185 BOOL ret = FALSE;
3187 TRACE("(%p)\n", hPrinter);
3189 EnterCriticalSection(&printer_handles_cs);
3191 if ((i > 0) && (i <= nb_printer_handles))
3192 printer = printer_handles[i - 1];
3195 if(printer)
3197 struct list *cursor, *cursor2;
3199 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
3200 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
3201 printer->hXcv, debugstr_w(printer->name), printer->doc );
3203 if(printer->doc)
3204 EndDocPrinter(hPrinter);
3206 if(InterlockedDecrement(&printer->queue->ref) == 0)
3208 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
3210 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3211 ScheduleJob(hPrinter, job->job_id);
3213 HeapFree(GetProcessHeap(), 0, printer->queue);
3215 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3216 monitor_unload(printer->pm);
3217 HeapFree(GetProcessHeap(), 0, printer->printername);
3218 HeapFree(GetProcessHeap(), 0, printer->name);
3219 HeapFree(GetProcessHeap(), 0, printer);
3220 printer_handles[i - 1] = NULL;
3221 ret = TRUE;
3223 LeaveCriticalSection(&printer_handles_cs);
3224 return ret;
3227 /*****************************************************************************
3228 * DeleteFormA [WINSPOOL.@]
3230 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3232 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3233 return 1;
3236 /*****************************************************************************
3237 * DeleteFormW [WINSPOOL.@]
3239 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3241 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3242 return 1;
3245 /*****************************************************************************
3246 * DeletePrinter [WINSPOOL.@]
3248 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3250 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3251 HKEY hkeyPrinters, hkey;
3253 if(!lpNameW) {
3254 SetLastError(ERROR_INVALID_HANDLE);
3255 return FALSE;
3257 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3258 RegDeleteTreeW(hkeyPrinters, lpNameW);
3259 RegCloseKey(hkeyPrinters);
3261 WriteProfileStringW(devicesW, lpNameW, NULL);
3262 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3263 RegDeleteValueW(hkey, lpNameW);
3264 RegCloseKey(hkey);
3266 return TRUE;
3269 /*****************************************************************************
3270 * SetPrinterA [WINSPOOL.@]
3272 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3273 DWORD Command)
3275 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3276 return FALSE;
3279 /*****************************************************************************
3280 * SetJobA [WINSPOOL.@]
3282 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3283 LPBYTE pJob, DWORD Command)
3285 BOOL ret;
3286 LPBYTE JobW;
3287 UNICODE_STRING usBuffer;
3289 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3291 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3292 are all ignored by SetJob, so we don't bother copying them */
3293 switch(Level)
3295 case 0:
3296 JobW = NULL;
3297 break;
3298 case 1:
3300 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3301 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3303 JobW = (LPBYTE)info1W;
3304 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3305 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3306 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3307 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3308 info1W->Status = info1A->Status;
3309 info1W->Priority = info1A->Priority;
3310 info1W->Position = info1A->Position;
3311 info1W->PagesPrinted = info1A->PagesPrinted;
3312 break;
3314 case 2:
3316 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3317 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3319 JobW = (LPBYTE)info2W;
3320 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3321 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3322 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3323 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3324 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3325 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3326 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3327 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3328 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3329 info2W->Status = info2A->Status;
3330 info2W->Priority = info2A->Priority;
3331 info2W->Position = info2A->Position;
3332 info2W->StartTime = info2A->StartTime;
3333 info2W->UntilTime = info2A->UntilTime;
3334 info2W->PagesPrinted = info2A->PagesPrinted;
3335 break;
3337 case 3:
3338 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3339 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3340 break;
3341 default:
3342 SetLastError(ERROR_INVALID_LEVEL);
3343 return FALSE;
3346 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3348 switch(Level)
3350 case 1:
3352 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3353 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3354 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3355 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3356 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3357 break;
3359 case 2:
3361 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3362 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3363 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3364 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3365 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3366 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3367 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3368 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3369 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3370 break;
3373 HeapFree(GetProcessHeap(), 0, JobW);
3375 return ret;
3378 /*****************************************************************************
3379 * SetJobW [WINSPOOL.@]
3381 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3382 LPBYTE pJob, DWORD Command)
3384 BOOL ret = FALSE;
3385 job_t *job;
3387 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3388 FIXME("Ignoring everything other than document title\n");
3390 EnterCriticalSection(&printer_handles_cs);
3391 job = get_job(hPrinter, JobId);
3392 if(!job)
3393 goto end;
3395 switch(Level)
3397 case 0:
3398 break;
3399 case 1:
3401 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3402 HeapFree(GetProcessHeap(), 0, job->document_title);
3403 job->document_title = strdupW(info1->pDocument);
3404 break;
3406 case 2:
3408 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3409 HeapFree(GetProcessHeap(), 0, job->document_title);
3410 job->document_title = strdupW(info2->pDocument);
3411 break;
3413 case 3:
3414 break;
3415 default:
3416 SetLastError(ERROR_INVALID_LEVEL);
3417 goto end;
3419 ret = TRUE;
3420 end:
3421 LeaveCriticalSection(&printer_handles_cs);
3422 return ret;
3425 /*****************************************************************************
3426 * EndDocPrinter [WINSPOOL.@]
3428 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3430 opened_printer_t *printer;
3431 BOOL ret = FALSE;
3432 TRACE("(%p)\n", hPrinter);
3434 EnterCriticalSection(&printer_handles_cs);
3436 printer = get_opened_printer(hPrinter);
3437 if(!printer)
3439 SetLastError(ERROR_INVALID_HANDLE);
3440 goto end;
3443 if(!printer->doc)
3445 SetLastError(ERROR_SPL_NO_STARTDOC);
3446 goto end;
3449 CloseHandle(printer->doc->hf);
3450 ScheduleJob(hPrinter, printer->doc->job_id);
3451 HeapFree(GetProcessHeap(), 0, printer->doc);
3452 printer->doc = NULL;
3453 ret = TRUE;
3454 end:
3455 LeaveCriticalSection(&printer_handles_cs);
3456 return ret;
3459 /*****************************************************************************
3460 * EndPagePrinter [WINSPOOL.@]
3462 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3464 FIXME("(%p): stub\n", hPrinter);
3465 return TRUE;
3468 /*****************************************************************************
3469 * StartDocPrinterA [WINSPOOL.@]
3471 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3473 UNICODE_STRING usBuffer;
3474 DOC_INFO_2W doc2W;
3475 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3476 DWORD ret;
3478 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3479 or one (DOC_INFO_3) extra DWORDs */
3481 switch(Level) {
3482 case 2:
3483 doc2W.JobId = doc2->JobId;
3484 /* fall through */
3485 case 3:
3486 doc2W.dwMode = doc2->dwMode;
3487 /* fall through */
3488 case 1:
3489 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3490 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3491 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3492 break;
3494 default:
3495 SetLastError(ERROR_INVALID_LEVEL);
3496 return FALSE;
3499 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3501 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3502 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3503 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3505 return ret;
3508 /*****************************************************************************
3509 * StartDocPrinterW [WINSPOOL.@]
3511 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3513 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3514 opened_printer_t *printer;
3515 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3516 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3517 JOB_INFO_1W job_info;
3518 DWORD needed, ret = 0;
3519 HANDLE hf;
3520 WCHAR *filename;
3522 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3523 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3524 debugstr_w(doc->pDatatype));
3526 if(Level < 1 || Level > 3)
3528 SetLastError(ERROR_INVALID_LEVEL);
3529 return 0;
3532 EnterCriticalSection(&printer_handles_cs);
3533 printer = get_opened_printer(hPrinter);
3534 if(!printer)
3536 SetLastError(ERROR_INVALID_HANDLE);
3537 goto end;
3540 if(printer->doc)
3542 SetLastError(ERROR_INVALID_PRINTER_STATE);
3543 goto end;
3546 /* Even if we're printing to a file we still add a print job, we'll
3547 just ignore the spool file name */
3549 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3551 ERR("AddJob failed gle %u\n", GetLastError());
3552 goto end;
3555 if(doc->pOutputFile)
3556 filename = doc->pOutputFile;
3557 else
3558 filename = addjob->Path;
3560 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3561 if(hf == INVALID_HANDLE_VALUE)
3562 goto end;
3564 memset(&job_info, 0, sizeof(job_info));
3565 job_info.pDocument = doc->pDocName;
3566 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3568 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3569 printer->doc->hf = hf;
3570 ret = printer->doc->job_id = addjob->JobId;
3571 end:
3572 LeaveCriticalSection(&printer_handles_cs);
3574 return ret;
3577 /*****************************************************************************
3578 * StartPagePrinter [WINSPOOL.@]
3580 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3582 FIXME("(%p): stub\n", hPrinter);
3583 return TRUE;
3586 /*****************************************************************************
3587 * GetFormA [WINSPOOL.@]
3589 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3590 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3592 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3593 Level,pForm,cbBuf,pcbNeeded);
3594 return FALSE;
3597 /*****************************************************************************
3598 * GetFormW [WINSPOOL.@]
3600 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3601 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3603 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3604 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3605 return FALSE;
3608 /*****************************************************************************
3609 * SetFormA [WINSPOOL.@]
3611 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3612 LPBYTE pForm)
3614 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3615 return FALSE;
3618 /*****************************************************************************
3619 * SetFormW [WINSPOOL.@]
3621 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3622 LPBYTE pForm)
3624 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3625 return FALSE;
3628 /*****************************************************************************
3629 * ReadPrinter [WINSPOOL.@]
3631 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3632 LPDWORD pNoBytesRead)
3634 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3635 return FALSE;
3638 /*****************************************************************************
3639 * ResetPrinterA [WINSPOOL.@]
3641 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3643 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3644 return FALSE;
3647 /*****************************************************************************
3648 * ResetPrinterW [WINSPOOL.@]
3650 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3652 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3653 return FALSE;
3656 /*****************************************************************************
3657 * WINSPOOL_GetDWORDFromReg
3659 * Return DWORD associated with ValueName from hkey.
3661 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3663 DWORD sz = sizeof(DWORD), type, value = 0;
3664 LONG ret;
3666 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3668 if(ret != ERROR_SUCCESS) {
3669 WARN("Got ret = %d on name %s\n", ret, ValueName);
3670 return 0;
3672 if(type != REG_DWORD) {
3673 ERR("Got type %d\n", type);
3674 return 0;
3676 return value;
3680 /*****************************************************************************
3681 * get_filename_from_reg [internal]
3683 * Get ValueName from hkey storing result in out
3684 * when the Value in the registry has only a filename, use driverdir as prefix
3685 * outlen is space left in out
3686 * String is stored either as unicode or ascii
3690 static BOOL get_filename_from_reg(HKEY hkey, LPCWSTR driverdir, DWORD dirlen, LPCWSTR ValueName,
3691 LPBYTE out, DWORD outlen, LPDWORD needed, BOOL unicode)
3693 WCHAR filename[MAX_PATH];
3694 DWORD size;
3695 DWORD type;
3696 LONG ret;
3697 LPWSTR buffer = filename;
3698 LPWSTR ptr;
3700 *needed = 0;
3701 size = sizeof(filename);
3702 buffer[0] = '\0';
3703 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3704 if (ret == ERROR_MORE_DATA) {
3705 TRACE("need dynamic buffer: %u\n", size);
3706 buffer = HeapAlloc(GetProcessHeap(), 0, size);
3707 if (!buffer) {
3708 /* No Memory is bad */
3709 return FALSE;
3711 buffer[0] = '\0';
3712 ret = RegQueryValueExW(hkey, ValueName, NULL, &type, (LPBYTE) buffer, &size);
3715 if ((ret != ERROR_SUCCESS) || (!buffer[0])) {
3716 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3717 return FALSE;
3720 ptr = buffer;
3721 while (ptr) {
3722 /* do we have a full path ? */
3723 ret = (((buffer[0] == '\\') && (buffer[1] == '\\')) ||
3724 (buffer[0] && (buffer[1] == ':') && (buffer[2] == '\\')) );
3726 if (!ret) {
3727 /* we must build the full Path */
3728 *needed += dirlen;
3729 if ((out) && (outlen > dirlen)) {
3730 if (unicode) {
3731 lstrcpyW((LPWSTR)out, driverdir);
3733 else
3735 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, (LPSTR)out, outlen, NULL, NULL);
3737 out += dirlen;
3738 outlen -= dirlen;
3740 else
3741 out = NULL;
3744 /* write the filename */
3745 if (unicode) {
3746 size = (lstrlenW(ptr) + 1) * sizeof(WCHAR);
3747 if ((out) && (outlen >= size)) {
3748 lstrcpyW((LPWSTR)out, ptr);
3749 out += size;
3750 outlen -= size;
3752 else
3753 out = NULL;
3755 else
3757 size = WideCharToMultiByte(CP_ACP, 0, ptr, -1, NULL, 0, NULL, NULL);
3758 if ((out) && (outlen >= size)) {
3759 WideCharToMultiByte(CP_ACP, 0, ptr, -1, (LPSTR)out, outlen, NULL, NULL);
3760 out += size;
3761 outlen -= size;
3763 else
3764 out = NULL;
3766 *needed += size;
3767 ptr += lstrlenW(ptr)+1;
3768 if ((type != REG_MULTI_SZ) || (!ptr[0])) ptr = NULL;
3771 if (buffer != filename) HeapFree(GetProcessHeap(), 0, buffer);
3773 /* write the multisz-termination */
3774 if (type == REG_MULTI_SZ) {
3775 size = (unicode) ? sizeof(WCHAR) : 1;
3777 *needed += size;
3778 if (out && (outlen >= size)) {
3779 memset (out, 0, size);
3782 return TRUE;
3785 /*****************************************************************************
3786 * WINSPOOL_GetStringFromReg
3788 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3789 * String is stored either as unicode or ascii.
3790 * Bit of a hack here to get the ValueName if we want ascii.
3792 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3793 DWORD buflen, DWORD *needed,
3794 BOOL unicode)
3796 DWORD sz = buflen, type;
3797 LONG ret;
3799 if(unicode)
3800 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3801 else {
3802 LPSTR ValueNameA = strdupWtoA(ValueName);
3803 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3804 HeapFree(GetProcessHeap(),0,ValueNameA);
3806 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3807 WARN("Got ret = %d\n", ret);
3808 *needed = 0;
3809 return FALSE;
3811 /* add space for terminating '\0' */
3812 sz += unicode ? sizeof(WCHAR) : 1;
3813 *needed = sz;
3815 if (ptr)
3816 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3818 return TRUE;
3821 /*****************************************************************************
3822 * WINSPOOL_GetDefaultDevMode
3824 * Get a default DevMode values for wineps.
3825 * FIXME - use ppd.
3828 static void WINSPOOL_GetDefaultDevMode(
3829 LPBYTE ptr,
3830 DWORD buflen, DWORD *needed,
3831 BOOL unicode)
3833 DEVMODEA dm;
3834 static const char szwps[] = "wineps.drv";
3836 /* fill default DEVMODE - should be read from ppd... */
3837 ZeroMemory( &dm, sizeof(dm) );
3838 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3839 dm.dmSpecVersion = DM_SPECVERSION;
3840 dm.dmDriverVersion = 1;
3841 dm.dmSize = sizeof(DEVMODEA);
3842 dm.dmDriverExtra = 0;
3843 dm.dmFields =
3844 DM_ORIENTATION | DM_PAPERSIZE |
3845 DM_PAPERLENGTH | DM_PAPERWIDTH |
3846 DM_SCALE |
3847 DM_COPIES |
3848 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3849 DM_YRESOLUTION | DM_TTOPTION;
3851 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3852 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3853 dm.u1.s1.dmPaperLength = 2970;
3854 dm.u1.s1.dmPaperWidth = 2100;
3856 dm.u1.s1.dmScale = 100;
3857 dm.u1.s1.dmCopies = 1;
3858 dm.u1.s1.dmDefaultSource = DMBIN_AUTO;
3859 dm.u1.s1.dmPrintQuality = DMRES_MEDIUM;
3860 /* dm.dmColor */
3861 /* dm.dmDuplex */
3862 dm.dmYResolution = 300; /* 300dpi */
3863 dm.dmTTOption = DMTT_BITMAP;
3864 /* dm.dmCollate */
3865 /* dm.dmFormName */
3866 /* dm.dmLogPixels */
3867 /* dm.dmBitsPerPel */
3868 /* dm.dmPelsWidth */
3869 /* dm.dmPelsHeight */
3870 /* dm.u2.dmDisplayFlags */
3871 /* dm.dmDisplayFrequency */
3872 /* dm.dmICMMethod */
3873 /* dm.dmICMIntent */
3874 /* dm.dmMediaType */
3875 /* dm.dmDitherType */
3876 /* dm.dmReserved1 */
3877 /* dm.dmReserved2 */
3878 /* dm.dmPanningWidth */
3879 /* dm.dmPanningHeight */
3881 if(unicode) {
3882 if(buflen >= sizeof(DEVMODEW)) {
3883 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3884 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3885 HeapFree(GetProcessHeap(),0,pdmW);
3887 *needed = sizeof(DEVMODEW);
3889 else
3891 if(buflen >= sizeof(DEVMODEA)) {
3892 memcpy(ptr, &dm, sizeof(DEVMODEA));
3894 *needed = sizeof(DEVMODEA);
3898 /*****************************************************************************
3899 * WINSPOOL_GetDevModeFromReg
3901 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3902 * DevMode is stored either as unicode or ascii.
3904 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3905 LPBYTE ptr,
3906 DWORD buflen, DWORD *needed,
3907 BOOL unicode)
3909 DWORD sz = buflen, type;
3910 LONG ret;
3912 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3913 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3914 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3915 if (sz < sizeof(DEVMODEA))
3917 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3918 return FALSE;
3920 /* ensures that dmSize is not erratically bogus if registry is invalid */
3921 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3922 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3923 if(unicode) {
3924 sz += (CCHDEVICENAME + CCHFORMNAME);
3925 if(buflen >= sz) {
3926 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3927 memcpy(ptr, dmW, sz);
3928 HeapFree(GetProcessHeap(),0,dmW);
3931 *needed = sz;
3932 return TRUE;
3935 /*********************************************************************
3936 * WINSPOOL_GetPrinter_1
3938 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3939 * The strings are either stored as unicode or ascii.
3941 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3942 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3943 BOOL unicode)
3945 DWORD size, left = cbBuf;
3946 BOOL space = (cbBuf > 0);
3947 LPBYTE ptr = buf;
3949 *pcbNeeded = 0;
3951 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3952 unicode)) {
3953 if(space && size <= left) {
3954 pi1->pName = (LPWSTR)ptr;
3955 ptr += size;
3956 left -= size;
3957 } else
3958 space = FALSE;
3959 *pcbNeeded += size;
3962 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3963 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3964 unicode)) {
3965 if(space && size <= left) {
3966 pi1->pDescription = (LPWSTR)ptr;
3967 ptr += size;
3968 left -= size;
3969 } else
3970 space = FALSE;
3971 *pcbNeeded += size;
3974 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3975 unicode)) {
3976 if(space && size <= left) {
3977 pi1->pComment = (LPWSTR)ptr;
3978 ptr += size;
3979 left -= size;
3980 } else
3981 space = FALSE;
3982 *pcbNeeded += size;
3985 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3987 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3988 memset(pi1, 0, sizeof(*pi1));
3990 return space;
3992 /*********************************************************************
3993 * WINSPOOL_GetPrinter_2
3995 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3996 * The strings are either stored as unicode or ascii.
3998 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3999 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4000 BOOL unicode)
4002 DWORD size, left = cbBuf;
4003 BOOL space = (cbBuf > 0);
4004 LPBYTE ptr = buf;
4006 *pcbNeeded = 0;
4008 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4009 unicode)) {
4010 if(space && size <= left) {
4011 pi2->pPrinterName = (LPWSTR)ptr;
4012 ptr += size;
4013 left -= size;
4014 } else
4015 space = FALSE;
4016 *pcbNeeded += size;
4018 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
4019 unicode)) {
4020 if(space && size <= left) {
4021 pi2->pShareName = (LPWSTR)ptr;
4022 ptr += size;
4023 left -= size;
4024 } else
4025 space = FALSE;
4026 *pcbNeeded += size;
4028 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4029 unicode)) {
4030 if(space && size <= left) {
4031 pi2->pPortName = (LPWSTR)ptr;
4032 ptr += size;
4033 left -= size;
4034 } else
4035 space = FALSE;
4036 *pcbNeeded += size;
4038 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
4039 &size, unicode)) {
4040 if(space && size <= left) {
4041 pi2->pDriverName = (LPWSTR)ptr;
4042 ptr += size;
4043 left -= size;
4044 } else
4045 space = FALSE;
4046 *pcbNeeded += size;
4048 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
4049 unicode)) {
4050 if(space && size <= left) {
4051 pi2->pComment = (LPWSTR)ptr;
4052 ptr += size;
4053 left -= size;
4054 } else
4055 space = FALSE;
4056 *pcbNeeded += size;
4058 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
4059 unicode)) {
4060 if(space && size <= left) {
4061 pi2->pLocation = (LPWSTR)ptr;
4062 ptr += size;
4063 left -= size;
4064 } else
4065 space = FALSE;
4066 *pcbNeeded += size;
4068 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
4069 &size, unicode)) {
4070 if(space && size <= left) {
4071 pi2->pDevMode = (LPDEVMODEW)ptr;
4072 ptr += size;
4073 left -= size;
4074 } else
4075 space = FALSE;
4076 *pcbNeeded += size;
4078 else
4080 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
4081 if(space && size <= left) {
4082 pi2->pDevMode = (LPDEVMODEW)ptr;
4083 ptr += size;
4084 left -= size;
4085 } else
4086 space = FALSE;
4087 *pcbNeeded += size;
4089 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
4090 &size, unicode)) {
4091 if(space && size <= left) {
4092 pi2->pSepFile = (LPWSTR)ptr;
4093 ptr += size;
4094 left -= size;
4095 } else
4096 space = FALSE;
4097 *pcbNeeded += size;
4099 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
4100 &size, unicode)) {
4101 if(space && size <= left) {
4102 pi2->pPrintProcessor = (LPWSTR)ptr;
4103 ptr += size;
4104 left -= size;
4105 } else
4106 space = FALSE;
4107 *pcbNeeded += size;
4109 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
4110 &size, unicode)) {
4111 if(space && size <= left) {
4112 pi2->pDatatype = (LPWSTR)ptr;
4113 ptr += size;
4114 left -= size;
4115 } else
4116 space = FALSE;
4117 *pcbNeeded += size;
4119 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
4120 &size, unicode)) {
4121 if(space && size <= left) {
4122 pi2->pParameters = (LPWSTR)ptr;
4123 ptr += size;
4124 left -= size;
4125 } else
4126 space = FALSE;
4127 *pcbNeeded += size;
4129 if(pi2) {
4130 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4131 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
4132 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4133 "Default Priority");
4134 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
4135 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
4138 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
4139 memset(pi2, 0, sizeof(*pi2));
4141 return space;
4144 /*********************************************************************
4145 * WINSPOOL_GetPrinter_4
4147 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
4149 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
4150 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4151 BOOL unicode)
4153 DWORD size, left = cbBuf;
4154 BOOL space = (cbBuf > 0);
4155 LPBYTE ptr = buf;
4157 *pcbNeeded = 0;
4159 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4160 unicode)) {
4161 if(space && size <= left) {
4162 pi4->pPrinterName = (LPWSTR)ptr;
4163 ptr += size;
4164 left -= size;
4165 } else
4166 space = FALSE;
4167 *pcbNeeded += size;
4169 if(pi4) {
4170 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4173 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
4174 memset(pi4, 0, sizeof(*pi4));
4176 return space;
4179 /*********************************************************************
4180 * WINSPOOL_GetPrinter_5
4182 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4184 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
4185 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
4186 BOOL unicode)
4188 DWORD size, left = cbBuf;
4189 BOOL space = (cbBuf > 0);
4190 LPBYTE ptr = buf;
4192 *pcbNeeded = 0;
4194 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
4195 unicode)) {
4196 if(space && size <= left) {
4197 pi5->pPrinterName = (LPWSTR)ptr;
4198 ptr += size;
4199 left -= size;
4200 } else
4201 space = FALSE;
4202 *pcbNeeded += size;
4204 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
4205 unicode)) {
4206 if(space && size <= left) {
4207 pi5->pPortName = (LPWSTR)ptr;
4208 ptr += size;
4209 left -= size;
4210 } else
4211 space = FALSE;
4212 *pcbNeeded += size;
4214 if(pi5) {
4215 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
4216 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4217 "dnsTimeout");
4218 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
4219 "txTimeout");
4222 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
4223 memset(pi5, 0, sizeof(*pi5));
4225 return space;
4228 /*********************************************************************
4229 * WINSPOOL_GetPrinter_7
4231 * Fills out a PRINTER_INFO_7 struct storing the strings in buf.
4233 static BOOL WINSPOOL_GetPrinter_7(HKEY hkeyPrinter, PRINTER_INFO_7W *pi7, LPBYTE buf,
4234 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4236 DWORD size, left = cbBuf;
4237 BOOL space = (cbBuf > 0);
4238 LPBYTE ptr = buf;
4240 *pcbNeeded = 0;
4242 if (WINSPOOL_GetStringFromReg(hkeyPrinter, ObjectGUIDW, ptr, left, &size, unicode))
4244 if (space && size <= left) {
4245 pi7->pszObjectGUID = (LPWSTR)ptr;
4246 ptr += size;
4247 left -= size;
4248 } else
4249 space = FALSE;
4250 *pcbNeeded += size;
4252 if (pi7) {
4253 /* We do not have a Directory Service */
4254 pi7->dwAction = DSPRINT_UNPUBLISH;
4257 if (!space && pi7) /* zero out pi7 if we can't completely fill buf */
4258 memset(pi7, 0, sizeof(*pi7));
4260 return space;
4263 /*********************************************************************
4264 * WINSPOOL_GetPrinter_9
4266 * Fills out a PRINTER_INFO_9A|W struct storing the strings in buf.
4267 * The strings are either stored as unicode or ascii.
4269 static BOOL WINSPOOL_GetPrinter_9(HKEY hkeyPrinter, PRINTER_INFO_9W *pi9, LPBYTE buf,
4270 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4272 DWORD size;
4273 BOOL space = (cbBuf > 0);
4275 *pcbNeeded = 0;
4277 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, buf, cbBuf, &size, unicode)) {
4278 if(space && size <= cbBuf) {
4279 pi9->pDevMode = (LPDEVMODEW)buf;
4280 } else
4281 space = FALSE;
4282 *pcbNeeded += size;
4284 else
4286 WINSPOOL_GetDefaultDevMode(buf, cbBuf, &size, unicode);
4287 if(space && size <= cbBuf) {
4288 pi9->pDevMode = (LPDEVMODEW)buf;
4289 } else
4290 space = FALSE;
4291 *pcbNeeded += size;
4294 if(!space && pi9) /* zero out pi9 if we can't completely fill buf */
4295 memset(pi9, 0, sizeof(*pi9));
4297 return space;
4300 /*****************************************************************************
4301 * WINSPOOL_GetPrinter
4303 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4304 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4305 * just a collection of pointers to strings.
4307 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4308 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
4310 LPCWSTR name;
4311 DWORD size, needed = 0;
4312 LPBYTE ptr = NULL;
4313 HKEY hkeyPrinter, hkeyPrinters;
4314 BOOL ret;
4316 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
4318 if (!(name = get_opened_printer_name(hPrinter))) {
4319 SetLastError(ERROR_INVALID_HANDLE);
4320 return FALSE;
4323 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4324 ERROR_SUCCESS) {
4325 ERR("Can't create Printers key\n");
4326 return FALSE;
4328 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
4330 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4331 RegCloseKey(hkeyPrinters);
4332 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4333 return FALSE;
4336 switch(Level) {
4337 case 2:
4339 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
4341 size = sizeof(PRINTER_INFO_2W);
4342 if(size <= cbBuf) {
4343 ptr = pPrinter + size;
4344 cbBuf -= size;
4345 memset(pPrinter, 0, size);
4346 } else {
4347 pi2 = NULL;
4348 cbBuf = 0;
4350 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
4351 unicode);
4352 needed += size;
4353 break;
4356 case 4:
4358 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
4360 size = sizeof(PRINTER_INFO_4W);
4361 if(size <= cbBuf) {
4362 ptr = pPrinter + size;
4363 cbBuf -= size;
4364 memset(pPrinter, 0, size);
4365 } else {
4366 pi4 = NULL;
4367 cbBuf = 0;
4369 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
4370 unicode);
4371 needed += size;
4372 break;
4376 case 5:
4378 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
4380 size = sizeof(PRINTER_INFO_5W);
4381 if(size <= cbBuf) {
4382 ptr = pPrinter + size;
4383 cbBuf -= size;
4384 memset(pPrinter, 0, size);
4385 } else {
4386 pi5 = NULL;
4387 cbBuf = 0;
4390 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4391 unicode);
4392 needed += size;
4393 break;
4397 case 6:
4399 PRINTER_INFO_6 *pi6 = (PRINTER_INFO_6 *) pPrinter;
4401 size = sizeof(PRINTER_INFO_6);
4402 if (size <= cbBuf) {
4403 /* FIXME: We do not update the status yet */
4404 pi6->dwStatus = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Status");
4405 ret = TRUE;
4406 } else {
4407 ret = FALSE;
4410 needed += size;
4411 break;
4414 case 7:
4416 PRINTER_INFO_7W *pi7 = (PRINTER_INFO_7W *) pPrinter;
4418 size = sizeof(PRINTER_INFO_7W);
4419 if (size <= cbBuf) {
4420 ptr = pPrinter + size;
4421 cbBuf -= size;
4422 memset(pPrinter, 0, size);
4423 } else {
4424 pi7 = NULL;
4425 cbBuf = 0;
4428 ret = WINSPOOL_GetPrinter_7(hkeyPrinter, pi7, ptr, cbBuf, &needed, unicode);
4429 needed += size;
4430 break;
4434 case 9:
4436 PRINTER_INFO_9W *pi9 = (PRINTER_INFO_9W *)pPrinter;
4438 size = sizeof(PRINTER_INFO_9W);
4439 if(size <= cbBuf) {
4440 ptr = pPrinter + size;
4441 cbBuf -= size;
4442 memset(pPrinter, 0, size);
4443 } else {
4444 pi9 = NULL;
4445 cbBuf = 0;
4448 ret = WINSPOOL_GetPrinter_9(hkeyPrinter, pi9, ptr, cbBuf, &needed, unicode);
4449 needed += size;
4450 break;
4454 default:
4455 FIXME("Unimplemented level %d\n", Level);
4456 SetLastError(ERROR_INVALID_LEVEL);
4457 RegCloseKey(hkeyPrinters);
4458 RegCloseKey(hkeyPrinter);
4459 return FALSE;
4462 RegCloseKey(hkeyPrinter);
4463 RegCloseKey(hkeyPrinters);
4465 TRACE("returning %d needed = %d\n", ret, needed);
4466 if(pcbNeeded) *pcbNeeded = needed;
4467 if(!ret)
4468 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4469 return ret;
4472 /*****************************************************************************
4473 * GetPrinterW [WINSPOOL.@]
4475 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4476 DWORD cbBuf, LPDWORD pcbNeeded)
4478 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4479 TRUE);
4482 /*****************************************************************************
4483 * GetPrinterA [WINSPOOL.@]
4485 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4486 DWORD cbBuf, LPDWORD pcbNeeded)
4488 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4489 FALSE);
4492 /*****************************************************************************
4493 * WINSPOOL_EnumPrinters
4495 * Implementation of EnumPrintersA|W
4497 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4498 DWORD dwLevel, LPBYTE lpbPrinters,
4499 DWORD cbBuf, LPDWORD lpdwNeeded,
4500 LPDWORD lpdwReturned, BOOL unicode)
4503 HKEY hkeyPrinters, hkeyPrinter;
4504 WCHAR PrinterName[255];
4505 DWORD needed = 0, number = 0;
4506 DWORD used, i, left;
4507 PBYTE pi, buf;
4509 if(lpbPrinters)
4510 memset(lpbPrinters, 0, cbBuf);
4511 if(lpdwReturned)
4512 *lpdwReturned = 0;
4513 if(lpdwNeeded)
4514 *lpdwNeeded = 0;
4516 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4517 if(dwType == PRINTER_ENUM_DEFAULT)
4518 return TRUE;
4520 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4521 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4522 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4523 if (!dwType) {
4524 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4525 *lpdwNeeded = 0;
4526 *lpdwReturned = 0;
4527 return TRUE;
4532 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4533 FIXME("dwType = %08x\n", dwType);
4534 SetLastError(ERROR_INVALID_FLAGS);
4535 return FALSE;
4538 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4539 ERROR_SUCCESS) {
4540 ERR("Can't create Printers key\n");
4541 return FALSE;
4544 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4545 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4546 RegCloseKey(hkeyPrinters);
4547 ERR("Can't query Printers key\n");
4548 return FALSE;
4550 TRACE("Found %d printers\n", number);
4552 switch(dwLevel) {
4553 case 1:
4554 used = number * sizeof(PRINTER_INFO_1W);
4555 break;
4556 case 2:
4557 used = number * sizeof(PRINTER_INFO_2W);
4558 break;
4559 case 4:
4560 used = number * sizeof(PRINTER_INFO_4W);
4561 break;
4562 case 5:
4563 used = number * sizeof(PRINTER_INFO_5W);
4564 break;
4566 default:
4567 SetLastError(ERROR_INVALID_LEVEL);
4568 RegCloseKey(hkeyPrinters);
4569 return FALSE;
4571 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4573 for(i = 0; i < number; i++) {
4574 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)/sizeof(PrinterName[0])) !=
4575 ERROR_SUCCESS) {
4576 ERR("Can't enum key number %d\n", i);
4577 RegCloseKey(hkeyPrinters);
4578 return FALSE;
4580 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4581 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4582 ERROR_SUCCESS) {
4583 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4584 RegCloseKey(hkeyPrinters);
4585 return FALSE;
4588 if(cbBuf > used) {
4589 buf = lpbPrinters + used;
4590 left = cbBuf - used;
4591 } else {
4592 buf = NULL;
4593 left = 0;
4596 switch(dwLevel) {
4597 case 1:
4598 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4599 left, &needed, unicode);
4600 used += needed;
4601 if(pi) pi += sizeof(PRINTER_INFO_1W);
4602 break;
4603 case 2:
4604 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4605 left, &needed, unicode);
4606 used += needed;
4607 if(pi) pi += sizeof(PRINTER_INFO_2W);
4608 break;
4609 case 4:
4610 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4611 left, &needed, unicode);
4612 used += needed;
4613 if(pi) pi += sizeof(PRINTER_INFO_4W);
4614 break;
4615 case 5:
4616 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4617 left, &needed, unicode);
4618 used += needed;
4619 if(pi) pi += sizeof(PRINTER_INFO_5W);
4620 break;
4621 default:
4622 ERR("Shouldn't be here!\n");
4623 RegCloseKey(hkeyPrinter);
4624 RegCloseKey(hkeyPrinters);
4625 return FALSE;
4627 RegCloseKey(hkeyPrinter);
4629 RegCloseKey(hkeyPrinters);
4631 if(lpdwNeeded)
4632 *lpdwNeeded = used;
4634 if(used > cbBuf) {
4635 if(lpbPrinters)
4636 memset(lpbPrinters, 0, cbBuf);
4637 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4638 return FALSE;
4640 if(lpdwReturned)
4641 *lpdwReturned = number;
4642 SetLastError(ERROR_SUCCESS);
4643 return TRUE;
4647 /******************************************************************
4648 * EnumPrintersW [WINSPOOL.@]
4650 * Enumerates the available printers, print servers and print
4651 * providers, depending on the specified flags, name and level.
4653 * RETURNS:
4655 * If level is set to 1:
4656 * Returns an array of PRINTER_INFO_1 data structures in the
4657 * lpbPrinters buffer.
4659 * If level is set to 2:
4660 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4661 * Returns an array of PRINTER_INFO_2 data structures in the
4662 * lpbPrinters buffer. Note that according to MSDN also an
4663 * OpenPrinter should be performed on every remote printer.
4665 * If level is set to 4 (officially WinNT only):
4666 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4667 * Fast: Only the registry is queried to retrieve printer names,
4668 * no connection to the driver is made.
4669 * Returns an array of PRINTER_INFO_4 data structures in the
4670 * lpbPrinters buffer.
4672 * If level is set to 5 (officially WinNT4/Win9x only):
4673 * Fast: Only the registry is queried to retrieve printer names,
4674 * no connection to the driver is made.
4675 * Returns an array of PRINTER_INFO_5 data structures in the
4676 * lpbPrinters buffer.
4678 * If level set to 3 or 6+:
4679 * returns zero (failure!)
4681 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4682 * for information.
4684 * BUGS:
4685 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4686 * - Only levels 2, 4 and 5 are implemented at the moment.
4687 * - 16-bit printer drivers are not enumerated.
4688 * - Returned amount of bytes used/needed does not match the real Windoze
4689 * implementation (as in this implementation, all strings are part
4690 * of the buffer, whereas Win32 keeps them somewhere else)
4691 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4693 * NOTE:
4694 * - In a regular Wine installation, no registry settings for printers
4695 * exist, which makes this function return an empty list.
4697 BOOL WINAPI EnumPrintersW(
4698 DWORD dwType, /* [in] Types of print objects to enumerate */
4699 LPWSTR lpszName, /* [in] name of objects to enumerate */
4700 DWORD dwLevel, /* [in] type of printer info structure */
4701 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4702 DWORD cbBuf, /* [in] max size of buffer in bytes */
4703 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4704 LPDWORD lpdwReturned /* [out] number of entries returned */
4707 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4708 lpdwNeeded, lpdwReturned, TRUE);
4711 /******************************************************************
4712 * EnumPrintersA [WINSPOOL.@]
4714 * See EnumPrintersW
4717 BOOL WINAPI EnumPrintersA(DWORD flags, LPSTR pName, DWORD level, LPBYTE pPrinters,
4718 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
4720 BOOL ret;
4721 UNICODE_STRING pNameU;
4722 LPWSTR pNameW;
4723 LPBYTE pPrintersW;
4725 TRACE("(0x%x, %s, %u, %p, %d, %p, %p)\n", flags, debugstr_a(pName), level,
4726 pPrinters, cbBuf, pcbNeeded, pcReturned);
4728 pNameW = asciitounicode(&pNameU, pName);
4730 /* Request a buffer with a size, that is big enough for EnumPrintersW.
4731 MS Office need this */
4732 pPrintersW = (pPrinters && cbBuf) ? HeapAlloc(GetProcessHeap(), 0, cbBuf) : NULL;
4734 ret = EnumPrintersW(flags, pNameW, level, pPrintersW, cbBuf, pcbNeeded, pcReturned);
4736 RtlFreeUnicodeString(&pNameU);
4737 if (ret) {
4738 convert_printerinfo_W_to_A(pPrinters, pPrintersW, level, *pcbNeeded, *pcReturned);
4740 HeapFree(GetProcessHeap(), 0, pPrintersW);
4741 return ret;
4744 /*****************************************************************************
4745 * WINSPOOL_GetDriverInfoFromReg [internal]
4747 * Enters the information from the registry into the DRIVER_INFO struct
4749 * RETURNS
4750 * zero if the printer driver does not exist in the registry
4751 * (only if Level > 1) otherwise nonzero
4753 static BOOL WINSPOOL_GetDriverInfoFromReg(
4754 HKEY hkeyDrivers,
4755 LPWSTR DriverName,
4756 const printenv_t * env,
4757 DWORD Level,
4758 LPBYTE ptr, /* DRIVER_INFO */
4759 LPBYTE pDriverStrings, /* strings buffer */
4760 DWORD cbBuf, /* size of string buffer */
4761 LPDWORD pcbNeeded, /* space needed for str. */
4762 BOOL unicode) /* type of strings */
4764 DWORD size, tmp;
4765 HKEY hkeyDriver;
4766 WCHAR driverdir[MAX_PATH];
4767 DWORD dirlen;
4768 LPBYTE strPtr = pDriverStrings;
4769 LPDRIVER_INFO_8W di = (LPDRIVER_INFO_8W) ptr;
4771 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers,
4772 debugstr_w(DriverName), env,
4773 Level, di, pDriverStrings, cbBuf, unicode);
4775 if (di) ZeroMemory(di, di_sizeof[Level]);
4777 if (unicode) {
4778 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4779 if (*pcbNeeded <= cbBuf)
4780 strcpyW((LPWSTR)strPtr, DriverName);
4782 else
4784 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0, NULL, NULL);
4785 if (*pcbNeeded <= cbBuf)
4786 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4789 /* pName for level 1 has a different offset! */
4790 if (Level == 1) {
4791 if (di) ((LPDRIVER_INFO_1W) di)->pName = (LPWSTR) strPtr;
4792 return TRUE;
4795 /* .cVersion and .pName for level > 1 */
4796 if (di) {
4797 di->cVersion = env->driverversion;
4798 di->pName = (LPWSTR) strPtr;
4799 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4802 /* Reserve Space for the largest subdir and a Backslash*/
4803 size = sizeof(driverdir) - sizeof(Version3_SubdirW) - sizeof(WCHAR);
4804 if (!GetPrinterDriverDirectoryW(NULL, (LPWSTR) env->envname, 1, (LPBYTE) driverdir, size, &size)) {
4805 /* Should never Fail */
4806 return FALSE;
4808 lstrcatW(driverdir, env->versionsubdir);
4809 lstrcatW(driverdir, backslashW);
4811 /* dirlen must not include the terminating zero */
4812 dirlen = (unicode) ? lstrlenW(driverdir) * sizeof(WCHAR) :
4813 WideCharToMultiByte(CP_ACP, 0, driverdir, -1, NULL, 0, NULL, NULL) -1;
4815 if (!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4816 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4817 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4818 return FALSE;
4821 /* pEnvironment */
4822 if (unicode)
4823 size = (lstrlenW(env->envname) + 1) * sizeof(WCHAR);
4824 else
4825 size = WideCharToMultiByte(CP_ACP, 0, env->envname, -1, NULL, 0, NULL, NULL);
4827 *pcbNeeded += size;
4828 if (*pcbNeeded <= cbBuf) {
4829 if (unicode) {
4830 lstrcpyW((LPWSTR)strPtr, env->envname);
4832 else
4834 WideCharToMultiByte(CP_ACP, 0, env->envname, -1, (LPSTR)strPtr, size, NULL, NULL);
4836 if (di) di->pEnvironment = (LPWSTR)strPtr;
4837 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4840 /* .pDriverPath is the Graphics rendering engine.
4841 The full Path is required to avoid a crash in some apps */
4842 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, 0, &size, unicode)) {
4843 *pcbNeeded += size;
4844 if (*pcbNeeded <= cbBuf)
4845 get_filename_from_reg(hkeyDriver, driverdir, dirlen, DriverW, strPtr, size, &tmp, unicode);
4847 if (di) di->pDriverPath = (LPWSTR)strPtr;
4848 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4851 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4852 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, 0, &size, unicode)) {
4853 *pcbNeeded += size;
4854 if (*pcbNeeded <= cbBuf)
4855 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Data_FileW, strPtr, size, &size, unicode);
4857 if (di) di->pDataFile = (LPWSTR)strPtr;
4858 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4861 /* .pConfigFile is the Driver user Interface */
4862 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, 0, &size, unicode)) {
4863 *pcbNeeded += size;
4864 if (*pcbNeeded <= cbBuf)
4865 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Configuration_FileW, strPtr, size, &size, unicode);
4867 if (di) di->pConfigFile = (LPWSTR)strPtr;
4868 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4871 if (Level == 2 ) {
4872 RegCloseKey(hkeyDriver);
4873 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4874 return TRUE;
4877 if (Level == 5 ) {
4878 RegCloseKey(hkeyDriver);
4879 FIXME("level 5: incomplete\n");
4880 return TRUE;
4883 /* .pHelpFile */
4884 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, 0, &size, unicode)) {
4885 *pcbNeeded += size;
4886 if (*pcbNeeded <= cbBuf)
4887 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Help_FileW, strPtr, size, &size, unicode);
4889 if (di) di->pHelpFile = (LPWSTR)strPtr;
4890 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4893 /* .pDependentFiles */
4894 if (get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, 0, &size, unicode)) {
4895 *pcbNeeded += size;
4896 if (*pcbNeeded <= cbBuf)
4897 get_filename_from_reg(hkeyDriver, driverdir, dirlen, Dependent_FilesW, strPtr, size, &size, unicode);
4899 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4900 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4902 else if (GetVersion() & 0x80000000) {
4903 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4904 size = 2 * ((unicode) ? sizeof(WCHAR) : 1);
4905 *pcbNeeded += size;
4906 if ((*pcbNeeded <= cbBuf) && strPtr) ZeroMemory(strPtr, size);
4908 if (di) di->pDependentFiles = (LPWSTR)strPtr;
4909 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4912 /* .pMonitorName is the optional Language Monitor */
4913 if (WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size, unicode)) {
4914 *pcbNeeded += size;
4915 if (*pcbNeeded <= cbBuf)
4916 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, size, &size, unicode);
4918 if (di) di->pMonitorName = (LPWSTR)strPtr;
4919 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4922 /* .pDefaultDataType */
4923 if (WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size, unicode)) {
4924 *pcbNeeded += size;
4925 if(*pcbNeeded <= cbBuf)
4926 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, size, &size, unicode);
4928 if (di) di->pDefaultDataType = (LPWSTR)strPtr;
4929 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4932 if (Level == 3 ) {
4933 RegCloseKey(hkeyDriver);
4934 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4935 return TRUE;
4938 /* .pszzPreviousNames */
4939 if (WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, 0, &size, unicode)) {
4940 *pcbNeeded += size;
4941 if(*pcbNeeded <= cbBuf)
4942 WINSPOOL_GetStringFromReg(hkeyDriver, Previous_NamesW, strPtr, size, &size, unicode);
4944 if (di) di->pszzPreviousNames = (LPWSTR)strPtr;
4945 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4948 if (Level == 4 ) {
4949 RegCloseKey(hkeyDriver);
4950 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4951 return TRUE;
4954 /* support is missing, but not important enough for a FIXME */
4955 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName));
4957 /* .pszMfgName */
4958 if (WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, 0, &size, unicode)) {
4959 *pcbNeeded += size;
4960 if(*pcbNeeded <= cbBuf)
4961 WINSPOOL_GetStringFromReg(hkeyDriver, ManufacturerW, strPtr, size, &size, unicode);
4963 if (di) di->pszMfgName = (LPWSTR)strPtr;
4964 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4967 /* .pszOEMUrl */
4968 if (WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, 0, &size, unicode)) {
4969 *pcbNeeded += size;
4970 if(*pcbNeeded <= cbBuf)
4971 WINSPOOL_GetStringFromReg(hkeyDriver, OEM_UrlW, strPtr, size, &size, unicode);
4973 if (di) di->pszOEMUrl = (LPWSTR)strPtr;
4974 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4977 /* .pszHardwareID */
4978 if (WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, 0, &size, unicode)) {
4979 *pcbNeeded += size;
4980 if(*pcbNeeded <= cbBuf)
4981 WINSPOOL_GetStringFromReg(hkeyDriver, HardwareIDW, strPtr, size, &size, unicode);
4983 if (di) di->pszHardwareID = (LPWSTR)strPtr;
4984 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4987 /* .pszProvider */
4988 if (WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, 0, &size, unicode)) {
4989 *pcbNeeded += size;
4990 if(*pcbNeeded <= cbBuf)
4991 WINSPOOL_GetStringFromReg(hkeyDriver, ProviderW, strPtr, size, &size, unicode);
4993 if (di) di->pszProvider = (LPWSTR)strPtr;
4994 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4997 if (Level == 6 ) {
4998 RegCloseKey(hkeyDriver);
4999 return TRUE;
5002 /* support is missing, but not important enough for a FIXME */
5003 TRACE("level 8: incomplete\n");
5005 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
5006 RegCloseKey(hkeyDriver);
5007 return TRUE;
5010 /*****************************************************************************
5011 * WINSPOOL_GetPrinterDriver
5013 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
5014 DWORD Level, LPBYTE pDriverInfo,
5015 DWORD cbBuf, LPDWORD pcbNeeded,
5016 BOOL unicode)
5018 LPCWSTR name;
5019 WCHAR DriverName[100];
5020 DWORD ret, type, size, needed = 0;
5021 LPBYTE ptr = NULL;
5022 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
5023 const printenv_t * env;
5025 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
5026 Level,pDriverInfo,cbBuf, pcbNeeded);
5029 if (!(name = get_opened_printer_name(hPrinter))) {
5030 SetLastError(ERROR_INVALID_HANDLE);
5031 return FALSE;
5034 if (Level < 1 || Level == 7 || Level > 8) {
5035 SetLastError(ERROR_INVALID_LEVEL);
5036 return FALSE;
5039 env = validate_envW(pEnvironment);
5040 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5042 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
5043 ERROR_SUCCESS) {
5044 ERR("Can't create Printers key\n");
5045 return FALSE;
5047 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
5048 != ERROR_SUCCESS) {
5049 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
5050 RegCloseKey(hkeyPrinters);
5051 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
5052 return FALSE;
5054 size = sizeof(DriverName);
5055 DriverName[0] = 0;
5056 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
5057 (LPBYTE)DriverName, &size);
5058 RegCloseKey(hkeyPrinter);
5059 RegCloseKey(hkeyPrinters);
5060 if(ret != ERROR_SUCCESS) {
5061 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
5062 return FALSE;
5065 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
5066 if(!hkeyDrivers) {
5067 ERR("Can't create Drivers key\n");
5068 return FALSE;
5071 size = di_sizeof[Level];
5072 if ((size <= cbBuf) && pDriverInfo)
5073 ptr = pDriverInfo + size;
5075 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
5076 env, Level, pDriverInfo, ptr,
5077 (cbBuf < size) ? 0 : cbBuf - size,
5078 &needed, unicode)) {
5079 RegCloseKey(hkeyDrivers);
5080 return FALSE;
5083 RegCloseKey(hkeyDrivers);
5085 if(pcbNeeded) *pcbNeeded = size + needed;
5086 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
5087 if(cbBuf >= needed) return TRUE;
5088 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5089 return FALSE;
5092 /*****************************************************************************
5093 * GetPrinterDriverA [WINSPOOL.@]
5095 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
5096 DWORD Level, LPBYTE pDriverInfo,
5097 DWORD cbBuf, LPDWORD pcbNeeded)
5099 BOOL ret;
5100 UNICODE_STRING pEnvW;
5101 PWSTR pwstrEnvW;
5103 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
5104 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
5105 cbBuf, pcbNeeded, FALSE);
5106 RtlFreeUnicodeString(&pEnvW);
5107 return ret;
5109 /*****************************************************************************
5110 * GetPrinterDriverW [WINSPOOL.@]
5112 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
5113 DWORD Level, LPBYTE pDriverInfo,
5114 DWORD cbBuf, LPDWORD pcbNeeded)
5116 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
5117 pDriverInfo, cbBuf, pcbNeeded, TRUE);
5120 /*****************************************************************************
5121 * GetPrinterDriverDirectoryW [WINSPOOL.@]
5123 * Return the PATH for the Printer-Drivers (UNICODE)
5125 * PARAMS
5126 * pName [I] Servername (NT only) or NULL (local Computer)
5127 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
5128 * Level [I] Structure-Level (must be 1)
5129 * pDriverDirectory [O] PTR to Buffer that receives the Result
5130 * cbBuf [I] Size of Buffer at pDriverDirectory
5131 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
5132 * required for pDriverDirectory
5134 * RETURNS
5135 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
5136 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
5137 * if cbBuf is too small
5139 * Native Values returned in pDriverDirectory on Success:
5140 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
5141 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
5142 *| win9x(Windows 4.0): "%winsysdir%"
5144 * "%winsysdir%" is the Value from GetSystemDirectoryW()
5146 * FIXME
5147 *- Only NULL or "" is supported for pName
5150 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
5151 DWORD Level, LPBYTE pDriverDirectory,
5152 DWORD cbBuf, LPDWORD pcbNeeded)
5154 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
5155 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5157 if ((backend == NULL) && !load_backend()) return FALSE;
5159 if (Level != 1) {
5160 /* (Level != 1) is ignored in win9x */
5161 SetLastError(ERROR_INVALID_LEVEL);
5162 return FALSE;
5164 if (pcbNeeded == NULL) {
5165 /* (pcbNeeded == NULL) is ignored in win9x */
5166 SetLastError(RPC_X_NULL_REF_POINTER);
5167 return FALSE;
5170 return backend->fpGetPrinterDriverDirectory(pName, pEnvironment, Level,
5171 pDriverDirectory, cbBuf, pcbNeeded);
5176 /*****************************************************************************
5177 * GetPrinterDriverDirectoryA [WINSPOOL.@]
5179 * Return the PATH for the Printer-Drivers (ANSI)
5181 * See GetPrinterDriverDirectoryW.
5183 * NOTES
5184 * On NT, pDriverDirectory need the same Size as the Unicode-Version
5187 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
5188 DWORD Level, LPBYTE pDriverDirectory,
5189 DWORD cbBuf, LPDWORD pcbNeeded)
5191 UNICODE_STRING nameW, environmentW;
5192 BOOL ret;
5193 DWORD pcbNeededW;
5194 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
5195 WCHAR *driverDirectoryW = NULL;
5197 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
5198 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
5200 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
5202 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
5203 else nameW.Buffer = NULL;
5204 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
5205 else environmentW.Buffer = NULL;
5207 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
5208 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
5209 if (ret) {
5210 DWORD needed;
5211 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
5212 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
5213 if(pcbNeeded)
5214 *pcbNeeded = needed;
5215 ret = (needed <= cbBuf) ? TRUE : FALSE;
5216 } else
5217 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
5219 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
5221 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
5222 RtlFreeUnicodeString(&environmentW);
5223 RtlFreeUnicodeString(&nameW);
5225 return ret;
5228 /*****************************************************************************
5229 * AddPrinterDriverA [WINSPOOL.@]
5231 * See AddPrinterDriverW.
5234 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
5236 TRACE("(%s, %d, %p)\n", debugstr_a(pName), level, pDriverInfo);
5237 return AddPrinterDriverExA(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5240 /******************************************************************************
5241 * AddPrinterDriverW (WINSPOOL.@)
5243 * Install a Printer Driver
5245 * PARAMS
5246 * pName [I] Servername or NULL (local Computer)
5247 * level [I] Level for the supplied DRIVER_INFO_*W struct
5248 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
5250 * RESULTS
5251 * Success: TRUE
5252 * Failure: FALSE
5255 BOOL WINAPI AddPrinterDriverW(LPWSTR pName, DWORD level, LPBYTE pDriverInfo)
5257 TRACE("(%s, %d, %p)\n", debugstr_w(pName), level, pDriverInfo);
5258 return AddPrinterDriverExW(pName, level, pDriverInfo, APD_COPY_NEW_FILES);
5261 /*****************************************************************************
5262 * AddPrintProcessorA [WINSPOOL.@]
5264 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
5265 LPSTR pPrintProcessorName)
5267 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
5268 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
5269 return FALSE;
5272 /*****************************************************************************
5273 * AddPrintProcessorW [WINSPOOL.@]
5275 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
5276 LPWSTR pPrintProcessorName)
5278 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
5279 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
5280 return FALSE;
5283 /*****************************************************************************
5284 * AddPrintProvidorA [WINSPOOL.@]
5286 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
5288 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
5289 return FALSE;
5292 /*****************************************************************************
5293 * AddPrintProvidorW [WINSPOOL.@]
5295 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
5297 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
5298 return FALSE;
5301 /*****************************************************************************
5302 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5304 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
5305 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
5307 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
5308 pDevModeOutput, pDevModeInput);
5309 return 0;
5312 /*****************************************************************************
5313 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5315 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
5316 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
5318 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
5319 pDevModeOutput, pDevModeInput);
5320 return 0;
5323 /*****************************************************************************
5324 * PrinterProperties [WINSPOOL.@]
5326 * Displays a dialog to set the properties of the printer.
5328 * RETURNS
5329 * nonzero on success or zero on failure
5331 * BUGS
5332 * implemented as stub only
5334 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
5335 HANDLE hPrinter /* [in] handle to printer object */
5337 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
5338 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5339 return FALSE;
5342 /*****************************************************************************
5343 * EnumJobsA [WINSPOOL.@]
5346 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5347 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5348 LPDWORD pcReturned)
5350 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5351 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5353 if(pcbNeeded) *pcbNeeded = 0;
5354 if(pcReturned) *pcReturned = 0;
5355 return FALSE;
5359 /*****************************************************************************
5360 * EnumJobsW [WINSPOOL.@]
5363 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
5364 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
5365 LPDWORD pcReturned)
5367 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5368 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
5370 if(pcbNeeded) *pcbNeeded = 0;
5371 if(pcReturned) *pcReturned = 0;
5372 return FALSE;
5375 /*****************************************************************************
5376 * WINSPOOL_EnumPrinterDrivers [internal]
5378 * Delivers information about all printer drivers installed on the
5379 * localhost or a given server
5381 * RETURNS
5382 * nonzero on success or zero on failure. If the buffer for the returned
5383 * information is too small the function will return an error
5385 * BUGS
5386 * - only implemented for localhost, foreign hosts will return an error
5388 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
5389 DWORD Level, LPBYTE pDriverInfo,
5390 DWORD cbBuf, LPDWORD pcbNeeded,
5391 LPDWORD pcReturned, BOOL unicode)
5393 { HKEY hkeyDrivers;
5394 DWORD i, needed, number = 0, size = 0;
5395 WCHAR DriverNameW[255];
5396 PBYTE ptr;
5397 const printenv_t * env;
5399 TRACE("%s,%s,%d,%p,%d,%d\n",
5400 debugstr_w(pName), debugstr_w(pEnvironment),
5401 Level, pDriverInfo, cbBuf, unicode);
5403 /* check for local drivers */
5404 if((pName) && (pName[0])) {
5405 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
5406 SetLastError(ERROR_ACCESS_DENIED);
5407 return FALSE;
5410 env = validate_envW(pEnvironment);
5411 if (!env) return FALSE; /* SetLastError() is in validate_envW */
5413 /* check input parameter */
5414 if ((Level < 1) || (Level == 7) || (Level > 8)) {
5415 SetLastError(ERROR_INVALID_LEVEL);
5416 return FALSE;
5419 if ((pcbNeeded == NULL) || (pcReturned == NULL)) {
5420 SetLastError(RPC_X_NULL_REF_POINTER);
5421 return FALSE;
5424 /* initialize return values */
5425 if(pDriverInfo)
5426 memset( pDriverInfo, 0, cbBuf);
5427 *pcbNeeded = 0;
5428 *pcReturned = 0;
5430 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
5431 if(!hkeyDrivers) {
5432 ERR("Can't open Drivers key\n");
5433 return FALSE;
5436 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
5437 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
5438 RegCloseKey(hkeyDrivers);
5439 ERR("Can't query Drivers key\n");
5440 return FALSE;
5442 TRACE("Found %d Drivers\n", number);
5444 /* get size of single struct
5445 * unicode and ascii structure have the same size
5447 size = di_sizeof[Level];
5449 /* calculate required buffer size */
5450 *pcbNeeded = size * number;
5452 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5453 i < number;
5454 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5455 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW)/sizeof(DriverNameW[0]))
5456 != ERROR_SUCCESS) {
5457 ERR("Can't enum key number %d\n", i);
5458 RegCloseKey(hkeyDrivers);
5459 return FALSE;
5461 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5462 env, Level, ptr,
5463 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5464 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5465 &needed, unicode)) {
5466 RegCloseKey(hkeyDrivers);
5467 return FALSE;
5469 (*pcbNeeded) += needed;
5472 RegCloseKey(hkeyDrivers);
5474 if(cbBuf < *pcbNeeded){
5475 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5476 return FALSE;
5479 *pcReturned = number;
5480 return TRUE;
5483 /*****************************************************************************
5484 * EnumPrinterDriversW [WINSPOOL.@]
5486 * see function EnumPrinterDrivers for RETURNS, BUGS
5488 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5489 LPBYTE pDriverInfo, DWORD cbBuf,
5490 LPDWORD pcbNeeded, LPDWORD pcReturned)
5492 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5493 cbBuf, pcbNeeded, pcReturned, TRUE);
5496 /*****************************************************************************
5497 * EnumPrinterDriversA [WINSPOOL.@]
5499 * see function EnumPrinterDrivers for RETURNS, BUGS
5501 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5502 LPBYTE pDriverInfo, DWORD cbBuf,
5503 LPDWORD pcbNeeded, LPDWORD pcReturned)
5504 { BOOL ret;
5505 UNICODE_STRING pNameW, pEnvironmentW;
5506 PWSTR pwstrNameW, pwstrEnvironmentW;
5508 pwstrNameW = asciitounicode(&pNameW, pName);
5509 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5511 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5512 Level, pDriverInfo, cbBuf, pcbNeeded,
5513 pcReturned, FALSE);
5514 RtlFreeUnicodeString(&pNameW);
5515 RtlFreeUnicodeString(&pEnvironmentW);
5517 return ret;
5520 /******************************************************************************
5521 * EnumPortsA (WINSPOOL.@)
5523 * See EnumPortsW.
5526 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5527 LPDWORD pcbNeeded, LPDWORD pcReturned)
5529 BOOL res;
5530 LPBYTE bufferW = NULL;
5531 LPWSTR nameW = NULL;
5532 DWORD needed = 0;
5533 DWORD numentries = 0;
5534 INT len;
5536 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5537 cbBuf, pcbNeeded, pcReturned);
5539 /* convert servername to unicode */
5540 if (pName) {
5541 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5542 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5543 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5545 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5546 needed = cbBuf * sizeof(WCHAR);
5547 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5548 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5550 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5551 if (pcbNeeded) needed = *pcbNeeded;
5552 /* HeapReAlloc return NULL, when bufferW was NULL */
5553 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5554 HeapAlloc(GetProcessHeap(), 0, needed);
5556 /* Try again with the large Buffer */
5557 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5559 needed = pcbNeeded ? *pcbNeeded : 0;
5560 numentries = pcReturned ? *pcReturned : 0;
5563 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5564 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5566 if (res) {
5567 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5568 DWORD entrysize = 0;
5569 DWORD index;
5570 LPSTR ptr;
5571 LPPORT_INFO_2W pi2w;
5572 LPPORT_INFO_2A pi2a;
5574 needed = 0;
5575 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5577 /* First pass: calculate the size for all Entries */
5578 pi2w = (LPPORT_INFO_2W) bufferW;
5579 pi2a = (LPPORT_INFO_2A) pPorts;
5580 index = 0;
5581 while (index < numentries) {
5582 index++;
5583 needed += entrysize; /* PORT_INFO_?A */
5584 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5586 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5587 NULL, 0, NULL, NULL);
5588 if (Level > 1) {
5589 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5590 NULL, 0, NULL, NULL);
5591 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5592 NULL, 0, NULL, NULL);
5594 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5595 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5596 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5599 /* check for errors and quit on failure */
5600 if (cbBuf < needed) {
5601 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5602 res = FALSE;
5603 goto cleanup;
5605 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5606 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5607 cbBuf -= len ; /* free Bytes in the user-Buffer */
5608 pi2w = (LPPORT_INFO_2W) bufferW;
5609 pi2a = (LPPORT_INFO_2A) pPorts;
5610 index = 0;
5611 /* Second Pass: Fill the User Buffer (if we have one) */
5612 while ((index < numentries) && pPorts) {
5613 index++;
5614 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5615 pi2a->pPortName = ptr;
5616 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5617 ptr, cbBuf , NULL, NULL);
5618 ptr += len;
5619 cbBuf -= len;
5620 if (Level > 1) {
5621 pi2a->pMonitorName = ptr;
5622 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5623 ptr, cbBuf, NULL, NULL);
5624 ptr += len;
5625 cbBuf -= len;
5627 pi2a->pDescription = ptr;
5628 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5629 ptr, cbBuf, NULL, NULL);
5630 ptr += len;
5631 cbBuf -= len;
5633 pi2a->fPortType = pi2w->fPortType;
5634 pi2a->Reserved = 0; /* documented: "must be zero" */
5637 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5638 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5639 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5643 cleanup:
5644 if (pcbNeeded) *pcbNeeded = needed;
5645 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5647 HeapFree(GetProcessHeap(), 0, nameW);
5648 HeapFree(GetProcessHeap(), 0, bufferW);
5650 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5651 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5653 return (res);
5657 /******************************************************************************
5658 * EnumPortsW (WINSPOOL.@)
5660 * Enumerate available Ports
5662 * PARAMS
5663 * name [I] Servername or NULL (local Computer)
5664 * level [I] Structure-Level (1 or 2)
5665 * buffer [O] PTR to Buffer that receives the Result
5666 * bufsize [I] Size of Buffer at buffer
5667 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5668 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5670 * RETURNS
5671 * Success: TRUE
5672 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5676 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5678 DWORD needed = 0;
5679 DWORD numentries = 0;
5680 BOOL res = FALSE;
5682 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5683 cbBuf, pcbNeeded, pcReturned);
5685 if (pName && (pName[0])) {
5686 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5687 SetLastError(ERROR_ACCESS_DENIED);
5688 goto emP_cleanup;
5691 /* Level is not checked in win9x */
5692 if (!Level || (Level > 2)) {
5693 WARN("level (%d) is ignored in win9x\n", Level);
5694 SetLastError(ERROR_INVALID_LEVEL);
5695 goto emP_cleanup;
5697 if (!pcbNeeded) {
5698 SetLastError(RPC_X_NULL_REF_POINTER);
5699 goto emP_cleanup;
5702 EnterCriticalSection(&monitor_handles_cs);
5703 monitor_loadall();
5705 /* Scan all local Ports */
5706 numentries = 0;
5707 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5709 /* we calculated the needed buffersize. now do the error-checks */
5710 if (cbBuf < needed) {
5711 monitor_unloadall();
5712 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5713 goto emP_cleanup_cs;
5715 else if (!pPorts || !pcReturned) {
5716 monitor_unloadall();
5717 SetLastError(RPC_X_NULL_REF_POINTER);
5718 goto emP_cleanup_cs;
5721 /* Fill the Buffer */
5722 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5723 res = TRUE;
5724 monitor_unloadall();
5726 emP_cleanup_cs:
5727 LeaveCriticalSection(&monitor_handles_cs);
5729 emP_cleanup:
5730 if (pcbNeeded) *pcbNeeded = needed;
5731 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5733 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5734 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5736 return (res);
5739 /******************************************************************************
5740 * GetDefaultPrinterW (WINSPOOL.@)
5742 * FIXME
5743 * This function must read the value from data 'device' of key
5744 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5746 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5748 BOOL retval = TRUE;
5749 DWORD insize, len;
5750 WCHAR *buffer, *ptr;
5752 if (!namesize)
5754 SetLastError(ERROR_INVALID_PARAMETER);
5755 return FALSE;
5758 /* make the buffer big enough for the stuff from the profile/registry,
5759 * the content must fit into the local buffer to compute the correct
5760 * size even if the extern buffer is too small or not given.
5761 * (20 for ,driver,port) */
5762 insize = *namesize;
5763 len = max(100, (insize + 20));
5764 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5766 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5768 SetLastError (ERROR_FILE_NOT_FOUND);
5769 retval = FALSE;
5770 goto end;
5772 TRACE("%s\n", debugstr_w(buffer));
5774 if ((ptr = strchrW(buffer, ',')) == NULL)
5776 SetLastError(ERROR_INVALID_NAME);
5777 retval = FALSE;
5778 goto end;
5781 *ptr = 0;
5782 *namesize = strlenW(buffer) + 1;
5783 if(!name || (*namesize > insize))
5785 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5786 retval = FALSE;
5787 goto end;
5789 strcpyW(name, buffer);
5791 end:
5792 HeapFree( GetProcessHeap(), 0, buffer);
5793 return retval;
5797 /******************************************************************************
5798 * GetDefaultPrinterA (WINSPOOL.@)
5800 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5802 BOOL retval = TRUE;
5803 DWORD insize = 0;
5804 WCHAR *bufferW = NULL;
5806 if (!namesize)
5808 SetLastError(ERROR_INVALID_PARAMETER);
5809 return FALSE;
5812 if(name && *namesize) {
5813 insize = *namesize;
5814 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5817 if(!GetDefaultPrinterW( bufferW, namesize)) {
5818 retval = FALSE;
5819 goto end;
5822 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5823 NULL, NULL);
5824 if (!*namesize)
5826 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5827 retval = FALSE;
5829 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5831 end:
5832 HeapFree( GetProcessHeap(), 0, bufferW);
5833 return retval;
5837 /******************************************************************************
5838 * SetDefaultPrinterW (WINSPOOL.204)
5840 * Set the Name of the Default Printer
5842 * PARAMS
5843 * pszPrinter [I] Name of the Printer or NULL
5845 * RETURNS
5846 * Success: True
5847 * Failure: FALSE
5849 * NOTES
5850 * When the Parameter is NULL or points to an Empty String and
5851 * a Default Printer was already present, then this Function changes nothing.
5852 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5853 * the First enumerated local Printer is used.
5856 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5859 TRACE("(%s)\n", debugstr_w(pszPrinter));
5861 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5862 return FALSE;
5865 /******************************************************************************
5866 * SetDefaultPrinterA (WINSPOOL.202)
5868 * See SetDefaultPrinterW.
5871 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5874 TRACE("(%s)\n", debugstr_a(pszPrinter));
5876 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5877 return FALSE;
5881 /******************************************************************************
5882 * SetPrinterDataExA (WINSPOOL.@)
5884 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5885 LPCSTR pValueName, DWORD Type,
5886 LPBYTE pData, DWORD cbData)
5888 HKEY hkeyPrinter, hkeySubkey;
5889 DWORD ret;
5891 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5892 debugstr_a(pValueName), Type, pData, cbData);
5894 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5895 != ERROR_SUCCESS)
5896 return ret;
5898 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5899 != ERROR_SUCCESS) {
5900 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5901 RegCloseKey(hkeyPrinter);
5902 return ret;
5904 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5905 RegCloseKey(hkeySubkey);
5906 RegCloseKey(hkeyPrinter);
5907 return ret;
5910 /******************************************************************************
5911 * SetPrinterDataExW (WINSPOOL.@)
5913 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5914 LPCWSTR pValueName, DWORD Type,
5915 LPBYTE pData, DWORD cbData)
5917 HKEY hkeyPrinter, hkeySubkey;
5918 DWORD ret;
5920 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5921 debugstr_w(pValueName), Type, pData, cbData);
5923 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5924 != ERROR_SUCCESS)
5925 return ret;
5927 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5928 != ERROR_SUCCESS) {
5929 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5930 RegCloseKey(hkeyPrinter);
5931 return ret;
5933 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5934 RegCloseKey(hkeySubkey);
5935 RegCloseKey(hkeyPrinter);
5936 return ret;
5939 /******************************************************************************
5940 * SetPrinterDataA (WINSPOOL.@)
5942 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5943 LPBYTE pData, DWORD cbData)
5945 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5946 pData, cbData);
5949 /******************************************************************************
5950 * SetPrinterDataW (WINSPOOL.@)
5952 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5953 LPBYTE pData, DWORD cbData)
5955 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5956 pData, cbData);
5959 /******************************************************************************
5960 * GetPrinterDataExA (WINSPOOL.@)
5962 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5963 LPCSTR pValueName, LPDWORD pType,
5964 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5966 HKEY hkeyPrinter, hkeySubkey;
5967 DWORD ret;
5969 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5970 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5971 pcbNeeded);
5973 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5974 != ERROR_SUCCESS)
5975 return ret;
5977 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5978 != ERROR_SUCCESS) {
5979 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5980 RegCloseKey(hkeyPrinter);
5981 return ret;
5983 *pcbNeeded = nSize;
5984 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5985 RegCloseKey(hkeySubkey);
5986 RegCloseKey(hkeyPrinter);
5987 return ret;
5990 /******************************************************************************
5991 * GetPrinterDataExW (WINSPOOL.@)
5993 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5994 LPCWSTR pValueName, LPDWORD pType,
5995 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5997 HKEY hkeyPrinter, hkeySubkey;
5998 DWORD ret;
6000 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
6001 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
6002 pcbNeeded);
6004 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
6005 != ERROR_SUCCESS)
6006 return ret;
6008 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
6009 != ERROR_SUCCESS) {
6010 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
6011 RegCloseKey(hkeyPrinter);
6012 return ret;
6014 *pcbNeeded = nSize;
6015 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
6016 RegCloseKey(hkeySubkey);
6017 RegCloseKey(hkeyPrinter);
6018 return ret;
6021 /******************************************************************************
6022 * GetPrinterDataA (WINSPOOL.@)
6024 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
6025 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6027 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
6028 pData, nSize, pcbNeeded);
6031 /******************************************************************************
6032 * GetPrinterDataW (WINSPOOL.@)
6034 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
6035 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
6037 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
6038 pData, nSize, pcbNeeded);
6041 /*******************************************************************************
6042 * EnumPrinterDataExW [WINSPOOL.@]
6044 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
6045 LPBYTE pEnumValues, DWORD cbEnumValues,
6046 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6048 HKEY hkPrinter, hkSubKey;
6049 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
6050 cbValueNameLen, cbMaxValueLen, cbValueLen,
6051 cbBufSize, dwType;
6052 LPWSTR lpValueName;
6053 HANDLE hHeap;
6054 PBYTE lpValue;
6055 PPRINTER_ENUM_VALUESW ppev;
6057 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
6059 if (pKeyName == NULL || *pKeyName == 0)
6060 return ERROR_INVALID_PARAMETER;
6062 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
6063 if (ret != ERROR_SUCCESS)
6065 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
6066 hPrinter, ret);
6067 return ret;
6070 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
6071 if (ret != ERROR_SUCCESS)
6073 r = RegCloseKey (hkPrinter);
6074 if (r != ERROR_SUCCESS)
6075 WARN ("RegCloseKey returned %i\n", r);
6076 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
6077 debugstr_w (pKeyName), ret);
6078 return ret;
6081 ret = RegCloseKey (hkPrinter);
6082 if (ret != ERROR_SUCCESS)
6084 ERR ("RegCloseKey returned %i\n", ret);
6085 r = RegCloseKey (hkSubKey);
6086 if (r != ERROR_SUCCESS)
6087 WARN ("RegCloseKey returned %i\n", r);
6088 return ret;
6091 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
6092 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
6093 if (ret != ERROR_SUCCESS)
6095 r = RegCloseKey (hkSubKey);
6096 if (r != ERROR_SUCCESS)
6097 WARN ("RegCloseKey returned %i\n", r);
6098 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
6099 return ret;
6102 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
6103 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
6105 if (cValues == 0) /* empty key */
6107 r = RegCloseKey (hkSubKey);
6108 if (r != ERROR_SUCCESS)
6109 WARN ("RegCloseKey returned %i\n", r);
6110 *pcbEnumValues = *pnEnumValues = 0;
6111 return ERROR_SUCCESS;
6114 ++cbMaxValueNameLen; /* allow for trailing '\0' */
6116 hHeap = GetProcessHeap ();
6117 if (hHeap == NULL)
6119 ERR ("GetProcessHeap failed\n");
6120 r = RegCloseKey (hkSubKey);
6121 if (r != ERROR_SUCCESS)
6122 WARN ("RegCloseKey returned %i\n", r);
6123 return ERROR_OUTOFMEMORY;
6126 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
6127 if (lpValueName == NULL)
6129 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
6130 r = RegCloseKey (hkSubKey);
6131 if (r != ERROR_SUCCESS)
6132 WARN ("RegCloseKey returned %i\n", r);
6133 return ERROR_OUTOFMEMORY;
6136 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
6137 if (lpValue == NULL)
6139 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
6140 if (HeapFree (hHeap, 0, lpValueName) == 0)
6141 WARN ("HeapFree failed with code %i\n", GetLastError ());
6142 r = RegCloseKey (hkSubKey);
6143 if (r != ERROR_SUCCESS)
6144 WARN ("RegCloseKey returned %i\n", r);
6145 return ERROR_OUTOFMEMORY;
6148 TRACE ("pass 1: calculating buffer required for all names and values\n");
6150 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
6152 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
6154 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6156 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6157 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6158 NULL, NULL, lpValue, &cbValueLen);
6159 if (ret != ERROR_SUCCESS)
6161 if (HeapFree (hHeap, 0, lpValue) == 0)
6162 WARN ("HeapFree failed with code %i\n", GetLastError ());
6163 if (HeapFree (hHeap, 0, lpValueName) == 0)
6164 WARN ("HeapFree failed with code %i\n", GetLastError ());
6165 r = RegCloseKey (hkSubKey);
6166 if (r != ERROR_SUCCESS)
6167 WARN ("RegCloseKey returned %i\n", r);
6168 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6169 return ret;
6172 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
6173 debugstr_w (lpValueName), dwIndex,
6174 cbValueNameLen + 1, cbValueLen);
6176 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
6177 cbBufSize += cbValueLen;
6180 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
6182 *pcbEnumValues = cbBufSize;
6183 *pnEnumValues = cValues;
6185 if (cbEnumValues < cbBufSize) /* buffer too small */
6187 if (HeapFree (hHeap, 0, lpValue) == 0)
6188 WARN ("HeapFree failed with code %i\n", GetLastError ());
6189 if (HeapFree (hHeap, 0, lpValueName) == 0)
6190 WARN ("HeapFree failed with code %i\n", GetLastError ());
6191 r = RegCloseKey (hkSubKey);
6192 if (r != ERROR_SUCCESS)
6193 WARN ("RegCloseKey returned %i\n", r);
6194 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
6195 return ERROR_MORE_DATA;
6198 TRACE ("pass 2: copying all names and values to buffer\n");
6200 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
6201 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
6203 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
6205 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
6206 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
6207 NULL, &dwType, lpValue, &cbValueLen);
6208 if (ret != ERROR_SUCCESS)
6210 if (HeapFree (hHeap, 0, lpValue) == 0)
6211 WARN ("HeapFree failed with code %i\n", GetLastError ());
6212 if (HeapFree (hHeap, 0, lpValueName) == 0)
6213 WARN ("HeapFree failed with code %i\n", GetLastError ());
6214 r = RegCloseKey (hkSubKey);
6215 if (r != ERROR_SUCCESS)
6216 WARN ("RegCloseKey returned %i\n", r);
6217 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
6218 return ret;
6221 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
6222 memcpy (pEnumValues, lpValueName, cbValueNameLen);
6223 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
6224 pEnumValues += cbValueNameLen;
6226 /* return # of *bytes* (including trailing \0), not # of chars */
6227 ppev[dwIndex].cbValueName = cbValueNameLen;
6229 ppev[dwIndex].dwType = dwType;
6231 memcpy (pEnumValues, lpValue, cbValueLen);
6232 ppev[dwIndex].pData = pEnumValues;
6233 pEnumValues += cbValueLen;
6235 ppev[dwIndex].cbData = cbValueLen;
6237 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
6238 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
6241 if (HeapFree (hHeap, 0, lpValue) == 0)
6243 ret = GetLastError ();
6244 ERR ("HeapFree failed with code %i\n", ret);
6245 if (HeapFree (hHeap, 0, lpValueName) == 0)
6246 WARN ("HeapFree failed with code %i\n", GetLastError ());
6247 r = RegCloseKey (hkSubKey);
6248 if (r != ERROR_SUCCESS)
6249 WARN ("RegCloseKey returned %i\n", r);
6250 return ret;
6253 if (HeapFree (hHeap, 0, lpValueName) == 0)
6255 ret = GetLastError ();
6256 ERR ("HeapFree failed with code %i\n", ret);
6257 r = RegCloseKey (hkSubKey);
6258 if (r != ERROR_SUCCESS)
6259 WARN ("RegCloseKey returned %i\n", r);
6260 return ret;
6263 ret = RegCloseKey (hkSubKey);
6264 if (ret != ERROR_SUCCESS)
6266 ERR ("RegCloseKey returned %i\n", ret);
6267 return ret;
6270 return ERROR_SUCCESS;
6273 /*******************************************************************************
6274 * EnumPrinterDataExA [WINSPOOL.@]
6276 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6277 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6278 * what Windows 2000 SP1 does.
6281 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
6282 LPBYTE pEnumValues, DWORD cbEnumValues,
6283 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
6285 INT len;
6286 LPWSTR pKeyNameW;
6287 DWORD ret, dwIndex, dwBufSize;
6288 HANDLE hHeap;
6289 LPSTR pBuffer;
6291 TRACE ("%p %s\n", hPrinter, pKeyName);
6293 if (pKeyName == NULL || *pKeyName == 0)
6294 return ERROR_INVALID_PARAMETER;
6296 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
6297 if (len == 0)
6299 ret = GetLastError ();
6300 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6301 return ret;
6304 hHeap = GetProcessHeap ();
6305 if (hHeap == NULL)
6307 ERR ("GetProcessHeap failed\n");
6308 return ERROR_OUTOFMEMORY;
6311 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
6312 if (pKeyNameW == NULL)
6314 ERR ("Failed to allocate %i bytes from process heap\n",
6315 (LONG)(len * sizeof (WCHAR)));
6316 return ERROR_OUTOFMEMORY;
6319 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
6321 ret = GetLastError ();
6322 ERR ("MultiByteToWideChar failed with code %i\n", ret);
6323 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6324 WARN ("HeapFree failed with code %i\n", GetLastError ());
6325 return ret;
6328 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
6329 pcbEnumValues, pnEnumValues);
6330 if (ret != ERROR_SUCCESS)
6332 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6333 WARN ("HeapFree failed with code %i\n", GetLastError ());
6334 TRACE ("EnumPrinterDataExW returned %i\n", ret);
6335 return ret;
6338 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
6340 ret = GetLastError ();
6341 ERR ("HeapFree failed with code %i\n", ret);
6342 return ret;
6345 if (*pnEnumValues == 0) /* empty key */
6346 return ERROR_SUCCESS;
6348 dwBufSize = 0;
6349 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6351 PPRINTER_ENUM_VALUESW ppev =
6352 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6354 if (dwBufSize < ppev->cbValueName)
6355 dwBufSize = ppev->cbValueName;
6357 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
6358 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
6359 dwBufSize = ppev->cbData;
6362 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
6364 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
6365 if (pBuffer == NULL)
6367 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
6368 return ERROR_OUTOFMEMORY;
6371 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
6373 PPRINTER_ENUM_VALUESW ppev =
6374 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
6376 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
6377 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
6378 NULL);
6379 if (len == 0)
6381 ret = GetLastError ();
6382 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6383 if (HeapFree (hHeap, 0, pBuffer) == 0)
6384 WARN ("HeapFree failed with code %i\n", GetLastError ());
6385 return ret;
6388 memcpy (ppev->pValueName, pBuffer, len);
6390 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6392 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
6393 ppev->dwType != REG_MULTI_SZ)
6394 continue;
6396 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
6397 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
6398 if (len == 0)
6400 ret = GetLastError ();
6401 ERR ("WideCharToMultiByte failed with code %i\n", ret);
6402 if (HeapFree (hHeap, 0, pBuffer) == 0)
6403 WARN ("HeapFree failed with code %i\n", GetLastError ());
6404 return ret;
6407 memcpy (ppev->pData, pBuffer, len);
6409 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
6410 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6413 if (HeapFree (hHeap, 0, pBuffer) == 0)
6415 ret = GetLastError ();
6416 ERR ("HeapFree failed with code %i\n", ret);
6417 return ret;
6420 return ERROR_SUCCESS;
6423 /******************************************************************************
6424 * AbortPrinter (WINSPOOL.@)
6426 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
6428 FIXME("(%p), stub!\n", hPrinter);
6429 return TRUE;
6432 /******************************************************************************
6433 * AddPortA (WINSPOOL.@)
6435 * See AddPortW.
6438 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
6440 LPWSTR nameW = NULL;
6441 LPWSTR monitorW = NULL;
6442 DWORD len;
6443 BOOL res;
6445 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6447 if (pName) {
6448 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6449 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6450 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6453 if (pMonitorName) {
6454 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6455 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6456 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6458 res = AddPortW(nameW, hWnd, monitorW);
6459 HeapFree(GetProcessHeap(), 0, nameW);
6460 HeapFree(GetProcessHeap(), 0, monitorW);
6461 return res;
6464 /******************************************************************************
6465 * AddPortW (WINSPOOL.@)
6467 * Add a Port for a specific Monitor
6469 * PARAMS
6470 * pName [I] Servername or NULL (local Computer)
6471 * hWnd [I] Handle to parent Window for the Dialog-Box
6472 * pMonitorName [I] Name of the Monitor that manage the Port
6474 * RETURNS
6475 * Success: TRUE
6476 * Failure: FALSE
6479 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6481 monitor_t * pm;
6482 monitor_t * pui;
6483 DWORD res;
6485 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6487 if (pName && pName[0]) {
6488 SetLastError(ERROR_INVALID_PARAMETER);
6489 return FALSE;
6492 if (!pMonitorName) {
6493 SetLastError(RPC_X_NULL_REF_POINTER);
6494 return FALSE;
6497 /* an empty Monitorname is Invalid */
6498 if (!pMonitorName[0]) {
6499 SetLastError(ERROR_NOT_SUPPORTED);
6500 return FALSE;
6503 pm = monitor_load(pMonitorName, NULL);
6504 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6505 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6506 TRACE("got %d with %u\n", res, GetLastError());
6507 res = TRUE;
6509 else
6511 pui = monitor_loadui(pm);
6512 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6513 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6514 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6515 TRACE("got %d with %u\n", res, GetLastError());
6516 res = TRUE;
6518 else
6520 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6521 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6523 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6524 SetLastError(ERROR_NOT_SUPPORTED);
6525 res = FALSE;
6527 monitor_unload(pui);
6529 monitor_unload(pm);
6530 TRACE("returning %d with %u\n", res, GetLastError());
6531 return res;
6534 /******************************************************************************
6535 * AddPortExA (WINSPOOL.@)
6537 * See AddPortExW.
6540 BOOL WINAPI AddPortExA(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6542 PORT_INFO_2W pi2W;
6543 PORT_INFO_2A * pi2A;
6544 LPWSTR nameW = NULL;
6545 LPWSTR monitorW = NULL;
6546 DWORD len;
6547 BOOL res;
6549 pi2A = (PORT_INFO_2A *) pBuffer;
6551 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6552 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6554 if ((level < 1) || (level > 2)) {
6555 SetLastError(ERROR_INVALID_LEVEL);
6556 return FALSE;
6559 if (!pi2A) {
6560 SetLastError(ERROR_INVALID_PARAMETER);
6561 return FALSE;
6564 if (pName) {
6565 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6566 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6567 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6570 if (pMonitorName) {
6571 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6572 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6573 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6576 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6578 if (pi2A->pPortName) {
6579 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6580 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6581 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6584 if (level > 1) {
6585 if (pi2A->pMonitorName) {
6586 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6587 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6588 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6591 if (pi2A->pDescription) {
6592 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6593 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6594 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6596 pi2W.fPortType = pi2A->fPortType;
6597 pi2W.Reserved = pi2A->Reserved;
6600 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6602 HeapFree(GetProcessHeap(), 0, nameW);
6603 HeapFree(GetProcessHeap(), 0, monitorW);
6604 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6605 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6606 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6607 return res;
6611 /******************************************************************************
6612 * AddPortExW (WINSPOOL.@)
6614 * Add a Port for a specific Monitor, without presenting a user interface
6616 * PARAMS
6617 * pName [I] Servername or NULL (local Computer)
6618 * level [I] Structure-Level (1 or 2) for pBuffer
6619 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6620 * pMonitorName [I] Name of the Monitor that manage the Port
6622 * RETURNS
6623 * Success: TRUE
6624 * Failure: FALSE
6627 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6629 PORT_INFO_2W * pi2;
6630 monitor_t * pm;
6631 DWORD res = FALSE;
6633 pi2 = (PORT_INFO_2W *) pBuffer;
6635 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6636 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6637 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6638 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6641 if ((level < 1) || (level > 2)) {
6642 SetLastError(ERROR_INVALID_LEVEL);
6643 return FALSE;
6646 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
6647 SetLastError(ERROR_INVALID_PARAMETER);
6648 return FALSE;
6651 /* load the Monitor */
6652 pm = monitor_load(pMonitorName, NULL);
6653 if (!pm) {
6654 SetLastError(ERROR_INVALID_PARAMETER);
6655 return FALSE;
6658 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6659 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6660 TRACE("got %u with %u\n", res, GetLastError());
6662 else
6664 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName), pm->monitor);
6666 monitor_unload(pm);
6667 return res;
6670 /******************************************************************************
6671 * AddPrinterConnectionA (WINSPOOL.@)
6673 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6675 FIXME("%s\n", debugstr_a(pName));
6676 return FALSE;
6679 /******************************************************************************
6680 * AddPrinterConnectionW (WINSPOOL.@)
6682 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6684 FIXME("%s\n", debugstr_w(pName));
6685 return FALSE;
6688 /******************************************************************************
6689 * AddPrinterDriverExW (WINSPOOL.@)
6691 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6693 * PARAMS
6694 * pName [I] Servername or NULL (local Computer)
6695 * level [I] Level for the supplied DRIVER_INFO_*W struct
6696 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6697 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6699 * RESULTS
6700 * Success: TRUE
6701 * Failure: FALSE
6704 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6706 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
6708 if ((backend == NULL) && !load_backend()) return FALSE;
6710 if (level < 2 || level == 5 || level == 7 || level > 8) {
6711 SetLastError(ERROR_INVALID_LEVEL);
6712 return FALSE;
6715 if (!pDriverInfo) {
6716 SetLastError(ERROR_INVALID_PARAMETER);
6717 return FALSE;
6720 return backend->fpAddPrinterDriverEx(pName, level, pDriverInfo, dwFileCopyFlags);
6723 /******************************************************************************
6724 * AddPrinterDriverExA (WINSPOOL.@)
6726 * See AddPrinterDriverExW.
6729 BOOL WINAPI AddPrinterDriverExA(LPSTR pName, DWORD Level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6731 DRIVER_INFO_8A *diA;
6732 DRIVER_INFO_8W diW;
6733 LPWSTR nameW = NULL;
6734 DWORD lenA;
6735 DWORD len;
6736 DWORD res = FALSE;
6738 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName), Level, pDriverInfo, dwFileCopyFlags);
6740 diA = (DRIVER_INFO_8A *) pDriverInfo;
6741 ZeroMemory(&diW, sizeof(diW));
6743 if (Level < 2 || Level == 5 || Level == 7 || Level > 8) {
6744 SetLastError(ERROR_INVALID_LEVEL);
6745 return FALSE;
6748 if (diA == NULL) {
6749 SetLastError(ERROR_INVALID_PARAMETER);
6750 return FALSE;
6753 /* convert servername to unicode */
6754 if (pName) {
6755 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6756 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6757 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6760 /* common fields */
6761 diW.cVersion = diA->cVersion;
6763 if (diA->pName) {
6764 len = MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, NULL, 0);
6765 diW.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6766 MultiByteToWideChar(CP_ACP, 0, diA->pName, -1, diW.pName, len);
6769 if (diA->pEnvironment) {
6770 len = MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, NULL, 0);
6771 diW.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6772 MultiByteToWideChar(CP_ACP, 0, diA->pEnvironment, -1, diW.pEnvironment, len);
6775 if (diA->pDriverPath) {
6776 len = MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, NULL, 0);
6777 diW.pDriverPath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6778 MultiByteToWideChar(CP_ACP, 0, diA->pDriverPath, -1, diW.pDriverPath, len);
6781 if (diA->pDataFile) {
6782 len = MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, NULL, 0);
6783 diW.pDataFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6784 MultiByteToWideChar(CP_ACP, 0, diA->pDataFile, -1, diW.pDataFile, len);
6787 if (diA->pConfigFile) {
6788 len = MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, NULL, 0);
6789 diW.pConfigFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6790 MultiByteToWideChar(CP_ACP, 0, diA->pConfigFile, -1, diW.pConfigFile, len);
6793 if ((Level > 2) && diA->pDependentFiles) {
6794 lenA = multi_sz_lenA(diA->pDependentFiles);
6795 len = MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, NULL, 0);
6796 diW.pDependentFiles = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6797 MultiByteToWideChar(CP_ACP, 0, diA->pDependentFiles, lenA, diW.pDependentFiles, len);
6800 if ((Level > 2) && diA->pMonitorName) {
6801 len = MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, NULL, 0);
6802 diW.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6803 MultiByteToWideChar(CP_ACP, 0, diA->pMonitorName, -1, diW.pMonitorName, len);
6806 if ((Level > 3) && diA->pDefaultDataType) {
6807 len = MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, NULL, 0);
6808 diW.pDefaultDataType = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6809 MultiByteToWideChar(CP_ACP, 0, diA->pDefaultDataType, -1, diW.pDefaultDataType, len);
6812 if ((Level > 3) && diA->pszzPreviousNames) {
6813 lenA = multi_sz_lenA(diA->pszzPreviousNames);
6814 len = MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, NULL, 0);
6815 diW.pszzPreviousNames = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6816 MultiByteToWideChar(CP_ACP, 0, diA->pszzPreviousNames, lenA, diW.pszzPreviousNames, len);
6819 if ((Level > 5) && diA->pszMfgName) {
6820 len = MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, NULL, 0);
6821 diW.pszMfgName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6822 MultiByteToWideChar(CP_ACP, 0, diA->pszMfgName, -1, diW.pszMfgName, len);
6825 if ((Level > 5) && diA->pszOEMUrl) {
6826 len = MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, NULL, 0);
6827 diW.pszOEMUrl = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6828 MultiByteToWideChar(CP_ACP, 0, diA->pszOEMUrl, -1, diW.pszOEMUrl, len);
6831 if ((Level > 5) && diA->pszHardwareID) {
6832 len = MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, NULL, 0);
6833 diW.pszHardwareID = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6834 MultiByteToWideChar(CP_ACP, 0, diA->pszHardwareID, -1, diW.pszHardwareID, len);
6837 if ((Level > 5) && diA->pszProvider) {
6838 len = MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, NULL, 0);
6839 diW.pszProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6840 MultiByteToWideChar(CP_ACP, 0, diA->pszProvider, -1, diW.pszProvider, len);
6843 if (Level > 7) {
6844 FIXME("level %u is incomplete\n", Level);
6847 res = AddPrinterDriverExW(nameW, Level, (LPBYTE) &diW, dwFileCopyFlags);
6848 TRACE("got %u with %u\n", res, GetLastError());
6849 HeapFree(GetProcessHeap(), 0, nameW);
6850 HeapFree(GetProcessHeap(), 0, diW.pName);
6851 HeapFree(GetProcessHeap(), 0, diW.pEnvironment);
6852 HeapFree(GetProcessHeap(), 0, diW.pDriverPath);
6853 HeapFree(GetProcessHeap(), 0, diW.pDataFile);
6854 HeapFree(GetProcessHeap(), 0, diW.pConfigFile);
6855 HeapFree(GetProcessHeap(), 0, diW.pDependentFiles);
6856 HeapFree(GetProcessHeap(), 0, diW.pMonitorName);
6857 HeapFree(GetProcessHeap(), 0, diW.pDefaultDataType);
6858 HeapFree(GetProcessHeap(), 0, diW.pszzPreviousNames);
6859 HeapFree(GetProcessHeap(), 0, diW.pszMfgName);
6860 HeapFree(GetProcessHeap(), 0, diW.pszOEMUrl);
6861 HeapFree(GetProcessHeap(), 0, diW.pszHardwareID);
6862 HeapFree(GetProcessHeap(), 0, diW.pszProvider);
6864 TRACE("=> %u with %u\n", res, GetLastError());
6865 return res;
6868 /******************************************************************************
6869 * ConfigurePortA (WINSPOOL.@)
6871 * See ConfigurePortW.
6874 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6876 LPWSTR nameW = NULL;
6877 LPWSTR portW = NULL;
6878 INT len;
6879 DWORD res;
6881 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6883 /* convert servername to unicode */
6884 if (pName) {
6885 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6886 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6887 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6890 /* convert portname to unicode */
6891 if (pPortName) {
6892 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6893 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6894 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6897 res = ConfigurePortW(nameW, hWnd, portW);
6898 HeapFree(GetProcessHeap(), 0, nameW);
6899 HeapFree(GetProcessHeap(), 0, portW);
6900 return res;
6903 /******************************************************************************
6904 * ConfigurePortW (WINSPOOL.@)
6906 * Display the Configuration-Dialog for a specific Port
6908 * PARAMS
6909 * pName [I] Servername or NULL (local Computer)
6910 * hWnd [I] Handle to parent Window for the Dialog-Box
6911 * pPortName [I] Name of the Port, that should be configured
6913 * RETURNS
6914 * Success: TRUE
6915 * Failure: FALSE
6918 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6920 monitor_t * pm;
6921 monitor_t * pui;
6922 DWORD res;
6924 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6926 if (pName && pName[0]) {
6927 SetLastError(ERROR_INVALID_PARAMETER);
6928 return FALSE;
6931 if (!pPortName) {
6932 SetLastError(RPC_X_NULL_REF_POINTER);
6933 return FALSE;
6936 /* an empty Portname is Invalid, but can popup a Dialog */
6937 if (!pPortName[0]) {
6938 SetLastError(ERROR_NOT_SUPPORTED);
6939 return FALSE;
6942 pm = monitor_load_by_port(pPortName);
6943 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6944 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6945 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6946 TRACE("got %d with %u\n", res, GetLastError());
6948 else
6950 pui = monitor_loadui(pm);
6951 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6952 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6953 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6954 TRACE("got %d with %u\n", res, GetLastError());
6956 else
6958 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6959 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6961 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6962 SetLastError(ERROR_NOT_SUPPORTED);
6963 res = FALSE;
6965 monitor_unload(pui);
6967 monitor_unload(pm);
6969 TRACE("returning %d with %u\n", res, GetLastError());
6970 return res;
6973 /******************************************************************************
6974 * ConnectToPrinterDlg (WINSPOOL.@)
6976 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6978 FIXME("%p %x\n", hWnd, Flags);
6979 return NULL;
6982 /******************************************************************************
6983 * DeletePrinterConnectionA (WINSPOOL.@)
6985 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6987 FIXME("%s\n", debugstr_a(pName));
6988 return TRUE;
6991 /******************************************************************************
6992 * DeletePrinterConnectionW (WINSPOOL.@)
6994 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6996 FIXME("%s\n", debugstr_w(pName));
6997 return TRUE;
7000 /******************************************************************************
7001 * DeletePrinterDriverExW (WINSPOOL.@)
7003 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
7004 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7006 HKEY hkey_drivers;
7007 BOOL ret = FALSE;
7009 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
7010 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
7012 if(pName && pName[0])
7014 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
7015 SetLastError(ERROR_INVALID_PARAMETER);
7016 return FALSE;
7019 if(dwDeleteFlag)
7021 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
7022 SetLastError(ERROR_INVALID_PARAMETER);
7023 return FALSE;
7026 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
7028 if(!hkey_drivers)
7030 ERR("Can't open drivers key\n");
7031 return FALSE;
7034 if(RegDeleteTreeW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
7035 ret = TRUE;
7037 RegCloseKey(hkey_drivers);
7039 return ret;
7042 /******************************************************************************
7043 * DeletePrinterDriverExA (WINSPOOL.@)
7045 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
7046 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
7048 UNICODE_STRING NameW, EnvW, DriverW;
7049 BOOL ret;
7051 asciitounicode(&NameW, pName);
7052 asciitounicode(&EnvW, pEnvironment);
7053 asciitounicode(&DriverW, pDriverName);
7055 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
7057 RtlFreeUnicodeString(&DriverW);
7058 RtlFreeUnicodeString(&EnvW);
7059 RtlFreeUnicodeString(&NameW);
7061 return ret;
7064 /******************************************************************************
7065 * DeletePrinterDataExW (WINSPOOL.@)
7067 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
7068 LPCWSTR pValueName)
7070 FIXME("%p %s %s\n", hPrinter,
7071 debugstr_w(pKeyName), debugstr_w(pValueName));
7072 return ERROR_INVALID_PARAMETER;
7075 /******************************************************************************
7076 * DeletePrinterDataExA (WINSPOOL.@)
7078 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
7079 LPCSTR pValueName)
7081 FIXME("%p %s %s\n", hPrinter,
7082 debugstr_a(pKeyName), debugstr_a(pValueName));
7083 return ERROR_INVALID_PARAMETER;
7086 /******************************************************************************
7087 * DeletePrintProcessorA (WINSPOOL.@)
7089 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
7091 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7092 debugstr_a(pPrintProcessorName));
7093 return TRUE;
7096 /******************************************************************************
7097 * DeletePrintProcessorW (WINSPOOL.@)
7099 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
7101 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7102 debugstr_w(pPrintProcessorName));
7103 return TRUE;
7106 /******************************************************************************
7107 * DeletePrintProvidorA (WINSPOOL.@)
7109 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
7111 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
7112 debugstr_a(pPrintProviderName));
7113 return TRUE;
7116 /******************************************************************************
7117 * DeletePrintProvidorW (WINSPOOL.@)
7119 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
7121 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
7122 debugstr_w(pPrintProviderName));
7123 return TRUE;
7126 /******************************************************************************
7127 * EnumFormsA (WINSPOOL.@)
7129 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7130 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7132 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7133 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7134 return FALSE;
7137 /******************************************************************************
7138 * EnumFormsW (WINSPOOL.@)
7140 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
7141 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
7143 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
7144 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
7145 return FALSE;
7148 /*****************************************************************************
7149 * EnumMonitorsA [WINSPOOL.@]
7151 * See EnumMonitorsW.
7154 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
7155 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7157 BOOL res;
7158 LPBYTE bufferW = NULL;
7159 LPWSTR nameW = NULL;
7160 DWORD needed = 0;
7161 DWORD numentries = 0;
7162 INT len;
7164 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
7165 cbBuf, pcbNeeded, pcReturned);
7167 /* convert servername to unicode */
7168 if (pName) {
7169 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
7170 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7171 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
7173 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7174 needed = cbBuf * sizeof(WCHAR);
7175 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
7176 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7178 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
7179 if (pcbNeeded) needed = *pcbNeeded;
7180 /* HeapReAlloc return NULL, when bufferW was NULL */
7181 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
7182 HeapAlloc(GetProcessHeap(), 0, needed);
7184 /* Try again with the large Buffer */
7185 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
7187 numentries = pcReturned ? *pcReturned : 0;
7188 needed = 0;
7190 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7191 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7193 if (res) {
7194 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7195 DWORD entrysize = 0;
7196 DWORD index;
7197 LPSTR ptr;
7198 LPMONITOR_INFO_2W mi2w;
7199 LPMONITOR_INFO_2A mi2a;
7201 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7202 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
7204 /* First pass: calculate the size for all Entries */
7205 mi2w = (LPMONITOR_INFO_2W) bufferW;
7206 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7207 index = 0;
7208 while (index < numentries) {
7209 index++;
7210 needed += entrysize; /* MONITOR_INFO_?A */
7211 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
7213 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7214 NULL, 0, NULL, NULL);
7215 if (Level > 1) {
7216 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7217 NULL, 0, NULL, NULL);
7218 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7219 NULL, 0, NULL, NULL);
7221 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7222 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7223 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7226 /* check for errors and quit on failure */
7227 if (cbBuf < needed) {
7228 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7229 res = FALSE;
7230 goto emA_cleanup;
7232 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
7233 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
7234 cbBuf -= len ; /* free Bytes in the user-Buffer */
7235 mi2w = (LPMONITOR_INFO_2W) bufferW;
7236 mi2a = (LPMONITOR_INFO_2A) pMonitors;
7237 index = 0;
7238 /* Second Pass: Fill the User Buffer (if we have one) */
7239 while ((index < numentries) && pMonitors) {
7240 index++;
7241 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
7242 mi2a->pName = ptr;
7243 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
7244 ptr, cbBuf , NULL, NULL);
7245 ptr += len;
7246 cbBuf -= len;
7247 if (Level > 1) {
7248 mi2a->pEnvironment = ptr;
7249 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
7250 ptr, cbBuf, NULL, NULL);
7251 ptr += len;
7252 cbBuf -= len;
7254 mi2a->pDLLName = ptr;
7255 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
7256 ptr, cbBuf, NULL, NULL);
7257 ptr += len;
7258 cbBuf -= len;
7260 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7261 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
7262 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
7265 emA_cleanup:
7266 if (pcbNeeded) *pcbNeeded = needed;
7267 if (pcReturned) *pcReturned = (res) ? numentries : 0;
7269 HeapFree(GetProcessHeap(), 0, nameW);
7270 HeapFree(GetProcessHeap(), 0, bufferW);
7272 TRACE("returning %d with %d (%d byte for %d entries)\n",
7273 (res), GetLastError(), needed, numentries);
7275 return (res);
7279 /*****************************************************************************
7280 * EnumMonitorsW [WINSPOOL.@]
7282 * Enumerate available Port-Monitors
7284 * PARAMS
7285 * pName [I] Servername or NULL (local Computer)
7286 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7287 * pMonitors [O] PTR to Buffer that receives the Result
7288 * cbBuf [I] Size of Buffer at pMonitors
7289 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7290 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7292 * RETURNS
7293 * Success: TRUE
7294 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7296 * NOTES
7297 * Windows reads the Registry once and cache the Results.
7299 *| Language-Monitors are also installed in the same Registry-Location but
7300 *| they are filtered in Windows (not returned by EnumMonitors).
7301 *| We do no filtering to simplify our Code.
7304 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
7305 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
7307 DWORD needed = 0;
7308 DWORD numentries = 0;
7309 BOOL res = FALSE;
7311 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
7312 cbBuf, pcbNeeded, pcReturned);
7314 if (pName && (lstrlenW(pName))) {
7315 FIXME("for Server %s not implemented\n", debugstr_w(pName));
7316 SetLastError(ERROR_ACCESS_DENIED);
7317 goto emW_cleanup;
7320 /* Level is not checked in win9x */
7321 if (!Level || (Level > 2)) {
7322 WARN("level (%d) is ignored in win9x\n", Level);
7323 SetLastError(ERROR_INVALID_LEVEL);
7324 goto emW_cleanup;
7326 if (!pcbNeeded) {
7327 SetLastError(RPC_X_NULL_REF_POINTER);
7328 goto emW_cleanup;
7331 /* Scan all Monitor-Keys */
7332 numentries = 0;
7333 needed = get_local_monitors(Level, NULL, 0, &numentries);
7335 /* we calculated the needed buffersize. now do the error-checks */
7336 if (cbBuf < needed) {
7337 SetLastError(ERROR_INSUFFICIENT_BUFFER);
7338 goto emW_cleanup;
7340 else if (!pMonitors || !pcReturned) {
7341 SetLastError(RPC_X_NULL_REF_POINTER);
7342 goto emW_cleanup;
7345 /* fill the Buffer with the Monitor-Keys */
7346 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
7347 res = TRUE;
7349 emW_cleanup:
7350 if (pcbNeeded) *pcbNeeded = needed;
7351 if (pcReturned) *pcReturned = numentries;
7353 TRACE("returning %d with %d (%d byte for %d entries)\n",
7354 res, GetLastError(), needed, numentries);
7356 return (res);
7359 /******************************************************************************
7360 * SpoolerInit (WINSPOOL.@)
7362 * Initialize the Spooler
7364 * RETURNS
7365 * Success: TRUE
7366 * Failure: FALSE
7368 * NOTES
7369 * The function fails on windows, when the spooler service is not running
7372 BOOL WINAPI SpoolerInit(void)
7375 if ((backend == NULL) && !load_backend()) return FALSE;
7376 return TRUE;
7379 /******************************************************************************
7380 * XcvDataW (WINSPOOL.@)
7382 * Execute commands in the Printmonitor DLL
7384 * PARAMS
7385 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7386 * pszDataName [i] Name of the command to execute
7387 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7388 * cbInputData [i] Size in Bytes of Buffer at pInputData
7389 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7390 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7391 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7392 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7394 * RETURNS
7395 * Success: TRUE
7396 * Failure: FALSE
7398 * NOTES
7399 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7400 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7402 * Minimal List of commands, that a Printmonitor DLL should support:
7404 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7405 *| "AddPort" : Add a Port
7406 *| "DeletePort": Delete a Port
7408 * Many Printmonitors support additional commands. Examples for localspl.dll:
7409 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7410 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7413 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
7414 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
7415 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
7417 opened_printer_t *printer;
7419 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
7420 pInputData, cbInputData, pOutputData,
7421 cbOutputData, pcbOutputNeeded, pdwStatus);
7423 printer = get_opened_printer(hXcv);
7424 if (!printer || (!printer->hXcv)) {
7425 SetLastError(ERROR_INVALID_HANDLE);
7426 return FALSE;
7429 if (!pcbOutputNeeded) {
7430 SetLastError(ERROR_INVALID_PARAMETER);
7431 return FALSE;
7434 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
7435 SetLastError(RPC_X_NULL_REF_POINTER);
7436 return FALSE;
7439 *pcbOutputNeeded = 0;
7441 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
7442 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
7444 return TRUE;
7447 /*****************************************************************************
7448 * EnumPrinterDataA [WINSPOOL.@]
7451 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
7452 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7453 DWORD cbData, LPDWORD pcbData )
7455 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7456 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7457 return ERROR_NO_MORE_ITEMS;
7460 /*****************************************************************************
7461 * EnumPrinterDataW [WINSPOOL.@]
7464 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
7465 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
7466 DWORD cbData, LPDWORD pcbData )
7468 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
7469 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
7470 return ERROR_NO_MORE_ITEMS;
7473 /*****************************************************************************
7474 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7477 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
7478 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7479 LPDWORD pcbNeeded, LPDWORD pcReturned)
7481 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
7482 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
7483 pcbNeeded, pcReturned);
7484 return FALSE;
7487 /*****************************************************************************
7488 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7491 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
7492 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
7493 LPDWORD pcbNeeded, LPDWORD pcReturned)
7495 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7496 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
7497 pcbNeeded, pcReturned);
7498 return FALSE;
7501 /*****************************************************************************
7502 * EnumPrintProcessorsA [WINSPOOL.@]
7505 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
7506 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7508 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
7509 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
7510 return FALSE;
7513 /*****************************************************************************
7514 * EnumPrintProcessorsW [WINSPOOL.@]
7517 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
7518 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
7520 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
7521 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
7522 cbBuf, pcbNeeded, pcbReturned);
7523 return FALSE;
7526 /*****************************************************************************
7527 * ExtDeviceMode [WINSPOOL.@]
7530 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
7531 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
7532 DWORD fMode)
7534 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
7535 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
7536 debugstr_a(pProfile), fMode);
7537 return -1;
7540 /*****************************************************************************
7541 * FindClosePrinterChangeNotification [WINSPOOL.@]
7544 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
7546 FIXME("Stub: %p\n", hChange);
7547 return TRUE;
7550 /*****************************************************************************
7551 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7554 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
7555 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
7557 FIXME("Stub: %p %x %x %p\n",
7558 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
7559 return INVALID_HANDLE_VALUE;
7562 /*****************************************************************************
7563 * FindNextPrinterChangeNotification [WINSPOOL.@]
7566 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
7567 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
7569 FIXME("Stub: %p %p %p %p\n",
7570 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
7571 return FALSE;
7574 /*****************************************************************************
7575 * FreePrinterNotifyInfo [WINSPOOL.@]
7578 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
7580 FIXME("Stub: %p\n", pPrinterNotifyInfo);
7581 return TRUE;
7584 /*****************************************************************************
7585 * string_to_buf
7587 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7588 * ansi depending on the unicode parameter.
7590 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
7592 if(!str)
7594 *size = 0;
7595 return TRUE;
7598 if(unicode)
7600 *size = (strlenW(str) + 1) * sizeof(WCHAR);
7601 if(*size <= cb)
7603 memcpy(ptr, str, *size);
7604 return TRUE;
7606 return FALSE;
7608 else
7610 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
7611 if(*size <= cb)
7613 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
7614 return TRUE;
7616 return FALSE;
7620 /*****************************************************************************
7621 * get_job_info_1
7623 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7624 LPDWORD pcbNeeded, BOOL unicode)
7626 DWORD size, left = cbBuf;
7627 BOOL space = (cbBuf > 0);
7628 LPBYTE ptr = buf;
7630 *pcbNeeded = 0;
7632 if(space)
7634 ji1->JobId = job->job_id;
7637 string_to_buf(job->document_title, ptr, left, &size, unicode);
7638 if(space && size <= left)
7640 ji1->pDocument = (LPWSTR)ptr;
7641 ptr += size;
7642 left -= size;
7644 else
7645 space = FALSE;
7646 *pcbNeeded += size;
7648 return space;
7651 /*****************************************************************************
7652 * get_job_info_2
7654 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7655 LPDWORD pcbNeeded, BOOL unicode)
7657 DWORD size, left = cbBuf;
7658 BOOL space = (cbBuf > 0);
7659 LPBYTE ptr = buf;
7661 *pcbNeeded = 0;
7663 if(space)
7665 ji2->JobId = job->job_id;
7668 string_to_buf(job->document_title, ptr, left, &size, unicode);
7669 if(space && size <= left)
7671 ji2->pDocument = (LPWSTR)ptr;
7672 ptr += size;
7673 left -= size;
7675 else
7676 space = FALSE;
7677 *pcbNeeded += size;
7679 return space;
7682 /*****************************************************************************
7683 * get_job_info
7685 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7686 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7688 BOOL ret = FALSE;
7689 DWORD needed = 0, size;
7690 job_t *job;
7691 LPBYTE ptr = pJob;
7693 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7695 EnterCriticalSection(&printer_handles_cs);
7696 job = get_job(hPrinter, JobId);
7697 if(!job)
7698 goto end;
7700 switch(Level)
7702 case 1:
7703 size = sizeof(JOB_INFO_1W);
7704 if(cbBuf >= size)
7706 cbBuf -= size;
7707 ptr += size;
7708 memset(pJob, 0, size);
7710 else
7711 cbBuf = 0;
7712 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7713 needed += size;
7714 break;
7716 case 2:
7717 size = sizeof(JOB_INFO_2W);
7718 if(cbBuf >= size)
7720 cbBuf -= size;
7721 ptr += size;
7722 memset(pJob, 0, size);
7724 else
7725 cbBuf = 0;
7726 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7727 needed += size;
7728 break;
7730 case 3:
7731 size = sizeof(JOB_INFO_3);
7732 if(cbBuf >= size)
7734 cbBuf -= size;
7735 memset(pJob, 0, size);
7736 ret = TRUE;
7738 else
7739 cbBuf = 0;
7740 needed = size;
7741 break;
7743 default:
7744 SetLastError(ERROR_INVALID_LEVEL);
7745 goto end;
7747 if(pcbNeeded)
7748 *pcbNeeded = needed;
7749 end:
7750 LeaveCriticalSection(&printer_handles_cs);
7751 return ret;
7754 /*****************************************************************************
7755 * GetJobA [WINSPOOL.@]
7758 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7759 DWORD cbBuf, LPDWORD pcbNeeded)
7761 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7764 /*****************************************************************************
7765 * GetJobW [WINSPOOL.@]
7768 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7769 DWORD cbBuf, LPDWORD pcbNeeded)
7771 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7774 /*****************************************************************************
7775 * schedule_lpr
7777 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7779 char *unixname, *queue, *cmd;
7780 char fmt[] = "lpr -P%s %s";
7781 DWORD len;
7783 if(!(unixname = wine_get_unix_file_name(filename)))
7784 return FALSE;
7786 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7787 queue = HeapAlloc(GetProcessHeap(), 0, len);
7788 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7790 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7791 sprintf(cmd, fmt, queue, unixname);
7793 TRACE("printing with: %s\n", cmd);
7794 system(cmd);
7796 HeapFree(GetProcessHeap(), 0, cmd);
7797 HeapFree(GetProcessHeap(), 0, queue);
7798 HeapFree(GetProcessHeap(), 0, unixname);
7799 return TRUE;
7802 /*****************************************************************************
7803 * schedule_cups
7805 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7807 #ifdef SONAME_LIBCUPS
7808 if(pcupsPrintFile)
7810 char *unixname, *queue, *doc_titleA;
7811 DWORD len;
7812 BOOL ret;
7814 if(!(unixname = wine_get_unix_file_name(filename)))
7815 return FALSE;
7817 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7818 queue = HeapAlloc(GetProcessHeap(), 0, len);
7819 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7821 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7822 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7823 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7825 TRACE("printing via cups\n");
7826 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7827 HeapFree(GetProcessHeap(), 0, doc_titleA);
7828 HeapFree(GetProcessHeap(), 0, queue);
7829 HeapFree(GetProcessHeap(), 0, unixname);
7830 return ret;
7832 else
7833 #endif
7835 return schedule_lpr(printer_name, filename);
7839 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7841 LPWSTR filename;
7843 switch(msg)
7845 case WM_INITDIALOG:
7846 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7847 return TRUE;
7849 case WM_COMMAND:
7850 if(HIWORD(wparam) == BN_CLICKED)
7852 if(LOWORD(wparam) == IDOK)
7854 HANDLE hf;
7855 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7856 LPWSTR *output;
7858 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7859 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7861 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7863 WCHAR caption[200], message[200];
7864 int mb_ret;
7866 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7867 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7868 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7869 if(mb_ret == IDCANCEL)
7871 HeapFree(GetProcessHeap(), 0, filename);
7872 return TRUE;
7875 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7876 if(hf == INVALID_HANDLE_VALUE)
7878 WCHAR caption[200], message[200];
7880 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7881 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7882 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7883 HeapFree(GetProcessHeap(), 0, filename);
7884 return TRUE;
7886 CloseHandle(hf);
7887 DeleteFileW(filename);
7888 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7889 *output = filename;
7890 EndDialog(hwnd, IDOK);
7891 return TRUE;
7893 if(LOWORD(wparam) == IDCANCEL)
7895 EndDialog(hwnd, IDCANCEL);
7896 return TRUE;
7899 return FALSE;
7901 return FALSE;
7904 /*****************************************************************************
7905 * get_filename
7907 static BOOL get_filename(LPWSTR *filename)
7909 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7910 file_dlg_proc, (LPARAM)filename) == IDOK;
7913 /*****************************************************************************
7914 * schedule_file
7916 static BOOL schedule_file(LPCWSTR filename)
7918 LPWSTR output = NULL;
7920 if(get_filename(&output))
7922 TRACE("copy to %s\n", debugstr_w(output));
7923 CopyFileW(filename, output, FALSE);
7924 HeapFree(GetProcessHeap(), 0, output);
7925 return TRUE;
7927 return FALSE;
7930 /*****************************************************************************
7931 * schedule_pipe
7933 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7935 #ifdef HAVE_FORK
7936 char *unixname, *cmdA;
7937 DWORD len;
7938 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7939 BOOL ret = FALSE;
7940 char buf[1024];
7942 if(!(unixname = wine_get_unix_file_name(filename)))
7943 return FALSE;
7945 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7946 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7947 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7949 TRACE("printing with: %s\n", cmdA);
7951 if((file_fd = open(unixname, O_RDONLY)) == -1)
7952 goto end;
7954 if (pipe(fds))
7956 ERR("pipe() failed!\n");
7957 goto end;
7960 if (fork() == 0)
7962 close(0);
7963 dup2(fds[0], 0);
7964 close(fds[1]);
7966 /* reset signals that we previously set to SIG_IGN */
7967 signal(SIGPIPE, SIG_DFL);
7968 signal(SIGCHLD, SIG_DFL);
7970 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7971 _exit(1);
7974 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7975 write(fds[1], buf, no_read);
7977 ret = TRUE;
7979 end:
7980 if(file_fd != -1) close(file_fd);
7981 if(fds[0] != -1) close(fds[0]);
7982 if(fds[1] != -1) close(fds[1]);
7984 HeapFree(GetProcessHeap(), 0, cmdA);
7985 HeapFree(GetProcessHeap(), 0, unixname);
7986 return ret;
7987 #else
7988 return FALSE;
7989 #endif
7992 /*****************************************************************************
7993 * schedule_unixfile
7995 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7997 int in_fd, out_fd, no_read;
7998 char buf[1024];
7999 BOOL ret = FALSE;
8000 char *unixname, *outputA;
8001 DWORD len;
8003 if(!(unixname = wine_get_unix_file_name(filename)))
8004 return FALSE;
8006 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
8007 outputA = HeapAlloc(GetProcessHeap(), 0, len);
8008 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
8010 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
8011 in_fd = open(unixname, O_RDONLY);
8012 if(out_fd == -1 || in_fd == -1)
8013 goto end;
8015 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
8016 write(out_fd, buf, no_read);
8018 ret = TRUE;
8019 end:
8020 if(in_fd != -1) close(in_fd);
8021 if(out_fd != -1) close(out_fd);
8022 HeapFree(GetProcessHeap(), 0, outputA);
8023 HeapFree(GetProcessHeap(), 0, unixname);
8024 return ret;
8027 /*****************************************************************************
8028 * ScheduleJob [WINSPOOL.@]
8031 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
8033 opened_printer_t *printer;
8034 BOOL ret = FALSE;
8035 struct list *cursor, *cursor2;
8037 TRACE("(%p, %x)\n", hPrinter, dwJobID);
8038 EnterCriticalSection(&printer_handles_cs);
8039 printer = get_opened_printer(hPrinter);
8040 if(!printer)
8041 goto end;
8043 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
8045 job_t *job = LIST_ENTRY(cursor, job_t, entry);
8046 HANDLE hf;
8048 if(job->job_id != dwJobID) continue;
8050 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
8051 if(hf != INVALID_HANDLE_VALUE)
8053 PRINTER_INFO_5W *pi5;
8054 DWORD needed;
8055 HKEY hkey;
8056 WCHAR output[1024];
8057 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
8058 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
8060 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
8061 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
8062 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
8063 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
8064 debugstr_w(pi5->pPortName));
8066 output[0] = 0;
8068 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
8069 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
8071 DWORD type, count = sizeof(output);
8072 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
8073 RegCloseKey(hkey);
8075 if(output[0] == '|')
8077 schedule_pipe(output + 1, job->filename);
8079 else if(output[0])
8081 schedule_unixfile(output, job->filename);
8083 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
8085 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
8087 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
8089 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
8091 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
8093 schedule_file(job->filename);
8095 else
8097 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
8099 HeapFree(GetProcessHeap(), 0, pi5);
8100 CloseHandle(hf);
8101 DeleteFileW(job->filename);
8103 list_remove(cursor);
8104 HeapFree(GetProcessHeap(), 0, job->document_title);
8105 HeapFree(GetProcessHeap(), 0, job->filename);
8106 HeapFree(GetProcessHeap(), 0, job);
8107 ret = TRUE;
8108 break;
8110 end:
8111 LeaveCriticalSection(&printer_handles_cs);
8112 return ret;
8115 /*****************************************************************************
8116 * StartDocDlgA [WINSPOOL.@]
8118 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
8120 UNICODE_STRING usBuffer;
8121 DOCINFOW docW;
8122 LPWSTR retW;
8123 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
8124 LPSTR ret = NULL;
8126 docW.cbSize = sizeof(docW);
8127 if (doc->lpszDocName)
8129 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
8130 if (!(docW.lpszDocName = docnameW)) return NULL;
8132 if (doc->lpszOutput)
8134 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
8135 if (!(docW.lpszOutput = outputW)) return NULL;
8137 if (doc->lpszDatatype)
8139 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
8140 if (!(docW.lpszDatatype = datatypeW)) return NULL;
8142 docW.fwType = doc->fwType;
8144 retW = StartDocDlgW(hPrinter, &docW);
8146 if(retW)
8148 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
8149 ret = HeapAlloc(GetProcessHeap(), 0, len);
8150 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
8151 HeapFree(GetProcessHeap(), 0, retW);
8154 HeapFree(GetProcessHeap(), 0, datatypeW);
8155 HeapFree(GetProcessHeap(), 0, outputW);
8156 HeapFree(GetProcessHeap(), 0, docnameW);
8158 return ret;
8161 /*****************************************************************************
8162 * StartDocDlgW [WINSPOOL.@]
8164 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8165 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8166 * port is "FILE:". Also returns the full path if passed a relative path.
8168 * The caller should free the returned string from the process heap.
8170 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
8172 LPWSTR ret = NULL;
8173 DWORD len, attr;
8175 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
8177 PRINTER_INFO_5W *pi5;
8178 GetPrinterW(hPrinter, 5, NULL, 0, &len);
8179 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
8180 return NULL;
8181 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
8182 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
8183 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
8185 HeapFree(GetProcessHeap(), 0, pi5);
8186 return NULL;
8188 HeapFree(GetProcessHeap(), 0, pi5);
8191 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
8193 LPWSTR name;
8195 if (get_filename(&name))
8197 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
8199 HeapFree(GetProcessHeap(), 0, name);
8200 return NULL;
8202 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8203 GetFullPathNameW(name, len, ret, NULL);
8204 HeapFree(GetProcessHeap(), 0, name);
8206 return ret;
8209 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
8210 return NULL;
8212 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
8213 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
8215 attr = GetFileAttributesW(ret);
8216 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
8218 HeapFree(GetProcessHeap(), 0, ret);
8219 ret = NULL;
8221 return ret;