rsaenh: Add support for mandatory parameters to RSAENH_CPGetProvParam.
[wine/winequartzdrv.git] / dlls / winspool.drv / info.c
blobe19c82c7247b154542ef29c65b34e5f685e86981
1 /*
2 * WINSPOOL functions
4 * Copyright 1996 John Harvey
5 * Copyright 1998 Andreas Mohr
6 * Copyright 1999 Klaas van Gend
7 * Copyright 1999, 2000 Huw D M Davies
8 * Copyright 2001 Marcus Meissner
9 * Copyright 2005, 2006, 2007 Detlef Riekenberg
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
27 #include "wine/port.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <stddef.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <signal.h>
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
41 # ifndef SONAME_LIBCUPS
42 # define SONAME_LIBCUPS "libcups.so"
43 # endif
44 #endif
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48 #include "wine/library.h"
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winuser.h"
52 #include "winerror.h"
53 #include "winreg.h"
54 #include "wingdi.h"
55 #include "winspool.h"
56 #include "winternl.h"
57 #include "wine/windef16.h"
58 #include "wine/unicode.h"
59 #include "wine/debug.h"
60 #include "wine/list.h"
61 #include "winnls.h"
63 #include "ddk/winsplp.h"
64 #include "wspool.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(winspool);
68 /* ############################### */
70 static CRITICAL_SECTION monitor_handles_cs;
71 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
73 0, 0, &monitor_handles_cs,
74 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
75 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
77 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
80 static CRITICAL_SECTION printer_handles_cs;
81 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug =
83 0, 0, &printer_handles_cs,
84 { &printer_handles_cs_debug.ProcessLocksList, &printer_handles_cs_debug.ProcessLocksList },
85 0, 0, { (DWORD_PTR)(__FILE__ ": printer_handles_cs") }
87 static CRITICAL_SECTION printer_handles_cs = { &printer_handles_cs_debug, -1, 0, 0, 0, 0 };
89 /* ############################### */
91 typedef struct {
92 struct list entry;
93 LPWSTR name;
94 LPWSTR dllname;
95 PMONITORUI monitorUI;
96 LPMONITOR monitor;
97 HMODULE hdll;
98 DWORD refcount;
99 DWORD dwMonitorSize;
100 } monitor_t;
102 typedef struct {
103 DWORD job_id;
104 HANDLE hf;
105 } started_doc_t;
107 typedef struct {
108 struct list jobs;
109 LONG ref;
110 } jobqueue_t;
112 typedef struct {
113 LPWSTR name;
114 LPWSTR printername;
115 monitor_t *pm;
116 HANDLE hXcv;
117 jobqueue_t *queue;
118 started_doc_t *doc;
119 } opened_printer_t;
121 typedef struct {
122 struct list entry;
123 DWORD job_id;
124 WCHAR *filename;
125 WCHAR *document_title;
126 } job_t;
129 typedef struct {
130 LPCWSTR envname;
131 LPCWSTR subdir;
132 DWORD driverversion;
133 LPCWSTR versionregpath;
134 LPCWSTR versionsubdir;
135 } printenv_t;
137 /* ############################### */
139 static struct list monitor_handles = LIST_INIT( monitor_handles );
140 static monitor_t * pm_localport;
142 static opened_printer_t **printer_handles;
143 static int nb_printer_handles;
144 static LONG next_job_id = 1;
146 static DWORD (WINAPI *GDI_CallDeviceCapabilities16)( LPCSTR lpszDevice, LPCSTR lpszPort,
147 WORD fwCapability, LPSTR lpszOutput,
148 LPDEVMODEA lpdm );
149 static INT (WINAPI *GDI_CallExtDeviceMode16)( HWND hwnd, LPDEVMODEA lpdmOutput,
150 LPSTR lpszDevice, LPSTR lpszPort,
151 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
152 DWORD fwMode );
154 static const WCHAR DriversW[] = { 'S','y','s','t','e','m','\\',
155 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
156 'c','o','n','t','r','o','l','\\',
157 'P','r','i','n','t','\\',
158 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
159 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
161 static const WCHAR MonitorsW[] = { 'S','y','s','t','e','m','\\',
162 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
163 'C','o','n','t','r','o','l','\\',
164 'P','r','i','n','t','\\',
165 'M','o','n','i','t','o','r','s','\\',0};
167 static const WCHAR PrintersW[] = {'S','y','s','t','e','m','\\',
168 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
169 'C','o','n','t','r','o','l','\\',
170 'P','r','i','n','t','\\',
171 'P','r','i','n','t','e','r','s',0};
173 static const WCHAR LocalPortW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
175 static const WCHAR user_default_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
176 'M','i','c','r','o','s','o','f','t','\\',
177 'W','i','n','d','o','w','s',' ','N','T','\\',
178 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
179 'W','i','n','d','o','w','s',0};
181 static const WCHAR user_printers_reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
182 'M','i','c','r','o','s','o','f','t','\\',
183 'W','i','n','d','o','w','s',' ','N','T','\\',
184 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
185 'D','e','v','i','c','e','s',0};
187 static const WCHAR WinNT_CV_PortsW[] = {'S','o','f','t','w','a','r','e','\\',
188 'M','i','c','r','o','s','o','f','t','\\',
189 'W','i','n','d','o','w','s',' ','N','T','\\',
190 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
191 'P','o','r','t','s',0};
193 static const WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
194 static const WCHAR envname_win40W[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
195 static const WCHAR envname_x86W[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
196 static const WCHAR subdir_win40W[] = {'w','i','n','4','0',0};
197 static const WCHAR subdir_x86W[] = {'w','3','2','x','8','6',0};
198 static const WCHAR Version3_RegPathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
199 static const WCHAR Version3_SubdirW[] = {'\\','3',0};
201 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
202 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',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',
209 'M','o','d','e',0};
210 static const WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
211 'i','l','e','s',0};
212 static const WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
213 static const WCHAR DriverW[] = {'D','r','i','v','e','r',0};
214 static const WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
215 static const WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',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 ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
220 static const WCHAR PortW[] = {'P','o','r','t',0};
221 static const WCHAR bs_Ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
222 static const WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
223 's','s','o','r',0};
224 static const WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
225 'v','e','r',0};
226 static const WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
227 'v','e','r','D','a','t','a',0};
228 static const WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
229 'i','l','e',0};
230 static const WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
231 static const WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
232 static const WCHAR deviceW[] = {'d','e','v','i','c','e',0};
233 static const WCHAR devicesW[] = {'d','e','v','i','c','e','s',0};
234 static const WCHAR windowsW[] = {'w','i','n','d','o','w','s',0};
235 static const WCHAR emptyStringW[] = {0};
236 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
237 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
239 static const WCHAR May_Delete_Value[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
241 static const WCHAR CUPS_Port[] = {'C','U','P','S',':',0};
242 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
243 static const WCHAR LPR_Port[] = {'L','P','R',':',0};
245 static const WCHAR default_doc_title[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
246 'D','o','c','u','m','e','n','t',0};
249 /*****************************************************************************
250 * WINSPOOL_SHRegDeleteKey
252 * Recursively delete subkeys.
253 * Cut & paste from shlwapi.
256 static DWORD WINSPOOL_SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
258 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
259 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
260 HKEY hSubKey = 0;
262 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
263 if(!dwRet)
265 /* Find how many subkeys there are */
266 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
267 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
268 if(!dwRet)
270 dwMaxSubkeyLen++;
271 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
272 /* Name too big: alloc a buffer for it */
273 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
275 if(!lpszName)
276 dwRet = ERROR_NOT_ENOUGH_MEMORY;
277 else
279 /* Recursively delete all the subkeys */
280 for(i = 0; i < dwKeyCount && !dwRet; i++)
282 dwSize = dwMaxSubkeyLen;
283 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
284 if(!dwRet)
285 dwRet = WINSPOOL_SHDeleteKeyW(hSubKey, lpszName);
288 if (lpszName != szNameBuf)
289 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
293 RegCloseKey(hSubKey);
294 if(!dwRet)
295 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
297 return dwRet;
301 /******************************************************************
302 * validate the user-supplied printing-environment [internal]
304 * PARAMS
305 * env [I] PTR to Environment-String or NULL
307 * RETURNS
308 * Failure: NULL
309 * Success: PTR to printenv_t
311 * NOTES
312 * An empty string is handled the same way as NULL.
313 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
317 static const printenv_t * validate_envW(LPCWSTR env)
319 static const printenv_t env_x86 = {envname_x86W, subdir_x86W,
320 3, Version3_RegPathW, Version3_SubdirW};
321 static const printenv_t env_win40 = {envname_win40W, subdir_win40W,
322 0, emptyStringW, emptyStringW};
323 static const printenv_t * const all_printenv[]={&env_x86, &env_win40};
325 const printenv_t *result = NULL;
326 unsigned int i;
328 TRACE("testing %s\n", debugstr_w(env));
329 if (env && env[0])
331 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
333 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
335 result = all_printenv[i];
336 break;
340 if (result == NULL) {
341 FIXME("unsupported Environment: %s\n", debugstr_w(env));
342 SetLastError(ERROR_INVALID_ENVIRONMENT);
344 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
346 else
348 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
350 TRACE("using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
352 return result;
356 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
357 if passed a NULL string. This returns NULLs to the result.
359 static inline PWSTR asciitounicode( UNICODE_STRING * usBufferPtr, LPCSTR src )
361 if ( (src) )
363 RtlCreateUnicodeStringFromAsciiz(usBufferPtr, src);
364 return usBufferPtr->Buffer;
366 usBufferPtr->Buffer = NULL; /* so that RtlFreeUnicodeString won't barf */
367 return NULL;
370 static LPWSTR strdupW(LPCWSTR p)
372 LPWSTR ret;
373 DWORD len;
375 if(!p) return NULL;
376 len = (strlenW(p) + 1) * sizeof(WCHAR);
377 ret = HeapAlloc(GetProcessHeap(), 0, len);
378 memcpy(ret, p, len);
379 return ret;
382 static LPSTR strdupWtoA( LPCWSTR str )
384 LPSTR ret;
385 INT len;
387 if (!str) return NULL;
388 len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
389 ret = HeapAlloc( GetProcessHeap(), 0, len );
390 if(ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
391 return ret;
394 /* Returns the number of bytes in an ansi \0\0 terminated string (multi_sz).
395 The result includes all \0s (specifically the last two). */
396 static int multi_sz_lenA(const char *str)
398 const char *ptr = str;
399 if(!str) return 0;
402 ptr += lstrlenA(ptr) + 1;
403 } while(*ptr);
405 return ptr - str + 1;
408 static void
409 WINSPOOL_SetDefaultPrinter(const char *devname, const char *name, BOOL force) {
410 char qbuf[200];
412 /* If forcing, or no profile string entry for device yet, set the entry
414 * The always change entry if not WINEPS yet is discussable.
416 if (force ||
417 !GetProfileStringA("windows","device","*",qbuf,sizeof(qbuf)) ||
418 !strcmp(qbuf,"*") ||
419 !strstr(qbuf,"WINEPS.DRV")
421 char *buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS.DRV,LPR:")+1);
422 HKEY hkey;
424 sprintf(buf,"%s,WINEPS.DRV,LPR:%s",devname,name);
425 WriteProfileStringA("windows","device",buf);
426 if(RegCreateKeyW(HKEY_CURRENT_USER, user_default_reg_key, &hkey) == ERROR_SUCCESS) {
427 RegSetValueExA(hkey, "Device", 0, REG_SZ, (LPBYTE)buf, strlen(buf) + 1);
428 RegCloseKey(hkey);
430 HeapFree(GetProcessHeap(),0,buf);
434 static BOOL add_printer_driver(const char *name)
436 DRIVER_INFO_3A di3a;
438 static char driver_path[] = "wineps16",
439 data_file[] = "<datafile?>",
440 config_file[] = "wineps16",
441 help_file[] = "<helpfile?>",
442 dep_file[] = "<dependent files?>\0",
443 monitor_name[] = "<monitor name?>",
444 default_data_type[] = "RAW";
446 di3a.cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
447 di3a.pName = (char *)name;
448 di3a.pEnvironment = NULL; /* NULL means auto */
449 di3a.pDriverPath = driver_path;
450 di3a.pDataFile = data_file;
451 di3a.pConfigFile = config_file;
452 di3a.pHelpFile = help_file;
453 di3a.pDependentFiles = dep_file;
454 di3a.pMonitorName = monitor_name;
455 di3a.pDefaultDataType = default_data_type;
457 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3a))
459 ERR("Failed adding driver (%d)\n", GetLastError());
460 return FALSE;
462 return TRUE;
465 #ifdef HAVE_CUPS_CUPS_H
466 static typeof(cupsGetDests) *pcupsGetDests;
467 static typeof(cupsGetPPD) *pcupsGetPPD;
468 static typeof(cupsPrintFile) *pcupsPrintFile;
469 static void *cupshandle;
471 static BOOL CUPS_LoadPrinters(void)
473 int i, nrofdests;
474 BOOL hadprinter = FALSE;
475 cups_dest_t *dests;
476 PRINTER_INFO_2A pinfo2a;
477 char *port,*devline;
478 HKEY hkeyPrinter, hkeyPrinters, hkey;
480 cupshandle = wine_dlopen(SONAME_LIBCUPS, RTLD_NOW, NULL, 0);
481 if (!cupshandle)
482 return FALSE;
483 TRACE("loaded %s\n", SONAME_LIBCUPS);
485 #define DYNCUPS(x) \
486 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
487 if (!p##x) return FALSE;
489 DYNCUPS(cupsGetPPD);
490 DYNCUPS(cupsGetDests);
491 DYNCUPS(cupsPrintFile);
492 #undef DYNCUPS
494 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
495 ERROR_SUCCESS) {
496 ERR("Can't create Printers key\n");
497 return FALSE;
500 nrofdests = pcupsGetDests(&dests);
501 TRACE("Found %d CUPS %s:\n", nrofdests, (nrofdests == 1) ? "printer" : "printers");
502 for (i=0;i<nrofdests;i++) {
503 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
504 sprintf(port,"LPR:%s",dests[i].name);
505 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
506 sprintf(devline,"WINEPS.DRV,%s",port);
507 WriteProfileStringA("devices",dests[i].name,devline);
508 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
509 RegSetValueExA(hkey, dests[i].name, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
510 RegCloseKey(hkey);
512 HeapFree(GetProcessHeap(),0,devline);
514 TRACE("Printer %d: %s\n", i, dests[i].name);
515 if(RegOpenKeyA(hkeyPrinters, dests[i].name, &hkeyPrinter) == ERROR_SUCCESS) {
516 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
517 and continue */
518 TRACE("Printer already exists\n");
519 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
520 RegCloseKey(hkeyPrinter);
521 } else {
522 static CHAR data_type[] = "RAW",
523 print_proc[] = "WinPrint",
524 comment[] = "WINEPS Printer using CUPS",
525 location[] = "<physical location of printer>",
526 params[] = "<parameters?>",
527 share_name[] = "<share name?>",
528 sep_file[] = "<sep file?>";
530 add_printer_driver(dests[i].name);
532 memset(&pinfo2a,0,sizeof(pinfo2a));
533 pinfo2a.pPrinterName = dests[i].name;
534 pinfo2a.pDatatype = data_type;
535 pinfo2a.pPrintProcessor = print_proc;
536 pinfo2a.pDriverName = dests[i].name;
537 pinfo2a.pComment = comment;
538 pinfo2a.pLocation = location;
539 pinfo2a.pPortName = port;
540 pinfo2a.pParameters = params;
541 pinfo2a.pShareName = share_name;
542 pinfo2a.pSepFile = sep_file;
544 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
545 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS)
546 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests[i].name,GetLastError());
549 HeapFree(GetProcessHeap(),0,port);
551 hadprinter = TRUE;
552 if (dests[i].is_default)
553 WINSPOOL_SetDefaultPrinter(dests[i].name, dests[i].name, TRUE);
555 RegCloseKey(hkeyPrinters);
556 return hadprinter;
558 #endif
560 static BOOL
561 PRINTCAP_ParseEntry(const char *pent, BOOL isfirst) {
562 PRINTER_INFO_2A pinfo2a;
563 char *e,*s,*name,*prettyname,*devname;
564 BOOL ret = FALSE, set_default = FALSE;
565 char *port,*devline,*env_default;
566 HKEY hkeyPrinter, hkeyPrinters, hkey;
568 while (isspace(*pent)) pent++;
569 s = strchr(pent,':');
570 if(s) *s='\0';
571 name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
572 strcpy(name,pent);
573 if(s) {
574 *s=':';
575 pent = s;
576 } else
577 pent = "";
579 TRACE("name=%s entry=%s\n",name, pent);
581 if(ispunct(*name)) { /* a tc entry, not a real printer */
582 TRACE("skipping tc entry\n");
583 goto end;
586 if(strstr(pent,":server")) { /* server only version so skip */
587 TRACE("skipping server entry\n");
588 goto end;
591 /* Determine whether this is a postscript printer. */
593 ret = TRUE;
594 env_default = getenv("PRINTER");
595 prettyname = name;
596 /* Get longest name, usually the one at the right for later display. */
597 while((s=strchr(prettyname,'|'))) {
598 *s = '\0';
599 e = s;
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;
603 for(prettyname = s+1; isspace(*prettyname); prettyname++)
606 e = prettyname + strlen(prettyname);
607 while(isspace(*--e)) *e = '\0';
608 TRACE("\t%s\n", debugstr_a(prettyname));
609 if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
611 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
612 * if it is too long, we use it as comment below. */
613 devname = prettyname;
614 if (strlen(devname)>=CCHDEVICENAME-1)
615 devname = name;
616 if (strlen(devname)>=CCHDEVICENAME-1) {
617 ret = FALSE;
618 goto end;
621 port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
622 sprintf(port,"LPR:%s",name);
624 devline=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port));
625 sprintf(devline,"WINEPS.DRV,%s",port);
626 WriteProfileStringA("devices",devname,devline);
627 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
628 RegSetValueExA(hkey, devname, 0, REG_SZ, (LPBYTE)devline, strlen(devline) + 1);
629 RegCloseKey(hkey);
631 HeapFree(GetProcessHeap(),0,devline);
633 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
634 ERROR_SUCCESS) {
635 ERR("Can't create Printers key\n");
636 ret = FALSE;
637 goto end;
639 if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
640 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
641 and continue */
642 TRACE("Printer already exists\n");
643 RegDeleteValueW(hkeyPrinter, May_Delete_Value);
644 RegCloseKey(hkeyPrinter);
645 } else {
646 static CHAR data_type[] = "RAW",
647 print_proc[] = "WinPrint",
648 comment[] = "WINEPS Printer using LPR",
649 params[] = "<parameters?>",
650 share_name[] = "<share name?>",
651 sep_file[] = "<sep file?>";
653 add_printer_driver(devname);
655 memset(&pinfo2a,0,sizeof(pinfo2a));
656 pinfo2a.pPrinterName = devname;
657 pinfo2a.pDatatype = data_type;
658 pinfo2a.pPrintProcessor = print_proc;
659 pinfo2a.pDriverName = devname;
660 pinfo2a.pComment = comment;
661 pinfo2a.pLocation = prettyname;
662 pinfo2a.pPortName = port;
663 pinfo2a.pParameters = params;
664 pinfo2a.pShareName = share_name;
665 pinfo2a.pSepFile = sep_file;
667 if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
668 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
669 ERR("%s not added by AddPrinterA (%d)\n",name,GetLastError());
672 RegCloseKey(hkeyPrinters);
674 if (isfirst || set_default)
675 WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
677 HeapFree(GetProcessHeap(), 0, port);
678 end:
679 HeapFree(GetProcessHeap(), 0, name);
680 return ret;
683 static BOOL
684 PRINTCAP_LoadPrinters(void) {
685 BOOL hadprinter = FALSE;
686 char buf[200];
687 FILE *f;
688 char *pent = NULL;
689 BOOL had_bash = FALSE;
691 f = fopen("/etc/printcap","r");
692 if (!f)
693 return FALSE;
695 while(fgets(buf,sizeof(buf),f)) {
696 char *start, *end;
698 end=strchr(buf,'\n');
699 if (end) *end='\0';
701 start = buf;
702 while(isspace(*start)) start++;
703 if(*start == '#' || *start == '\0')
704 continue;
706 if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
707 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
708 HeapFree(GetProcessHeap(),0,pent);
709 pent = NULL;
712 if (end && *--end == '\\') {
713 *end = '\0';
714 had_bash = TRUE;
715 } else
716 had_bash = FALSE;
718 if (pent) {
719 pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
720 strcat(pent,start);
721 } else {
722 pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
723 strcpy(pent,start);
727 if(pent) {
728 hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
729 HeapFree(GetProcessHeap(),0,pent);
731 fclose(f);
732 return hadprinter;
735 static inline DWORD set_reg_szW(HKEY hkey, const WCHAR *keyname, const WCHAR *value)
737 if (value)
738 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (const BYTE*)value,
739 (lstrlenW(value) + 1) * sizeof(WCHAR));
740 else
741 return ERROR_FILE_NOT_FOUND;
744 /*****************************************************************************
745 * enumerate the local monitors (INTERNAL)
747 * returns the needed size (in bytes) for pMonitors
748 * and *lpreturned is set to number of entries returned in pMonitors
751 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
753 HKEY hroot = NULL;
754 HKEY hentry = NULL;
755 LPWSTR ptr;
756 LPMONITOR_INFO_2W mi;
757 WCHAR buffer[MAX_PATH];
758 WCHAR dllname[MAX_PATH];
759 DWORD dllsize;
760 DWORD len;
761 DWORD index = 0;
762 DWORD needed = 0;
763 DWORD numentries;
764 DWORD entrysize;
766 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
768 numentries = *lpreturned; /* this is 0, when we scan the registry */
769 len = entrysize * numentries;
770 ptr = (LPWSTR) &pMonitors[len];
772 numentries = 0;
773 len = sizeof(buffer);
774 buffer[0] = '\0';
776 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
777 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
778 /* Scan all Monitor-Registry-Keys */
779 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
780 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
781 dllsize = sizeof(dllname);
782 dllname[0] = '\0';
784 /* The Monitor must have a Driver-DLL */
785 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
786 if (RegQueryValueExW(hentry, DriverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
787 /* We found a valid DLL for this Monitor. */
788 TRACE("using Driver: %s\n", debugstr_w(dllname));
790 RegCloseKey(hentry);
793 /* Windows returns only Port-Monitors here, but to simplify our code,
794 we do no filtering for Language-Monitors */
795 if (dllname[0]) {
796 numentries++;
797 needed += entrysize;
798 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
799 if (level > 1) {
800 /* we install and return only monitors for "Windows NT x86" */
801 needed += (lstrlenW(envname_x86W) +1) * sizeof(WCHAR);
802 needed += dllsize;
805 /* required size is calculated. Now fill the user-buffer */
806 if (pMonitors && (cbBuf >= needed)){
807 mi = (LPMONITOR_INFO_2W) pMonitors;
808 pMonitors += entrysize;
810 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
811 mi->pName = ptr;
812 lstrcpyW(ptr, buffer); /* Name of the Monitor */
813 ptr += (len+1); /* len is lstrlenW(monitorname) */
814 if (level > 1) {
815 mi->pEnvironment = ptr;
816 lstrcpyW(ptr, envname_x86W); /* fixed to "Windows NT x86" */
817 ptr += (lstrlenW(envname_x86W)+1);
819 mi->pDLLName = ptr;
820 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
821 ptr += (dllsize / sizeof(WCHAR));
825 index++;
826 len = sizeof(buffer);
827 buffer[0] = '\0';
829 RegCloseKey(hroot);
831 *lpreturned = numentries;
832 TRACE("need %d byte for %d entries\n", needed, numentries);
833 return needed;
836 /******************************************************************
837 * monitor_unload [internal]
839 * release a printmonitor and unload it from memory, when needed
842 static void monitor_unload(monitor_t * pm)
844 if (pm == NULL) return;
845 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
847 EnterCriticalSection(&monitor_handles_cs);
849 if (pm->refcount) pm->refcount--;
851 if (pm->refcount == 0) {
852 list_remove(&pm->entry);
853 FreeLibrary(pm->hdll);
854 HeapFree(GetProcessHeap(), 0, pm->name);
855 HeapFree(GetProcessHeap(), 0, pm->dllname);
856 HeapFree(GetProcessHeap(), 0, pm);
858 LeaveCriticalSection(&monitor_handles_cs);
861 /******************************************************************
862 * monitor_unloadall [internal]
864 * release all printmonitors and unload them from memory, when needed
867 static void monitor_unloadall(void)
869 monitor_t * pm;
870 monitor_t * next;
872 EnterCriticalSection(&monitor_handles_cs);
873 /* iterate through the list, with safety against removal */
874 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
876 monitor_unload(pm);
878 LeaveCriticalSection(&monitor_handles_cs);
881 /******************************************************************
882 * monitor_load [internal]
884 * load a printmonitor, get the dllname from the registry, when needed
885 * initialize the monitor and dump found function-pointers
887 * On failure, SetLastError() is called and NULL is returned
890 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
892 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
893 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
894 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
895 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
896 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
898 monitor_t * pm = NULL;
899 monitor_t * cursor;
900 LPWSTR regroot = NULL;
901 LPWSTR driver = dllname;
903 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
904 /* Is the Monitor already loaded? */
905 EnterCriticalSection(&monitor_handles_cs);
907 if (name) {
908 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
910 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
911 pm = cursor;
912 break;
917 if (pm == NULL) {
918 pm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(monitor_t));
919 if (pm == NULL) goto cleanup;
920 list_add_tail(&monitor_handles, &pm->entry);
922 pm->refcount++;
924 if (pm->name == NULL) {
925 /* Load the monitor */
926 LPMONITOREX pmonitorEx;
927 DWORD len;
929 if (name) {
930 len = lstrlenW(MonitorsW) + lstrlenW(name) + 2;
931 regroot = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
934 if (regroot) {
935 lstrcpyW(regroot, MonitorsW);
936 lstrcatW(regroot, name);
937 /* Get the Driver from the Registry */
938 if (driver == NULL) {
939 HKEY hroot;
940 DWORD namesize;
941 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
942 if (RegQueryValueExW(hroot, DriverW, NULL, NULL, NULL,
943 &namesize) == ERROR_SUCCESS) {
944 driver = HeapAlloc(GetProcessHeap(), 0, namesize);
945 RegQueryValueExW(hroot, DriverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
947 RegCloseKey(hroot);
952 pm->name = strdupW(name);
953 pm->dllname = strdupW(driver);
955 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
956 monitor_unload(pm);
957 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
958 pm = NULL;
959 goto cleanup;
962 pm->hdll = LoadLibraryW(driver);
963 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
965 if (pm->hdll == NULL) {
966 monitor_unload(pm);
967 SetLastError(ERROR_MOD_NOT_FOUND);
968 pm = NULL;
969 goto cleanup;
972 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
973 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
974 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
975 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
976 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
979 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
980 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
981 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
982 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
983 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
985 if (pInitializePrintMonitorUI != NULL) {
986 pm->monitorUI = pInitializePrintMonitorUI();
987 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
988 if (pm->monitorUI) {
989 TRACE( "0x%08x: dwMonitorSize (%d)\n",
990 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize );
995 if (pInitializePrintMonitor && regroot) {
996 pmonitorEx = pInitializePrintMonitor(regroot);
997 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
998 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
1000 if (pmonitorEx) {
1001 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
1002 pm->monitor = &(pmonitorEx->Monitor);
1006 if (pm->monitor) {
1007 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize );
1011 if (!pm->monitor && regroot) {
1012 if (pInitializePrintMonitor2 != NULL) {
1013 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
1015 if (pInitializeMonitorEx != NULL) {
1016 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
1018 if (pInitializeMonitor != NULL) {
1019 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
1022 if (!pm->monitor && !pm->monitorUI) {
1023 monitor_unload(pm);
1024 SetLastError(ERROR_PROC_NOT_FOUND);
1025 pm = NULL;
1028 cleanup:
1029 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, LocalPortW) == 0)) {
1030 pm->refcount++;
1031 pm_localport = pm;
1033 LeaveCriticalSection(&monitor_handles_cs);
1034 if (driver != dllname) HeapFree(GetProcessHeap(), 0, driver);
1035 HeapFree(GetProcessHeap(), 0, regroot);
1036 TRACE("=> %p\n", pm);
1037 return pm;
1040 /******************************************************************
1041 * monitor_loadall [internal]
1043 * Load all registered monitors
1046 static DWORD monitor_loadall(void)
1048 monitor_t * pm;
1049 DWORD registered = 0;
1050 DWORD loaded = 0;
1051 HKEY hmonitors;
1052 WCHAR buffer[MAX_PATH];
1053 DWORD id = 0;
1055 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
1056 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
1057 NULL, NULL, NULL, NULL, NULL);
1059 TRACE("%d monitors registered\n", registered);
1061 EnterCriticalSection(&monitor_handles_cs);
1062 while (id < registered) {
1063 buffer[0] = '\0';
1064 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
1065 pm = monitor_load(buffer, NULL);
1066 if (pm) loaded++;
1067 id++;
1069 LeaveCriticalSection(&monitor_handles_cs);
1070 RegCloseKey(hmonitors);
1072 TRACE("%d monitors loaded\n", loaded);
1073 return loaded;
1076 /******************************************************************
1077 * monitor_loadui [internal]
1079 * load the userinterface-dll for a given portmonitor
1081 * On failure, NULL is returned
1084 static monitor_t * monitor_loadui(monitor_t * pm)
1086 monitor_t * pui = NULL;
1087 LPWSTR buffer[MAX_PATH];
1088 HANDLE hXcv;
1089 DWORD len;
1090 DWORD res;
1092 if (pm == NULL) return NULL;
1093 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
1095 /* Try the Portmonitor first; works for many monitors */
1096 if (pm->monitorUI) {
1097 EnterCriticalSection(&monitor_handles_cs);
1098 pm->refcount++;
1099 LeaveCriticalSection(&monitor_handles_cs);
1100 return pm;
1103 /* query the userinterface-dllname from the Portmonitor */
1104 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
1105 /* building (",XcvMonitor %s",pm->name) not needed yet */
1106 res = pm->monitor->pfnXcvOpenPort(emptyStringW, SERVER_ACCESS_ADMINISTER, &hXcv);
1107 TRACE("got %u with %p\n", res, hXcv);
1108 if (res) {
1109 res = pm->monitor->pfnXcvDataPort(hXcv, MonitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
1110 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
1111 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
1112 pm->monitor->pfnXcvClosePort(hXcv);
1115 return pui;
1119 /******************************************************************
1120 * monitor_load_by_port [internal]
1122 * load a printmonitor for a given port
1124 * On failure, NULL is returned
1127 static monitor_t * monitor_load_by_port(LPCWSTR portname)
1129 HKEY hroot;
1130 HKEY hport;
1131 LPWSTR buffer;
1132 monitor_t * pm = NULL;
1133 DWORD registered = 0;
1134 DWORD id = 0;
1135 DWORD len;
1137 TRACE("(%s)\n", debugstr_w(portname));
1139 /* Try the Local Monitor first */
1140 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, WinNT_CV_PortsW, &hroot) == ERROR_SUCCESS) {
1141 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
1142 /* found the portname */
1143 RegCloseKey(hroot);
1144 return monitor_load(LocalPortW, NULL);
1146 RegCloseKey(hroot);
1149 len = MAX_PATH + lstrlenW(bs_Ports_bsW) + lstrlenW(portname) + 1;
1150 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1151 if (buffer == NULL) return NULL;
1153 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) == ERROR_SUCCESS) {
1154 EnterCriticalSection(&monitor_handles_cs);
1155 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1157 while ((pm == NULL) && (id < registered)) {
1158 buffer[0] = '\0';
1159 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
1160 TRACE("testing %s\n", debugstr_w(buffer));
1161 len = lstrlenW(buffer);
1162 lstrcatW(buffer, bs_Ports_bsW);
1163 lstrcatW(buffer, portname);
1164 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
1165 RegCloseKey(hport);
1166 buffer[len] = '\0'; /* use only the Monitor-Name */
1167 pm = monitor_load(buffer, NULL);
1169 id++;
1171 LeaveCriticalSection(&monitor_handles_cs);
1172 RegCloseKey(hroot);
1174 HeapFree(GetProcessHeap(), 0, buffer);
1175 return pm;
1178 /******************************************************************
1179 * enumerate the local Ports from all loaded monitors (internal)
1181 * returns the needed size (in bytes) for pPorts
1182 * and *lpreturned is set to number of entries returned in pPorts
1185 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
1187 monitor_t * pm;
1188 LPWSTR ptr;
1189 LPPORT_INFO_2W cache;
1190 LPPORT_INFO_2W out;
1191 LPBYTE pi_buffer = NULL;
1192 DWORD pi_allocated = 0;
1193 DWORD pi_needed;
1194 DWORD pi_index;
1195 DWORD pi_returned;
1196 DWORD res;
1197 DWORD outindex = 0;
1198 DWORD needed;
1199 DWORD numentries;
1200 DWORD entrysize;
1203 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
1204 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
1206 numentries = *lpreturned; /* this is 0, when we scan the registry */
1207 needed = entrysize * numentries;
1208 ptr = (LPWSTR) &pPorts[needed];
1210 numentries = 0;
1211 needed = 0;
1213 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
1215 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
1216 pi_needed = 0;
1217 pi_returned = 0;
1218 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1219 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
1220 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1221 HeapFree(GetProcessHeap(), 0, pi_buffer);
1222 pi_buffer = HeapAlloc(GetProcessHeap(), 0, pi_needed);
1223 pi_allocated = (pi_buffer) ? pi_needed : 0;
1224 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
1226 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1227 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
1229 numentries += pi_returned;
1230 needed += pi_needed;
1232 /* fill the output-buffer (pPorts), if we have one */
1233 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
1234 pi_index = 0;
1235 while (pi_returned > pi_index) {
1236 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
1237 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
1238 out->pPortName = ptr;
1239 lstrcpyW(ptr, cache->pPortName);
1240 ptr += (lstrlenW(ptr)+1);
1241 if (level > 1) {
1242 out->pMonitorName = ptr;
1243 lstrcpyW(ptr, cache->pMonitorName);
1244 ptr += (lstrlenW(ptr)+1);
1246 out->pDescription = ptr;
1247 lstrcpyW(ptr, cache->pDescription);
1248 ptr += (lstrlenW(ptr)+1);
1249 out->fPortType = cache->fPortType;
1250 out->Reserved = cache->Reserved;
1252 pi_index++;
1253 outindex++;
1258 /* the temporary portinfo-buffer is no longer needed */
1259 HeapFree(GetProcessHeap(), 0, pi_buffer);
1261 *lpreturned = numentries;
1262 TRACE("need %d byte for %d entries\n", needed, numentries);
1263 return needed;
1266 /******************************************************************
1267 * get_servername_from_name (internal)
1269 * for an external server, a copy of the serverpart from the full name is returned
1272 static LPWSTR get_servername_from_name(LPCWSTR name)
1274 LPWSTR server;
1275 LPWSTR ptr;
1276 WCHAR buffer[MAX_PATH];
1277 DWORD len;
1279 if (name == NULL) return NULL;
1280 if ((name[0] != '\\') || (name[1] != '\\')) return NULL;
1282 server = strdupW(&name[2]); /* skip over both backslash */
1283 if (server == NULL) return NULL;
1285 /* strip '\' and the printername */
1286 ptr = strchrW(server, '\\');
1287 if (ptr) ptr[0] = '\0';
1289 TRACE("found %s\n", debugstr_w(server));
1291 len = sizeof(buffer)/sizeof(buffer[0]);
1292 if (GetComputerNameW(buffer, &len)) {
1293 if (lstrcmpW(buffer, server) == 0) {
1294 /* The requested Servername is our computername */
1295 HeapFree(GetProcessHeap(), 0, server);
1296 return NULL;
1299 return server;
1302 /******************************************************************
1303 * get_basename_from_name (internal)
1305 * skip over the serverpart from the full name
1308 static LPCWSTR get_basename_from_name(LPCWSTR name)
1310 if (name == NULL) return NULL;
1311 if ((name[0] == '\\') && (name[1] == '\\')) {
1312 /* skip over the servername and search for the following '\' */
1313 name = strchrW(&name[2], '\\');
1314 if ((name) && (name[1])) {
1315 /* found a separator ('\') followed by a name:
1316 skip over the separator and return the rest */
1317 name++;
1319 else
1321 /* no basename present (we found only a servername) */
1322 return NULL;
1325 return name;
1328 /******************************************************************
1329 * get_opened_printer_entry
1330 * Get the first place empty in the opened printer table
1332 * ToDo:
1333 * - pDefault is ignored
1335 static HANDLE get_opened_printer_entry(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1337 UINT_PTR handle = nb_printer_handles, i;
1338 jobqueue_t *queue = NULL;
1339 opened_printer_t *printer = NULL;
1340 LPWSTR servername;
1341 LPCWSTR printername;
1342 HKEY hkeyPrinters;
1343 HKEY hkeyPrinter;
1344 DWORD len;
1346 servername = get_servername_from_name(name);
1347 if (servername) {
1348 FIXME("server %s not supported\n", debugstr_w(servername));
1349 HeapFree(GetProcessHeap(), 0, servername);
1350 SetLastError(ERROR_INVALID_PRINTER_NAME);
1351 return NULL;
1354 printername = get_basename_from_name(name);
1355 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1357 /* an empty printername is invalid */
1358 if (printername && (!printername[0])) {
1359 SetLastError(ERROR_INVALID_PARAMETER);
1360 return NULL;
1363 EnterCriticalSection(&printer_handles_cs);
1365 for (i = 0; i < nb_printer_handles; i++)
1367 if (!printer_handles[i])
1369 if(handle == nb_printer_handles)
1370 handle = i;
1372 else
1374 if(!queue && (name) && !lstrcmpW(name, printer_handles[i]->name))
1375 queue = printer_handles[i]->queue;
1379 if (handle >= nb_printer_handles)
1381 opened_printer_t **new_array;
1382 if (printer_handles)
1383 new_array = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, printer_handles,
1384 (nb_printer_handles + 16) * sizeof(*new_array) );
1385 else
1386 new_array = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1387 (nb_printer_handles + 16) * sizeof(*new_array) );
1389 if (!new_array)
1391 handle = 0;
1392 goto end;
1394 printer_handles = new_array;
1395 nb_printer_handles += 16;
1398 if (!(printer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*printer))))
1400 handle = 0;
1401 goto end;
1405 /* clone the base name. This is NULL for the printserver */
1406 printer->printername = strdupW(printername);
1408 /* clone the full name */
1409 printer->name = strdupW(name);
1410 if (name && (!printer->name)) {
1411 handle = 0;
1412 goto end;
1415 if (printername) {
1416 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1417 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1418 /* OpenPrinter(",XcvMonitor " detected */
1419 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1420 printer->pm = monitor_load(&printername[len], NULL);
1421 if (printer->pm == NULL) {
1422 SetLastError(ERROR_UNKNOWN_PORT);
1423 handle = 0;
1424 goto end;
1427 else
1429 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1430 if (strncmpW( printername, XcvPortW, len) == 0) {
1431 /* OpenPrinter(",XcvPort " detected */
1432 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1433 printer->pm = monitor_load_by_port(&printername[len]);
1434 if (printer->pm == NULL) {
1435 SetLastError(ERROR_UNKNOWN_PORT);
1436 handle = 0;
1437 goto end;
1442 if (printer->pm) {
1443 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1444 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1445 pDefault ? pDefault->DesiredAccess : 0,
1446 &printer->hXcv);
1448 if (printer->hXcv == NULL) {
1449 SetLastError(ERROR_INVALID_PARAMETER);
1450 handle = 0;
1451 goto end;
1454 else
1456 /* Does the Printer exist? */
1457 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) != ERROR_SUCCESS) {
1458 ERR("Can't create Printers key\n");
1459 handle = 0;
1460 goto end;
1462 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1463 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1464 RegCloseKey(hkeyPrinters);
1465 SetLastError(ERROR_INVALID_PRINTER_NAME);
1466 handle = 0;
1467 goto end;
1469 RegCloseKey(hkeyPrinter);
1470 RegCloseKey(hkeyPrinters);
1473 else
1475 TRACE("using the local printserver\n");
1478 if(queue)
1479 printer->queue = queue;
1480 else
1482 printer->queue = HeapAlloc(GetProcessHeap(), 0, sizeof(*queue));
1483 if (!printer->queue) {
1484 handle = 0;
1485 goto end;
1487 list_init(&printer->queue->jobs);
1488 printer->queue->ref = 0;
1490 InterlockedIncrement(&printer->queue->ref);
1492 printer_handles[handle] = printer;
1493 handle++;
1494 end:
1495 LeaveCriticalSection(&printer_handles_cs);
1496 if (!handle && printer) {
1497 /* Something failed: Free all resources */
1498 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1499 monitor_unload(printer->pm);
1500 HeapFree(GetProcessHeap(), 0, printer->printername);
1501 HeapFree(GetProcessHeap(), 0, printer->name);
1502 if (!queue) HeapFree(GetProcessHeap(), 0, printer->queue);
1503 HeapFree(GetProcessHeap(), 0, printer);
1506 return (HANDLE)handle;
1509 /******************************************************************
1510 * get_opened_printer
1511 * Get the pointer to the opened printer referred by the handle
1513 static opened_printer_t *get_opened_printer(HANDLE hprn)
1515 UINT_PTR idx = (UINT_PTR)hprn;
1516 opened_printer_t *ret = NULL;
1518 EnterCriticalSection(&printer_handles_cs);
1520 if ((idx <= 0) || (idx > nb_printer_handles))
1521 goto end;
1523 ret = printer_handles[idx - 1];
1524 end:
1525 LeaveCriticalSection(&printer_handles_cs);
1526 return ret;
1529 /******************************************************************
1530 * get_opened_printer_name
1531 * Get the pointer to the opened printer name referred by the handle
1533 static LPCWSTR get_opened_printer_name(HANDLE hprn)
1535 opened_printer_t *printer = get_opened_printer(hprn);
1536 if(!printer) return NULL;
1537 return printer->name;
1540 /******************************************************************
1541 * WINSPOOL_GetOpenedPrinterRegKey
1544 static DWORD WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter, HKEY *phkey)
1546 LPCWSTR name = get_opened_printer_name(hPrinter);
1547 DWORD ret;
1548 HKEY hkeyPrinters;
1550 if(!name) return ERROR_INVALID_HANDLE;
1552 if((ret = RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters)) !=
1553 ERROR_SUCCESS)
1554 return ret;
1556 if(RegOpenKeyW(hkeyPrinters, name, phkey) != ERROR_SUCCESS)
1558 ERR("Can't find opened printer %s in registry\n",
1559 debugstr_w(name));
1560 RegCloseKey(hkeyPrinters);
1561 return ERROR_INVALID_PRINTER_NAME; /* ? */
1563 RegCloseKey(hkeyPrinters);
1564 return ERROR_SUCCESS;
1567 void WINSPOOL_LoadSystemPrinters(void)
1569 HKEY hkey, hkeyPrinters;
1570 HANDLE hprn;
1571 DWORD needed, num, i;
1572 WCHAR PrinterName[256];
1573 BOOL done = FALSE;
1575 /* This ensures that all printer entries have a valid Name value. If causes
1576 problems later if they don't. If one is found to be missed we create one
1577 and set it equal to the name of the key */
1578 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
1579 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &num, NULL, NULL,
1580 NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
1581 for(i = 0; i < num; i++) {
1582 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) == ERROR_SUCCESS) {
1583 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkey) == ERROR_SUCCESS) {
1584 if(RegQueryValueExW(hkey, NameW, 0, 0, 0, &needed) == ERROR_FILE_NOT_FOUND) {
1585 set_reg_szW(hkey, NameW, PrinterName);
1587 RegCloseKey(hkey);
1592 RegCloseKey(hkeyPrinters);
1595 /* We want to avoid calling AddPrinter on printers as much as
1596 possible, because on cups printers this will (eventually) lead
1597 to a call to cupsGetPPD which takes forever, even with non-cups
1598 printers AddPrinter takes a while. So we'll tag all printers that
1599 were automatically added last time around, if they still exist
1600 we'll leave them be otherwise we'll delete them. */
1601 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1602 if(needed) {
1603 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1604 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1605 for(i = 0; i < num; i++) {
1606 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1607 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1608 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1609 DWORD dw = 1;
1610 RegSetValueExW(hkey, May_Delete_Value, 0, REG_DWORD, (LPBYTE)&dw, sizeof(dw));
1611 RegCloseKey(hkey);
1613 ClosePrinter(hprn);
1618 HeapFree(GetProcessHeap(), 0, pi);
1622 #ifdef HAVE_CUPS_CUPS_H
1623 done = CUPS_LoadPrinters();
1624 #endif
1626 if(!done) /* If we have any CUPS based printers, skip looking for printcap printers */
1627 PRINTCAP_LoadPrinters();
1629 /* Now enumerate the list again and delete any printers that a still tagged */
1630 EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
1631 if(needed) {
1632 PRINTER_INFO_5A* pi = HeapAlloc(GetProcessHeap(), 0, needed);
1633 if(EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, (LPBYTE)pi, needed, &needed, &num)) {
1634 for(i = 0; i < num; i++) {
1635 if(pi[i].pPortName == NULL || !strncmp(pi[i].pPortName,"CUPS:", 5) || !strncmp(pi[i].pPortName, "LPR:", 4)) {
1636 if(OpenPrinterA(pi[i].pPrinterName, &hprn, NULL)) {
1637 BOOL delete_driver = FALSE;
1638 if(WINSPOOL_GetOpenedPrinterRegKey(hprn, &hkey) == ERROR_SUCCESS) {
1639 DWORD dw, type, size = sizeof(dw);
1640 if(RegQueryValueExW(hkey, May_Delete_Value, NULL, &type, (LPBYTE)&dw, &size) == ERROR_SUCCESS) {
1641 TRACE("Deleting old printer %s\n", pi[i].pPrinterName);
1642 DeletePrinter(hprn);
1643 delete_driver = TRUE;
1645 RegCloseKey(hkey);
1647 ClosePrinter(hprn);
1648 if(delete_driver)
1649 DeletePrinterDriverExA(NULL, NULL, pi[i].pPrinterName, 0, 0);
1654 HeapFree(GetProcessHeap(), 0, pi);
1657 return;
1661 /******************************************************************
1662 * get_job
1664 * Get the pointer to the specified job.
1665 * Should hold the printer_handles_cs before calling.
1667 static job_t *get_job(HANDLE hprn, DWORD JobId)
1669 opened_printer_t *printer = get_opened_printer(hprn);
1670 job_t *job;
1672 if(!printer) return NULL;
1673 LIST_FOR_EACH_ENTRY(job, &printer->queue->jobs, job_t, entry)
1675 if(job->job_id == JobId)
1676 return job;
1678 return NULL;
1681 /***********************************************************
1682 * DEVMODEcpyAtoW
1684 static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
1686 BOOL Formname;
1687 ptrdiff_t off_formname = (const char *)dmA->dmFormName - (const char *)dmA;
1688 DWORD size;
1690 Formname = (dmA->dmSize > off_formname);
1691 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
1692 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1,
1693 dmW->dmDeviceName, CCHDEVICENAME);
1694 if(!Formname) {
1695 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1696 dmA->dmSize - CCHDEVICENAME);
1697 } else {
1698 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
1699 off_formname - CCHDEVICENAME);
1700 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1,
1701 dmW->dmFormName, CCHFORMNAME);
1702 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
1703 (off_formname + CCHFORMNAME));
1705 dmW->dmSize = size;
1706 memcpy((char *)dmW + dmW->dmSize, (const char *)dmA + dmA->dmSize,
1707 dmA->dmDriverExtra);
1708 return dmW;
1711 /***********************************************************
1712 * DEVMODEdupWtoA
1713 * Creates an ascii copy of supplied devmode on heap
1715 static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
1717 LPDEVMODEA dmA;
1718 DWORD size;
1719 BOOL Formname;
1720 ptrdiff_t off_formname = (const char *)dmW->dmFormName - (const char *)dmW;
1722 if(!dmW) return NULL;
1723 Formname = (dmW->dmSize > off_formname);
1724 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
1725 dmA = HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
1726 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1,
1727 (LPSTR)dmA->dmDeviceName, CCHDEVICENAME, NULL, NULL);
1728 if(!Formname) {
1729 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1730 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
1731 } else {
1732 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
1733 off_formname - CCHDEVICENAME * sizeof(WCHAR));
1734 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1,
1735 (LPSTR)dmA->dmFormName, CCHFORMNAME, NULL, NULL);
1736 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
1737 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
1739 dmA->dmSize = size;
1740 memcpy((char *)dmA + dmA->dmSize, (const char *)dmW + dmW->dmSize,
1741 dmW->dmDriverExtra);
1742 return dmA;
1745 /***********************************************************
1746 * PRINTER_INFO_2AtoW
1747 * Creates a unicode copy of PRINTER_INFO_2A on heap
1749 static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1751 LPPRINTER_INFO_2W piW;
1752 UNICODE_STRING usBuffer;
1754 if(!piA) return NULL;
1755 piW = HeapAlloc(heap, 0, sizeof(*piW));
1756 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1758 piW->pServerName = asciitounicode(&usBuffer,piA->pServerName);
1759 piW->pPrinterName = asciitounicode(&usBuffer,piA->pPrinterName);
1760 piW->pShareName = asciitounicode(&usBuffer,piA->pShareName);
1761 piW->pPortName = asciitounicode(&usBuffer,piA->pPortName);
1762 piW->pDriverName = asciitounicode(&usBuffer,piA->pDriverName);
1763 piW->pComment = asciitounicode(&usBuffer,piA->pComment);
1764 piW->pLocation = asciitounicode(&usBuffer,piA->pLocation);
1765 piW->pDevMode = piA->pDevMode ? GdiConvertToDevmodeW(piA->pDevMode) : NULL;
1766 piW->pSepFile = asciitounicode(&usBuffer,piA->pSepFile);
1767 piW->pPrintProcessor = asciitounicode(&usBuffer,piA->pPrintProcessor);
1768 piW->pDatatype = asciitounicode(&usBuffer,piA->pDatatype);
1769 piW->pParameters = asciitounicode(&usBuffer,piA->pParameters);
1770 return piW;
1773 /***********************************************************
1774 * FREE_PRINTER_INFO_2W
1775 * Free PRINTER_INFO_2W and all strings
1777 static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1779 if(!piW) return;
1781 HeapFree(heap,0,piW->pServerName);
1782 HeapFree(heap,0,piW->pPrinterName);
1783 HeapFree(heap,0,piW->pShareName);
1784 HeapFree(heap,0,piW->pPortName);
1785 HeapFree(heap,0,piW->pDriverName);
1786 HeapFree(heap,0,piW->pComment);
1787 HeapFree(heap,0,piW->pLocation);
1788 HeapFree(heap,0,piW->pDevMode);
1789 HeapFree(heap,0,piW->pSepFile);
1790 HeapFree(heap,0,piW->pPrintProcessor);
1791 HeapFree(heap,0,piW->pDatatype);
1792 HeapFree(heap,0,piW->pParameters);
1793 HeapFree(heap,0,piW);
1794 return;
1797 /******************************************************************
1798 * DeviceCapabilities [WINSPOOL.@]
1799 * DeviceCapabilitiesA [WINSPOOL.@]
1802 INT WINAPI DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort, WORD cap,
1803 LPSTR pOutput, LPDEVMODEA lpdm)
1805 INT ret;
1807 if (!GDI_CallDeviceCapabilities16)
1809 GDI_CallDeviceCapabilities16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1810 (LPCSTR)104 );
1811 if (!GDI_CallDeviceCapabilities16) return -1;
1813 ret = GDI_CallDeviceCapabilities16(pDevice, pPort, cap, pOutput, lpdm);
1815 /* If DC_PAPERSIZE map POINT16s to POINTs */
1816 if(ret != -1 && cap == DC_PAPERSIZE && pOutput) {
1817 POINT16 *tmp = HeapAlloc( GetProcessHeap(), 0, ret * sizeof(POINT16) );
1818 POINT *pt = (POINT *)pOutput;
1819 INT i;
1820 memcpy(tmp, pOutput, ret * sizeof(POINT16));
1821 for(i = 0; i < ret; i++, pt++)
1823 pt->x = tmp[i].x;
1824 pt->y = tmp[i].y;
1826 HeapFree( GetProcessHeap(), 0, tmp );
1828 return ret;
1832 /*****************************************************************************
1833 * DeviceCapabilitiesW [WINSPOOL.@]
1835 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1838 INT WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
1839 WORD fwCapability, LPWSTR pOutput,
1840 const DEVMODEW *pDevMode)
1842 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
1843 LPSTR pDeviceA = strdupWtoA(pDevice);
1844 LPSTR pPortA = strdupWtoA(pPort);
1845 INT ret;
1847 if(pOutput && (fwCapability == DC_BINNAMES ||
1848 fwCapability == DC_FILEDEPENDENCIES ||
1849 fwCapability == DC_PAPERNAMES)) {
1850 /* These need A -> W translation */
1851 INT size = 0, i;
1852 LPSTR pOutputA;
1853 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
1854 dmA);
1855 if(ret == -1)
1856 return ret;
1857 switch(fwCapability) {
1858 case DC_BINNAMES:
1859 size = 24;
1860 break;
1861 case DC_PAPERNAMES:
1862 case DC_FILEDEPENDENCIES:
1863 size = 64;
1864 break;
1866 pOutputA = HeapAlloc(GetProcessHeap(), 0, size * ret);
1867 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
1868 dmA);
1869 for(i = 0; i < ret; i++)
1870 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
1871 pOutput + (i * size), size);
1872 HeapFree(GetProcessHeap(), 0, pOutputA);
1873 } else {
1874 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
1875 (LPSTR)pOutput, dmA);
1877 HeapFree(GetProcessHeap(),0,pPortA);
1878 HeapFree(GetProcessHeap(),0,pDeviceA);
1879 HeapFree(GetProcessHeap(),0,dmA);
1880 return ret;
1883 /******************************************************************
1884 * DocumentPropertiesA [WINSPOOL.@]
1886 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1888 LONG WINAPI DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,
1889 LPSTR pDeviceName, LPDEVMODEA pDevModeOutput,
1890 LPDEVMODEA pDevModeInput,DWORD fMode )
1892 LPSTR lpName = pDeviceName;
1893 static CHAR port[] = "LPT1:";
1894 LONG ret;
1896 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1897 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1900 if(!pDeviceName) {
1901 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
1902 if(!lpNameW) {
1903 ERR("no name from hPrinter?\n");
1904 SetLastError(ERROR_INVALID_HANDLE);
1905 return -1;
1907 lpName = strdupWtoA(lpNameW);
1910 if (!GDI_CallExtDeviceMode16)
1912 GDI_CallExtDeviceMode16 = (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1913 (LPCSTR)102 );
1914 if (!GDI_CallExtDeviceMode16) {
1915 ERR("No CallExtDeviceMode16?\n");
1916 return -1;
1919 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, port,
1920 pDevModeInput, NULL, fMode);
1922 if(!pDeviceName)
1923 HeapFree(GetProcessHeap(),0,lpName);
1924 return ret;
1928 /*****************************************************************************
1929 * DocumentPropertiesW (WINSPOOL.@)
1931 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1933 LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter,
1934 LPWSTR pDeviceName,
1935 LPDEVMODEW pDevModeOutput,
1936 LPDEVMODEW pDevModeInput, DWORD fMode)
1939 LPSTR pDeviceNameA = strdupWtoA(pDeviceName);
1940 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
1941 LPDEVMODEA pDevModeOutputA = NULL;
1942 LONG ret;
1944 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1945 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
1946 fMode);
1947 if(pDevModeOutput) {
1948 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
1949 if(ret < 0) return ret;
1950 pDevModeOutputA = HeapAlloc(GetProcessHeap(), 0, ret);
1952 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
1953 pDevModeInputA, fMode);
1954 if(pDevModeOutput) {
1955 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
1956 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
1958 if(fMode == 0 && ret > 0)
1959 ret += (CCHDEVICENAME + CCHFORMNAME);
1960 HeapFree(GetProcessHeap(),0,pDevModeInputA);
1961 HeapFree(GetProcessHeap(),0,pDeviceNameA);
1962 return ret;
1965 /******************************************************************
1966 * OpenPrinterA [WINSPOOL.@]
1968 * See OpenPrinterW.
1971 BOOL WINAPI OpenPrinterA(LPSTR lpPrinterName,HANDLE *phPrinter,
1972 LPPRINTER_DEFAULTSA pDefault)
1974 UNICODE_STRING lpPrinterNameW;
1975 UNICODE_STRING usBuffer;
1976 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1977 PWSTR pwstrPrinterNameW;
1978 BOOL ret;
1980 pwstrPrinterNameW = asciitounicode(&lpPrinterNameW,lpPrinterName);
1982 if(pDefault) {
1983 DefaultW.pDatatype = asciitounicode(&usBuffer,pDefault->pDatatype);
1984 DefaultW.pDevMode = pDefault->pDevMode ? GdiConvertToDevmodeW(pDefault->pDevMode) : NULL;
1985 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1986 pDefaultW = &DefaultW;
1988 ret = OpenPrinterW(pwstrPrinterNameW, phPrinter, pDefaultW);
1989 if(pDefault) {
1990 RtlFreeUnicodeString(&usBuffer);
1991 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1993 RtlFreeUnicodeString(&lpPrinterNameW);
1994 return ret;
1997 /******************************************************************
1998 * OpenPrinterW [WINSPOOL.@]
2000 * Open a Printer / Printserver or a Printer-Object
2002 * PARAMS
2003 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2004 * phPrinter [O] The resulting Handle is stored here
2005 * pDefault [I] PTR to Default Printer Settings or NULL
2007 * RETURNS
2008 * Success: TRUE
2009 * Failure: FALSE
2011 * NOTES
2012 * lpPrinterName is one of:
2013 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2014 *| Printer: "PrinterName"
2015 *| Printer-Object: "PrinterName,Job xxx"
2016 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2017 *| XcvPort: "Servername,XcvPort PortName"
2019 * BUGS
2020 *| Printer-Object not supported
2021 *| pDefaults is ignored
2024 BOOL WINAPI OpenPrinterW(LPWSTR lpPrinterName,HANDLE *phPrinter, LPPRINTER_DEFAULTSW pDefault)
2027 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), phPrinter, pDefault);
2028 if (pDefault) {
2029 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2030 debugstr_w(pDefault->pDatatype), pDefault->pDevMode, pDefault->DesiredAccess);
2033 if(!phPrinter) {
2034 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2035 SetLastError(ERROR_INVALID_PARAMETER);
2036 return FALSE;
2039 /* Get the unique handle of the printer or Printserver */
2040 *phPrinter = get_opened_printer_entry(lpPrinterName, pDefault);
2041 TRACE("returning %d with %u and %p\n", *phPrinter != NULL, GetLastError(), *phPrinter);
2042 return (*phPrinter != 0);
2045 /******************************************************************
2046 * AddMonitorA [WINSPOOL.@]
2048 * See AddMonitorW.
2051 BOOL WINAPI AddMonitorA(LPSTR pName, DWORD Level, LPBYTE pMonitors)
2053 LPWSTR nameW = NULL;
2054 INT len;
2055 BOOL res;
2056 LPMONITOR_INFO_2A mi2a;
2057 MONITOR_INFO_2W mi2w;
2059 mi2a = (LPMONITOR_INFO_2A) pMonitors;
2060 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName), Level, pMonitors,
2061 mi2a ? debugstr_a(mi2a->pName) : NULL,
2062 mi2a ? debugstr_a(mi2a->pEnvironment) : NULL,
2063 mi2a ? debugstr_a(mi2a->pDLLName) : NULL);
2065 if (Level != 2) {
2066 SetLastError(ERROR_INVALID_LEVEL);
2067 return FALSE;
2070 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2071 if (mi2a == NULL) {
2072 return FALSE;
2075 if (pName) {
2076 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2077 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2078 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2081 memset(&mi2w, 0, sizeof(MONITOR_INFO_2W));
2082 if (mi2a->pName) {
2083 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, NULL, 0);
2084 mi2w.pName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2085 MultiByteToWideChar(CP_ACP, 0, mi2a->pName, -1, mi2w.pName, len);
2087 if (mi2a->pEnvironment) {
2088 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, NULL, 0);
2089 mi2w.pEnvironment = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2090 MultiByteToWideChar(CP_ACP, 0, mi2a->pEnvironment, -1, mi2w.pEnvironment, len);
2092 if (mi2a->pDLLName) {
2093 len = MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, NULL, 0);
2094 mi2w.pDLLName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2095 MultiByteToWideChar(CP_ACP, 0, mi2a->pDLLName, -1, mi2w.pDLLName, len);
2098 res = AddMonitorW(nameW, Level, (LPBYTE) &mi2w);
2100 HeapFree(GetProcessHeap(), 0, mi2w.pName);
2101 HeapFree(GetProcessHeap(), 0, mi2w.pEnvironment);
2102 HeapFree(GetProcessHeap(), 0, mi2w.pDLLName);
2104 HeapFree(GetProcessHeap(), 0, nameW);
2105 return (res);
2108 /******************************************************************************
2109 * AddMonitorW [WINSPOOL.@]
2111 * Install a Printmonitor
2113 * PARAMS
2114 * pName [I] Servername or NULL (local Computer)
2115 * Level [I] Structure-Level (Must be 2)
2116 * pMonitors [I] PTR to MONITOR_INFO_2
2118 * RETURNS
2119 * Success: TRUE
2120 * Failure: FALSE
2122 * NOTES
2123 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2126 BOOL WINAPI AddMonitorW(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
2128 monitor_t * pm = NULL;
2129 LPMONITOR_INFO_2W mi2w;
2130 HKEY hroot = NULL;
2131 HKEY hentry = NULL;
2132 DWORD disposition;
2133 BOOL res = FALSE;
2135 mi2w = (LPMONITOR_INFO_2W) pMonitors;
2136 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName), Level, pMonitors,
2137 mi2w ? debugstr_w(mi2w->pName) : NULL,
2138 mi2w ? debugstr_w(mi2w->pEnvironment) : NULL,
2139 mi2w ? debugstr_w(mi2w->pDLLName) : NULL);
2141 if (Level != 2) {
2142 SetLastError(ERROR_INVALID_LEVEL);
2143 return FALSE;
2146 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2147 if (mi2w == NULL) {
2148 return FALSE;
2151 if (pName && (pName[0])) {
2152 FIXME("for server %s not implemented\n", debugstr_w(pName));
2153 SetLastError(ERROR_ACCESS_DENIED);
2154 return FALSE;
2158 if (!mi2w->pName || (! mi2w->pName[0])) {
2159 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
2160 SetLastError(ERROR_INVALID_PARAMETER);
2161 return FALSE;
2163 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, envname_x86W)) {
2164 WARN("Environment %s requested (we support only %s)\n",
2165 debugstr_w(mi2w->pEnvironment), debugstr_w(envname_x86W));
2166 SetLastError(ERROR_INVALID_ENVIRONMENT);
2167 return FALSE;
2170 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
2171 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
2172 SetLastError(ERROR_INVALID_PARAMETER);
2173 return FALSE;
2176 /* Load and initialize the monitor. SetLastError() is called on failure */
2177 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
2178 return FALSE;
2180 monitor_unload(pm);
2182 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2183 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2184 return FALSE;
2187 if(RegCreateKeyExW( hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
2188 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
2189 &disposition) == ERROR_SUCCESS) {
2191 /* Some installers set options for the port before calling AddMonitor.
2192 We query the "Driver" entry to verify that the monitor is installed,
2193 before we return an error.
2194 When a user installs two print monitors at the same time with the
2195 same name but with a different driver DLL and a task switch comes
2196 between RegQueryValueExW and RegSetValueExW, a race condition
2197 is possible but silently ignored. */
2199 DWORD namesize = 0;
2201 if ((disposition == REG_OPENED_EXISTING_KEY) &&
2202 (RegQueryValueExW(hentry, DriverW, NULL, NULL, NULL,
2203 &namesize) == ERROR_SUCCESS)) {
2204 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
2205 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2206 9x: ERROR_ALREADY_EXISTS (183) */
2207 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
2209 else
2211 INT len;
2212 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
2213 res = (RegSetValueExW(hentry, DriverW, 0,
2214 REG_SZ, (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
2216 RegCloseKey(hentry);
2219 RegCloseKey(hroot);
2220 return (res);
2223 /******************************************************************
2224 * DeletePrinterDriverA [WINSPOOL.@]
2227 BOOL WINAPI DeletePrinterDriverA (LPSTR pName, LPSTR pEnvironment, LPSTR pDriverName)
2229 return DeletePrinterDriverExA(pName, pEnvironment, pDriverName, 0, 0);
2232 /******************************************************************
2233 * DeletePrinterDriverW [WINSPOOL.@]
2236 BOOL WINAPI DeletePrinterDriverW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pDriverName)
2238 return DeletePrinterDriverExW(pName, pEnvironment, pDriverName, 0, 0);
2241 /******************************************************************
2242 * DeleteMonitorA [WINSPOOL.@]
2244 * See DeleteMonitorW.
2247 BOOL WINAPI DeleteMonitorA (LPSTR pName, LPSTR pEnvironment, LPSTR pMonitorName)
2249 LPWSTR nameW = NULL;
2250 LPWSTR EnvironmentW = NULL;
2251 LPWSTR MonitorNameW = NULL;
2252 BOOL res;
2253 INT len;
2255 if (pName) {
2256 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2257 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2258 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2261 if (pEnvironment) {
2262 len = MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, NULL, 0);
2263 EnvironmentW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2264 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, EnvironmentW, len);
2266 if (pMonitorName) {
2267 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
2268 MonitorNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2269 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, MonitorNameW, len);
2272 res = DeleteMonitorW(nameW, EnvironmentW, MonitorNameW);
2274 HeapFree(GetProcessHeap(), 0, MonitorNameW);
2275 HeapFree(GetProcessHeap(), 0, EnvironmentW);
2276 HeapFree(GetProcessHeap(), 0, nameW);
2277 return (res);
2280 /******************************************************************
2281 * DeleteMonitorW [WINSPOOL.@]
2283 * Delete a specific Printmonitor from a Printing-Environment
2285 * PARAMS
2286 * pName [I] Servername or NULL (local Computer)
2287 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2288 * pMonitorName [I] Name of the Monitor, that should be deleted
2290 * RETURNS
2291 * Success: TRUE
2292 * Failure: FALSE
2294 * NOTES
2295 * pEnvironment is ignored in Windows for the local Computer.
2299 BOOL WINAPI DeleteMonitorW (LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
2301 HKEY hroot = NULL;
2303 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
2304 debugstr_w(pMonitorName));
2306 if (pName && (pName[0])) {
2307 FIXME("for server %s not implemented\n", debugstr_w(pName));
2308 SetLastError(ERROR_ACCESS_DENIED);
2309 return FALSE;
2312 /* pEnvironment is ignored in Windows for the local Computer */
2314 if (!pMonitorName || !pMonitorName[0]) {
2315 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
2316 SetLastError(ERROR_INVALID_PARAMETER);
2317 return FALSE;
2320 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hroot) != ERROR_SUCCESS) {
2321 ERR("unable to create key %s\n", debugstr_w(MonitorsW));
2322 return FALSE;
2325 /* change this, when advapi32.dll/RegDeleteTree is implemented */
2326 if(WINSPOOL_SHDeleteKeyW(hroot, pMonitorName) == ERROR_SUCCESS) {
2327 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName));
2328 RegCloseKey(hroot);
2329 return TRUE;
2332 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName));
2333 RegCloseKey(hroot);
2335 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2336 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
2337 return (FALSE);
2340 /******************************************************************
2341 * DeletePortA [WINSPOOL.@]
2343 * See DeletePortW.
2346 BOOL WINAPI DeletePortA (LPSTR pName, HWND hWnd, LPSTR pPortName)
2348 LPWSTR nameW = NULL;
2349 LPWSTR portW = NULL;
2350 INT len;
2351 DWORD res;
2353 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
2355 /* convert servername to unicode */
2356 if (pName) {
2357 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
2358 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2359 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
2362 /* convert portname to unicode */
2363 if (pPortName) {
2364 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
2365 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2366 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
2369 res = DeletePortW(nameW, hWnd, portW);
2370 HeapFree(GetProcessHeap(), 0, nameW);
2371 HeapFree(GetProcessHeap(), 0, portW);
2372 return res;
2375 /******************************************************************
2376 * DeletePortW [WINSPOOL.@]
2378 * Delete a specific Port
2380 * PARAMS
2381 * pName [I] Servername or NULL (local Computer)
2382 * hWnd [I] Handle to parent Window for the Dialog-Box
2383 * pPortName [I] Name of the Port, that should be deleted
2385 * RETURNS
2386 * Success: TRUE
2387 * Failure: FALSE
2390 BOOL WINAPI DeletePortW (LPWSTR pName, HWND hWnd, LPWSTR pPortName)
2392 monitor_t * pm;
2393 monitor_t * pui;
2394 DWORD res;
2396 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
2398 if (pName && pName[0]) {
2399 SetLastError(ERROR_INVALID_PARAMETER);
2400 return FALSE;
2403 if (!pPortName) {
2404 SetLastError(RPC_X_NULL_REF_POINTER);
2405 return FALSE;
2408 /* an empty Portname is Invalid */
2409 if (!pPortName[0]) {
2410 SetLastError(ERROR_NOT_SUPPORTED);
2411 return FALSE;
2414 pm = monitor_load_by_port(pPortName);
2415 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
2416 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
2417 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
2418 TRACE("got %d with %u\n", res, GetLastError());
2420 else
2422 pui = monitor_loadui(pm);
2423 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
2424 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
2425 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
2426 TRACE("got %d with %u\n", res, GetLastError());
2428 else
2430 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
2431 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
2433 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2434 SetLastError(ERROR_NOT_SUPPORTED);
2435 res = FALSE;
2437 monitor_unload(pui);
2439 monitor_unload(pm);
2441 TRACE("returning %d with %u\n", res, GetLastError());
2442 return res;
2445 /******************************************************************************
2446 * SetPrinterW [WINSPOOL.@]
2448 BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD Command)
2450 FIXME("(%p, %d, %p, %d): stub\n", hPrinter, Level, pPrinter, Command);
2451 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2452 return FALSE;
2455 /******************************************************************************
2456 * WritePrinter [WINSPOOL.@]
2458 BOOL WINAPI WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2460 opened_printer_t *printer;
2461 BOOL ret = FALSE;
2463 TRACE("(%p, %p, %d, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
2465 EnterCriticalSection(&printer_handles_cs);
2466 printer = get_opened_printer(hPrinter);
2467 if(!printer)
2469 SetLastError(ERROR_INVALID_HANDLE);
2470 goto end;
2473 if(!printer->doc)
2475 SetLastError(ERROR_SPL_NO_STARTDOC);
2476 goto end;
2479 ret = WriteFile(printer->doc->hf, pBuf, cbBuf, pcWritten, NULL);
2480 end:
2481 LeaveCriticalSection(&printer_handles_cs);
2482 return ret;
2485 /*****************************************************************************
2486 * AddFormA [WINSPOOL.@]
2488 BOOL WINAPI AddFormA(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2490 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2491 return 1;
2494 /*****************************************************************************
2495 * AddFormW [WINSPOOL.@]
2497 BOOL WINAPI AddFormW(HANDLE hPrinter, DWORD Level, LPBYTE pForm)
2499 FIXME("(%p,%d,%p): stub\n", hPrinter, Level, pForm);
2500 return 1;
2503 /*****************************************************************************
2504 * AddJobA [WINSPOOL.@]
2506 BOOL WINAPI AddJobA(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2508 BOOL ret;
2509 BYTE buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
2510 DWORD needed;
2512 if(Level != 1) {
2513 SetLastError(ERROR_INVALID_LEVEL);
2514 return FALSE;
2517 ret = AddJobW(hPrinter, Level, buf, sizeof(buf), &needed);
2519 if(ret) {
2520 ADDJOB_INFO_1W *addjobW = (ADDJOB_INFO_1W*)buf;
2521 DWORD len = WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, NULL, 0, NULL, NULL);
2522 *pcbNeeded = len + sizeof(ADDJOB_INFO_1A);
2523 if(*pcbNeeded > cbBuf) {
2524 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2525 ret = FALSE;
2526 } else {
2527 ADDJOB_INFO_1A *addjobA = (ADDJOB_INFO_1A*)pData;
2528 addjobA->JobId = addjobW->JobId;
2529 addjobA->Path = (char *)(addjobA + 1);
2530 WideCharToMultiByte(CP_ACP, 0, addjobW->Path, -1, addjobA->Path, len, NULL, NULL);
2533 return ret;
2536 /*****************************************************************************
2537 * AddJobW [WINSPOOL.@]
2539 BOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
2541 opened_printer_t *printer;
2542 job_t *job;
2543 BOOL ret = FALSE;
2544 static const WCHAR spool_path[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2545 static const WCHAR fmtW[] = {'%','s','%','0','5','d','.','S','P','L',0};
2546 WCHAR path[MAX_PATH], filename[MAX_PATH];
2547 DWORD len;
2548 ADDJOB_INFO_1W *addjob;
2550 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
2552 EnterCriticalSection(&printer_handles_cs);
2554 printer = get_opened_printer(hPrinter);
2556 if(!printer) {
2557 SetLastError(ERROR_INVALID_HANDLE);
2558 goto end;
2561 if(Level != 1) {
2562 SetLastError(ERROR_INVALID_LEVEL);
2563 goto end;
2566 job = HeapAlloc(GetProcessHeap(), 0, sizeof(*job));
2567 if(!job)
2568 goto end;
2570 job->job_id = InterlockedIncrement(&next_job_id);
2572 len = GetSystemDirectoryW(path, sizeof(path) / sizeof(WCHAR));
2573 if(path[len - 1] != '\\')
2574 path[len++] = '\\';
2575 memcpy(path + len, spool_path, sizeof(spool_path));
2576 sprintfW(filename, fmtW, path, job->job_id);
2578 len = strlenW(filename);
2579 job->filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
2580 memcpy(job->filename, filename, (len + 1) * sizeof(WCHAR));
2581 job->document_title = strdupW(default_doc_title);
2582 list_add_tail(&printer->queue->jobs, &job->entry);
2584 *pcbNeeded = (len + 1) * sizeof(WCHAR) + sizeof(*addjob);
2585 if(*pcbNeeded <= cbBuf) {
2586 addjob = (ADDJOB_INFO_1W*)pData;
2587 addjob->JobId = job->job_id;
2588 addjob->Path = (WCHAR *)(addjob + 1);
2589 memcpy(addjob->Path, filename, (len + 1) * sizeof(WCHAR));
2590 ret = TRUE;
2591 } else
2592 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2594 end:
2595 LeaveCriticalSection(&printer_handles_cs);
2596 return ret;
2599 /*****************************************************************************
2600 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2602 * Return the PATH for the Print-Processors
2604 * See GetPrintProcessorDirectoryW.
2608 BOOL WINAPI GetPrintProcessorDirectoryA(LPSTR server, LPSTR env,
2609 DWORD level, LPBYTE Info,
2610 DWORD cbBuf, LPDWORD pcbNeeded)
2612 LPWSTR serverW = NULL;
2613 LPWSTR envW = NULL;
2614 BOOL ret;
2615 INT len;
2617 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server),
2618 debugstr_a(env), level, Info, cbBuf, pcbNeeded);
2621 if (server) {
2622 len = MultiByteToWideChar(CP_ACP, 0, server, -1, NULL, 0);
2623 serverW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2624 MultiByteToWideChar(CP_ACP, 0, server, -1, serverW, len);
2627 if (env) {
2628 len = MultiByteToWideChar(CP_ACP, 0, env, -1, NULL, 0);
2629 envW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2630 MultiByteToWideChar(CP_ACP, 0, env, -1, envW, len);
2633 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2634 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2636 ret = GetPrintProcessorDirectoryW(serverW, envW, level, Info,
2637 cbBuf, pcbNeeded);
2639 if (ret) ret = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)Info, -1, (LPSTR)Info,
2640 cbBuf, NULL, NULL) > 0;
2643 TRACE(" required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
2644 HeapFree(GetProcessHeap(), 0, envW);
2645 HeapFree(GetProcessHeap(), 0, serverW);
2646 return ret;
2649 /*****************************************************************************
2650 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2652 * Return the PATH for the Print-Processors
2654 * PARAMS
2655 * server [I] Servername (NT only) or NULL (local Computer)
2656 * env [I] Printing-Environment (see below) or NULL (Default)
2657 * level [I] Structure-Level (must be 1)
2658 * Info [O] PTR to Buffer that receives the Result
2659 * cbBuf [I] Size of Buffer at "Info"
2660 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2661 * required for the Buffer at "Info"
2663 * RETURNS
2664 * Success: TRUE and in pcbNeeded the Bytes used in Info
2665 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2666 * if cbBuf is too small
2668 * Native Values returned in Info on Success:
2669 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2670 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2671 *| win9x(Windows 4.0): "%winsysdir%"
2673 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2675 * BUGS
2676 * Only NULL or "" is supported for server
2679 BOOL WINAPI GetPrintProcessorDirectoryW(LPWSTR server, LPWSTR env,
2680 DWORD level, LPBYTE Info,
2681 DWORD cbBuf, LPDWORD pcbNeeded)
2683 DWORD needed;
2684 const printenv_t * env_t;
2686 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server),
2687 debugstr_w(env), level, Info, cbBuf, pcbNeeded);
2689 if(server != NULL && server[0]) {
2690 FIXME("server not supported: %s\n", debugstr_w(server));
2691 SetLastError(ERROR_INVALID_PARAMETER);
2692 return FALSE;
2695 env_t = validate_envW(env);
2696 if(!env_t) return FALSE; /* environment invalid or unsupported */
2698 if(level != 1) {
2699 WARN("(Level: %d) is ignored in win9x\n", level);
2700 SetLastError(ERROR_INVALID_LEVEL);
2701 return FALSE;
2704 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2705 needed = GetSystemDirectoryW(NULL, 0);
2706 /* add the Size for the Subdirectories */
2707 needed += lstrlenW(spoolprtprocsW);
2708 needed += lstrlenW(env_t->subdir);
2709 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2711 if(pcbNeeded) *pcbNeeded = needed;
2712 TRACE ("required: 0x%x/%d\n", needed, needed);
2713 if (needed > cbBuf) {
2714 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2715 return FALSE;
2717 if(pcbNeeded == NULL) {
2718 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2719 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2720 SetLastError(RPC_X_NULL_REF_POINTER);
2721 return FALSE;
2723 if(Info == NULL) {
2724 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2725 SetLastError(RPC_X_NULL_REF_POINTER);
2726 return FALSE;
2729 GetSystemDirectoryW((LPWSTR) Info, cbBuf/sizeof(WCHAR));
2730 /* add the Subdirectories */
2731 lstrcatW((LPWSTR) Info, spoolprtprocsW);
2732 lstrcatW((LPWSTR) Info, env_t->subdir);
2733 TRACE(" => %s\n", debugstr_w((LPWSTR) Info));
2734 return TRUE;
2737 /*****************************************************************************
2738 * WINSPOOL_OpenDriverReg [internal]
2740 * opens the registry for the printer drivers depending on the given input
2741 * variable pEnvironment
2743 * RETURNS:
2744 * the opened hkey on success
2745 * NULL on error
2747 static HKEY WINSPOOL_OpenDriverReg( LPCVOID pEnvironment, BOOL unicode)
2749 HKEY retval = NULL;
2750 LPWSTR buffer;
2751 const printenv_t * env;
2753 TRACE("(%s, %d)\n",
2754 (unicode) ? debugstr_w(pEnvironment) : debugstr_a(pEnvironment), unicode);
2756 if (!pEnvironment || unicode) {
2757 /* pEnvironment was NULL or an Unicode-String: use it direct */
2758 env = validate_envW(pEnvironment);
2760 else
2762 /* pEnvironment was an ANSI-String: convert to unicode first */
2763 LPWSTR buffer;
2764 INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, NULL, 0);
2765 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
2766 if (buffer) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pEnvironment, -1, buffer, len);
2767 env = validate_envW(buffer);
2768 HeapFree(GetProcessHeap(), 0, buffer);
2770 if (!env) return NULL;
2772 buffer = HeapAlloc( GetProcessHeap(), 0,
2773 (strlenW(DriversW) + strlenW(env->envname) +
2774 strlenW(env->versionregpath) + 1) * sizeof(WCHAR));
2775 if(buffer) {
2776 wsprintfW(buffer, DriversW, env->envname, env->versionregpath);
2777 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
2778 HeapFree(GetProcessHeap(), 0, buffer);
2780 return retval;
2783 /*****************************************************************************
2784 * AddPrinterW [WINSPOOL.@]
2786 HANDLE WINAPI AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
2788 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
2789 LPDEVMODEA dmA;
2790 LPDEVMODEW dmW;
2791 HANDLE retval;
2792 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
2793 LONG size;
2794 static const WCHAR attributesW[] = {'A','t','t','r','i','b','u','t','e','s',0},
2795 default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2796 priorityW[] = {'P','r','i','o','r','i','t','y',0},
2797 start_timeW[] = {'S','t','a','r','t','T','i','m','e',0},
2798 statusW[] = {'S','t','a','t','u','s',0},
2799 until_timeW[] = {'U','n','t','i','l','T','i','m','e',0};
2801 TRACE("(%s,%d,%p)\n", debugstr_w(pName), Level, pPrinter);
2803 if(pName != NULL) {
2804 ERR("pName = %s - unsupported\n", debugstr_w(pName));
2805 SetLastError(ERROR_INVALID_PARAMETER);
2806 return 0;
2808 if(Level != 2) {
2809 ERR("Level = %d, unsupported!\n", Level);
2810 SetLastError(ERROR_INVALID_LEVEL);
2811 return 0;
2813 if(!pPrinter) {
2814 SetLastError(ERROR_INVALID_PARAMETER);
2815 return 0;
2817 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
2818 ERROR_SUCCESS) {
2819 ERR("Can't create Printers key\n");
2820 return 0;
2822 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2823 if (!RegQueryValueW(hkeyPrinter, attributesW, NULL, NULL)) {
2824 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2825 RegCloseKey(hkeyPrinter);
2826 RegCloseKey(hkeyPrinters);
2827 return 0;
2829 RegCloseKey(hkeyPrinter);
2831 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2832 if(!hkeyDrivers) {
2833 ERR("Can't create Drivers key\n");
2834 RegCloseKey(hkeyPrinters);
2835 return 0;
2837 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2838 ERROR_SUCCESS) {
2839 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2840 RegCloseKey(hkeyPrinters);
2841 RegCloseKey(hkeyDrivers);
2842 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2843 return 0;
2845 RegCloseKey(hkeyDriver);
2846 RegCloseKey(hkeyDrivers);
2848 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2849 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2850 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2851 RegCloseKey(hkeyPrinters);
2852 return 0;
2855 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2856 ERROR_SUCCESS) {
2857 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2858 SetLastError(ERROR_INVALID_PRINTER_NAME);
2859 RegCloseKey(hkeyPrinters);
2860 return 0;
2862 RegSetValueExW(hkeyPrinter, attributesW, 0, REG_DWORD,
2863 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2864 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2866 /* See if we can load the driver. We may need the devmode structure anyway
2868 * FIXME:
2869 * Note that DocumentPropertiesW will briefly try to open the printer we
2870 * just create to find a DEVMODEA struct (it will use the WINEPS default
2871 * one in case it is not there, so we are ok).
2873 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2875 if(size < 0) {
2876 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi->pPrinterName));
2877 size = sizeof(DEVMODEW);
2879 if(pi->pDevMode)
2880 dmW = pi->pDevMode;
2881 else
2883 dmW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
2884 dmW->dmSize = size;
2885 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER))
2887 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi->pPrinterName));
2888 HeapFree(GetProcessHeap(),0,dmW);
2889 dmW=NULL;
2891 else
2893 /* set devmode to printer name */
2894 lstrcpynW(dmW->dmDeviceName, pi->pPrinterName, CCHDEVICENAME);
2898 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2899 and we support these drivers. NT writes DEVMODEW so somehow
2900 we'll need to distinguish between these when we support NT
2901 drivers */
2902 if (dmW)
2904 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2905 RegSetValueExW(hkeyPrinter, default_devmodeW, 0, REG_BINARY,
2906 (LPBYTE)dmA, dmA->dmSize + dmA->dmDriverExtra);
2907 HeapFree(GetProcessHeap(), 0, dmA);
2908 if(!pi->pDevMode)
2909 HeapFree(GetProcessHeap(), 0, dmW);
2911 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2912 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2913 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2914 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2916 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2917 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2918 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2919 RegSetValueExW(hkeyPrinter, priorityW, 0, REG_DWORD,
2920 (LPBYTE)&pi->Priority, sizeof(DWORD));
2921 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2922 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2923 RegSetValueExW(hkeyPrinter, start_timeW, 0, REG_DWORD,
2924 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2925 RegSetValueExW(hkeyPrinter, statusW, 0, REG_DWORD,
2926 (LPBYTE)&pi->Status, sizeof(DWORD));
2927 RegSetValueExW(hkeyPrinter, until_timeW, 0, REG_DWORD,
2928 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2930 RegCloseKey(hkeyPrinter);
2931 RegCloseKey(hkeyPrinters);
2932 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2933 ERR("OpenPrinter failing\n");
2934 return 0;
2936 return retval;
2939 /*****************************************************************************
2940 * AddPrinterA [WINSPOOL.@]
2942 HANDLE WINAPI AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
2944 UNICODE_STRING pNameW;
2945 PWSTR pwstrNameW;
2946 PRINTER_INFO_2W *piW;
2947 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
2948 HANDLE ret;
2950 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName), Level, pPrinter);
2951 if(Level != 2) {
2952 ERR("Level = %d, unsupported!\n", Level);
2953 SetLastError(ERROR_INVALID_LEVEL);
2954 return 0;
2956 pwstrNameW = asciitounicode(&pNameW,pName);
2957 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
2959 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)piW);
2961 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
2962 RtlFreeUnicodeString(&pNameW);
2963 return ret;
2967 /*****************************************************************************
2968 * ClosePrinter [WINSPOOL.@]
2970 BOOL WINAPI ClosePrinter(HANDLE hPrinter)
2972 UINT_PTR i = (UINT_PTR)hPrinter;
2973 opened_printer_t *printer = NULL;
2974 BOOL ret = FALSE;
2976 TRACE("(%p)\n", hPrinter);
2978 EnterCriticalSection(&printer_handles_cs);
2980 if ((i > 0) && (i <= nb_printer_handles))
2981 printer = printer_handles[i - 1];
2984 if(printer)
2986 struct list *cursor, *cursor2;
2988 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer->pm,
2989 debugstr_w(printer->pm ? printer->pm->dllname : NULL),
2990 printer->hXcv, debugstr_w(printer->name), printer->doc );
2992 if(printer->doc)
2993 EndDocPrinter(hPrinter);
2995 if(InterlockedDecrement(&printer->queue->ref) == 0)
2997 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
2999 job_t *job = LIST_ENTRY(cursor, job_t, entry);
3000 ScheduleJob(hPrinter, job->job_id);
3002 HeapFree(GetProcessHeap(), 0, printer->queue);
3004 if (printer->hXcv) printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
3005 monitor_unload(printer->pm);
3006 HeapFree(GetProcessHeap(), 0, printer->printername);
3007 HeapFree(GetProcessHeap(), 0, printer->name);
3008 HeapFree(GetProcessHeap(), 0, printer);
3009 printer_handles[i - 1] = NULL;
3010 ret = TRUE;
3012 LeaveCriticalSection(&printer_handles_cs);
3013 return ret;
3016 /*****************************************************************************
3017 * DeleteFormA [WINSPOOL.@]
3019 BOOL WINAPI DeleteFormA(HANDLE hPrinter, LPSTR pFormName)
3021 FIXME("(%p,%s): stub\n", hPrinter, pFormName);
3022 return 1;
3025 /*****************************************************************************
3026 * DeleteFormW [WINSPOOL.@]
3028 BOOL WINAPI DeleteFormW(HANDLE hPrinter, LPWSTR pFormName)
3030 FIXME("(%p,%s): stub\n", hPrinter, debugstr_w(pFormName));
3031 return 1;
3034 /*****************************************************************************
3035 * DeletePrinter [WINSPOOL.@]
3037 BOOL WINAPI DeletePrinter(HANDLE hPrinter)
3039 LPCWSTR lpNameW = get_opened_printer_name(hPrinter);
3040 HKEY hkeyPrinters, hkey;
3042 if(!lpNameW) {
3043 SetLastError(ERROR_INVALID_HANDLE);
3044 return FALSE;
3046 if(RegOpenKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) == ERROR_SUCCESS) {
3047 WINSPOOL_SHDeleteKeyW(hkeyPrinters, lpNameW);
3048 RegCloseKey(hkeyPrinters);
3050 WriteProfileStringW(devicesW, lpNameW, NULL);
3051 if(RegCreateKeyW(HKEY_CURRENT_USER, user_printers_reg_key, &hkey) == ERROR_SUCCESS) {
3052 RegDeleteValueW(hkey, lpNameW);
3053 RegCloseKey(hkey);
3055 return TRUE;
3058 /*****************************************************************************
3059 * SetPrinterA [WINSPOOL.@]
3061 BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3062 DWORD Command)
3064 FIXME("(%p,%d,%p,%d): stub\n",hPrinter,Level,pPrinter,Command);
3065 return FALSE;
3068 /*****************************************************************************
3069 * SetJobA [WINSPOOL.@]
3071 BOOL WINAPI SetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level,
3072 LPBYTE pJob, DWORD Command)
3074 BOOL ret;
3075 LPBYTE JobW;
3076 UNICODE_STRING usBuffer;
3078 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter, JobId, Level, pJob, Command);
3080 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3081 are all ignored by SetJob, so we don't bother copying them */
3082 switch(Level)
3084 case 0:
3085 JobW = NULL;
3086 break;
3087 case 1:
3089 JOB_INFO_1W *info1W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W));
3090 JOB_INFO_1A *info1A = (JOB_INFO_1A*)pJob;
3092 JobW = (LPBYTE)info1W;
3093 info1W->pUserName = asciitounicode(&usBuffer, info1A->pUserName);
3094 info1W->pDocument = asciitounicode(&usBuffer, info1A->pDocument);
3095 info1W->pDatatype = asciitounicode(&usBuffer, info1A->pDatatype);
3096 info1W->pStatus = asciitounicode(&usBuffer, info1A->pStatus);
3097 info1W->Status = info1A->Status;
3098 info1W->Priority = info1A->Priority;
3099 info1W->Position = info1A->Position;
3100 info1W->PagesPrinted = info1A->PagesPrinted;
3101 break;
3103 case 2:
3105 JOB_INFO_2W *info2W = HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W));
3106 JOB_INFO_2A *info2A = (JOB_INFO_2A*)pJob;
3108 JobW = (LPBYTE)info2W;
3109 info2W->pUserName = asciitounicode(&usBuffer, info2A->pUserName);
3110 info2W->pDocument = asciitounicode(&usBuffer, info2A->pDocument);
3111 info2W->pNotifyName = asciitounicode(&usBuffer, info2A->pNotifyName);
3112 info2W->pDatatype = asciitounicode(&usBuffer, info2A->pDatatype);
3113 info2W->pPrintProcessor = asciitounicode(&usBuffer, info2A->pPrintProcessor);
3114 info2W->pParameters = asciitounicode(&usBuffer, info2A->pParameters);
3115 info2W->pDevMode = info2A->pDevMode ? GdiConvertToDevmodeW(info2A->pDevMode) : NULL;
3116 info2W->pStatus = asciitounicode(&usBuffer, info2A->pStatus);
3117 info2W->pSecurityDescriptor = info2A->pSecurityDescriptor;
3118 info2W->Status = info2A->Status;
3119 info2W->Priority = info2A->Priority;
3120 info2W->Position = info2A->Position;
3121 info2W->StartTime = info2A->StartTime;
3122 info2W->UntilTime = info2A->UntilTime;
3123 info2W->PagesPrinted = info2A->PagesPrinted;
3124 break;
3126 case 3:
3127 JobW = HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3));
3128 memcpy(JobW, pJob, sizeof(JOB_INFO_3));
3129 break;
3130 default:
3131 SetLastError(ERROR_INVALID_LEVEL);
3132 return FALSE;
3135 ret = SetJobW(hPrinter, JobId, Level, JobW, Command);
3137 switch(Level)
3139 case 1:
3141 JOB_INFO_1W *info1W = (JOB_INFO_1W*)JobW;
3142 HeapFree(GetProcessHeap(), 0, info1W->pUserName);
3143 HeapFree(GetProcessHeap(), 0, info1W->pDocument);
3144 HeapFree(GetProcessHeap(), 0, info1W->pDatatype);
3145 HeapFree(GetProcessHeap(), 0, info1W->pStatus);
3146 break;
3148 case 2:
3150 JOB_INFO_2W *info2W = (JOB_INFO_2W*)JobW;
3151 HeapFree(GetProcessHeap(), 0, info2W->pUserName);
3152 HeapFree(GetProcessHeap(), 0, info2W->pDocument);
3153 HeapFree(GetProcessHeap(), 0, info2W->pNotifyName);
3154 HeapFree(GetProcessHeap(), 0, info2W->pDatatype);
3155 HeapFree(GetProcessHeap(), 0, info2W->pPrintProcessor);
3156 HeapFree(GetProcessHeap(), 0, info2W->pParameters);
3157 HeapFree(GetProcessHeap(), 0, info2W->pDevMode);
3158 HeapFree(GetProcessHeap(), 0, info2W->pStatus);
3159 break;
3162 HeapFree(GetProcessHeap(), 0, JobW);
3164 return ret;
3167 /*****************************************************************************
3168 * SetJobW [WINSPOOL.@]
3170 BOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level,
3171 LPBYTE pJob, DWORD Command)
3173 BOOL ret = FALSE;
3174 job_t *job;
3176 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter, JobId, Level, pJob, Command);
3177 FIXME("Ignoring everything other than document title\n");
3179 EnterCriticalSection(&printer_handles_cs);
3180 job = get_job(hPrinter, JobId);
3181 if(!job)
3182 goto end;
3184 switch(Level)
3186 case 0:
3187 break;
3188 case 1:
3190 JOB_INFO_1W *info1 = (JOB_INFO_1W*)pJob;
3191 HeapFree(GetProcessHeap(), 0, job->document_title);
3192 job->document_title = strdupW(info1->pDocument);
3193 break;
3195 case 2:
3197 JOB_INFO_2W *info2 = (JOB_INFO_2W*)pJob;
3198 HeapFree(GetProcessHeap(), 0, job->document_title);
3199 job->document_title = strdupW(info2->pDocument);
3200 break;
3202 case 3:
3203 break;
3204 default:
3205 SetLastError(ERROR_INVALID_LEVEL);
3206 goto end;
3208 ret = TRUE;
3209 end:
3210 LeaveCriticalSection(&printer_handles_cs);
3211 return ret;
3214 /*****************************************************************************
3215 * EndDocPrinter [WINSPOOL.@]
3217 BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
3219 opened_printer_t *printer;
3220 BOOL ret = FALSE;
3221 TRACE("(%p)\n", hPrinter);
3223 EnterCriticalSection(&printer_handles_cs);
3225 printer = get_opened_printer(hPrinter);
3226 if(!printer)
3228 SetLastError(ERROR_INVALID_HANDLE);
3229 goto end;
3232 if(!printer->doc)
3234 SetLastError(ERROR_SPL_NO_STARTDOC);
3235 goto end;
3238 CloseHandle(printer->doc->hf);
3239 ScheduleJob(hPrinter, printer->doc->job_id);
3240 HeapFree(GetProcessHeap(), 0, printer->doc);
3241 printer->doc = NULL;
3242 ret = TRUE;
3243 end:
3244 LeaveCriticalSection(&printer_handles_cs);
3245 return ret;
3248 /*****************************************************************************
3249 * EndPagePrinter [WINSPOOL.@]
3251 BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
3253 FIXME("(%p): stub\n", hPrinter);
3254 return TRUE;
3257 /*****************************************************************************
3258 * StartDocPrinterA [WINSPOOL.@]
3260 DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3262 UNICODE_STRING usBuffer;
3263 DOC_INFO_2W doc2W;
3264 DOC_INFO_2A *doc2 = (DOC_INFO_2A*)pDocInfo;
3265 DWORD ret;
3267 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3268 or one (DOC_INFO_3) extra DWORDs */
3270 switch(Level) {
3271 case 2:
3272 doc2W.JobId = doc2->JobId;
3273 /* fall through */
3274 case 3:
3275 doc2W.dwMode = doc2->dwMode;
3276 /* fall through */
3277 case 1:
3278 doc2W.pDocName = asciitounicode(&usBuffer, doc2->pDocName);
3279 doc2W.pOutputFile = asciitounicode(&usBuffer, doc2->pOutputFile);
3280 doc2W.pDatatype = asciitounicode(&usBuffer, doc2->pDatatype);
3281 break;
3283 default:
3284 SetLastError(ERROR_INVALID_LEVEL);
3285 return FALSE;
3288 ret = StartDocPrinterW(hPrinter, Level, (LPBYTE)&doc2W);
3290 HeapFree(GetProcessHeap(), 0, doc2W.pDatatype);
3291 HeapFree(GetProcessHeap(), 0, doc2W.pOutputFile);
3292 HeapFree(GetProcessHeap(), 0, doc2W.pDocName);
3294 return ret;
3297 /*****************************************************************************
3298 * StartDocPrinterW [WINSPOOL.@]
3300 DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
3302 DOC_INFO_2W *doc = (DOC_INFO_2W *)pDocInfo;
3303 opened_printer_t *printer;
3304 BYTE addjob_buf[MAX_PATH * sizeof(WCHAR) + sizeof(ADDJOB_INFO_1W)];
3305 ADDJOB_INFO_1W *addjob = (ADDJOB_INFO_1W*) addjob_buf;
3306 JOB_INFO_1W job_info;
3307 DWORD needed, ret = 0;
3308 HANDLE hf;
3309 WCHAR *filename;
3311 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3312 hPrinter, Level, doc, debugstr_w(doc->pDocName), debugstr_w(doc->pOutputFile),
3313 debugstr_w(doc->pDatatype));
3315 if(Level < 1 || Level > 3)
3317 SetLastError(ERROR_INVALID_LEVEL);
3318 return 0;
3321 EnterCriticalSection(&printer_handles_cs);
3322 printer = get_opened_printer(hPrinter);
3323 if(!printer)
3325 SetLastError(ERROR_INVALID_HANDLE);
3326 goto end;
3329 if(printer->doc)
3331 SetLastError(ERROR_INVALID_PRINTER_STATE);
3332 goto end;
3335 /* Even if we're printing to a file we still add a print job, we'll
3336 just ignore the spool file name */
3338 if(!AddJobW(hPrinter, 1, addjob_buf, sizeof(addjob_buf), &needed))
3340 ERR("AddJob failed gle %u\n", GetLastError());
3341 goto end;
3344 if(doc->pOutputFile)
3345 filename = doc->pOutputFile;
3346 else
3347 filename = addjob->Path;
3349 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
3350 if(hf == INVALID_HANDLE_VALUE)
3351 goto end;
3353 memset(&job_info, 0, sizeof(job_info));
3354 job_info.pDocument = doc->pDocName;
3355 SetJobW(hPrinter, addjob->JobId, 1, (LPBYTE)&job_info, 0);
3357 printer->doc = HeapAlloc(GetProcessHeap(), 0, sizeof(*printer->doc));
3358 printer->doc->hf = hf;
3359 ret = printer->doc->job_id = addjob->JobId;
3360 end:
3361 LeaveCriticalSection(&printer_handles_cs);
3363 return ret;
3366 /*****************************************************************************
3367 * StartPagePrinter [WINSPOOL.@]
3369 BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
3371 FIXME("(%p): stub\n", hPrinter);
3372 return TRUE;
3375 /*****************************************************************************
3376 * GetFormA [WINSPOOL.@]
3378 BOOL WINAPI GetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3379 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3381 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,pFormName,
3382 Level,pForm,cbBuf,pcbNeeded);
3383 return FALSE;
3386 /*****************************************************************************
3387 * GetFormW [WINSPOOL.@]
3389 BOOL WINAPI GetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3390 LPBYTE pForm, DWORD cbBuf, LPDWORD pcbNeeded)
3392 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter,
3393 debugstr_w(pFormName),Level,pForm,cbBuf,pcbNeeded);
3394 return FALSE;
3397 /*****************************************************************************
3398 * SetFormA [WINSPOOL.@]
3400 BOOL WINAPI SetFormA(HANDLE hPrinter, LPSTR pFormName, DWORD Level,
3401 LPBYTE pForm)
3403 FIXME("(%p,%s,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3404 return FALSE;
3407 /*****************************************************************************
3408 * SetFormW [WINSPOOL.@]
3410 BOOL WINAPI SetFormW(HANDLE hPrinter, LPWSTR pFormName, DWORD Level,
3411 LPBYTE pForm)
3413 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pFormName,Level,pForm);
3414 return FALSE;
3417 /*****************************************************************************
3418 * ReadPrinter [WINSPOOL.@]
3420 BOOL WINAPI ReadPrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf,
3421 LPDWORD pNoBytesRead)
3423 FIXME("(%p,%p,%d,%p): stub\n",hPrinter,pBuf,cbBuf,pNoBytesRead);
3424 return FALSE;
3427 /*****************************************************************************
3428 * ResetPrinterA [WINSPOOL.@]
3430 BOOL WINAPI ResetPrinterA(HANDLE hPrinter, LPPRINTER_DEFAULTSA pDefault)
3432 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3433 return FALSE;
3436 /*****************************************************************************
3437 * ResetPrinterW [WINSPOOL.@]
3439 BOOL WINAPI ResetPrinterW(HANDLE hPrinter, LPPRINTER_DEFAULTSW pDefault)
3441 FIXME("(%p, %p): stub\n", hPrinter, pDefault);
3442 return FALSE;
3445 /*****************************************************************************
3446 * WINSPOOL_GetDWORDFromReg
3448 * Return DWORD associated with ValueName from hkey.
3450 static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
3452 DWORD sz = sizeof(DWORD), type, value = 0;
3453 LONG ret;
3455 ret = RegQueryValueExA(hkey, ValueName, 0, &type, (LPBYTE)&value, &sz);
3457 if(ret != ERROR_SUCCESS) {
3458 WARN("Got ret = %d on name %s\n", ret, ValueName);
3459 return 0;
3461 if(type != REG_DWORD) {
3462 ERR("Got type %d\n", type);
3463 return 0;
3465 return value;
3468 /*****************************************************************************
3469 * WINSPOOL_GetStringFromReg
3471 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3472 * String is stored either as unicode or ascii.
3473 * Bit of a hack here to get the ValueName if we want ascii.
3475 static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
3476 DWORD buflen, DWORD *needed,
3477 BOOL unicode)
3479 DWORD sz = buflen, type;
3480 LONG ret;
3482 if(unicode)
3483 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3484 else {
3485 LPSTR ValueNameA = strdupWtoA(ValueName);
3486 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
3487 HeapFree(GetProcessHeap(),0,ValueNameA);
3489 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
3490 WARN("Got ret = %d\n", ret);
3491 *needed = 0;
3492 return FALSE;
3494 /* add space for terminating '\0' */
3495 sz += unicode ? sizeof(WCHAR) : 1;
3496 *needed = sz;
3498 if (ptr)
3499 TRACE("%s: %s\n", debugstr_w(ValueName), unicode ? debugstr_w((LPCWSTR)ptr) : debugstr_a((LPCSTR)ptr));
3501 return TRUE;
3504 /*****************************************************************************
3505 * WINSPOOL_GetDefaultDevMode
3507 * Get a default DevMode values for wineps.
3508 * FIXME - use ppd.
3511 static void WINSPOOL_GetDefaultDevMode(
3512 LPBYTE ptr,
3513 DWORD buflen, DWORD *needed,
3514 BOOL unicode)
3516 DEVMODEA dm;
3517 static const char szwps[] = "wineps.drv";
3519 /* fill default DEVMODE - should be read from ppd... */
3520 ZeroMemory( &dm, sizeof(dm) );
3521 memcpy(dm.dmDeviceName,szwps,sizeof szwps);
3522 dm.dmSpecVersion = DM_SPECVERSION;
3523 dm.dmDriverVersion = 1;
3524 dm.dmSize = sizeof(DEVMODEA);
3525 dm.dmDriverExtra = 0;
3526 dm.dmFields =
3527 DM_ORIENTATION | DM_PAPERSIZE |
3528 DM_PAPERLENGTH | DM_PAPERWIDTH |
3529 DM_SCALE |
3530 DM_COPIES |
3531 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
3532 DM_YRESOLUTION | DM_TTOPTION;
3534 dm.u1.s1.dmOrientation = DMORIENT_PORTRAIT;
3535 dm.u1.s1.dmPaperSize = DMPAPER_A4;
3536 dm.u1.s1.dmPaperLength = 2970;
3537 dm.u1.s1.dmPaperWidth = 2100;
3539 dm.dmScale = 100;
3540 dm.dmCopies = 1;
3541 dm.dmDefaultSource = DMBIN_AUTO;
3542 dm.dmPrintQuality = DMRES_MEDIUM;
3543 /* dm.dmColor */
3544 /* dm.dmDuplex */
3545 dm.dmYResolution = 300; /* 300dpi */
3546 dm.dmTTOption = DMTT_BITMAP;
3547 /* dm.dmCollate */
3548 /* dm.dmFormName */
3549 /* dm.dmLogPixels */
3550 /* dm.dmBitsPerPel */
3551 /* dm.dmPelsWidth */
3552 /* dm.dmPelsHeight */
3553 /* dm.dmDisplayFlags */
3554 /* dm.dmDisplayFrequency */
3555 /* dm.dmICMMethod */
3556 /* dm.dmICMIntent */
3557 /* dm.dmMediaType */
3558 /* dm.dmDitherType */
3559 /* dm.dmReserved1 */
3560 /* dm.dmReserved2 */
3561 /* dm.dmPanningWidth */
3562 /* dm.dmPanningHeight */
3564 if(unicode) {
3565 if(buflen >= sizeof(DEVMODEW)) {
3566 DEVMODEW *pdmW = GdiConvertToDevmodeW(&dm);
3567 memcpy(ptr, pdmW, sizeof(DEVMODEW));
3568 HeapFree(GetProcessHeap(),0,pdmW);
3570 *needed = sizeof(DEVMODEW);
3572 else
3574 if(buflen >= sizeof(DEVMODEA)) {
3575 memcpy(ptr, &dm, sizeof(DEVMODEA));
3577 *needed = sizeof(DEVMODEA);
3581 /*****************************************************************************
3582 * WINSPOOL_GetDevModeFromReg
3584 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3585 * DevMode is stored either as unicode or ascii.
3587 static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
3588 LPBYTE ptr,
3589 DWORD buflen, DWORD *needed,
3590 BOOL unicode)
3592 DWORD sz = buflen, type;
3593 LONG ret;
3595 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
3596 ret = RegQueryValueExW(hkey, ValueName, 0, &type, ptr, &sz);
3597 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
3598 if (sz < sizeof(DEVMODEA))
3600 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName),sz);
3601 return FALSE;
3603 /* ensures that dmSize is not erratically bogus if registry is invalid */
3604 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
3605 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
3606 if(unicode) {
3607 sz += (CCHDEVICENAME + CCHFORMNAME);
3608 if(buflen >= sz) {
3609 DEVMODEW *dmW = GdiConvertToDevmodeW((DEVMODEA*)ptr);
3610 memcpy(ptr, dmW, sz);
3611 HeapFree(GetProcessHeap(),0,dmW);
3614 *needed = sz;
3615 return TRUE;
3618 /*********************************************************************
3619 * WINSPOOL_GetPrinter_1
3621 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3622 * The strings are either stored as unicode or ascii.
3624 static BOOL WINSPOOL_GetPrinter_1(HKEY hkeyPrinter, PRINTER_INFO_1W *pi1,
3625 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3626 BOOL unicode)
3628 DWORD size, left = cbBuf;
3629 BOOL space = (cbBuf > 0);
3630 LPBYTE ptr = buf;
3632 *pcbNeeded = 0;
3634 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3635 unicode)) {
3636 if(space && size <= left) {
3637 pi1->pName = (LPWSTR)ptr;
3638 ptr += size;
3639 left -= size;
3640 } else
3641 space = FALSE;
3642 *pcbNeeded += size;
3645 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3646 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3647 unicode)) {
3648 if(space && size <= left) {
3649 pi1->pDescription = (LPWSTR)ptr;
3650 ptr += size;
3651 left -= size;
3652 } else
3653 space = FALSE;
3654 *pcbNeeded += size;
3657 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3658 unicode)) {
3659 if(space && size <= left) {
3660 pi1->pComment = (LPWSTR)ptr;
3661 ptr += size;
3662 left -= size;
3663 } else
3664 space = FALSE;
3665 *pcbNeeded += size;
3668 if(pi1) pi1->Flags = PRINTER_ENUM_ICON8; /* We're a printer */
3670 if(!space && pi1) /* zero out pi1 if we can't completely fill buf */
3671 memset(pi1, 0, sizeof(*pi1));
3673 return space;
3675 /*********************************************************************
3676 * WINSPOOL_GetPrinter_2
3678 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3679 * The strings are either stored as unicode or ascii.
3681 static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
3682 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3683 BOOL unicode)
3685 DWORD size, left = cbBuf;
3686 BOOL space = (cbBuf > 0);
3687 LPBYTE ptr = buf;
3689 *pcbNeeded = 0;
3691 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3692 unicode)) {
3693 if(space && size <= left) {
3694 pi2->pPrinterName = (LPWSTR)ptr;
3695 ptr += size;
3696 left -= size;
3697 } else
3698 space = FALSE;
3699 *pcbNeeded += size;
3701 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
3702 unicode)) {
3703 if(space && size <= left) {
3704 pi2->pShareName = (LPWSTR)ptr;
3705 ptr += size;
3706 left -= size;
3707 } else
3708 space = FALSE;
3709 *pcbNeeded += size;
3711 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3712 unicode)) {
3713 if(space && size <= left) {
3714 pi2->pPortName = (LPWSTR)ptr;
3715 ptr += size;
3716 left -= size;
3717 } else
3718 space = FALSE;
3719 *pcbNeeded += size;
3721 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
3722 &size, unicode)) {
3723 if(space && size <= left) {
3724 pi2->pDriverName = (LPWSTR)ptr;
3725 ptr += size;
3726 left -= size;
3727 } else
3728 space = FALSE;
3729 *pcbNeeded += size;
3731 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
3732 unicode)) {
3733 if(space && size <= left) {
3734 pi2->pComment = (LPWSTR)ptr;
3735 ptr += size;
3736 left -= size;
3737 } else
3738 space = FALSE;
3739 *pcbNeeded += size;
3741 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
3742 unicode)) {
3743 if(space && size <= left) {
3744 pi2->pLocation = (LPWSTR)ptr;
3745 ptr += size;
3746 left -= size;
3747 } else
3748 space = FALSE;
3749 *pcbNeeded += size;
3751 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
3752 &size, unicode)) {
3753 if(space && size <= left) {
3754 pi2->pDevMode = (LPDEVMODEW)ptr;
3755 ptr += size;
3756 left -= size;
3757 } else
3758 space = FALSE;
3759 *pcbNeeded += size;
3761 else
3763 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
3764 if(space && size <= left) {
3765 pi2->pDevMode = (LPDEVMODEW)ptr;
3766 ptr += size;
3767 left -= size;
3768 } else
3769 space = FALSE;
3770 *pcbNeeded += size;
3772 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
3773 &size, unicode)) {
3774 if(space && size <= left) {
3775 pi2->pSepFile = (LPWSTR)ptr;
3776 ptr += size;
3777 left -= size;
3778 } else
3779 space = FALSE;
3780 *pcbNeeded += size;
3782 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
3783 &size, unicode)) {
3784 if(space && size <= left) {
3785 pi2->pPrintProcessor = (LPWSTR)ptr;
3786 ptr += size;
3787 left -= size;
3788 } else
3789 space = FALSE;
3790 *pcbNeeded += size;
3792 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
3793 &size, unicode)) {
3794 if(space && size <= left) {
3795 pi2->pDatatype = (LPWSTR)ptr;
3796 ptr += size;
3797 left -= size;
3798 } else
3799 space = FALSE;
3800 *pcbNeeded += size;
3802 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
3803 &size, unicode)) {
3804 if(space && size <= left) {
3805 pi2->pParameters = (LPWSTR)ptr;
3806 ptr += size;
3807 left -= size;
3808 } else
3809 space = FALSE;
3810 *pcbNeeded += size;
3812 if(pi2) {
3813 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3814 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
3815 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3816 "Default Priority");
3817 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
3818 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
3821 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
3822 memset(pi2, 0, sizeof(*pi2));
3824 return space;
3827 /*********************************************************************
3828 * WINSPOOL_GetPrinter_4
3830 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3832 static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
3833 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3834 BOOL unicode)
3836 DWORD size, left = cbBuf;
3837 BOOL space = (cbBuf > 0);
3838 LPBYTE ptr = buf;
3840 *pcbNeeded = 0;
3842 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3843 unicode)) {
3844 if(space && size <= left) {
3845 pi4->pPrinterName = (LPWSTR)ptr;
3846 ptr += size;
3847 left -= size;
3848 } else
3849 space = FALSE;
3850 *pcbNeeded += size;
3852 if(pi4) {
3853 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3856 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
3857 memset(pi4, 0, sizeof(*pi4));
3859 return space;
3862 /*********************************************************************
3863 * WINSPOOL_GetPrinter_5
3865 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
3867 static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
3868 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
3869 BOOL unicode)
3871 DWORD size, left = cbBuf;
3872 BOOL space = (cbBuf > 0);
3873 LPBYTE ptr = buf;
3875 *pcbNeeded = 0;
3877 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
3878 unicode)) {
3879 if(space && size <= left) {
3880 pi5->pPrinterName = (LPWSTR)ptr;
3881 ptr += size;
3882 left -= size;
3883 } else
3884 space = FALSE;
3885 *pcbNeeded += size;
3887 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
3888 unicode)) {
3889 if(space && size <= left) {
3890 pi5->pPortName = (LPWSTR)ptr;
3891 ptr += size;
3892 left -= size;
3893 } else
3894 space = FALSE;
3895 *pcbNeeded += size;
3897 if(pi5) {
3898 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
3899 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3900 "dnsTimeout");
3901 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
3902 "txTimeout");
3905 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
3906 memset(pi5, 0, sizeof(*pi5));
3908 return space;
3911 /*****************************************************************************
3912 * WINSPOOL_GetPrinter
3914 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
3915 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
3916 * just a collection of pointers to strings.
3918 static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
3919 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
3921 LPCWSTR name;
3922 DWORD size, needed = 0;
3923 LPBYTE ptr = NULL;
3924 HKEY hkeyPrinter, hkeyPrinters;
3925 BOOL ret;
3927 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
3929 if (!(name = get_opened_printer_name(hPrinter))) {
3930 SetLastError(ERROR_INVALID_HANDLE);
3931 return FALSE;
3934 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
3935 ERROR_SUCCESS) {
3936 ERR("Can't create Printers key\n");
3937 return FALSE;
3939 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
3941 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
3942 RegCloseKey(hkeyPrinters);
3943 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
3944 return FALSE;
3947 switch(Level) {
3948 case 2:
3950 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
3952 size = sizeof(PRINTER_INFO_2W);
3953 if(size <= cbBuf) {
3954 ptr = pPrinter + size;
3955 cbBuf -= size;
3956 memset(pPrinter, 0, size);
3957 } else {
3958 pi2 = NULL;
3959 cbBuf = 0;
3961 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
3962 unicode);
3963 needed += size;
3964 break;
3967 case 4:
3969 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
3971 size = sizeof(PRINTER_INFO_4W);
3972 if(size <= cbBuf) {
3973 ptr = pPrinter + size;
3974 cbBuf -= size;
3975 memset(pPrinter, 0, size);
3976 } else {
3977 pi4 = NULL;
3978 cbBuf = 0;
3980 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
3981 unicode);
3982 needed += size;
3983 break;
3987 case 5:
3989 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
3991 size = sizeof(PRINTER_INFO_5W);
3992 if(size <= cbBuf) {
3993 ptr = pPrinter + size;
3994 cbBuf -= size;
3995 memset(pPrinter, 0, size);
3996 } else {
3997 pi5 = NULL;
3998 cbBuf = 0;
4001 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
4002 unicode);
4003 needed += size;
4004 break;
4007 default:
4008 FIXME("Unimplemented level %d\n", Level);
4009 SetLastError(ERROR_INVALID_LEVEL);
4010 RegCloseKey(hkeyPrinters);
4011 RegCloseKey(hkeyPrinter);
4012 return FALSE;
4015 RegCloseKey(hkeyPrinter);
4016 RegCloseKey(hkeyPrinters);
4018 TRACE("returning %d needed = %d\n", ret, needed);
4019 if(pcbNeeded) *pcbNeeded = needed;
4020 if(!ret)
4021 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4022 return ret;
4025 /*****************************************************************************
4026 * GetPrinterW [WINSPOOL.@]
4028 BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4029 DWORD cbBuf, LPDWORD pcbNeeded)
4031 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4032 TRUE);
4035 /*****************************************************************************
4036 * GetPrinterA [WINSPOOL.@]
4038 BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
4039 DWORD cbBuf, LPDWORD pcbNeeded)
4041 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
4042 FALSE);
4045 /*****************************************************************************
4046 * WINSPOOL_EnumPrinters
4048 * Implementation of EnumPrintersA|W
4050 static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
4051 DWORD dwLevel, LPBYTE lpbPrinters,
4052 DWORD cbBuf, LPDWORD lpdwNeeded,
4053 LPDWORD lpdwReturned, BOOL unicode)
4056 HKEY hkeyPrinters, hkeyPrinter;
4057 WCHAR PrinterName[255];
4058 DWORD needed = 0, number = 0;
4059 DWORD used, i, left;
4060 PBYTE pi, buf;
4062 if(lpbPrinters)
4063 memset(lpbPrinters, 0, cbBuf);
4064 if(lpdwReturned)
4065 *lpdwReturned = 0;
4066 if(lpdwNeeded)
4067 *lpdwNeeded = 0;
4069 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4070 if(dwType == PRINTER_ENUM_DEFAULT)
4071 return TRUE;
4073 if (dwType & PRINTER_ENUM_CONNECTIONS) {
4074 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4075 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we don't handle that */
4076 if (!dwType) {
4077 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4078 *lpdwNeeded = 0;
4079 *lpdwReturned = 0;
4080 return TRUE;
4085 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
4086 FIXME("dwType = %08x\n", dwType);
4087 SetLastError(ERROR_INVALID_FLAGS);
4088 return FALSE;
4091 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4092 ERROR_SUCCESS) {
4093 ERR("Can't create Printers key\n");
4094 return FALSE;
4097 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
4098 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4099 RegCloseKey(hkeyPrinters);
4100 ERR("Can't query Printers key\n");
4101 return FALSE;
4103 TRACE("Found %d printers\n", number);
4105 switch(dwLevel) {
4106 case 1:
4107 used = number * sizeof(PRINTER_INFO_1W);
4108 break;
4109 case 2:
4110 used = number * sizeof(PRINTER_INFO_2W);
4111 break;
4112 case 4:
4113 used = number * sizeof(PRINTER_INFO_4W);
4114 break;
4115 case 5:
4116 used = number * sizeof(PRINTER_INFO_5W);
4117 break;
4119 default:
4120 SetLastError(ERROR_INVALID_LEVEL);
4121 RegCloseKey(hkeyPrinters);
4122 return FALSE;
4124 pi = (used <= cbBuf) ? lpbPrinters : NULL;
4126 for(i = 0; i < number; i++) {
4127 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
4128 ERROR_SUCCESS) {
4129 ERR("Can't enum key number %d\n", i);
4130 RegCloseKey(hkeyPrinters);
4131 return FALSE;
4133 TRACE("Printer %d is %s\n", i, debugstr_w(PrinterName));
4134 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
4135 ERROR_SUCCESS) {
4136 ERR("Can't open key %s\n", debugstr_w(PrinterName));
4137 RegCloseKey(hkeyPrinters);
4138 return FALSE;
4141 if(cbBuf > used) {
4142 buf = lpbPrinters + used;
4143 left = cbBuf - used;
4144 } else {
4145 buf = NULL;
4146 left = 0;
4149 switch(dwLevel) {
4150 case 1:
4151 WINSPOOL_GetPrinter_1(hkeyPrinter, (PRINTER_INFO_1W *)pi, buf,
4152 left, &needed, unicode);
4153 used += needed;
4154 if(pi) pi += sizeof(PRINTER_INFO_1W);
4155 break;
4156 case 2:
4157 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
4158 left, &needed, unicode);
4159 used += needed;
4160 if(pi) pi += sizeof(PRINTER_INFO_2W);
4161 break;
4162 case 4:
4163 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
4164 left, &needed, unicode);
4165 used += needed;
4166 if(pi) pi += sizeof(PRINTER_INFO_4W);
4167 break;
4168 case 5:
4169 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
4170 left, &needed, unicode);
4171 used += needed;
4172 if(pi) pi += sizeof(PRINTER_INFO_5W);
4173 break;
4174 default:
4175 ERR("Shouldn't be here!\n");
4176 RegCloseKey(hkeyPrinter);
4177 RegCloseKey(hkeyPrinters);
4178 return FALSE;
4180 RegCloseKey(hkeyPrinter);
4182 RegCloseKey(hkeyPrinters);
4184 if(lpdwNeeded)
4185 *lpdwNeeded = used;
4187 if(used > cbBuf) {
4188 if(lpbPrinters)
4189 memset(lpbPrinters, 0, cbBuf);
4190 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4191 return FALSE;
4193 if(lpdwReturned)
4194 *lpdwReturned = number;
4195 SetLastError(ERROR_SUCCESS);
4196 return TRUE;
4200 /******************************************************************
4201 * EnumPrintersW [WINSPOOL.@]
4203 * Enumerates the available printers, print servers and print
4204 * providers, depending on the specified flags, name and level.
4206 * RETURNS:
4208 * If level is set to 1:
4209 * Returns an array of PRINTER_INFO_1 data structures in the
4210 * lpbPrinters buffer.
4212 * If level is set to 2:
4213 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4214 * Returns an array of PRINTER_INFO_2 data structures in the
4215 * lpbPrinters buffer. Note that according to MSDN also an
4216 * OpenPrinter should be performed on every remote printer.
4218 * If level is set to 4 (officially WinNT only):
4219 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4220 * Fast: Only the registry is queried to retrieve printer names,
4221 * no connection to the driver is made.
4222 * Returns an array of PRINTER_INFO_4 data structures in the
4223 * lpbPrinters buffer.
4225 * If level is set to 5 (officially WinNT4/Win9x only):
4226 * Fast: Only the registry is queried to retrieve printer names,
4227 * no connection to the driver is made.
4228 * Returns an array of PRINTER_INFO_5 data structures in the
4229 * lpbPrinters buffer.
4231 * If level set to 3 or 6+:
4232 * returns zero (failure!)
4234 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4235 * for information.
4237 * BUGS:
4238 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4239 * - Only levels 2, 4 and 5 are implemented at the moment.
4240 * - 16-bit printer drivers are not enumerated.
4241 * - Returned amount of bytes used/needed does not match the real Windoze
4242 * implementation (as in this implementation, all strings are part
4243 * of the buffer, whereas Win32 keeps them somewhere else)
4244 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4246 * NOTE:
4247 * - In a regular Wine installation, no registry settings for printers
4248 * exist, which makes this function return an empty list.
4250 BOOL WINAPI EnumPrintersW(
4251 DWORD dwType, /* [in] Types of print objects to enumerate */
4252 LPWSTR lpszName, /* [in] name of objects to enumerate */
4253 DWORD dwLevel, /* [in] type of printer info structure */
4254 LPBYTE lpbPrinters, /* [out] buffer which receives info */
4255 DWORD cbBuf, /* [in] max size of buffer in bytes */
4256 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
4257 LPDWORD lpdwReturned /* [out] number of entries returned */
4260 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
4261 lpdwNeeded, lpdwReturned, TRUE);
4264 /******************************************************************
4265 * EnumPrintersA [WINSPOOL.@]
4268 BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
4269 DWORD dwLevel, LPBYTE lpbPrinters,
4270 DWORD cbBuf, LPDWORD lpdwNeeded,
4271 LPDWORD lpdwReturned)
4273 BOOL ret, unicode = FALSE;
4274 UNICODE_STRING lpszNameW;
4275 PWSTR pwstrNameW;
4277 pwstrNameW = asciitounicode(&lpszNameW,lpszName);
4278 if(!cbBuf) unicode = TRUE; /* return a buffer that's big enough for the unicode version */
4279 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
4280 lpdwNeeded, lpdwReturned, unicode);
4281 RtlFreeUnicodeString(&lpszNameW);
4282 return ret;
4285 /*****************************************************************************
4286 * WINSPOOL_GetDriverInfoFromReg [internal]
4288 * Enters the information from the registry into the DRIVER_INFO struct
4290 * RETURNS
4291 * zero if the printer driver does not exist in the registry
4292 * (only if Level > 1) otherwise nonzero
4294 static BOOL WINSPOOL_GetDriverInfoFromReg(
4295 HKEY hkeyDrivers,
4296 LPWSTR DriverName,
4297 LPCWSTR pEnvironment,
4298 DWORD Level,
4299 LPBYTE ptr, /* DRIVER_INFO */
4300 LPBYTE pDriverStrings, /* strings buffer */
4301 DWORD cbBuf, /* size of string buffer */
4302 LPDWORD pcbNeeded, /* space needed for str. */
4303 BOOL unicode) /* type of strings */
4305 DWORD size, tmp;
4306 HKEY hkeyDriver;
4307 LPBYTE strPtr = pDriverStrings;
4309 TRACE("%s,%s,%d,%p,%p,%d,%d\n",
4310 debugstr_w(DriverName), debugstr_w(pEnvironment),
4311 Level, ptr, pDriverStrings, cbBuf, unicode);
4313 if(unicode) {
4314 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
4315 if (*pcbNeeded <= cbBuf)
4316 strcpyW((LPWSTR)strPtr, DriverName);
4317 } else {
4318 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
4319 NULL, NULL);
4320 if(*pcbNeeded <= cbBuf)
4321 WideCharToMultiByte(CP_ACP, 0, DriverName, -1,
4322 (LPSTR)strPtr, *pcbNeeded, NULL, NULL);
4324 if(Level == 1) {
4325 if(ptr)
4326 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
4327 return TRUE;
4328 } else {
4329 if(ptr)
4330 ((PDRIVER_INFO_2W) ptr)->pName = (LPWSTR) strPtr;
4331 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4334 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
4335 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName));
4336 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
4337 return FALSE;
4340 if(ptr)
4341 ((PDRIVER_INFO_2A) ptr)->cVersion = (GetVersion() & 0x80000000) ? 0 : 3; /* FIXME: add 1, 2 */
4343 if(!pEnvironment)
4344 pEnvironment = DefaultEnvironmentW;
4345 if(unicode)
4346 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
4347 else
4348 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
4349 NULL, NULL);
4350 *pcbNeeded += size;
4351 if(*pcbNeeded <= cbBuf) {
4352 if(unicode)
4353 strcpyW((LPWSTR)strPtr, pEnvironment);
4354 else
4355 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1,
4356 (LPSTR)strPtr, size, NULL, NULL);
4357 if(ptr)
4358 ((PDRIVER_INFO_2W) ptr)->pEnvironment = (LPWSTR)strPtr;
4359 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4362 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
4363 unicode)) {
4364 *pcbNeeded += size;
4365 if(*pcbNeeded <= cbBuf)
4366 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
4367 unicode);
4368 if(ptr)
4369 ((PDRIVER_INFO_2W) ptr)->pDriverPath = (LPWSTR)strPtr;
4370 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
4373 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
4374 unicode)) {
4375 *pcbNeeded += size;
4376 if(*pcbNeeded <= cbBuf)
4377 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
4378 &tmp, unicode);
4379 if(ptr)
4380 ((PDRIVER_INFO_2W) ptr)->pDataFile = (LPWSTR)strPtr;
4381 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4384 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4385 0, &size, unicode)) {
4386 *pcbNeeded += size;
4387 if(*pcbNeeded <= cbBuf)
4388 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
4389 size, &tmp, unicode);
4390 if(ptr)
4391 ((PDRIVER_INFO_2W) ptr)->pConfigFile = (LPWSTR)strPtr;
4392 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4395 if(Level == 2 ) {
4396 RegCloseKey(hkeyDriver);
4397 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4398 return TRUE;
4401 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
4402 unicode)) {
4403 *pcbNeeded += size;
4404 if(*pcbNeeded <= cbBuf)
4405 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
4406 size, &tmp, unicode);
4407 if(ptr)
4408 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
4409 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4412 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
4413 &size, unicode)) {
4414 *pcbNeeded += size;
4415 if(*pcbNeeded <= cbBuf)
4416 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
4417 size, &tmp, unicode);
4418 if(ptr)
4419 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
4420 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4423 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
4424 unicode)) {
4425 *pcbNeeded += size;
4426 if(*pcbNeeded <= cbBuf)
4427 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
4428 size, &tmp, unicode);
4429 if(ptr)
4430 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
4431 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4434 if (Level != 5 && WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
4435 unicode)) {
4436 *pcbNeeded += size;
4437 if(*pcbNeeded <= cbBuf)
4438 WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr,
4439 size, &tmp, unicode);
4440 if(ptr)
4441 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
4442 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
4445 TRACE("buffer space %d required %d\n", cbBuf, *pcbNeeded);
4446 RegCloseKey(hkeyDriver);
4447 return TRUE;
4450 /*****************************************************************************
4451 * WINSPOOL_GetPrinterDriver
4453 static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPCWSTR pEnvironment,
4454 DWORD Level, LPBYTE pDriverInfo,
4455 DWORD cbBuf, LPDWORD pcbNeeded,
4456 BOOL unicode)
4458 LPCWSTR name;
4459 WCHAR DriverName[100];
4460 DWORD ret, type, size, needed = 0;
4461 LPBYTE ptr = NULL;
4462 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
4464 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter,debugstr_w(pEnvironment),
4465 Level,pDriverInfo,cbBuf, pcbNeeded);
4467 ZeroMemory(pDriverInfo, cbBuf);
4469 if (!(name = get_opened_printer_name(hPrinter))) {
4470 SetLastError(ERROR_INVALID_HANDLE);
4471 return FALSE;
4473 if(Level < 1 || Level > 6) {
4474 SetLastError(ERROR_INVALID_LEVEL);
4475 return FALSE;
4477 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, PrintersW, &hkeyPrinters) !=
4478 ERROR_SUCCESS) {
4479 ERR("Can't create Printers key\n");
4480 return FALSE;
4482 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
4483 != ERROR_SUCCESS) {
4484 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
4485 RegCloseKey(hkeyPrinters);
4486 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
4487 return FALSE;
4489 size = sizeof(DriverName);
4490 DriverName[0] = 0;
4491 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
4492 (LPBYTE)DriverName, &size);
4493 RegCloseKey(hkeyPrinter);
4494 RegCloseKey(hkeyPrinters);
4495 if(ret != ERROR_SUCCESS) {
4496 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
4497 return FALSE;
4500 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
4501 if(!hkeyDrivers) {
4502 ERR("Can't create Drivers key\n");
4503 return FALSE;
4506 switch(Level) {
4507 case 1:
4508 size = sizeof(DRIVER_INFO_1W);
4509 break;
4510 case 2:
4511 size = sizeof(DRIVER_INFO_2W);
4512 break;
4513 case 3:
4514 size = sizeof(DRIVER_INFO_3W);
4515 break;
4516 case 4:
4517 size = sizeof(DRIVER_INFO_4W);
4518 break;
4519 case 5:
4520 size = sizeof(DRIVER_INFO_5W);
4521 break;
4522 case 6:
4523 size = sizeof(DRIVER_INFO_6W);
4524 break;
4525 default:
4526 ERR("Invalid level\n");
4527 return FALSE;
4530 if(size <= cbBuf)
4531 ptr = pDriverInfo + size;
4533 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
4534 pEnvironment, Level, pDriverInfo,
4535 (cbBuf < size) ? NULL : ptr,
4536 (cbBuf < size) ? 0 : cbBuf - size,
4537 &needed, unicode)) {
4538 RegCloseKey(hkeyDrivers);
4539 return FALSE;
4542 RegCloseKey(hkeyDrivers);
4544 if(pcbNeeded) *pcbNeeded = size + needed;
4545 TRACE("buffer space %d required %d\n", cbBuf, size + needed);
4546 if(cbBuf >= needed) return TRUE;
4547 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4548 return FALSE;
4551 /*****************************************************************************
4552 * GetPrinterDriverA [WINSPOOL.@]
4554 BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment,
4555 DWORD Level, LPBYTE pDriverInfo,
4556 DWORD cbBuf, LPDWORD pcbNeeded)
4558 BOOL ret;
4559 UNICODE_STRING pEnvW;
4560 PWSTR pwstrEnvW;
4562 pwstrEnvW = asciitounicode(&pEnvW, pEnvironment);
4563 ret = WINSPOOL_GetPrinterDriver(hPrinter, pwstrEnvW, Level, pDriverInfo,
4564 cbBuf, pcbNeeded, FALSE);
4565 RtlFreeUnicodeString(&pEnvW);
4566 return ret;
4568 /*****************************************************************************
4569 * GetPrinterDriverW [WINSPOOL.@]
4571 BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment,
4572 DWORD Level, LPBYTE pDriverInfo,
4573 DWORD cbBuf, LPDWORD pcbNeeded)
4575 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level,
4576 pDriverInfo, cbBuf, pcbNeeded, TRUE);
4579 /*****************************************************************************
4580 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4582 * Return the PATH for the Printer-Drivers (UNICODE)
4584 * PARAMS
4585 * pName [I] Servername (NT only) or NULL (local Computer)
4586 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4587 * Level [I] Structure-Level (must be 1)
4588 * pDriverDirectory [O] PTR to Buffer that receives the Result
4589 * cbBuf [I] Size of Buffer at pDriverDirectory
4590 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4591 * required for pDriverDirectory
4593 * RETURNS
4594 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4595 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4596 * if cbBuf is too small
4598 * Native Values returned in pDriverDirectory on Success:
4599 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4600 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4601 *| win9x(Windows 4.0): "%winsysdir%"
4603 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4605 * FIXME
4606 *- Only NULL or "" is supported for pName
4609 BOOL WINAPI GetPrinterDriverDirectoryW(LPWSTR pName, LPWSTR pEnvironment,
4610 DWORD Level, LPBYTE pDriverDirectory,
4611 DWORD cbBuf, LPDWORD pcbNeeded)
4613 DWORD needed;
4614 const printenv_t * env;
4616 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
4617 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4618 if(pName != NULL && pName[0]) {
4619 FIXME("pName unsupported: %s\n", debugstr_w(pName));
4620 SetLastError(ERROR_INVALID_PARAMETER);
4621 return FALSE;
4624 env = validate_envW(pEnvironment);
4625 if(!env) return FALSE; /* pEnvironment invalid or unsupported */
4627 if(Level != 1) {
4628 WARN("(Level: %d) is ignored in win9x\n", Level);
4629 SetLastError(ERROR_INVALID_LEVEL);
4630 return FALSE;
4633 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4634 needed = GetSystemDirectoryW(NULL, 0);
4635 /* add the Size for the Subdirectories */
4636 needed += lstrlenW(spooldriversW);
4637 needed += lstrlenW(env->subdir);
4638 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
4640 if(pcbNeeded)
4641 *pcbNeeded = needed;
4642 TRACE("required: 0x%x/%d\n", needed, needed);
4643 if(needed > cbBuf) {
4644 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4645 return FALSE;
4647 if(pcbNeeded == NULL) {
4648 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4649 SetLastError(RPC_X_NULL_REF_POINTER);
4650 return FALSE;
4652 if(pDriverDirectory == NULL) {
4653 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4654 SetLastError(ERROR_INVALID_USER_BUFFER);
4655 return FALSE;
4658 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
4659 /* add the Subdirectories */
4660 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
4661 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
4662 TRACE(" => %s\n", debugstr_w((LPWSTR) pDriverDirectory));
4663 return TRUE;
4667 /*****************************************************************************
4668 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4670 * Return the PATH for the Printer-Drivers (ANSI)
4672 * See GetPrinterDriverDirectoryW.
4674 * NOTES
4675 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4678 BOOL WINAPI GetPrinterDriverDirectoryA(LPSTR pName, LPSTR pEnvironment,
4679 DWORD Level, LPBYTE pDriverDirectory,
4680 DWORD cbBuf, LPDWORD pcbNeeded)
4682 UNICODE_STRING nameW, environmentW;
4683 BOOL ret;
4684 DWORD pcbNeededW;
4685 INT len = cbBuf * sizeof(WCHAR)/sizeof(CHAR);
4686 WCHAR *driverDirectoryW = NULL;
4688 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName),
4689 debugstr_a(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
4691 if (len) driverDirectoryW = HeapAlloc( GetProcessHeap(), 0, len );
4693 if(pName) RtlCreateUnicodeStringFromAsciiz(&nameW, pName);
4694 else nameW.Buffer = NULL;
4695 if(pEnvironment) RtlCreateUnicodeStringFromAsciiz(&environmentW, pEnvironment);
4696 else environmentW.Buffer = NULL;
4698 ret = GetPrinterDriverDirectoryW( nameW.Buffer, environmentW.Buffer, Level,
4699 (LPBYTE)driverDirectoryW, len, &pcbNeededW );
4700 if (ret) {
4701 DWORD needed;
4702 needed = WideCharToMultiByte( CP_ACP, 0, driverDirectoryW, -1,
4703 (LPSTR)pDriverDirectory, cbBuf, NULL, NULL);
4704 if(pcbNeeded)
4705 *pcbNeeded = needed;
4706 ret = (needed <= cbBuf) ? TRUE : FALSE;
4707 } else
4708 if(pcbNeeded) *pcbNeeded = pcbNeededW * sizeof(CHAR)/sizeof(WCHAR);
4710 TRACE("required: 0x%x/%d\n", pcbNeeded ? *pcbNeeded : 0, pcbNeeded ? *pcbNeeded : 0);
4712 HeapFree( GetProcessHeap(), 0, driverDirectoryW );
4713 RtlFreeUnicodeString(&environmentW);
4714 RtlFreeUnicodeString(&nameW);
4716 return ret;
4719 /*****************************************************************************
4720 * AddPrinterDriverA [WINSPOOL.@]
4722 BOOL WINAPI AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
4724 DRIVER_INFO_3A di3;
4725 HKEY hkeyDrivers, hkeyName;
4726 static CHAR empty[] = "",
4727 nullnull[] = "\0";
4729 TRACE("(%s,%d,%p)\n",debugstr_a(pName),level,pDriverInfo);
4731 if(level != 2 && level != 3) {
4732 SetLastError(ERROR_INVALID_LEVEL);
4733 return FALSE;
4735 if ((pName) && (pName[0])) {
4736 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
4737 SetLastError(ERROR_INVALID_PARAMETER);
4738 return FALSE;
4740 if(!pDriverInfo) {
4741 WARN("pDriverInfo == NULL\n");
4742 SetLastError(ERROR_INVALID_PARAMETER);
4743 return FALSE;
4746 if(level == 3)
4747 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
4748 else {
4749 memset(&di3, 0, sizeof(di3));
4750 memcpy(&di3, pDriverInfo, sizeof(DRIVER_INFO_2A));
4753 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
4754 !di3.pDataFile) {
4755 SetLastError(ERROR_INVALID_PARAMETER);
4756 return FALSE;
4759 if(!di3.pDefaultDataType) di3.pDefaultDataType = empty;
4760 if(!di3.pDependentFiles) di3.pDependentFiles = nullnull;
4761 if(!di3.pHelpFile) di3.pHelpFile = empty;
4762 if(!di3.pMonitorName) di3.pMonitorName = empty;
4764 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
4766 if(!hkeyDrivers) {
4767 ERR("Can't create Drivers key\n");
4768 return FALSE;
4771 if(level == 2) { /* apparently can't overwrite with level2 */
4772 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
4773 RegCloseKey(hkeyName);
4774 RegCloseKey(hkeyDrivers);
4775 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
4776 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
4777 return FALSE;
4780 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
4781 RegCloseKey(hkeyDrivers);
4782 ERR("Can't create Name key\n");
4783 return FALSE;
4785 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE) di3.pConfigFile,
4786 lstrlenA(di3.pConfigFile) + 1);
4787 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE) di3.pDataFile, lstrlenA(di3.pDataFile) + 1);
4788 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE) di3.pDriverPath, lstrlenA(di3.pDriverPath) + 1);
4789 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE) &di3.cVersion,
4790 sizeof(DWORD));
4791 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE) di3.pDefaultDataType, lstrlenA(di3.pDefaultDataType));
4792 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
4793 (LPBYTE) di3.pDependentFiles, multi_sz_lenA(di3.pDependentFiles));
4794 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE) di3.pHelpFile, lstrlenA(di3.pHelpFile) + 1);
4795 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE) di3.pMonitorName, lstrlenA(di3.pMonitorName) + 1);
4796 RegCloseKey(hkeyName);
4797 RegCloseKey(hkeyDrivers);
4799 return TRUE;
4802 /*****************************************************************************
4803 * AddPrinterDriverW [WINSPOOL.@]
4805 BOOL WINAPI AddPrinterDriverW(LPWSTR printerName,DWORD level,
4806 LPBYTE pDriverInfo)
4808 FIXME("(%s,%d,%p): stub\n",debugstr_w(printerName),
4809 level,pDriverInfo);
4810 return FALSE;
4813 /*****************************************************************************
4814 * AddPrintProcessorA [WINSPOOL.@]
4816 BOOL WINAPI AddPrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPathName,
4817 LPSTR pPrintProcessorName)
4819 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName), debugstr_a(pEnvironment),
4820 debugstr_a(pPathName), debugstr_a(pPrintProcessorName));
4821 return FALSE;
4824 /*****************************************************************************
4825 * AddPrintProcessorW [WINSPOOL.@]
4827 BOOL WINAPI AddPrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPathName,
4828 LPWSTR pPrintProcessorName)
4830 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName), debugstr_w(pEnvironment),
4831 debugstr_w(pPathName), debugstr_w(pPrintProcessorName));
4832 return FALSE;
4835 /*****************************************************************************
4836 * AddPrintProvidorA [WINSPOOL.@]
4838 BOOL WINAPI AddPrintProvidorA(LPSTR pName, DWORD Level, LPBYTE pProviderInfo)
4840 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName), Level, pProviderInfo);
4841 return FALSE;
4844 /*****************************************************************************
4845 * AddPrintProvidorW [WINSPOOL.@]
4847 BOOL WINAPI AddPrintProvidorW(LPWSTR pName, DWORD Level, LPBYTE pProviderInfo)
4849 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName), Level, pProviderInfo);
4850 return FALSE;
4853 /*****************************************************************************
4854 * AdvancedDocumentPropertiesA [WINSPOOL.@]
4856 LONG WINAPI AdvancedDocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName,
4857 PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput)
4859 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_a(pDeviceName),
4860 pDevModeOutput, pDevModeInput);
4861 return 0;
4864 /*****************************************************************************
4865 * AdvancedDocumentPropertiesW [WINSPOOL.@]
4867 LONG WINAPI AdvancedDocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName,
4868 PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput)
4870 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd, hPrinter, debugstr_w(pDeviceName),
4871 pDevModeOutput, pDevModeInput);
4872 return 0;
4875 /*****************************************************************************
4876 * PrinterProperties [WINSPOOL.@]
4878 * Displays a dialog to set the properties of the printer.
4880 * RETURNS
4881 * nonzero on success or zero on failure
4883 * BUGS
4884 * implemented as stub only
4886 BOOL WINAPI PrinterProperties(HWND hWnd, /* [in] handle to parent window */
4887 HANDLE hPrinter /* [in] handle to printer object */
4889 FIXME("(%p,%p): stub\n", hWnd, hPrinter);
4890 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4891 return FALSE;
4894 /*****************************************************************************
4895 * EnumJobsA [WINSPOOL.@]
4898 BOOL WINAPI EnumJobsA(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4899 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4900 LPDWORD pcReturned)
4902 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4903 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4905 if(pcbNeeded) *pcbNeeded = 0;
4906 if(pcReturned) *pcReturned = 0;
4907 return FALSE;
4911 /*****************************************************************************
4912 * EnumJobsW [WINSPOOL.@]
4915 BOOL WINAPI EnumJobsW(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs,
4916 DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded,
4917 LPDWORD pcReturned)
4919 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
4920 hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf, pcbNeeded, pcReturned
4922 if(pcbNeeded) *pcbNeeded = 0;
4923 if(pcReturned) *pcReturned = 0;
4924 return FALSE;
4927 /*****************************************************************************
4928 * WINSPOOL_EnumPrinterDrivers [internal]
4930 * Delivers information about all printer drivers installed on the
4931 * localhost or a given server
4933 * RETURNS
4934 * nonzero on success or zero on failure. If the buffer for the returned
4935 * information is too small the function will return an error
4937 * BUGS
4938 * - only implemented for localhost, foreign hosts will return an error
4940 static BOOL WINSPOOL_EnumPrinterDrivers(LPWSTR pName, LPCWSTR pEnvironment,
4941 DWORD Level, LPBYTE pDriverInfo,
4942 DWORD cbBuf, LPDWORD pcbNeeded,
4943 LPDWORD pcReturned, BOOL unicode)
4945 { HKEY hkeyDrivers;
4946 DWORD i, needed, number = 0, size = 0;
4947 WCHAR DriverNameW[255];
4948 PBYTE ptr;
4950 TRACE("%s,%s,%d,%p,%d,%d\n",
4951 debugstr_w(pName), debugstr_w(pEnvironment),
4952 Level, pDriverInfo, cbBuf, unicode);
4954 /* check for local drivers */
4955 if((pName) && (pName[0])) {
4956 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName));
4957 SetLastError(ERROR_ACCESS_DENIED);
4958 return FALSE;
4961 /* check input parameter */
4962 if((Level < 1) || (Level > 3)) {
4963 ERR("unsupported level %d\n", Level);
4964 SetLastError(ERROR_INVALID_LEVEL);
4965 return FALSE;
4968 /* initialize return values */
4969 if(pDriverInfo)
4970 memset( pDriverInfo, 0, cbBuf);
4971 *pcbNeeded = 0;
4972 *pcReturned = 0;
4974 hkeyDrivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
4975 if(!hkeyDrivers) {
4976 ERR("Can't open Drivers key\n");
4977 return FALSE;
4980 if(RegQueryInfoKeyA(hkeyDrivers, NULL, NULL, NULL, &number, NULL, NULL,
4981 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
4982 RegCloseKey(hkeyDrivers);
4983 ERR("Can't query Drivers key\n");
4984 return FALSE;
4986 TRACE("Found %d Drivers\n", number);
4988 /* get size of single struct
4989 * unicode and ascii structure have the same size
4991 switch (Level) {
4992 case 1:
4993 size = sizeof(DRIVER_INFO_1A);
4994 break;
4995 case 2:
4996 size = sizeof(DRIVER_INFO_2A);
4997 break;
4998 case 3:
4999 size = sizeof(DRIVER_INFO_3A);
5000 break;
5003 /* calculate required buffer size */
5004 *pcbNeeded = size * number;
5006 for( i = 0, ptr = (pDriverInfo && (cbBuf >= size)) ? pDriverInfo : NULL ;
5007 i < number;
5008 i++, ptr = (ptr && (cbBuf >= size * i)) ? ptr + size : NULL) {
5009 if(RegEnumKeyW(hkeyDrivers, i, DriverNameW, sizeof(DriverNameW))
5010 != ERROR_SUCCESS) {
5011 ERR("Can't enum key number %d\n", i);
5012 RegCloseKey(hkeyDrivers);
5013 return FALSE;
5015 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverNameW,
5016 pEnvironment, Level, ptr,
5017 (cbBuf < *pcbNeeded) ? NULL : pDriverInfo + *pcbNeeded,
5018 (cbBuf < *pcbNeeded) ? 0 : cbBuf - *pcbNeeded,
5019 &needed, unicode)) {
5020 RegCloseKey(hkeyDrivers);
5021 return FALSE;
5023 (*pcbNeeded) += needed;
5026 RegCloseKey(hkeyDrivers);
5028 if(cbBuf < *pcbNeeded){
5029 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5030 return FALSE;
5033 *pcReturned = number;
5034 return TRUE;
5037 /*****************************************************************************
5038 * EnumPrinterDriversW [WINSPOOL.@]
5040 * see function EnumPrinterDrivers for RETURNS, BUGS
5042 BOOL WINAPI EnumPrinterDriversW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
5043 LPBYTE pDriverInfo, DWORD cbBuf,
5044 LPDWORD pcbNeeded, LPDWORD pcReturned)
5046 return WINSPOOL_EnumPrinterDrivers(pName, pEnvironment, Level, pDriverInfo,
5047 cbBuf, pcbNeeded, pcReturned, TRUE);
5050 /*****************************************************************************
5051 * EnumPrinterDriversA [WINSPOOL.@]
5053 * see function EnumPrinterDrivers for RETURNS, BUGS
5055 BOOL WINAPI EnumPrinterDriversA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
5056 LPBYTE pDriverInfo, DWORD cbBuf,
5057 LPDWORD pcbNeeded, LPDWORD pcReturned)
5058 { BOOL ret;
5059 UNICODE_STRING pNameW, pEnvironmentW;
5060 PWSTR pwstrNameW, pwstrEnvironmentW;
5062 pwstrNameW = asciitounicode(&pNameW, pName);
5063 pwstrEnvironmentW = asciitounicode(&pEnvironmentW, pEnvironment);
5065 ret = WINSPOOL_EnumPrinterDrivers(pwstrNameW, pwstrEnvironmentW,
5066 Level, pDriverInfo, cbBuf, pcbNeeded,
5067 pcReturned, FALSE);
5068 RtlFreeUnicodeString(&pNameW);
5069 RtlFreeUnicodeString(&pEnvironmentW);
5071 return ret;
5074 /******************************************************************************
5075 * EnumPortsA (WINSPOOL.@)
5077 * See EnumPortsW.
5080 BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
5081 LPDWORD pcbNeeded, LPDWORD pcReturned)
5083 BOOL res;
5084 LPBYTE bufferW = NULL;
5085 LPWSTR nameW = NULL;
5086 DWORD needed = 0;
5087 DWORD numentries = 0;
5088 INT len;
5090 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
5091 cbBuf, pcbNeeded, pcReturned);
5093 /* convert servername to unicode */
5094 if (pName) {
5095 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
5096 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
5097 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
5099 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5100 needed = cbBuf * sizeof(WCHAR);
5101 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
5102 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5104 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
5105 if (pcbNeeded) needed = *pcbNeeded;
5106 /* HeapReAlloc return NULL, when bufferW was NULL */
5107 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
5108 HeapAlloc(GetProcessHeap(), 0, needed);
5110 /* Try again with the large Buffer */
5111 res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
5113 needed = pcbNeeded ? *pcbNeeded : 0;
5114 numentries = pcReturned ? *pcReturned : 0;
5117 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5118 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5120 if (res) {
5121 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5122 DWORD entrysize = 0;
5123 DWORD index;
5124 LPSTR ptr;
5125 LPPORT_INFO_2W pi2w;
5126 LPPORT_INFO_2A pi2a;
5128 needed = 0;
5129 entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
5131 /* First pass: calculate the size for all Entries */
5132 pi2w = (LPPORT_INFO_2W) bufferW;
5133 pi2a = (LPPORT_INFO_2A) pPorts;
5134 index = 0;
5135 while (index < numentries) {
5136 index++;
5137 needed += entrysize; /* PORT_INFO_?A */
5138 TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
5140 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5141 NULL, 0, NULL, NULL);
5142 if (Level > 1) {
5143 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5144 NULL, 0, NULL, NULL);
5145 needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5146 NULL, 0, NULL, NULL);
5148 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5149 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5150 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5153 /* check for errors and quit on failure */
5154 if (cbBuf < needed) {
5155 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5156 res = FALSE;
5157 goto cleanup;
5159 len = entrysize * numentries; /* room for all PORT_INFO_?A */
5160 ptr = (LPSTR) &pPorts[len]; /* room for strings */
5161 cbBuf -= len ; /* free Bytes in the user-Buffer */
5162 pi2w = (LPPORT_INFO_2W) bufferW;
5163 pi2a = (LPPORT_INFO_2A) pPorts;
5164 index = 0;
5165 /* Second Pass: Fill the User Buffer (if we have one) */
5166 while ((index < numentries) && pPorts) {
5167 index++;
5168 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
5169 pi2a->pPortName = ptr;
5170 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
5171 ptr, cbBuf , NULL, NULL);
5172 ptr += len;
5173 cbBuf -= len;
5174 if (Level > 1) {
5175 pi2a->pMonitorName = ptr;
5176 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
5177 ptr, cbBuf, NULL, NULL);
5178 ptr += len;
5179 cbBuf -= len;
5181 pi2a->pDescription = ptr;
5182 len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
5183 ptr, cbBuf, NULL, NULL);
5184 ptr += len;
5185 cbBuf -= len;
5187 pi2a->fPortType = pi2w->fPortType;
5188 pi2a->Reserved = 0; /* documented: "must be zero" */
5191 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5192 pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
5193 pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
5197 cleanup:
5198 if (pcbNeeded) *pcbNeeded = needed;
5199 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5201 HeapFree(GetProcessHeap(), 0, nameW);
5202 HeapFree(GetProcessHeap(), 0, bufferW);
5204 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5205 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5207 return (res);
5211 /******************************************************************************
5212 * EnumPortsW (WINSPOOL.@)
5214 * Enumerate available Ports
5216 * PARAMS
5217 * name [I] Servername or NULL (local Computer)
5218 * level [I] Structure-Level (1 or 2)
5219 * buffer [O] PTR to Buffer that receives the Result
5220 * bufsize [I] Size of Buffer at buffer
5221 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5222 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5224 * RETURNS
5225 * Success: TRUE
5226 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5230 BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
5232 DWORD needed = 0;
5233 DWORD numentries = 0;
5234 BOOL res = FALSE;
5236 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
5237 cbBuf, pcbNeeded, pcReturned);
5239 if (pName && (pName[0])) {
5240 FIXME("not implemented for Server %s\n", debugstr_w(pName));
5241 SetLastError(ERROR_ACCESS_DENIED);
5242 goto emP_cleanup;
5245 /* Level is not checked in win9x */
5246 if (!Level || (Level > 2)) {
5247 WARN("level (%d) is ignored in win9x\n", Level);
5248 SetLastError(ERROR_INVALID_LEVEL);
5249 goto emP_cleanup;
5251 if (!pcbNeeded) {
5252 SetLastError(RPC_X_NULL_REF_POINTER);
5253 goto emP_cleanup;
5256 EnterCriticalSection(&monitor_handles_cs);
5257 monitor_loadall();
5259 /* Scan all local Ports */
5260 numentries = 0;
5261 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
5263 /* we calculated the needed buffersize. now do the error-checks */
5264 if (cbBuf < needed) {
5265 monitor_unloadall();
5266 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5267 goto emP_cleanup_cs;
5269 else if (!pPorts || !pcReturned) {
5270 monitor_unloadall();
5271 SetLastError(RPC_X_NULL_REF_POINTER);
5272 goto emP_cleanup_cs;
5275 /* Fill the Buffer */
5276 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
5277 res = TRUE;
5278 monitor_unloadall();
5280 emP_cleanup_cs:
5281 LeaveCriticalSection(&monitor_handles_cs);
5283 emP_cleanup:
5284 if (pcbNeeded) *pcbNeeded = needed;
5285 if (pcReturned) *pcReturned = (res) ? numentries : 0;
5287 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5288 (res), GetLastError(), needed, (res)? numentries : 0, numentries);
5290 return (res);
5293 /******************************************************************************
5294 * GetDefaultPrinterW (WINSPOOL.@)
5296 * FIXME
5297 * This function must read the value from data 'device' of key
5298 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5300 BOOL WINAPI GetDefaultPrinterW(LPWSTR name, LPDWORD namesize)
5302 BOOL retval = TRUE;
5303 DWORD insize, len;
5304 WCHAR *buffer, *ptr;
5306 if (!namesize)
5308 SetLastError(ERROR_INVALID_PARAMETER);
5309 return FALSE;
5312 /* make the buffer big enough for the stuff from the profile/registry,
5313 * the content must fit into the local buffer to compute the correct
5314 * size even if the extern buffer is too small or not given.
5315 * (20 for ,driver,port) */
5316 insize = *namesize;
5317 len = max(100, (insize + 20));
5318 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR));
5320 if (!GetProfileStringW(windowsW, deviceW, emptyStringW, buffer, len))
5322 SetLastError (ERROR_FILE_NOT_FOUND);
5323 retval = FALSE;
5324 goto end;
5326 TRACE("%s\n", debugstr_w(buffer));
5328 if ((ptr = strchrW(buffer, ',')) == NULL)
5330 SetLastError(ERROR_INVALID_NAME);
5331 retval = FALSE;
5332 goto end;
5335 *ptr = 0;
5336 *namesize = strlenW(buffer) + 1;
5337 if(!name || (*namesize > insize))
5339 SetLastError(ERROR_INSUFFICIENT_BUFFER);
5340 retval = FALSE;
5341 goto end;
5343 strcpyW(name, buffer);
5345 end:
5346 HeapFree( GetProcessHeap(), 0, buffer);
5347 return retval;
5351 /******************************************************************************
5352 * GetDefaultPrinterA (WINSPOOL.@)
5354 BOOL WINAPI GetDefaultPrinterA(LPSTR name, LPDWORD namesize)
5356 BOOL retval = TRUE;
5357 DWORD insize = 0;
5358 WCHAR *bufferW = NULL;
5360 if (!namesize)
5362 SetLastError(ERROR_INVALID_PARAMETER);
5363 return FALSE;
5366 if(name && *namesize) {
5367 insize = *namesize;
5368 bufferW = HeapAlloc( GetProcessHeap(), 0, insize * sizeof(WCHAR));
5371 if(!GetDefaultPrinterW( bufferW, namesize)) {
5372 retval = FALSE;
5373 goto end;
5376 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, name, insize,
5377 NULL, NULL);
5378 if (!*namesize)
5380 *namesize = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
5381 retval = FALSE;
5383 TRACE("0x%08x/0x%08x:%s\n", *namesize, insize, debugstr_w(bufferW));
5385 end:
5386 HeapFree( GetProcessHeap(), 0, bufferW);
5387 return retval;
5391 /******************************************************************************
5392 * SetDefaultPrinterW (WINSPOOL.204)
5394 * Set the Name of the Default Printer
5396 * PARAMS
5397 * pszPrinter [I] Name of the Printer or NULL
5399 * RETURNS
5400 * Success: True
5401 * Failure: FALSE
5403 * NOTES
5404 * When the Parameter is NULL or points to an Empty String and
5405 * a Default Printer was already present, then this Function changes nothing.
5406 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5407 * the First enumerated local Printer is used.
5410 BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
5413 TRACE("(%s)\n", debugstr_w(pszPrinter));
5415 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5416 return FALSE;
5419 /******************************************************************************
5420 * SetDefaultPrinterA (WINSPOOL.202)
5422 * See SetDefaultPrinterW.
5425 BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
5428 TRACE("(%s)\n", debugstr_a(pszPrinter));
5430 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
5431 return FALSE;
5435 /******************************************************************************
5436 * SetPrinterDataExA (WINSPOOL.@)
5438 DWORD WINAPI SetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5439 LPCSTR pValueName, DWORD Type,
5440 LPBYTE pData, DWORD cbData)
5442 HKEY hkeyPrinter, hkeySubkey;
5443 DWORD ret;
5445 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_a(pKeyName),
5446 debugstr_a(pValueName), Type, pData, cbData);
5448 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5449 != ERROR_SUCCESS)
5450 return ret;
5452 if((ret = RegCreateKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5453 != ERROR_SUCCESS) {
5454 ERR("Can't create subkey %s\n", debugstr_a(pKeyName));
5455 RegCloseKey(hkeyPrinter);
5456 return ret;
5458 ret = RegSetValueExA(hkeySubkey, pValueName, 0, Type, pData, cbData);
5459 RegCloseKey(hkeySubkey);
5460 RegCloseKey(hkeyPrinter);
5461 return ret;
5464 /******************************************************************************
5465 * SetPrinterDataExW (WINSPOOL.@)
5467 DWORD WINAPI SetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5468 LPCWSTR pValueName, DWORD Type,
5469 LPBYTE pData, DWORD cbData)
5471 HKEY hkeyPrinter, hkeySubkey;
5472 DWORD ret;
5474 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter, debugstr_w(pKeyName),
5475 debugstr_w(pValueName), Type, pData, cbData);
5477 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5478 != ERROR_SUCCESS)
5479 return ret;
5481 if((ret = RegCreateKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5482 != ERROR_SUCCESS) {
5483 ERR("Can't create subkey %s\n", debugstr_w(pKeyName));
5484 RegCloseKey(hkeyPrinter);
5485 return ret;
5487 ret = RegSetValueExW(hkeySubkey, pValueName, 0, Type, pData, cbData);
5488 RegCloseKey(hkeySubkey);
5489 RegCloseKey(hkeyPrinter);
5490 return ret;
5493 /******************************************************************************
5494 * SetPrinterDataA (WINSPOOL.@)
5496 DWORD WINAPI SetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, DWORD Type,
5497 LPBYTE pData, DWORD cbData)
5499 return SetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, Type,
5500 pData, cbData);
5503 /******************************************************************************
5504 * SetPrinterDataW (WINSPOOL.@)
5506 DWORD WINAPI SetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, DWORD Type,
5507 LPBYTE pData, DWORD cbData)
5509 return SetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, Type,
5510 pData, cbData);
5513 /******************************************************************************
5514 * GetPrinterDataExA (WINSPOOL.@)
5516 DWORD WINAPI GetPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5517 LPCSTR pValueName, LPDWORD pType,
5518 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5520 HKEY hkeyPrinter, hkeySubkey;
5521 DWORD ret;
5523 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5524 debugstr_a(pKeyName), debugstr_a(pValueName), pType, pData, nSize,
5525 pcbNeeded);
5527 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5528 != ERROR_SUCCESS)
5529 return ret;
5531 if((ret = RegOpenKeyA(hkeyPrinter, pKeyName, &hkeySubkey))
5532 != ERROR_SUCCESS) {
5533 WARN("Can't open subkey %s\n", debugstr_a(pKeyName));
5534 RegCloseKey(hkeyPrinter);
5535 return ret;
5537 *pcbNeeded = nSize;
5538 ret = RegQueryValueExA(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5539 RegCloseKey(hkeySubkey);
5540 RegCloseKey(hkeyPrinter);
5541 return ret;
5544 /******************************************************************************
5545 * GetPrinterDataExW (WINSPOOL.@)
5547 DWORD WINAPI GetPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5548 LPCWSTR pValueName, LPDWORD pType,
5549 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5551 HKEY hkeyPrinter, hkeySubkey;
5552 DWORD ret;
5554 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter,
5555 debugstr_w(pKeyName), debugstr_w(pValueName), pType, pData, nSize,
5556 pcbNeeded);
5558 if((ret = WINSPOOL_GetOpenedPrinterRegKey(hPrinter, &hkeyPrinter))
5559 != ERROR_SUCCESS)
5560 return ret;
5562 if((ret = RegOpenKeyW(hkeyPrinter, pKeyName, &hkeySubkey))
5563 != ERROR_SUCCESS) {
5564 WARN("Can't open subkey %s\n", debugstr_w(pKeyName));
5565 RegCloseKey(hkeyPrinter);
5566 return ret;
5568 *pcbNeeded = nSize;
5569 ret = RegQueryValueExW(hkeySubkey, pValueName, 0, pType, pData, pcbNeeded);
5570 RegCloseKey(hkeySubkey);
5571 RegCloseKey(hkeyPrinter);
5572 return ret;
5575 /******************************************************************************
5576 * GetPrinterDataA (WINSPOOL.@)
5578 DWORD WINAPI GetPrinterDataA(HANDLE hPrinter, LPSTR pValueName, LPDWORD pType,
5579 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5581 return GetPrinterDataExA(hPrinter, "PrinterDriverData", pValueName, pType,
5582 pData, nSize, pcbNeeded);
5585 /******************************************************************************
5586 * GetPrinterDataW (WINSPOOL.@)
5588 DWORD WINAPI GetPrinterDataW(HANDLE hPrinter, LPWSTR pValueName, LPDWORD pType,
5589 LPBYTE pData, DWORD nSize, LPDWORD pcbNeeded)
5591 return GetPrinterDataExW(hPrinter, PrinterDriverDataW, pValueName, pType,
5592 pData, nSize, pcbNeeded);
5595 /*******************************************************************************
5596 * EnumPrinterDataExW [WINSPOOL.@]
5598 DWORD WINAPI EnumPrinterDataExW(HANDLE hPrinter, LPCWSTR pKeyName,
5599 LPBYTE pEnumValues, DWORD cbEnumValues,
5600 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5602 HKEY hkPrinter, hkSubKey;
5603 DWORD r, ret, dwIndex, cValues, cbMaxValueNameLen,
5604 cbValueNameLen, cbMaxValueLen, cbValueLen,
5605 cbBufSize, dwType;
5606 LPWSTR lpValueName;
5607 HANDLE hHeap;
5608 PBYTE lpValue;
5609 PPRINTER_ENUM_VALUESW ppev;
5611 TRACE ("%p %s\n", hPrinter, debugstr_w (pKeyName));
5613 if (pKeyName == NULL || *pKeyName == 0)
5614 return ERROR_INVALID_PARAMETER;
5616 ret = WINSPOOL_GetOpenedPrinterRegKey (hPrinter, &hkPrinter);
5617 if (ret != ERROR_SUCCESS)
5619 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5620 hPrinter, ret);
5621 return ret;
5624 ret = RegOpenKeyExW (hkPrinter, pKeyName, 0, KEY_READ, &hkSubKey);
5625 if (ret != ERROR_SUCCESS)
5627 r = RegCloseKey (hkPrinter);
5628 if (r != ERROR_SUCCESS)
5629 WARN ("RegCloseKey returned %i\n", r);
5630 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter,
5631 debugstr_w (pKeyName), ret);
5632 return ret;
5635 ret = RegCloseKey (hkPrinter);
5636 if (ret != ERROR_SUCCESS)
5638 ERR ("RegCloseKey returned %i\n", ret);
5639 r = RegCloseKey (hkSubKey);
5640 if (r != ERROR_SUCCESS)
5641 WARN ("RegCloseKey returned %i\n", r);
5642 return ret;
5645 ret = RegQueryInfoKeyW (hkSubKey, NULL, NULL, NULL, NULL, NULL, NULL,
5646 &cValues, &cbMaxValueNameLen, &cbMaxValueLen, NULL, NULL);
5647 if (ret != ERROR_SUCCESS)
5649 r = RegCloseKey (hkSubKey);
5650 if (r != ERROR_SUCCESS)
5651 WARN ("RegCloseKey returned %i\n", r);
5652 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey, ret);
5653 return ret;
5656 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5657 "cbMaxValueLen = %i\n", cValues, cbMaxValueNameLen, cbMaxValueLen);
5659 if (cValues == 0) /* empty key */
5661 r = RegCloseKey (hkSubKey);
5662 if (r != ERROR_SUCCESS)
5663 WARN ("RegCloseKey returned %i\n", r);
5664 *pcbEnumValues = *pnEnumValues = 0;
5665 return ERROR_SUCCESS;
5668 ++cbMaxValueNameLen; /* allow for trailing '\0' */
5670 hHeap = GetProcessHeap ();
5671 if (hHeap == NULL)
5673 ERR ("GetProcessHeap failed\n");
5674 r = RegCloseKey (hkSubKey);
5675 if (r != ERROR_SUCCESS)
5676 WARN ("RegCloseKey returned %i\n", r);
5677 return ERROR_OUTOFMEMORY;
5680 lpValueName = HeapAlloc (hHeap, 0, cbMaxValueNameLen * sizeof (WCHAR));
5681 if (lpValueName == NULL)
5683 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen);
5684 r = RegCloseKey (hkSubKey);
5685 if (r != ERROR_SUCCESS)
5686 WARN ("RegCloseKey returned %i\n", r);
5687 return ERROR_OUTOFMEMORY;
5690 lpValue = HeapAlloc (hHeap, 0, cbMaxValueLen);
5691 if (lpValue == NULL)
5693 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen);
5694 if (HeapFree (hHeap, 0, lpValueName) == 0)
5695 WARN ("HeapFree failed with code %i\n", GetLastError ());
5696 r = RegCloseKey (hkSubKey);
5697 if (r != ERROR_SUCCESS)
5698 WARN ("RegCloseKey returned %i\n", r);
5699 return ERROR_OUTOFMEMORY;
5702 TRACE ("pass 1: calculating buffer required for all names and values\n");
5704 cbBufSize = cValues * sizeof (PRINTER_ENUM_VALUESW);
5706 TRACE ("%i bytes required for %i headers\n", cbBufSize, cValues);
5708 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5710 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5711 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5712 NULL, NULL, lpValue, &cbValueLen);
5713 if (ret != ERROR_SUCCESS)
5715 if (HeapFree (hHeap, 0, lpValue) == 0)
5716 WARN ("HeapFree failed with code %i\n", GetLastError ());
5717 if (HeapFree (hHeap, 0, lpValueName) == 0)
5718 WARN ("HeapFree failed with code %i\n", GetLastError ());
5719 r = RegCloseKey (hkSubKey);
5720 if (r != ERROR_SUCCESS)
5721 WARN ("RegCloseKey returned %i\n", r);
5722 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5723 return ret;
5726 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5727 debugstr_w (lpValueName), dwIndex,
5728 cbValueNameLen + 1, cbValueLen);
5730 cbBufSize += (cbValueNameLen + 1) * sizeof (WCHAR);
5731 cbBufSize += cbValueLen;
5734 TRACE ("%i bytes required for all %i values\n", cbBufSize, cValues);
5736 *pcbEnumValues = cbBufSize;
5737 *pnEnumValues = cValues;
5739 if (cbEnumValues < cbBufSize) /* buffer too small */
5741 if (HeapFree (hHeap, 0, lpValue) == 0)
5742 WARN ("HeapFree failed with code %i\n", GetLastError ());
5743 if (HeapFree (hHeap, 0, lpValueName) == 0)
5744 WARN ("HeapFree failed with code %i\n", GetLastError ());
5745 r = RegCloseKey (hkSubKey);
5746 if (r != ERROR_SUCCESS)
5747 WARN ("RegCloseKey returned %i\n", r);
5748 TRACE ("%i byte buffer is not large enough\n", cbEnumValues);
5749 return ERROR_MORE_DATA;
5752 TRACE ("pass 2: copying all names and values to buffer\n");
5754 ppev = (PPRINTER_ENUM_VALUESW) pEnumValues; /* array of structs */
5755 pEnumValues += cValues * sizeof (PRINTER_ENUM_VALUESW);
5757 for (dwIndex = 0; dwIndex < cValues; ++dwIndex)
5759 cbValueNameLen = cbMaxValueNameLen; cbValueLen = cbMaxValueLen;
5760 ret = RegEnumValueW (hkSubKey, dwIndex, lpValueName, &cbValueNameLen,
5761 NULL, &dwType, lpValue, &cbValueLen);
5762 if (ret != ERROR_SUCCESS)
5764 if (HeapFree (hHeap, 0, lpValue) == 0)
5765 WARN ("HeapFree failed with code %i\n", GetLastError ());
5766 if (HeapFree (hHeap, 0, lpValueName) == 0)
5767 WARN ("HeapFree failed with code %i\n", GetLastError ());
5768 r = RegCloseKey (hkSubKey);
5769 if (r != ERROR_SUCCESS)
5770 WARN ("RegCloseKey returned %i\n", r);
5771 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex, ret);
5772 return ret;
5775 cbValueNameLen = (cbValueNameLen + 1) * sizeof (WCHAR);
5776 memcpy (pEnumValues, lpValueName, cbValueNameLen);
5777 ppev[dwIndex].pValueName = (LPWSTR) pEnumValues;
5778 pEnumValues += cbValueNameLen;
5780 /* return # of *bytes* (including trailing \0), not # of chars */
5781 ppev[dwIndex].cbValueName = cbValueNameLen;
5783 ppev[dwIndex].dwType = dwType;
5785 memcpy (pEnumValues, lpValue, cbValueLen);
5786 ppev[dwIndex].pData = pEnumValues;
5787 pEnumValues += cbValueLen;
5789 ppev[dwIndex].cbData = cbValueLen;
5791 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5792 debugstr_w (lpValueName), dwIndex, cbValueNameLen, cbValueLen);
5795 if (HeapFree (hHeap, 0, lpValue) == 0)
5797 ret = GetLastError ();
5798 ERR ("HeapFree failed with code %i\n", ret);
5799 if (HeapFree (hHeap, 0, lpValueName) == 0)
5800 WARN ("HeapFree failed with code %i\n", GetLastError ());
5801 r = RegCloseKey (hkSubKey);
5802 if (r != ERROR_SUCCESS)
5803 WARN ("RegCloseKey returned %i\n", r);
5804 return ret;
5807 if (HeapFree (hHeap, 0, lpValueName) == 0)
5809 ret = GetLastError ();
5810 ERR ("HeapFree failed with code %i\n", ret);
5811 r = RegCloseKey (hkSubKey);
5812 if (r != ERROR_SUCCESS)
5813 WARN ("RegCloseKey returned %i\n", r);
5814 return ret;
5817 ret = RegCloseKey (hkSubKey);
5818 if (ret != ERROR_SUCCESS)
5820 ERR ("RegCloseKey returned %i\n", ret);
5821 return ret;
5824 return ERROR_SUCCESS;
5827 /*******************************************************************************
5828 * EnumPrinterDataExA [WINSPOOL.@]
5830 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
5831 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
5832 * what Windows 2000 SP1 does.
5835 DWORD WINAPI EnumPrinterDataExA(HANDLE hPrinter, LPCSTR pKeyName,
5836 LPBYTE pEnumValues, DWORD cbEnumValues,
5837 LPDWORD pcbEnumValues, LPDWORD pnEnumValues)
5839 INT len;
5840 LPWSTR pKeyNameW;
5841 DWORD ret, dwIndex, dwBufSize;
5842 HANDLE hHeap;
5843 LPSTR pBuffer;
5845 TRACE ("%p %s\n", hPrinter, pKeyName);
5847 if (pKeyName == NULL || *pKeyName == 0)
5848 return ERROR_INVALID_PARAMETER;
5850 len = MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, NULL, 0);
5851 if (len == 0)
5853 ret = GetLastError ();
5854 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5855 return ret;
5858 hHeap = GetProcessHeap ();
5859 if (hHeap == NULL)
5861 ERR ("GetProcessHeap failed\n");
5862 return ERROR_OUTOFMEMORY;
5865 pKeyNameW = HeapAlloc (hHeap, 0, len * sizeof (WCHAR));
5866 if (pKeyNameW == NULL)
5868 ERR ("Failed to allocate %i bytes from process heap\n",
5869 (LONG)(len * sizeof (WCHAR)));
5870 return ERROR_OUTOFMEMORY;
5873 if (MultiByteToWideChar (CP_ACP, 0, pKeyName, -1, pKeyNameW, len) == 0)
5875 ret = GetLastError ();
5876 ERR ("MultiByteToWideChar failed with code %i\n", ret);
5877 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5878 WARN ("HeapFree failed with code %i\n", GetLastError ());
5879 return ret;
5882 ret = EnumPrinterDataExW (hPrinter, pKeyNameW, pEnumValues, cbEnumValues,
5883 pcbEnumValues, pnEnumValues);
5884 if (ret != ERROR_SUCCESS)
5886 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5887 WARN ("HeapFree failed with code %i\n", GetLastError ());
5888 TRACE ("EnumPrinterDataExW returned %i\n", ret);
5889 return ret;
5892 if (HeapFree (hHeap, 0, pKeyNameW) == 0)
5894 ret = GetLastError ();
5895 ERR ("HeapFree failed with code %i\n", ret);
5896 return ret;
5899 if (*pnEnumValues == 0) /* empty key */
5900 return ERROR_SUCCESS;
5902 dwBufSize = 0;
5903 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5905 PPRINTER_ENUM_VALUESW ppev =
5906 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5908 if (dwBufSize < ppev->cbValueName)
5909 dwBufSize = ppev->cbValueName;
5911 if (dwBufSize < ppev->cbData && (ppev->dwType == REG_SZ ||
5912 ppev->dwType == REG_EXPAND_SZ || ppev->dwType == REG_MULTI_SZ))
5913 dwBufSize = ppev->cbData;
5916 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize);
5918 pBuffer = HeapAlloc (hHeap, 0, dwBufSize);
5919 if (pBuffer == NULL)
5921 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize);
5922 return ERROR_OUTOFMEMORY;
5925 for (dwIndex = 0; dwIndex < *pnEnumValues; ++dwIndex)
5927 PPRINTER_ENUM_VALUESW ppev =
5928 &((PPRINTER_ENUM_VALUESW) pEnumValues)[dwIndex];
5930 len = WideCharToMultiByte (CP_ACP, 0, ppev->pValueName,
5931 ppev->cbValueName / sizeof (WCHAR), pBuffer, dwBufSize, NULL,
5932 NULL);
5933 if (len == 0)
5935 ret = GetLastError ();
5936 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5937 if (HeapFree (hHeap, 0, pBuffer) == 0)
5938 WARN ("HeapFree failed with code %i\n", GetLastError ());
5939 return ret;
5942 memcpy (ppev->pValueName, pBuffer, len);
5944 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5946 if (ppev->dwType != REG_SZ && ppev->dwType != REG_EXPAND_SZ &&
5947 ppev->dwType != REG_MULTI_SZ)
5948 continue;
5950 len = WideCharToMultiByte (CP_ACP, 0, (LPWSTR) ppev->pData,
5951 ppev->cbData / sizeof (WCHAR), pBuffer, dwBufSize, NULL, NULL);
5952 if (len == 0)
5954 ret = GetLastError ();
5955 ERR ("WideCharToMultiByte failed with code %i\n", ret);
5956 if (HeapFree (hHeap, 0, pBuffer) == 0)
5957 WARN ("HeapFree failed with code %i\n", GetLastError ());
5958 return ret;
5961 memcpy (ppev->pData, pBuffer, len);
5963 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer);
5964 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
5967 if (HeapFree (hHeap, 0, pBuffer) == 0)
5969 ret = GetLastError ();
5970 ERR ("HeapFree failed with code %i\n", ret);
5971 return ret;
5974 return ERROR_SUCCESS;
5977 /******************************************************************************
5978 * AbortPrinter (WINSPOOL.@)
5980 BOOL WINAPI AbortPrinter( HANDLE hPrinter )
5982 FIXME("(%p), stub!\n", hPrinter);
5983 return TRUE;
5986 /******************************************************************************
5987 * AddPortA (WINSPOOL.@)
5989 * See AddPortW.
5992 BOOL WINAPI AddPortA(LPSTR pName, HWND hWnd, LPSTR pMonitorName)
5994 LPWSTR nameW = NULL;
5995 LPWSTR monitorW = NULL;
5996 DWORD len;
5997 BOOL res;
5999 TRACE("(%s, %p, %s)\n",debugstr_a(pName), hWnd, debugstr_a(pMonitorName));
6001 if (pName) {
6002 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6003 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6004 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6007 if (pMonitorName) {
6008 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6009 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6010 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6012 res = AddPortW(nameW, hWnd, monitorW);
6013 HeapFree(GetProcessHeap(), 0, nameW);
6014 HeapFree(GetProcessHeap(), 0, monitorW);
6015 return res;
6018 /******************************************************************************
6019 * AddPortW (WINSPOOL.@)
6021 * Add a Port for a specific Monitor
6023 * PARAMS
6024 * pName [I] Servername or NULL (local Computer)
6025 * hWnd [I] Handle to parent Window for the Dialog-Box
6026 * pMonitorName [I] Name of the Monitor that manage the Port
6028 * RETURNS
6029 * Success: TRUE
6030 * Failure: FALSE
6033 BOOL WINAPI AddPortW(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
6035 monitor_t * pm;
6036 monitor_t * pui;
6037 DWORD res;
6039 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
6041 if (pName && pName[0]) {
6042 SetLastError(ERROR_INVALID_PARAMETER);
6043 return FALSE;
6046 if (!pMonitorName) {
6047 SetLastError(RPC_X_NULL_REF_POINTER);
6048 return FALSE;
6051 /* an empty Monitorname is Invalid */
6052 if (!pMonitorName[0]) {
6053 SetLastError(ERROR_NOT_SUPPORTED);
6054 return FALSE;
6057 pm = monitor_load(pMonitorName, NULL);
6058 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
6059 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
6060 TRACE("got %d with %u\n", res, GetLastError());
6061 res = TRUE;
6063 else
6065 pui = monitor_loadui(pm);
6066 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
6067 TRACE("use %p: %s\n", pui, debugstr_w(pui->dllname));
6068 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
6069 TRACE("got %d with %u\n", res, GetLastError());
6070 res = TRUE;
6072 else
6074 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName),
6075 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6077 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6078 SetLastError(ERROR_NOT_SUPPORTED);
6079 res = FALSE;
6081 monitor_unload(pui);
6083 monitor_unload(pm);
6084 TRACE("returning %d with %u\n", res, GetLastError());
6085 return res;
6088 /******************************************************************************
6089 * AddPortExA (WINSPOOL.@)
6091 * See AddPortExW.
6094 BOOL WINAPI AddPortExA(HANDLE hMonitor, LPSTR pName, DWORD Level, LPBYTE lpBuffer, LPSTR lpMonitorName)
6096 FIXME("(%p, %s, %d, %p, %s), stub!\n",hMonitor, debugstr_a(pName), Level,
6097 lpBuffer, debugstr_a(lpMonitorName));
6098 return FALSE;
6101 /******************************************************************************
6102 * AddPortExW (WINSPOOL.@)
6104 * Add a Port for a specific Monitor, without presenting a user interface
6106 * PARAMS
6107 * hMonitor [I] Handle from InitializePrintMonitor2()
6108 * pName [I] Servername or NULL (local Computer)
6109 * Level [I] Structure-Level (1 or 2) for lpBuffer
6110 * lpBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6111 * lpMonitorName [I] Name of the Monitor that manage the Port or NULL
6113 * RETURNS
6114 * Success: TRUE
6115 * Failure: FALSE
6117 * BUGS
6118 * only a Stub
6121 BOOL WINAPI AddPortExW(HANDLE hMonitor, LPWSTR pName, DWORD Level, LPBYTE lpBuffer, LPWSTR lpMonitorName)
6123 FIXME("(%p, %s, %d, %p, %s), stub!\n", hMonitor, debugstr_w(pName), Level,
6124 lpBuffer, debugstr_w(lpMonitorName));
6125 return FALSE;
6128 /******************************************************************************
6129 * AddPrinterConnectionA (WINSPOOL.@)
6131 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6133 FIXME("%s\n", debugstr_a(pName));
6134 return FALSE;
6137 /******************************************************************************
6138 * AddPrinterConnectionW (WINSPOOL.@)
6140 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6142 FIXME("%s\n", debugstr_w(pName));
6143 return FALSE;
6146 /******************************************************************************
6147 * AddPrinterDriverExW (WINSPOOL.@)
6149 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6150 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6152 FIXME("%s %d %p %d\n", debugstr_w(pName),
6153 Level, pDriverInfo, dwFileCopyFlags);
6154 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6155 return FALSE;
6158 /******************************************************************************
6159 * AddPrinterDriverExA (WINSPOOL.@)
6161 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6162 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6164 FIXME("%s %d %p %d\n", debugstr_a(pName),
6165 Level, pDriverInfo, dwFileCopyFlags);
6166 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6167 return FALSE;
6170 /******************************************************************************
6171 * ConfigurePortA (WINSPOOL.@)
6173 * See ConfigurePortW.
6176 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6178 LPWSTR nameW = NULL;
6179 LPWSTR portW = NULL;
6180 INT len;
6181 DWORD res;
6183 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6185 /* convert servername to unicode */
6186 if (pName) {
6187 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6188 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6189 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6192 /* convert portname to unicode */
6193 if (pPortName) {
6194 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6195 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6196 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6199 res = ConfigurePortW(nameW, hWnd, portW);
6200 HeapFree(GetProcessHeap(), 0, nameW);
6201 HeapFree(GetProcessHeap(), 0, portW);
6202 return res;
6205 /******************************************************************************
6206 * ConfigurePortW (WINSPOOL.@)
6208 * Display the Configuration-Dialog for a specific Port
6210 * PARAMS
6211 * pName [I] Servername or NULL (local Computer)
6212 * hWnd [I] Handle to parent Window for the Dialog-Box
6213 * pPortName [I] Name of the Port, that should be configured
6215 * RETURNS
6216 * Success: TRUE
6217 * Failure: FALSE
6220 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6222 monitor_t * pm;
6223 monitor_t * pui;
6224 DWORD res;
6226 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6228 if (pName && pName[0]) {
6229 SetLastError(ERROR_INVALID_PARAMETER);
6230 return FALSE;
6233 if (!pPortName) {
6234 SetLastError(RPC_X_NULL_REF_POINTER);
6235 return FALSE;
6238 /* an empty Portname is Invalid, but can popup a Dialog */
6239 if (!pPortName[0]) {
6240 SetLastError(ERROR_NOT_SUPPORTED);
6241 return FALSE;
6244 pm = monitor_load_by_port(pPortName);
6245 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6246 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6247 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6248 TRACE("got %d with %u\n", res, GetLastError());
6250 else
6252 pui = monitor_loadui(pm);
6253 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6254 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6255 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6256 TRACE("got %d with %u\n", res, GetLastError());
6258 else
6260 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6261 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6263 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6264 SetLastError(ERROR_NOT_SUPPORTED);
6265 res = FALSE;
6267 monitor_unload(pui);
6269 monitor_unload(pm);
6271 TRACE("returning %d with %u\n", res, GetLastError());
6272 return res;
6275 /******************************************************************************
6276 * ConnectToPrinterDlg (WINSPOOL.@)
6278 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6280 FIXME("%p %x\n", hWnd, Flags);
6281 return NULL;
6284 /******************************************************************************
6285 * DeletePrinterConnectionA (WINSPOOL.@)
6287 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6289 FIXME("%s\n", debugstr_a(pName));
6290 return TRUE;
6293 /******************************************************************************
6294 * DeletePrinterConnectionW (WINSPOOL.@)
6296 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6298 FIXME("%s\n", debugstr_w(pName));
6299 return TRUE;
6302 /******************************************************************************
6303 * DeletePrinterDriverExW (WINSPOOL.@)
6305 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6306 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6308 HKEY hkey_drivers;
6309 BOOL ret = FALSE;
6311 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6312 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6314 if(pName && pName[0])
6316 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6317 SetLastError(ERROR_INVALID_PARAMETER);
6318 return FALSE;
6321 if(dwDeleteFlag)
6323 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6324 SetLastError(ERROR_INVALID_PARAMETER);
6325 return FALSE;
6328 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6330 if(!hkey_drivers)
6332 ERR("Can't open drivers key\n");
6333 return FALSE;
6336 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6337 ret = TRUE;
6339 RegCloseKey(hkey_drivers);
6341 return ret;
6344 /******************************************************************************
6345 * DeletePrinterDriverExA (WINSPOOL.@)
6347 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6348 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6350 UNICODE_STRING NameW, EnvW, DriverW;
6351 BOOL ret;
6353 asciitounicode(&NameW, pName);
6354 asciitounicode(&EnvW, pEnvironment);
6355 asciitounicode(&DriverW, pDriverName);
6357 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6359 RtlFreeUnicodeString(&DriverW);
6360 RtlFreeUnicodeString(&EnvW);
6361 RtlFreeUnicodeString(&NameW);
6363 return ret;
6366 /******************************************************************************
6367 * DeletePrinterDataExW (WINSPOOL.@)
6369 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6370 LPCWSTR pValueName)
6372 FIXME("%p %s %s\n", hPrinter,
6373 debugstr_w(pKeyName), debugstr_w(pValueName));
6374 return ERROR_INVALID_PARAMETER;
6377 /******************************************************************************
6378 * DeletePrinterDataExA (WINSPOOL.@)
6380 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6381 LPCSTR pValueName)
6383 FIXME("%p %s %s\n", hPrinter,
6384 debugstr_a(pKeyName), debugstr_a(pValueName));
6385 return ERROR_INVALID_PARAMETER;
6388 /******************************************************************************
6389 * DeletePrintProcessorA (WINSPOOL.@)
6391 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6393 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6394 debugstr_a(pPrintProcessorName));
6395 return TRUE;
6398 /******************************************************************************
6399 * DeletePrintProcessorW (WINSPOOL.@)
6401 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6403 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6404 debugstr_w(pPrintProcessorName));
6405 return TRUE;
6408 /******************************************************************************
6409 * DeletePrintProvidorA (WINSPOOL.@)
6411 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6413 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6414 debugstr_a(pPrintProviderName));
6415 return TRUE;
6418 /******************************************************************************
6419 * DeletePrintProvidorW (WINSPOOL.@)
6421 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6423 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6424 debugstr_w(pPrintProviderName));
6425 return TRUE;
6428 /******************************************************************************
6429 * EnumFormsA (WINSPOOL.@)
6431 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6432 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6434 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6435 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6436 return FALSE;
6439 /******************************************************************************
6440 * EnumFormsW (WINSPOOL.@)
6442 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6443 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6445 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6446 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6447 return FALSE;
6450 /*****************************************************************************
6451 * EnumMonitorsA [WINSPOOL.@]
6453 * See EnumMonitorsW.
6456 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6457 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6459 BOOL res;
6460 LPBYTE bufferW = NULL;
6461 LPWSTR nameW = NULL;
6462 DWORD needed = 0;
6463 DWORD numentries = 0;
6464 INT len;
6466 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6467 cbBuf, pcbNeeded, pcReturned);
6469 /* convert servername to unicode */
6470 if (pName) {
6471 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6472 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6473 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6475 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6476 needed = cbBuf * sizeof(WCHAR);
6477 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6478 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6480 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6481 if (pcbNeeded) needed = *pcbNeeded;
6482 /* HeapReAlloc return NULL, when bufferW was NULL */
6483 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6484 HeapAlloc(GetProcessHeap(), 0, needed);
6486 /* Try again with the large Buffer */
6487 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6489 numentries = pcReturned ? *pcReturned : 0;
6490 needed = 0;
6492 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6493 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6495 if (res) {
6496 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6497 DWORD entrysize = 0;
6498 DWORD index;
6499 LPSTR ptr;
6500 LPMONITOR_INFO_2W mi2w;
6501 LPMONITOR_INFO_2A mi2a;
6503 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6504 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6506 /* First pass: calculate the size for all Entries */
6507 mi2w = (LPMONITOR_INFO_2W) bufferW;
6508 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6509 index = 0;
6510 while (index < numentries) {
6511 index++;
6512 needed += entrysize; /* MONITOR_INFO_?A */
6513 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6515 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6516 NULL, 0, NULL, NULL);
6517 if (Level > 1) {
6518 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6519 NULL, 0, NULL, NULL);
6520 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6521 NULL, 0, NULL, NULL);
6523 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6524 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6525 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6528 /* check for errors and quit on failure */
6529 if (cbBuf < needed) {
6530 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6531 res = FALSE;
6532 goto emA_cleanup;
6534 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6535 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6536 cbBuf -= len ; /* free Bytes in the user-Buffer */
6537 mi2w = (LPMONITOR_INFO_2W) bufferW;
6538 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6539 index = 0;
6540 /* Second Pass: Fill the User Buffer (if we have one) */
6541 while ((index < numentries) && pMonitors) {
6542 index++;
6543 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6544 mi2a->pName = ptr;
6545 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6546 ptr, cbBuf , NULL, NULL);
6547 ptr += len;
6548 cbBuf -= len;
6549 if (Level > 1) {
6550 mi2a->pEnvironment = ptr;
6551 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6552 ptr, cbBuf, NULL, NULL);
6553 ptr += len;
6554 cbBuf -= len;
6556 mi2a->pDLLName = ptr;
6557 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6558 ptr, cbBuf, NULL, NULL);
6559 ptr += len;
6560 cbBuf -= len;
6562 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6563 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6564 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6567 emA_cleanup:
6568 if (pcbNeeded) *pcbNeeded = needed;
6569 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6571 HeapFree(GetProcessHeap(), 0, nameW);
6572 HeapFree(GetProcessHeap(), 0, bufferW);
6574 TRACE("returning %d with %d (%d byte for %d entries)\n",
6575 (res), GetLastError(), needed, numentries);
6577 return (res);
6581 /*****************************************************************************
6582 * EnumMonitorsW [WINSPOOL.@]
6584 * Enumerate available Port-Monitors
6586 * PARAMS
6587 * pName [I] Servername or NULL (local Computer)
6588 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6589 * pMonitors [O] PTR to Buffer that receives the Result
6590 * cbBuf [I] Size of Buffer at pMonitors
6591 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6592 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6594 * RETURNS
6595 * Success: TRUE
6596 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6598 * NOTES
6599 * Windows reads the Registry once and cache the Results.
6601 *| Language-Monitors are also installed in the same Registry-Location but
6602 *| they are filtered in Windows (not returned by EnumMonitors).
6603 *| We do no filtering to simplify our Code.
6606 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6607 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6609 DWORD needed = 0;
6610 DWORD numentries = 0;
6611 BOOL res = FALSE;
6613 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6614 cbBuf, pcbNeeded, pcReturned);
6616 if (pName && (lstrlenW(pName))) {
6617 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6618 SetLastError(ERROR_ACCESS_DENIED);
6619 goto emW_cleanup;
6622 /* Level is not checked in win9x */
6623 if (!Level || (Level > 2)) {
6624 WARN("level (%d) is ignored in win9x\n", Level);
6625 SetLastError(ERROR_INVALID_LEVEL);
6626 goto emW_cleanup;
6628 if (!pcbNeeded) {
6629 SetLastError(RPC_X_NULL_REF_POINTER);
6630 goto emW_cleanup;
6633 /* Scan all Monitor-Keys */
6634 numentries = 0;
6635 needed = get_local_monitors(Level, NULL, 0, &numentries);
6637 /* we calculated the needed buffersize. now do the error-checks */
6638 if (cbBuf < needed) {
6639 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6640 goto emW_cleanup;
6642 else if (!pMonitors || !pcReturned) {
6643 SetLastError(RPC_X_NULL_REF_POINTER);
6644 goto emW_cleanup;
6647 /* fill the Buffer with the Monitor-Keys */
6648 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6649 res = TRUE;
6651 emW_cleanup:
6652 if (pcbNeeded) *pcbNeeded = needed;
6653 if (pcReturned) *pcReturned = numentries;
6655 TRACE("returning %d with %d (%d byte for %d entries)\n",
6656 res, GetLastError(), needed, numentries);
6658 return (res);
6661 /******************************************************************************
6662 * XcvDataW (WINSPOOL.@)
6664 * Execute commands in the Printmonitor DLL
6666 * PARAMS
6667 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6668 * pszDataName [i] Name of the command to execute
6669 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6670 * cbInputData [i] Size in Bytes of Buffer at pInputData
6671 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6672 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6673 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6674 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6676 * RETURNS
6677 * Success: TRUE
6678 * Failure: FALSE
6680 * NOTES
6681 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6682 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6684 * Minimal List of commands, that a Printmonitor DLL should support:
6686 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6687 *| "AddPort" : Add a Port
6688 *| "DeletePort": Delete a Port
6690 * Many Printmonitors support additional commands. Examples for localspl.dll:
6691 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6692 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6695 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6696 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6697 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6699 opened_printer_t *printer;
6701 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6702 pInputData, cbInputData, pOutputData,
6703 cbOutputData, pcbOutputNeeded, pdwStatus);
6705 printer = get_opened_printer(hXcv);
6706 if (!printer || (!printer->hXcv)) {
6707 SetLastError(ERROR_INVALID_HANDLE);
6708 return FALSE;
6711 if (!pcbOutputNeeded) {
6712 SetLastError(ERROR_INVALID_PARAMETER);
6713 return FALSE;
6716 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6717 SetLastError(RPC_X_NULL_REF_POINTER);
6718 return FALSE;
6721 *pcbOutputNeeded = 0;
6723 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6724 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6726 return TRUE;
6729 /*****************************************************************************
6730 * EnumPrinterDataA [WINSPOOL.@]
6733 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6734 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6735 DWORD cbData, LPDWORD pcbData )
6737 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6738 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6739 return ERROR_NO_MORE_ITEMS;
6742 /*****************************************************************************
6743 * EnumPrinterDataW [WINSPOOL.@]
6746 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6747 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6748 DWORD cbData, LPDWORD pcbData )
6750 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6751 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6752 return ERROR_NO_MORE_ITEMS;
6755 /*****************************************************************************
6756 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6759 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6760 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6761 LPDWORD pcbNeeded, LPDWORD pcReturned)
6763 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6764 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6765 pcbNeeded, pcReturned);
6766 return FALSE;
6769 /*****************************************************************************
6770 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6773 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6774 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6775 LPDWORD pcbNeeded, LPDWORD pcReturned)
6777 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6778 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6779 pcbNeeded, pcReturned);
6780 return FALSE;
6783 /*****************************************************************************
6784 * EnumPrintProcessorsA [WINSPOOL.@]
6787 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6788 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6790 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6791 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6792 return FALSE;
6795 /*****************************************************************************
6796 * EnumPrintProcessorsW [WINSPOOL.@]
6799 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6800 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6802 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6803 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6804 cbBuf, pcbNeeded, pcbReturned);
6805 return FALSE;
6808 /*****************************************************************************
6809 * ExtDeviceMode [WINSPOOL.@]
6812 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6813 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6814 DWORD fMode)
6816 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6817 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6818 debugstr_a(pProfile), fMode);
6819 return -1;
6822 /*****************************************************************************
6823 * FindClosePrinterChangeNotification [WINSPOOL.@]
6826 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6828 FIXME("Stub: %p\n", hChange);
6829 return TRUE;
6832 /*****************************************************************************
6833 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6836 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6837 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6839 FIXME("Stub: %p %x %x %p\n",
6840 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6841 return INVALID_HANDLE_VALUE;
6844 /*****************************************************************************
6845 * FindNextPrinterChangeNotification [WINSPOOL.@]
6848 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6849 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6851 FIXME("Stub: %p %p %p %p\n",
6852 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6853 return FALSE;
6856 /*****************************************************************************
6857 * FreePrinterNotifyInfo [WINSPOOL.@]
6860 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6862 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6863 return TRUE;
6866 /*****************************************************************************
6867 * string_to_buf
6869 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6870 * ansi depending on the unicode parameter.
6872 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6874 if(!str)
6876 *size = 0;
6877 return TRUE;
6880 if(unicode)
6882 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6883 if(*size <= cb)
6885 memcpy(ptr, str, *size);
6886 return TRUE;
6888 return FALSE;
6890 else
6892 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6893 if(*size <= cb)
6895 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6896 return TRUE;
6898 return FALSE;
6902 /*****************************************************************************
6903 * get_job_info_1
6905 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
6906 LPDWORD pcbNeeded, BOOL unicode)
6908 DWORD size, left = cbBuf;
6909 BOOL space = (cbBuf > 0);
6910 LPBYTE ptr = buf;
6912 *pcbNeeded = 0;
6914 if(space)
6916 ji1->JobId = job->job_id;
6919 string_to_buf(job->document_title, ptr, left, &size, unicode);
6920 if(space && size <= left)
6922 ji1->pDocument = (LPWSTR)ptr;
6923 ptr += size;
6924 left -= size;
6926 else
6927 space = FALSE;
6928 *pcbNeeded += size;
6930 return space;
6933 /*****************************************************************************
6934 * get_job_info_2
6936 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
6937 LPDWORD pcbNeeded, BOOL unicode)
6939 DWORD size, left = cbBuf;
6940 BOOL space = (cbBuf > 0);
6941 LPBYTE ptr = buf;
6943 *pcbNeeded = 0;
6945 if(space)
6947 ji2->JobId = job->job_id;
6950 string_to_buf(job->document_title, ptr, left, &size, unicode);
6951 if(space && size <= left)
6953 ji2->pDocument = (LPWSTR)ptr;
6954 ptr += size;
6955 left -= size;
6957 else
6958 space = FALSE;
6959 *pcbNeeded += size;
6961 return space;
6964 /*****************************************************************************
6965 * get_job_info
6967 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
6968 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
6970 BOOL ret = FALSE;
6971 DWORD needed = 0, size;
6972 job_t *job;
6973 LPBYTE ptr = pJob;
6975 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
6977 EnterCriticalSection(&printer_handles_cs);
6978 job = get_job(hPrinter, JobId);
6979 if(!job)
6980 goto end;
6982 switch(Level)
6984 case 1:
6985 size = sizeof(JOB_INFO_1W);
6986 if(cbBuf >= size)
6988 cbBuf -= size;
6989 ptr += size;
6990 memset(pJob, 0, size);
6992 else
6993 cbBuf = 0;
6994 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
6995 needed += size;
6996 break;
6998 case 2:
6999 size = sizeof(JOB_INFO_2W);
7000 if(cbBuf >= size)
7002 cbBuf -= size;
7003 ptr += size;
7004 memset(pJob, 0, size);
7006 else
7007 cbBuf = 0;
7008 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7009 needed += size;
7010 break;
7012 case 3:
7013 size = sizeof(JOB_INFO_3);
7014 if(cbBuf >= size)
7016 cbBuf -= size;
7017 memset(pJob, 0, size);
7018 ret = TRUE;
7020 else
7021 cbBuf = 0;
7022 needed = size;
7023 break;
7025 default:
7026 SetLastError(ERROR_INVALID_LEVEL);
7027 goto end;
7029 if(pcbNeeded)
7030 *pcbNeeded = needed;
7031 end:
7032 LeaveCriticalSection(&printer_handles_cs);
7033 return ret;
7036 /*****************************************************************************
7037 * GetJobA [WINSPOOL.@]
7040 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7041 DWORD cbBuf, LPDWORD pcbNeeded)
7043 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7046 /*****************************************************************************
7047 * GetJobW [WINSPOOL.@]
7050 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7051 DWORD cbBuf, LPDWORD pcbNeeded)
7053 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7056 /*****************************************************************************
7057 * schedule_lpr
7059 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7061 char *unixname, *queue, *cmd;
7062 char fmt[] = "lpr -P%s %s";
7063 DWORD len;
7065 if(!(unixname = wine_get_unix_file_name(filename)))
7066 return FALSE;
7068 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7069 queue = HeapAlloc(GetProcessHeap(), 0, len);
7070 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7072 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7073 sprintf(cmd, fmt, queue, unixname);
7075 TRACE("printing with: %s\n", cmd);
7076 system(cmd);
7078 HeapFree(GetProcessHeap(), 0, cmd);
7079 HeapFree(GetProcessHeap(), 0, queue);
7080 HeapFree(GetProcessHeap(), 0, unixname);
7081 return TRUE;
7084 /*****************************************************************************
7085 * schedule_cups
7087 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7089 #if HAVE_CUPS_CUPS_H
7090 if(pcupsPrintFile)
7092 char *unixname, *queue, *doc_titleA;
7093 DWORD len;
7094 BOOL ret;
7096 if(!(unixname = wine_get_unix_file_name(filename)))
7097 return FALSE;
7099 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7100 queue = HeapAlloc(GetProcessHeap(), 0, len);
7101 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7103 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7104 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7105 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7107 TRACE("printing via cups\n");
7108 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7109 HeapFree(GetProcessHeap(), 0, doc_titleA);
7110 HeapFree(GetProcessHeap(), 0, queue);
7111 HeapFree(GetProcessHeap(), 0, unixname);
7112 return ret;
7114 else
7115 #endif
7117 return schedule_lpr(printer_name, filename);
7121 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7123 LPWSTR filename;
7125 switch(msg)
7127 case WM_INITDIALOG:
7128 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7129 return TRUE;
7131 case WM_COMMAND:
7132 if(HIWORD(wparam) == BN_CLICKED)
7134 if(LOWORD(wparam) == IDOK)
7136 HANDLE hf;
7137 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7138 LPWSTR *output;
7140 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7141 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7143 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7145 WCHAR caption[200], message[200];
7146 int mb_ret;
7148 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7149 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7150 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7151 if(mb_ret == IDCANCEL)
7153 HeapFree(GetProcessHeap(), 0, filename);
7154 return TRUE;
7157 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7158 if(hf == INVALID_HANDLE_VALUE)
7160 WCHAR caption[200], message[200];
7162 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7163 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7164 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7165 HeapFree(GetProcessHeap(), 0, filename);
7166 return TRUE;
7168 CloseHandle(hf);
7169 DeleteFileW(filename);
7170 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7171 *output = filename;
7172 EndDialog(hwnd, IDOK);
7173 return TRUE;
7175 if(LOWORD(wparam) == IDCANCEL)
7177 EndDialog(hwnd, IDCANCEL);
7178 return TRUE;
7181 return FALSE;
7183 return FALSE;
7186 /*****************************************************************************
7187 * get_filename
7189 static BOOL get_filename(LPWSTR *filename)
7191 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7192 file_dlg_proc, (LPARAM)filename) == IDOK;
7195 /*****************************************************************************
7196 * schedule_file
7198 static BOOL schedule_file(LPCWSTR filename)
7200 LPWSTR output = NULL;
7202 if(get_filename(&output))
7204 TRACE("copy to %s\n", debugstr_w(output));
7205 CopyFileW(filename, output, FALSE);
7206 HeapFree(GetProcessHeap(), 0, output);
7207 return TRUE;
7209 return FALSE;
7212 /*****************************************************************************
7213 * schedule_pipe
7215 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7217 #ifdef HAVE_FORK
7218 char *unixname, *cmdA;
7219 DWORD len;
7220 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7221 BOOL ret = FALSE;
7222 char buf[1024];
7224 if(!(unixname = wine_get_unix_file_name(filename)))
7225 return FALSE;
7227 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7228 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7229 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7231 TRACE("printing with: %s\n", cmdA);
7233 if((file_fd = open(unixname, O_RDONLY)) == -1)
7234 goto end;
7236 if (pipe(fds))
7238 ERR("pipe() failed!\n");
7239 goto end;
7242 if (fork() == 0)
7244 close(0);
7245 dup2(fds[0], 0);
7246 close(fds[1]);
7248 /* reset signals that we previously set to SIG_IGN */
7249 signal(SIGPIPE, SIG_DFL);
7250 signal(SIGCHLD, SIG_DFL);
7252 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7253 _exit(1);
7256 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7257 write(fds[1], buf, no_read);
7259 ret = TRUE;
7261 end:
7262 if(file_fd != -1) close(file_fd);
7263 if(fds[0] != -1) close(fds[0]);
7264 if(fds[1] != -1) close(fds[1]);
7266 HeapFree(GetProcessHeap(), 0, cmdA);
7267 HeapFree(GetProcessHeap(), 0, unixname);
7268 return ret;
7269 #else
7270 return FALSE;
7271 #endif
7274 /*****************************************************************************
7275 * schedule_unixfile
7277 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7279 int in_fd, out_fd, no_read;
7280 char buf[1024];
7281 BOOL ret = FALSE;
7282 char *unixname, *outputA;
7283 DWORD len;
7285 if(!(unixname = wine_get_unix_file_name(filename)))
7286 return FALSE;
7288 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7289 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7290 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7292 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7293 in_fd = open(unixname, O_RDONLY);
7294 if(out_fd == -1 || in_fd == -1)
7295 goto end;
7297 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7298 write(out_fd, buf, no_read);
7300 ret = TRUE;
7301 end:
7302 if(in_fd != -1) close(in_fd);
7303 if(out_fd != -1) close(out_fd);
7304 HeapFree(GetProcessHeap(), 0, outputA);
7305 HeapFree(GetProcessHeap(), 0, unixname);
7306 return ret;
7309 /*****************************************************************************
7310 * ScheduleJob [WINSPOOL.@]
7313 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7315 opened_printer_t *printer;
7316 BOOL ret = FALSE;
7317 struct list *cursor, *cursor2;
7319 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7320 EnterCriticalSection(&printer_handles_cs);
7321 printer = get_opened_printer(hPrinter);
7322 if(!printer)
7323 goto end;
7325 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7327 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7328 HANDLE hf;
7330 if(job->job_id != dwJobID) continue;
7332 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7333 if(hf != INVALID_HANDLE_VALUE)
7335 PRINTER_INFO_5W *pi5;
7336 DWORD needed;
7337 HKEY hkey;
7338 WCHAR output[1024];
7339 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7340 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7342 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7343 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7344 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7345 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7346 debugstr_w(pi5->pPortName));
7348 output[0] = 0;
7350 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7351 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7353 DWORD type, count = sizeof(output);
7354 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7355 RegCloseKey(hkey);
7357 if(output[0] == '|')
7359 schedule_pipe(output + 1, job->filename);
7361 else if(output[0])
7363 schedule_unixfile(output, job->filename);
7365 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7367 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7369 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7371 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7373 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7375 schedule_file(job->filename);
7377 else
7379 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7381 HeapFree(GetProcessHeap(), 0, pi5);
7382 CloseHandle(hf);
7383 DeleteFileW(job->filename);
7385 list_remove(cursor);
7386 HeapFree(GetProcessHeap(), 0, job->document_title);
7387 HeapFree(GetProcessHeap(), 0, job->filename);
7388 HeapFree(GetProcessHeap(), 0, job);
7389 ret = TRUE;
7390 break;
7392 end:
7393 LeaveCriticalSection(&printer_handles_cs);
7394 return ret;
7397 /*****************************************************************************
7398 * StartDocDlgA [WINSPOOL.@]
7400 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7402 UNICODE_STRING usBuffer;
7403 DOCINFOW docW;
7404 LPWSTR retW;
7405 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7406 LPSTR ret = NULL;
7408 docW.cbSize = sizeof(docW);
7409 if (doc->lpszDocName)
7411 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7412 if (!(docW.lpszDocName = docnameW)) return NULL;
7414 if (doc->lpszOutput)
7416 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7417 if (!(docW.lpszOutput = outputW)) return NULL;
7419 if (doc->lpszDatatype)
7421 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7422 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7424 docW.fwType = doc->fwType;
7426 retW = StartDocDlgW(hPrinter, &docW);
7428 if(retW)
7430 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7431 ret = HeapAlloc(GetProcessHeap(), 0, len);
7432 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7433 HeapFree(GetProcessHeap(), 0, retW);
7436 HeapFree(GetProcessHeap(), 0, datatypeW);
7437 HeapFree(GetProcessHeap(), 0, outputW);
7438 HeapFree(GetProcessHeap(), 0, docnameW);
7440 return ret;
7443 /*****************************************************************************
7444 * StartDocDlgW [WINSPOOL.@]
7446 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7447 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7448 * port is "FILE:". Also returns the full path if passed a relative path.
7450 * The caller should free the returned string from the process heap.
7452 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7454 LPWSTR ret = NULL;
7455 DWORD len, attr;
7457 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7459 PRINTER_INFO_5W *pi5;
7460 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7461 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7462 return NULL;
7463 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7464 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7465 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7467 HeapFree(GetProcessHeap(), 0, pi5);
7468 return NULL;
7470 HeapFree(GetProcessHeap(), 0, pi5);
7473 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7475 LPWSTR name;
7477 if (get_filename(&name))
7479 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7481 HeapFree(GetProcessHeap(), 0, name);
7482 return NULL;
7484 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7485 GetFullPathNameW(name, len, ret, NULL);
7486 HeapFree(GetProcessHeap(), 0, name);
7488 return ret;
7491 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7492 return NULL;
7494 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7495 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7497 attr = GetFileAttributesW(ret);
7498 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7500 HeapFree(GetProcessHeap(), 0, ret);
7501 ret = NULL;
7503 return ret;