push 7a18a4ae7c2bf2ba4d68ac56f1ac427d00926089
[wine/hacks.git] / dlls / winspool.drv / info.c
blob162f6c3d8d88529bdcec02ea0885cce06c7c83ab
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(LPSTR pName, DWORD level, LPBYTE pBuffer, LPSTR pMonitorName)
6096 PORT_INFO_2W pi2W;
6097 PORT_INFO_2A * pi2A;
6098 LPWSTR nameW = NULL;
6099 LPWSTR monitorW = NULL;
6100 DWORD len;
6101 BOOL res;
6103 pi2A = (PORT_INFO_2A *) pBuffer;
6105 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName), level, pBuffer,
6106 debugstr_a(pMonitorName), debugstr_a(pi2A ? pi2A->pPortName : NULL));
6108 if ((level < 1) || (level > 2)) {
6109 SetLastError(ERROR_INVALID_LEVEL);
6110 return FALSE;
6113 if (!pi2A) {
6114 SetLastError(ERROR_INVALID_PARAMETER);
6115 return FALSE;
6118 if (pName) {
6119 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6120 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6121 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6124 if (pMonitorName) {
6125 len = MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, NULL, 0);
6126 monitorW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6127 MultiByteToWideChar(CP_ACP, 0, pMonitorName, -1, monitorW, len);
6130 ZeroMemory(&pi2W, sizeof(PORT_INFO_2W));
6132 if (pi2A->pPortName) {
6133 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, NULL, 0);
6134 pi2W.pPortName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6135 MultiByteToWideChar(CP_ACP, 0, pi2A->pPortName, -1, pi2W.pPortName, len);
6138 if (level > 1) {
6139 if (pi2A->pMonitorName) {
6140 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, NULL, 0);
6141 pi2W.pMonitorName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6142 MultiByteToWideChar(CP_ACP, 0, pi2A->pMonitorName, -1, pi2W.pMonitorName, len);
6145 if (pi2A->pDescription) {
6146 len = MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, NULL, 0);
6147 pi2W.pDescription = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6148 MultiByteToWideChar(CP_ACP, 0, pi2A->pDescription, -1, pi2W.pDescription, len);
6150 pi2W.fPortType = pi2A->fPortType;
6151 pi2W.Reserved = pi2A->Reserved;
6154 res = AddPortExW(nameW, level, (LPBYTE) &pi2W, monitorW);
6156 HeapFree(GetProcessHeap(), 0, nameW);
6157 HeapFree(GetProcessHeap(), 0, monitorW);
6158 HeapFree(GetProcessHeap(), 0, pi2W.pPortName);
6159 HeapFree(GetProcessHeap(), 0, pi2W.pMonitorName);
6160 HeapFree(GetProcessHeap(), 0, pi2W.pDescription);
6161 return res;
6165 /******************************************************************************
6166 * AddPortExW (WINSPOOL.@)
6168 * Add a Port for a specific Monitor, without presenting a user interface
6170 * PARAMS
6171 * pName [I] Servername or NULL (local Computer)
6172 * level [I] Structure-Level (1 or 2) for pBuffer
6173 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6174 * pMonitorName [I] Name of the Monitor that manage the Port
6176 * RETURNS
6177 * Success: TRUE
6178 * Failure: FALSE
6181 BOOL WINAPI AddPortExW(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
6183 PORT_INFO_2W * pi2;
6184 monitor_t * pm;
6185 DWORD res = FALSE;
6187 pi2 = (PORT_INFO_2W *) pBuffer;
6189 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
6190 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
6191 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
6192 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
6195 if ((level < 1) || (level > 2)) {
6196 SetLastError(ERROR_INVALID_LEVEL);
6197 return FALSE;
6200 if (!pi2) {
6201 SetLastError(ERROR_INVALID_PARAMETER);
6202 return FALSE;
6205 /* we need a valid Monitorname */
6206 if (!pMonitorName) {
6207 SetLastError(RPC_X_NULL_REF_POINTER);
6208 return FALSE;
6210 if (!pMonitorName[0]) {
6211 SetLastError(ERROR_NOT_SUPPORTED);
6212 return FALSE;
6215 /* load the Monitor */
6216 pm = monitor_load(pMonitorName, NULL);
6217 if (!pm) return FALSE;
6219 if (pm->monitor && pm->monitor->pfnAddPortEx) {
6220 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
6221 TRACE("got %u with %u\n", res, GetLastError());
6223 monitor_unload(pm);
6224 return res;
6227 /******************************************************************************
6228 * AddPrinterConnectionA (WINSPOOL.@)
6230 BOOL WINAPI AddPrinterConnectionA( LPSTR pName )
6232 FIXME("%s\n", debugstr_a(pName));
6233 return FALSE;
6236 /******************************************************************************
6237 * AddPrinterConnectionW (WINSPOOL.@)
6239 BOOL WINAPI AddPrinterConnectionW( LPWSTR pName )
6241 FIXME("%s\n", debugstr_w(pName));
6242 return FALSE;
6245 /******************************************************************************
6246 * AddPrinterDriverExW (WINSPOOL.@)
6248 BOOL WINAPI AddPrinterDriverExW( LPWSTR pName, DWORD Level,
6249 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6251 FIXME("%s %d %p %d\n", debugstr_w(pName),
6252 Level, pDriverInfo, dwFileCopyFlags);
6253 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6254 return FALSE;
6257 /******************************************************************************
6258 * AddPrinterDriverExA (WINSPOOL.@)
6260 BOOL WINAPI AddPrinterDriverExA( LPSTR pName, DWORD Level,
6261 LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
6263 FIXME("%s %d %p %d\n", debugstr_a(pName),
6264 Level, pDriverInfo, dwFileCopyFlags);
6265 SetLastError(ERROR_PRINTER_DRIVER_BLOCKED);
6266 return FALSE;
6269 /******************************************************************************
6270 * ConfigurePortA (WINSPOOL.@)
6272 * See ConfigurePortW.
6275 BOOL WINAPI ConfigurePortA(LPSTR pName, HWND hWnd, LPSTR pPortName)
6277 LPWSTR nameW = NULL;
6278 LPWSTR portW = NULL;
6279 INT len;
6280 DWORD res;
6282 TRACE("(%s, %p, %s)\n", debugstr_a(pName), hWnd, debugstr_a(pPortName));
6284 /* convert servername to unicode */
6285 if (pName) {
6286 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6287 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6288 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6291 /* convert portname to unicode */
6292 if (pPortName) {
6293 len = MultiByteToWideChar(CP_ACP, 0, pPortName, -1, NULL, 0);
6294 portW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6295 MultiByteToWideChar(CP_ACP, 0, pPortName, -1, portW, len);
6298 res = ConfigurePortW(nameW, hWnd, portW);
6299 HeapFree(GetProcessHeap(), 0, nameW);
6300 HeapFree(GetProcessHeap(), 0, portW);
6301 return res;
6304 /******************************************************************************
6305 * ConfigurePortW (WINSPOOL.@)
6307 * Display the Configuration-Dialog for a specific Port
6309 * PARAMS
6310 * pName [I] Servername or NULL (local Computer)
6311 * hWnd [I] Handle to parent Window for the Dialog-Box
6312 * pPortName [I] Name of the Port, that should be configured
6314 * RETURNS
6315 * Success: TRUE
6316 * Failure: FALSE
6319 BOOL WINAPI ConfigurePortW(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
6321 monitor_t * pm;
6322 monitor_t * pui;
6323 DWORD res;
6325 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
6327 if (pName && pName[0]) {
6328 SetLastError(ERROR_INVALID_PARAMETER);
6329 return FALSE;
6332 if (!pPortName) {
6333 SetLastError(RPC_X_NULL_REF_POINTER);
6334 return FALSE;
6337 /* an empty Portname is Invalid, but can popup a Dialog */
6338 if (!pPortName[0]) {
6339 SetLastError(ERROR_NOT_SUPPORTED);
6340 return FALSE;
6343 pm = monitor_load_by_port(pPortName);
6344 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
6345 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm->name), debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
6346 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
6347 TRACE("got %d with %u\n", res, GetLastError());
6349 else
6351 pui = monitor_loadui(pm);
6352 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
6353 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui->name), debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
6354 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
6355 TRACE("got %d with %u\n", res, GetLastError());
6357 else
6359 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName),
6360 pm, pm ? debugstr_w(pm->dllname) : NULL, pui, pui ? debugstr_w(pui->dllname) : NULL);
6362 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6363 SetLastError(ERROR_NOT_SUPPORTED);
6364 res = FALSE;
6366 monitor_unload(pui);
6368 monitor_unload(pm);
6370 TRACE("returning %d with %u\n", res, GetLastError());
6371 return res;
6374 /******************************************************************************
6375 * ConnectToPrinterDlg (WINSPOOL.@)
6377 HANDLE WINAPI ConnectToPrinterDlg( HWND hWnd, DWORD Flags )
6379 FIXME("%p %x\n", hWnd, Flags);
6380 return NULL;
6383 /******************************************************************************
6384 * DeletePrinterConnectionA (WINSPOOL.@)
6386 BOOL WINAPI DeletePrinterConnectionA( LPSTR pName )
6388 FIXME("%s\n", debugstr_a(pName));
6389 return TRUE;
6392 /******************************************************************************
6393 * DeletePrinterConnectionW (WINSPOOL.@)
6395 BOOL WINAPI DeletePrinterConnectionW( LPWSTR pName )
6397 FIXME("%s\n", debugstr_w(pName));
6398 return TRUE;
6401 /******************************************************************************
6402 * DeletePrinterDriverExW (WINSPOOL.@)
6404 BOOL WINAPI DeletePrinterDriverExW( LPWSTR pName, LPWSTR pEnvironment,
6405 LPWSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6407 HKEY hkey_drivers;
6408 BOOL ret = FALSE;
6410 TRACE("%s %s %s %x %x\n", debugstr_w(pName), debugstr_w(pEnvironment),
6411 debugstr_w(pDriverName), dwDeleteFlag, dwVersionFlag);
6413 if(pName && pName[0])
6415 FIXME("pName = %s - unsupported\n", debugstr_w(pName));
6416 SetLastError(ERROR_INVALID_PARAMETER);
6417 return FALSE;
6420 if(dwDeleteFlag)
6422 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag);
6423 SetLastError(ERROR_INVALID_PARAMETER);
6424 return FALSE;
6427 hkey_drivers = WINSPOOL_OpenDriverReg(pEnvironment, TRUE);
6429 if(!hkey_drivers)
6431 ERR("Can't open drivers key\n");
6432 return FALSE;
6435 if(WINSPOOL_SHDeleteKeyW(hkey_drivers, pDriverName) == ERROR_SUCCESS)
6436 ret = TRUE;
6438 RegCloseKey(hkey_drivers);
6440 return ret;
6443 /******************************************************************************
6444 * DeletePrinterDriverExA (WINSPOOL.@)
6446 BOOL WINAPI DeletePrinterDriverExA( LPSTR pName, LPSTR pEnvironment,
6447 LPSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag)
6449 UNICODE_STRING NameW, EnvW, DriverW;
6450 BOOL ret;
6452 asciitounicode(&NameW, pName);
6453 asciitounicode(&EnvW, pEnvironment);
6454 asciitounicode(&DriverW, pDriverName);
6456 ret = DeletePrinterDriverExW(NameW.Buffer, EnvW.Buffer, DriverW.Buffer, dwDeleteFlag, dwVersionFlag);
6458 RtlFreeUnicodeString(&DriverW);
6459 RtlFreeUnicodeString(&EnvW);
6460 RtlFreeUnicodeString(&NameW);
6462 return ret;
6465 /******************************************************************************
6466 * DeletePrinterDataExW (WINSPOOL.@)
6468 DWORD WINAPI DeletePrinterDataExW( HANDLE hPrinter, LPCWSTR pKeyName,
6469 LPCWSTR pValueName)
6471 FIXME("%p %s %s\n", hPrinter,
6472 debugstr_w(pKeyName), debugstr_w(pValueName));
6473 return ERROR_INVALID_PARAMETER;
6476 /******************************************************************************
6477 * DeletePrinterDataExA (WINSPOOL.@)
6479 DWORD WINAPI DeletePrinterDataExA( HANDLE hPrinter, LPCSTR pKeyName,
6480 LPCSTR pValueName)
6482 FIXME("%p %s %s\n", hPrinter,
6483 debugstr_a(pKeyName), debugstr_a(pValueName));
6484 return ERROR_INVALID_PARAMETER;
6487 /******************************************************************************
6488 * DeletePrintProcessorA (WINSPOOL.@)
6490 BOOL WINAPI DeletePrintProcessorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProcessorName)
6492 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6493 debugstr_a(pPrintProcessorName));
6494 return TRUE;
6497 /******************************************************************************
6498 * DeletePrintProcessorW (WINSPOOL.@)
6500 BOOL WINAPI DeletePrintProcessorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProcessorName)
6502 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6503 debugstr_w(pPrintProcessorName));
6504 return TRUE;
6507 /******************************************************************************
6508 * DeletePrintProvidorA (WINSPOOL.@)
6510 BOOL WINAPI DeletePrintProvidorA(LPSTR pName, LPSTR pEnvironment, LPSTR pPrintProviderName)
6512 FIXME("%s %s %s\n", debugstr_a(pName), debugstr_a(pEnvironment),
6513 debugstr_a(pPrintProviderName));
6514 return TRUE;
6517 /******************************************************************************
6518 * DeletePrintProvidorW (WINSPOOL.@)
6520 BOOL WINAPI DeletePrintProvidorW(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pPrintProviderName)
6522 FIXME("%s %s %s\n", debugstr_w(pName), debugstr_w(pEnvironment),
6523 debugstr_w(pPrintProviderName));
6524 return TRUE;
6527 /******************************************************************************
6528 * EnumFormsA (WINSPOOL.@)
6530 BOOL WINAPI EnumFormsA( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6531 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6533 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6534 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6535 return FALSE;
6538 /******************************************************************************
6539 * EnumFormsW (WINSPOOL.@)
6541 BOOL WINAPI EnumFormsW( HANDLE hPrinter, DWORD Level, LPBYTE pForm,
6542 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned )
6544 FIXME("%p %x %p %x %p %p\n", hPrinter, Level, pForm, cbBuf, pcbNeeded, pcReturned);
6545 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
6546 return FALSE;
6549 /*****************************************************************************
6550 * EnumMonitorsA [WINSPOOL.@]
6552 * See EnumMonitorsW.
6555 BOOL WINAPI EnumMonitorsA(LPSTR pName, DWORD Level, LPBYTE pMonitors,
6556 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6558 BOOL res;
6559 LPBYTE bufferW = NULL;
6560 LPWSTR nameW = NULL;
6561 DWORD needed = 0;
6562 DWORD numentries = 0;
6563 INT len;
6565 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pMonitors,
6566 cbBuf, pcbNeeded, pcReturned);
6568 /* convert servername to unicode */
6569 if (pName) {
6570 len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
6571 nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
6572 MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
6574 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
6575 needed = cbBuf * sizeof(WCHAR);
6576 if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
6577 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6579 if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
6580 if (pcbNeeded) needed = *pcbNeeded;
6581 /* HeapReAlloc return NULL, when bufferW was NULL */
6582 bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
6583 HeapAlloc(GetProcessHeap(), 0, needed);
6585 /* Try again with the large Buffer */
6586 res = EnumMonitorsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
6588 numentries = pcReturned ? *pcReturned : 0;
6589 needed = 0;
6591 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
6592 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
6594 if (res) {
6595 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
6596 DWORD entrysize = 0;
6597 DWORD index;
6598 LPSTR ptr;
6599 LPMONITOR_INFO_2W mi2w;
6600 LPMONITOR_INFO_2A mi2a;
6602 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
6603 entrysize = (Level == 1) ? sizeof(MONITOR_INFO_1A) : sizeof(MONITOR_INFO_2A);
6605 /* First pass: calculate the size for all Entries */
6606 mi2w = (LPMONITOR_INFO_2W) bufferW;
6607 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6608 index = 0;
6609 while (index < numentries) {
6610 index++;
6611 needed += entrysize; /* MONITOR_INFO_?A */
6612 TRACE("%p: parsing #%d (%s)\n", mi2w, index, debugstr_w(mi2w->pName));
6614 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6615 NULL, 0, NULL, NULL);
6616 if (Level > 1) {
6617 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6618 NULL, 0, NULL, NULL);
6619 needed += WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6620 NULL, 0, NULL, NULL);
6622 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6623 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6624 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6627 /* check for errors and quit on failure */
6628 if (cbBuf < needed) {
6629 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6630 res = FALSE;
6631 goto emA_cleanup;
6633 len = entrysize * numentries; /* room for all MONITOR_INFO_?A */
6634 ptr = (LPSTR) &pMonitors[len]; /* room for strings */
6635 cbBuf -= len ; /* free Bytes in the user-Buffer */
6636 mi2w = (LPMONITOR_INFO_2W) bufferW;
6637 mi2a = (LPMONITOR_INFO_2A) pMonitors;
6638 index = 0;
6639 /* Second Pass: Fill the User Buffer (if we have one) */
6640 while ((index < numentries) && pMonitors) {
6641 index++;
6642 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a, Level, index);
6643 mi2a->pName = ptr;
6644 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pName, -1,
6645 ptr, cbBuf , NULL, NULL);
6646 ptr += len;
6647 cbBuf -= len;
6648 if (Level > 1) {
6649 mi2a->pEnvironment = ptr;
6650 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pEnvironment, -1,
6651 ptr, cbBuf, NULL, NULL);
6652 ptr += len;
6653 cbBuf -= len;
6655 mi2a->pDLLName = ptr;
6656 len = WideCharToMultiByte(CP_ACP, 0, mi2w->pDLLName, -1,
6657 ptr, cbBuf, NULL, NULL);
6658 ptr += len;
6659 cbBuf -= len;
6661 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
6662 mi2w = (LPMONITOR_INFO_2W) (((LPBYTE)mi2w) + entrysize);
6663 mi2a = (LPMONITOR_INFO_2A) (((LPBYTE)mi2a) + entrysize);
6666 emA_cleanup:
6667 if (pcbNeeded) *pcbNeeded = needed;
6668 if (pcReturned) *pcReturned = (res) ? numentries : 0;
6670 HeapFree(GetProcessHeap(), 0, nameW);
6671 HeapFree(GetProcessHeap(), 0, bufferW);
6673 TRACE("returning %d with %d (%d byte for %d entries)\n",
6674 (res), GetLastError(), needed, numentries);
6676 return (res);
6680 /*****************************************************************************
6681 * EnumMonitorsW [WINSPOOL.@]
6683 * Enumerate available Port-Monitors
6685 * PARAMS
6686 * pName [I] Servername or NULL (local Computer)
6687 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
6688 * pMonitors [O] PTR to Buffer that receives the Result
6689 * cbBuf [I] Size of Buffer at pMonitors
6690 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
6691 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
6693 * RETURNS
6694 * Success: TRUE
6695 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
6697 * NOTES
6698 * Windows reads the Registry once and cache the Results.
6700 *| Language-Monitors are also installed in the same Registry-Location but
6701 *| they are filtered in Windows (not returned by EnumMonitors).
6702 *| We do no filtering to simplify our Code.
6705 BOOL WINAPI EnumMonitorsW(LPWSTR pName, DWORD Level, LPBYTE pMonitors,
6706 DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
6708 DWORD needed = 0;
6709 DWORD numentries = 0;
6710 BOOL res = FALSE;
6712 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
6713 cbBuf, pcbNeeded, pcReturned);
6715 if (pName && (lstrlenW(pName))) {
6716 FIXME("for Server %s not implemented\n", debugstr_w(pName));
6717 SetLastError(ERROR_ACCESS_DENIED);
6718 goto emW_cleanup;
6721 /* Level is not checked in win9x */
6722 if (!Level || (Level > 2)) {
6723 WARN("level (%d) is ignored in win9x\n", Level);
6724 SetLastError(ERROR_INVALID_LEVEL);
6725 goto emW_cleanup;
6727 if (!pcbNeeded) {
6728 SetLastError(RPC_X_NULL_REF_POINTER);
6729 goto emW_cleanup;
6732 /* Scan all Monitor-Keys */
6733 numentries = 0;
6734 needed = get_local_monitors(Level, NULL, 0, &numentries);
6736 /* we calculated the needed buffersize. now do the error-checks */
6737 if (cbBuf < needed) {
6738 SetLastError(ERROR_INSUFFICIENT_BUFFER);
6739 goto emW_cleanup;
6741 else if (!pMonitors || !pcReturned) {
6742 SetLastError(RPC_X_NULL_REF_POINTER);
6743 goto emW_cleanup;
6746 /* fill the Buffer with the Monitor-Keys */
6747 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
6748 res = TRUE;
6750 emW_cleanup:
6751 if (pcbNeeded) *pcbNeeded = needed;
6752 if (pcReturned) *pcReturned = numentries;
6754 TRACE("returning %d with %d (%d byte for %d entries)\n",
6755 res, GetLastError(), needed, numentries);
6757 return (res);
6760 /******************************************************************************
6761 * XcvDataW (WINSPOOL.@)
6763 * Execute commands in the Printmonitor DLL
6765 * PARAMS
6766 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
6767 * pszDataName [i] Name of the command to execute
6768 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
6769 * cbInputData [i] Size in Bytes of Buffer at pInputData
6770 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
6771 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
6772 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
6773 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
6775 * RETURNS
6776 * Success: TRUE
6777 * Failure: FALSE
6779 * NOTES
6780 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
6781 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
6783 * Minimal List of commands, that a Printmonitor DLL should support:
6785 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
6786 *| "AddPort" : Add a Port
6787 *| "DeletePort": Delete a Port
6789 * Many Printmonitors support additional commands. Examples for localspl.dll:
6790 * "GetDefaultCommConfig", "SetDefaultCommConfig",
6791 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
6794 BOOL WINAPI XcvDataW( HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
6795 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
6796 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
6798 opened_printer_t *printer;
6800 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
6801 pInputData, cbInputData, pOutputData,
6802 cbOutputData, pcbOutputNeeded, pdwStatus);
6804 printer = get_opened_printer(hXcv);
6805 if (!printer || (!printer->hXcv)) {
6806 SetLastError(ERROR_INVALID_HANDLE);
6807 return FALSE;
6810 if (!pcbOutputNeeded) {
6811 SetLastError(ERROR_INVALID_PARAMETER);
6812 return FALSE;
6815 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
6816 SetLastError(RPC_X_NULL_REF_POINTER);
6817 return FALSE;
6820 *pcbOutputNeeded = 0;
6822 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
6823 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
6825 return TRUE;
6828 /*****************************************************************************
6829 * EnumPrinterDataA [WINSPOOL.@]
6832 DWORD WINAPI EnumPrinterDataA( HANDLE hPrinter, DWORD dwIndex, LPSTR pValueName,
6833 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6834 DWORD cbData, LPDWORD pcbData )
6836 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6837 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6838 return ERROR_NO_MORE_ITEMS;
6841 /*****************************************************************************
6842 * EnumPrinterDataW [WINSPOOL.@]
6845 DWORD WINAPI EnumPrinterDataW( HANDLE hPrinter, DWORD dwIndex, LPWSTR pValueName,
6846 DWORD cbValueName, LPDWORD pcbValueName, LPDWORD pType, LPBYTE pData,
6847 DWORD cbData, LPDWORD pcbData )
6849 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter, dwIndex, pValueName,
6850 cbValueName, pcbValueName, pType, pData, cbData, pcbData);
6851 return ERROR_NO_MORE_ITEMS;
6854 /*****************************************************************************
6855 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
6858 BOOL WINAPI EnumPrintProcessorDatatypesA(LPSTR pName, LPSTR pPrintProcessorName,
6859 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6860 LPDWORD pcbNeeded, LPDWORD pcReturned)
6862 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName),
6863 debugstr_a(pPrintProcessorName), Level, pDatatypes, cbBuf,
6864 pcbNeeded, pcReturned);
6865 return FALSE;
6868 /*****************************************************************************
6869 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
6872 BOOL WINAPI EnumPrintProcessorDatatypesW(LPWSTR pName, LPWSTR pPrintProcessorName,
6873 DWORD Level, LPBYTE pDatatypes, DWORD cbBuf,
6874 LPDWORD pcbNeeded, LPDWORD pcReturned)
6876 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6877 debugstr_w(pPrintProcessorName), Level, pDatatypes, cbBuf,
6878 pcbNeeded, pcReturned);
6879 return FALSE;
6882 /*****************************************************************************
6883 * EnumPrintProcessorsA [WINSPOOL.@]
6886 BOOL WINAPI EnumPrintProcessorsA(LPSTR pName, LPSTR pEnvironment, DWORD Level,
6887 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6889 FIXME("Stub: %s %s %d %p %d %p %p\n", pName, pEnvironment, Level,
6890 pPrintProcessorInfo, cbBuf, pcbNeeded, pcbReturned);
6891 return FALSE;
6894 /*****************************************************************************
6895 * EnumPrintProcessorsW [WINSPOOL.@]
6898 BOOL WINAPI EnumPrintProcessorsW(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
6899 LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcbReturned)
6901 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName),
6902 debugstr_w(pEnvironment), Level, pPrintProcessorInfo,
6903 cbBuf, pcbNeeded, pcbReturned);
6904 return FALSE;
6907 /*****************************************************************************
6908 * ExtDeviceMode [WINSPOOL.@]
6911 LONG WINAPI ExtDeviceMode( HWND hWnd, HANDLE hInst, LPDEVMODEA pDevModeOutput,
6912 LPSTR pDeviceName, LPSTR pPort, LPDEVMODEA pDevModeInput, LPSTR pProfile,
6913 DWORD fMode)
6915 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd, hInst, pDevModeOutput,
6916 debugstr_a(pDeviceName), debugstr_a(pPort), pDevModeInput,
6917 debugstr_a(pProfile), fMode);
6918 return -1;
6921 /*****************************************************************************
6922 * FindClosePrinterChangeNotification [WINSPOOL.@]
6925 BOOL WINAPI FindClosePrinterChangeNotification( HANDLE hChange )
6927 FIXME("Stub: %p\n", hChange);
6928 return TRUE;
6931 /*****************************************************************************
6932 * FindFirstPrinterChangeNotification [WINSPOOL.@]
6935 HANDLE WINAPI FindFirstPrinterChangeNotification( HANDLE hPrinter,
6936 DWORD fdwFlags, DWORD fdwOptions, LPVOID pPrinterNotifyOptions )
6938 FIXME("Stub: %p %x %x %p\n",
6939 hPrinter, fdwFlags, fdwOptions, pPrinterNotifyOptions);
6940 return INVALID_HANDLE_VALUE;
6943 /*****************************************************************************
6944 * FindNextPrinterChangeNotification [WINSPOOL.@]
6947 BOOL WINAPI FindNextPrinterChangeNotification( HANDLE hChange, PDWORD pdwChange,
6948 LPVOID pPrinterNotifyOptions, LPVOID *ppPrinterNotifyInfo )
6950 FIXME("Stub: %p %p %p %p\n",
6951 hChange, pdwChange, pPrinterNotifyOptions, ppPrinterNotifyInfo);
6952 return FALSE;
6955 /*****************************************************************************
6956 * FreePrinterNotifyInfo [WINSPOOL.@]
6959 BOOL WINAPI FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo )
6961 FIXME("Stub: %p\n", pPrinterNotifyInfo);
6962 return TRUE;
6965 /*****************************************************************************
6966 * string_to_buf
6968 * Copies a unicode string into a buffer. The buffer will either contain unicode or
6969 * ansi depending on the unicode parameter.
6971 static BOOL string_to_buf(LPCWSTR str, LPBYTE ptr, DWORD cb, DWORD *size, BOOL unicode)
6973 if(!str)
6975 *size = 0;
6976 return TRUE;
6979 if(unicode)
6981 *size = (strlenW(str) + 1) * sizeof(WCHAR);
6982 if(*size <= cb)
6984 memcpy(ptr, str, *size);
6985 return TRUE;
6987 return FALSE;
6989 else
6991 *size = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
6992 if(*size <= cb)
6994 WideCharToMultiByte(CP_ACP, 0, str, -1, (LPSTR)ptr, *size, NULL, NULL);
6995 return TRUE;
6997 return FALSE;
7001 /*****************************************************************************
7002 * get_job_info_1
7004 static BOOL get_job_info_1(job_t *job, JOB_INFO_1W *ji1, LPBYTE buf, DWORD cbBuf,
7005 LPDWORD pcbNeeded, BOOL unicode)
7007 DWORD size, left = cbBuf;
7008 BOOL space = (cbBuf > 0);
7009 LPBYTE ptr = buf;
7011 *pcbNeeded = 0;
7013 if(space)
7015 ji1->JobId = job->job_id;
7018 string_to_buf(job->document_title, ptr, left, &size, unicode);
7019 if(space && size <= left)
7021 ji1->pDocument = (LPWSTR)ptr;
7022 ptr += size;
7023 left -= size;
7025 else
7026 space = FALSE;
7027 *pcbNeeded += size;
7029 return space;
7032 /*****************************************************************************
7033 * get_job_info_2
7035 static BOOL get_job_info_2(job_t *job, JOB_INFO_2W *ji2, LPBYTE buf, DWORD cbBuf,
7036 LPDWORD pcbNeeded, BOOL unicode)
7038 DWORD size, left = cbBuf;
7039 BOOL space = (cbBuf > 0);
7040 LPBYTE ptr = buf;
7042 *pcbNeeded = 0;
7044 if(space)
7046 ji2->JobId = job->job_id;
7049 string_to_buf(job->document_title, ptr, left, &size, unicode);
7050 if(space && size <= left)
7052 ji2->pDocument = (LPWSTR)ptr;
7053 ptr += size;
7054 left -= size;
7056 else
7057 space = FALSE;
7058 *pcbNeeded += size;
7060 return space;
7063 /*****************************************************************************
7064 * get_job_info
7066 static BOOL get_job_info(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7067 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
7069 BOOL ret = FALSE;
7070 DWORD needed = 0, size;
7071 job_t *job;
7072 LPBYTE ptr = pJob;
7074 TRACE("%p %d %d %p %d %p\n", hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
7076 EnterCriticalSection(&printer_handles_cs);
7077 job = get_job(hPrinter, JobId);
7078 if(!job)
7079 goto end;
7081 switch(Level)
7083 case 1:
7084 size = sizeof(JOB_INFO_1W);
7085 if(cbBuf >= size)
7087 cbBuf -= size;
7088 ptr += size;
7089 memset(pJob, 0, size);
7091 else
7092 cbBuf = 0;
7093 ret = get_job_info_1(job, (JOB_INFO_1W *)pJob, ptr, cbBuf, &needed, unicode);
7094 needed += size;
7095 break;
7097 case 2:
7098 size = sizeof(JOB_INFO_2W);
7099 if(cbBuf >= size)
7101 cbBuf -= size;
7102 ptr += size;
7103 memset(pJob, 0, size);
7105 else
7106 cbBuf = 0;
7107 ret = get_job_info_2(job, (JOB_INFO_2W *)pJob, ptr, cbBuf, &needed, unicode);
7108 needed += size;
7109 break;
7111 case 3:
7112 size = sizeof(JOB_INFO_3);
7113 if(cbBuf >= size)
7115 cbBuf -= size;
7116 memset(pJob, 0, size);
7117 ret = TRUE;
7119 else
7120 cbBuf = 0;
7121 needed = size;
7122 break;
7124 default:
7125 SetLastError(ERROR_INVALID_LEVEL);
7126 goto end;
7128 if(pcbNeeded)
7129 *pcbNeeded = needed;
7130 end:
7131 LeaveCriticalSection(&printer_handles_cs);
7132 return ret;
7135 /*****************************************************************************
7136 * GetJobA [WINSPOOL.@]
7139 BOOL WINAPI GetJobA(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7140 DWORD cbBuf, LPDWORD pcbNeeded)
7142 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, FALSE);
7145 /*****************************************************************************
7146 * GetJobW [WINSPOOL.@]
7149 BOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob,
7150 DWORD cbBuf, LPDWORD pcbNeeded)
7152 return get_job_info(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded, TRUE);
7155 /*****************************************************************************
7156 * schedule_lpr
7158 static BOOL schedule_lpr(LPCWSTR printer_name, LPCWSTR filename)
7160 char *unixname, *queue, *cmd;
7161 char fmt[] = "lpr -P%s %s";
7162 DWORD len;
7164 if(!(unixname = wine_get_unix_file_name(filename)))
7165 return FALSE;
7167 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7168 queue = HeapAlloc(GetProcessHeap(), 0, len);
7169 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7171 cmd = HeapAlloc(GetProcessHeap(), 0, strlen(unixname) + len + sizeof(fmt) - 5);
7172 sprintf(cmd, fmt, queue, unixname);
7174 TRACE("printing with: %s\n", cmd);
7175 system(cmd);
7177 HeapFree(GetProcessHeap(), 0, cmd);
7178 HeapFree(GetProcessHeap(), 0, queue);
7179 HeapFree(GetProcessHeap(), 0, unixname);
7180 return TRUE;
7183 /*****************************************************************************
7184 * schedule_cups
7186 static BOOL schedule_cups(LPCWSTR printer_name, LPCWSTR filename, LPCWSTR document_title)
7188 #if HAVE_CUPS_CUPS_H
7189 if(pcupsPrintFile)
7191 char *unixname, *queue, *doc_titleA;
7192 DWORD len;
7193 BOOL ret;
7195 if(!(unixname = wine_get_unix_file_name(filename)))
7196 return FALSE;
7198 len = WideCharToMultiByte(CP_ACP, 0, printer_name, -1, NULL, 0, NULL, NULL);
7199 queue = HeapAlloc(GetProcessHeap(), 0, len);
7200 WideCharToMultiByte(CP_ACP, 0, printer_name, -1, queue, len, NULL, NULL);
7202 len = WideCharToMultiByte(CP_ACP, 0, document_title, -1, NULL, 0, NULL, NULL);
7203 doc_titleA = HeapAlloc(GetProcessHeap(), 0, len);
7204 WideCharToMultiByte(CP_ACP, 0, document_title, -1, doc_titleA, len, NULL, NULL);
7206 TRACE("printing via cups\n");
7207 ret = pcupsPrintFile(queue, unixname, doc_titleA, 0, NULL);
7208 HeapFree(GetProcessHeap(), 0, doc_titleA);
7209 HeapFree(GetProcessHeap(), 0, queue);
7210 HeapFree(GetProcessHeap(), 0, unixname);
7211 return ret;
7213 else
7214 #endif
7216 return schedule_lpr(printer_name, filename);
7220 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
7222 LPWSTR filename;
7224 switch(msg)
7226 case WM_INITDIALOG:
7227 SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
7228 return TRUE;
7230 case WM_COMMAND:
7231 if(HIWORD(wparam) == BN_CLICKED)
7233 if(LOWORD(wparam) == IDOK)
7235 HANDLE hf;
7236 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
7237 LPWSTR *output;
7239 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
7240 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
7242 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
7244 WCHAR caption[200], message[200];
7245 int mb_ret;
7247 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7248 LoadStringW(WINSPOOL_hInstance, IDS_FILE_EXISTS, message, sizeof(message) / sizeof(WCHAR));
7249 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
7250 if(mb_ret == IDCANCEL)
7252 HeapFree(GetProcessHeap(), 0, filename);
7253 return TRUE;
7256 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
7257 if(hf == INVALID_HANDLE_VALUE)
7259 WCHAR caption[200], message[200];
7261 LoadStringW(WINSPOOL_hInstance, IDS_CAPTION, caption, sizeof(caption) / sizeof(WCHAR));
7262 LoadStringW(WINSPOOL_hInstance, IDS_CANNOT_OPEN, message, sizeof(message) / sizeof(WCHAR));
7263 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
7264 HeapFree(GetProcessHeap(), 0, filename);
7265 return TRUE;
7267 CloseHandle(hf);
7268 DeleteFileW(filename);
7269 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
7270 *output = filename;
7271 EndDialog(hwnd, IDOK);
7272 return TRUE;
7274 if(LOWORD(wparam) == IDCANCEL)
7276 EndDialog(hwnd, IDCANCEL);
7277 return TRUE;
7280 return FALSE;
7282 return FALSE;
7285 /*****************************************************************************
7286 * get_filename
7288 static BOOL get_filename(LPWSTR *filename)
7290 return DialogBoxParamW(WINSPOOL_hInstance, MAKEINTRESOURCEW(FILENAME_DIALOG), GetForegroundWindow(),
7291 file_dlg_proc, (LPARAM)filename) == IDOK;
7294 /*****************************************************************************
7295 * schedule_file
7297 static BOOL schedule_file(LPCWSTR filename)
7299 LPWSTR output = NULL;
7301 if(get_filename(&output))
7303 TRACE("copy to %s\n", debugstr_w(output));
7304 CopyFileW(filename, output, FALSE);
7305 HeapFree(GetProcessHeap(), 0, output);
7306 return TRUE;
7308 return FALSE;
7311 /*****************************************************************************
7312 * schedule_pipe
7314 static BOOL schedule_pipe(LPCWSTR cmd, LPCWSTR filename)
7316 #ifdef HAVE_FORK
7317 char *unixname, *cmdA;
7318 DWORD len;
7319 int fds[2] = {-1, -1}, file_fd = -1, no_read;
7320 BOOL ret = FALSE;
7321 char buf[1024];
7323 if(!(unixname = wine_get_unix_file_name(filename)))
7324 return FALSE;
7326 len = WideCharToMultiByte(CP_ACP, 0, cmd, -1, NULL, 0, NULL, NULL);
7327 cmdA = HeapAlloc(GetProcessHeap(), 0, len);
7328 WideCharToMultiByte(CP_ACP, 0, cmd, -1, cmdA, len, NULL, NULL);
7330 TRACE("printing with: %s\n", cmdA);
7332 if((file_fd = open(unixname, O_RDONLY)) == -1)
7333 goto end;
7335 if (pipe(fds))
7337 ERR("pipe() failed!\n");
7338 goto end;
7341 if (fork() == 0)
7343 close(0);
7344 dup2(fds[0], 0);
7345 close(fds[1]);
7347 /* reset signals that we previously set to SIG_IGN */
7348 signal(SIGPIPE, SIG_DFL);
7349 signal(SIGCHLD, SIG_DFL);
7351 execl("/bin/sh", "/bin/sh", "-c", cmdA, (char*)0);
7352 _exit(1);
7355 while((no_read = read(file_fd, buf, sizeof(buf))) > 0)
7356 write(fds[1], buf, no_read);
7358 ret = TRUE;
7360 end:
7361 if(file_fd != -1) close(file_fd);
7362 if(fds[0] != -1) close(fds[0]);
7363 if(fds[1] != -1) close(fds[1]);
7365 HeapFree(GetProcessHeap(), 0, cmdA);
7366 HeapFree(GetProcessHeap(), 0, unixname);
7367 return ret;
7368 #else
7369 return FALSE;
7370 #endif
7373 /*****************************************************************************
7374 * schedule_unixfile
7376 static BOOL schedule_unixfile(LPCWSTR output, LPCWSTR filename)
7378 int in_fd, out_fd, no_read;
7379 char buf[1024];
7380 BOOL ret = FALSE;
7381 char *unixname, *outputA;
7382 DWORD len;
7384 if(!(unixname = wine_get_unix_file_name(filename)))
7385 return FALSE;
7387 len = WideCharToMultiByte(CP_ACP, 0, output, -1, NULL, 0, NULL, NULL);
7388 outputA = HeapAlloc(GetProcessHeap(), 0, len);
7389 WideCharToMultiByte(CP_ACP, 0, output, -1, outputA, len, NULL, NULL);
7391 out_fd = open(outputA, O_CREAT | O_TRUNC | O_WRONLY, 0666);
7392 in_fd = open(unixname, O_RDONLY);
7393 if(out_fd == -1 || in_fd == -1)
7394 goto end;
7396 while((no_read = read(in_fd, buf, sizeof(buf))) > 0)
7397 write(out_fd, buf, no_read);
7399 ret = TRUE;
7400 end:
7401 if(in_fd != -1) close(in_fd);
7402 if(out_fd != -1) close(out_fd);
7403 HeapFree(GetProcessHeap(), 0, outputA);
7404 HeapFree(GetProcessHeap(), 0, unixname);
7405 return ret;
7408 /*****************************************************************************
7409 * ScheduleJob [WINSPOOL.@]
7412 BOOL WINAPI ScheduleJob( HANDLE hPrinter, DWORD dwJobID )
7414 opened_printer_t *printer;
7415 BOOL ret = FALSE;
7416 struct list *cursor, *cursor2;
7418 TRACE("(%p, %x)\n", hPrinter, dwJobID);
7419 EnterCriticalSection(&printer_handles_cs);
7420 printer = get_opened_printer(hPrinter);
7421 if(!printer)
7422 goto end;
7424 LIST_FOR_EACH_SAFE(cursor, cursor2, &printer->queue->jobs)
7426 job_t *job = LIST_ENTRY(cursor, job_t, entry);
7427 HANDLE hf;
7429 if(job->job_id != dwJobID) continue;
7431 hf = CreateFileW(job->filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
7432 if(hf != INVALID_HANDLE_VALUE)
7434 PRINTER_INFO_5W *pi5;
7435 DWORD needed;
7436 HKEY hkey;
7437 WCHAR output[1024];
7438 static const WCHAR spooler_key[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7439 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7441 GetPrinterW(hPrinter, 5, NULL, 0, &needed);
7442 pi5 = HeapAlloc(GetProcessHeap(), 0, needed);
7443 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, needed, &needed);
7444 TRACE("need to schedule job %d filename %s to port %s\n", job->job_id, debugstr_w(job->filename),
7445 debugstr_w(pi5->pPortName));
7447 output[0] = 0;
7449 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7450 if(RegOpenKeyW(HKEY_CURRENT_USER, spooler_key, &hkey) == ERROR_SUCCESS)
7452 DWORD type, count = sizeof(output);
7453 RegQueryValueExW(hkey, pi5->pPortName, NULL, &type, (LPBYTE)output, &count);
7454 RegCloseKey(hkey);
7456 if(output[0] == '|')
7458 schedule_pipe(output + 1, job->filename);
7460 else if(output[0])
7462 schedule_unixfile(output, job->filename);
7464 else if(!strncmpW(pi5->pPortName, LPR_Port, strlenW(LPR_Port)))
7466 schedule_lpr(pi5->pPortName + strlenW(LPR_Port), job->filename);
7468 else if(!strncmpW(pi5->pPortName, CUPS_Port, strlenW(CUPS_Port)))
7470 schedule_cups(pi5->pPortName + strlenW(CUPS_Port), job->filename, job->document_title);
7472 else if(!strncmpW(pi5->pPortName, FILE_Port, strlenW(FILE_Port)))
7474 schedule_file(job->filename);
7476 else
7478 FIXME("can't schedule to port %s\n", debugstr_w(pi5->pPortName));
7480 HeapFree(GetProcessHeap(), 0, pi5);
7481 CloseHandle(hf);
7482 DeleteFileW(job->filename);
7484 list_remove(cursor);
7485 HeapFree(GetProcessHeap(), 0, job->document_title);
7486 HeapFree(GetProcessHeap(), 0, job->filename);
7487 HeapFree(GetProcessHeap(), 0, job);
7488 ret = TRUE;
7489 break;
7491 end:
7492 LeaveCriticalSection(&printer_handles_cs);
7493 return ret;
7496 /*****************************************************************************
7497 * StartDocDlgA [WINSPOOL.@]
7499 LPSTR WINAPI StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
7501 UNICODE_STRING usBuffer;
7502 DOCINFOW docW;
7503 LPWSTR retW;
7504 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
7505 LPSTR ret = NULL;
7507 docW.cbSize = sizeof(docW);
7508 if (doc->lpszDocName)
7510 docnameW = asciitounicode(&usBuffer, doc->lpszDocName);
7511 if (!(docW.lpszDocName = docnameW)) return NULL;
7513 if (doc->lpszOutput)
7515 outputW = asciitounicode(&usBuffer, doc->lpszOutput);
7516 if (!(docW.lpszOutput = outputW)) return NULL;
7518 if (doc->lpszDatatype)
7520 datatypeW = asciitounicode(&usBuffer, doc->lpszDatatype);
7521 if (!(docW.lpszDatatype = datatypeW)) return NULL;
7523 docW.fwType = doc->fwType;
7525 retW = StartDocDlgW(hPrinter, &docW);
7527 if(retW)
7529 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
7530 ret = HeapAlloc(GetProcessHeap(), 0, len);
7531 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
7532 HeapFree(GetProcessHeap(), 0, retW);
7535 HeapFree(GetProcessHeap(), 0, datatypeW);
7536 HeapFree(GetProcessHeap(), 0, outputW);
7537 HeapFree(GetProcessHeap(), 0, docnameW);
7539 return ret;
7542 /*****************************************************************************
7543 * StartDocDlgW [WINSPOOL.@]
7545 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
7546 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
7547 * port is "FILE:". Also returns the full path if passed a relative path.
7549 * The caller should free the returned string from the process heap.
7551 LPWSTR WINAPI StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
7553 LPWSTR ret = NULL;
7554 DWORD len, attr;
7556 if(doc->lpszOutput == NULL) /* Check whether default port is FILE: */
7558 PRINTER_INFO_5W *pi5;
7559 GetPrinterW(hPrinter, 5, NULL, 0, &len);
7560 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
7561 return NULL;
7562 pi5 = HeapAlloc(GetProcessHeap(), 0, len);
7563 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
7564 if(!pi5->pPortName || strcmpW(pi5->pPortName, FILE_Port))
7566 HeapFree(GetProcessHeap(), 0, pi5);
7567 return NULL;
7569 HeapFree(GetProcessHeap(), 0, pi5);
7572 if(doc->lpszOutput == NULL || !strcmpW(doc->lpszOutput, FILE_Port))
7574 LPWSTR name;
7576 if (get_filename(&name))
7578 if(!(len = GetFullPathNameW(name, 0, NULL, NULL)))
7580 HeapFree(GetProcessHeap(), 0, name);
7581 return NULL;
7583 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7584 GetFullPathNameW(name, len, ret, NULL);
7585 HeapFree(GetProcessHeap(), 0, name);
7587 return ret;
7590 if(!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
7591 return NULL;
7593 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
7594 GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
7596 attr = GetFileAttributesW(ret);
7597 if(attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
7599 HeapFree(GetProcessHeap(), 0, ret);
7600 ret = NULL;
7602 return ret;