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
27 #include "wine/port.h"
39 #ifdef HAVE_CUPS_CUPS_H
40 # include <cups/cups.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
45 #include "wine/library.h"
54 #include "wine/windef16.h"
55 #include "wine/unicode.h"
56 #include "wine/debug.h"
57 #include "wine/list.h"
60 #include "ddk/winsplp.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(winspool
);
65 /* ############################### */
67 static CRITICAL_SECTION monitor_handles_cs
;
68 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
70 0, 0, &monitor_handles_cs
,
71 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
72 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
74 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
77 static CRITICAL_SECTION printer_handles_cs
;
78 static CRITICAL_SECTION_DEBUG printer_handles_cs_debug
=
80 0, 0, &printer_handles_cs
,
81 { &printer_handles_cs_debug
.ProcessLocksList
, &printer_handles_cs_debug
.ProcessLocksList
},
82 0, 0, { (DWORD_PTR
)(__FILE__
": printer_handles_cs") }
84 static CRITICAL_SECTION printer_handles_cs
= { &printer_handles_cs_debug
, -1, 0, 0, 0, 0 };
86 /* ############################### */
89 WCHAR src
[MAX_PATH
+MAX_PATH
];
90 WCHAR dst
[MAX_PATH
+MAX_PATH
];
100 PMONITORUI monitorUI
;
130 WCHAR
*document_title
;
138 LPCWSTR versionregpath
;
139 LPCWSTR versionsubdir
;
142 /* ############################### */
144 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
145 static monitor_t
* pm_localport
;
147 static opened_printer_t
**printer_handles
;
148 static int nb_printer_handles
;
149 static LONG next_job_id
= 1;
151 static DWORD (WINAPI
*GDI_CallDeviceCapabilities16
)( LPCSTR lpszDevice
, LPCSTR lpszPort
,
152 WORD fwCapability
, LPSTR lpszOutput
,
154 static INT (WINAPI
*GDI_CallExtDeviceMode16
)( HWND hwnd
, LPDEVMODEA lpdmOutput
,
155 LPSTR lpszDevice
, LPSTR lpszPort
,
156 LPDEVMODEA lpdmInput
, LPSTR lpszProfile
,
159 static const WCHAR DriversW
[] = { 'S','y','s','t','e','m','\\',
160 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
161 'c','o','n','t','r','o','l','\\',
162 'P','r','i','n','t','\\',
163 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
164 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
166 static const WCHAR MonitorsW
[] = { 'S','y','s','t','e','m','\\',
167 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
168 'C','o','n','t','r','o','l','\\',
169 'P','r','i','n','t','\\',
170 'M','o','n','i','t','o','r','s','\\',0};
172 static const WCHAR PrintersW
[] = {'S','y','s','t','e','m','\\',
173 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
174 'C','o','n','t','r','o','l','\\',
175 'P','r','i','n','t','\\',
176 'P','r','i','n','t','e','r','s',0};
178 static const WCHAR LocalPortW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
180 static const WCHAR user_default_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
181 'M','i','c','r','o','s','o','f','t','\\',
182 'W','i','n','d','o','w','s',' ','N','T','\\',
183 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
184 'W','i','n','d','o','w','s',0};
186 static const WCHAR user_printers_reg_key
[] = { 'S','o','f','t','w','a','r','e','\\',
187 'M','i','c','r','o','s','o','f','t','\\',
188 'W','i','n','d','o','w','s',' ','N','T','\\',
189 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
190 'D','e','v','i','c','e','s',0};
192 static const WCHAR WinNT_CV_PortsW
[] = {'S','o','f','t','w','a','r','e','\\',
193 'M','i','c','r','o','s','o','f','t','\\',
194 'W','i','n','d','o','w','s',' ','N','T','\\',
195 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
196 'P','o','r','t','s',0};
198 static const WCHAR DefaultEnvironmentW
[] = {'W','i','n','e',0};
199 static const WCHAR envname_win40W
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
200 static const WCHAR envname_x86W
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
201 static const WCHAR subdir_win40W
[] = {'w','i','n','4','0',0};
202 static const WCHAR subdir_x86W
[] = {'w','3','2','x','8','6',0};
203 static const WCHAR Version0_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
204 static const WCHAR Version0_SubdirW
[] = {'\\','0',0};
205 static const WCHAR Version3_RegPathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
206 static const WCHAR Version3_SubdirW
[] = {'\\','3',0};
208 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
209 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
211 static const WCHAR backslashW
[] = {'\\',0};
212 static const WCHAR Configuration_FileW
[] = {'C','o','n','f','i','g','u','r','a','t',
213 'i','o','n',' ','F','i','l','e',0};
214 static const WCHAR DatatypeW
[] = {'D','a','t','a','t','y','p','e',0};
215 static const WCHAR Data_FileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
216 static const WCHAR Default_DevModeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
217 static const WCHAR Dependent_FilesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
218 static const WCHAR DescriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
219 static const WCHAR DriverW
[] = {'D','r','i','v','e','r',0};
220 static const WCHAR HardwareIDW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
221 static const WCHAR Help_FileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
222 static const WCHAR LocationW
[] = {'L','o','c','a','t','i','o','n',0};
223 static const WCHAR ManufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
224 static const WCHAR MonitorW
[] = {'M','o','n','i','t','o','r',0};
225 static const WCHAR MonitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
226 static const WCHAR NameW
[] = {'N','a','m','e',0};
227 static const WCHAR OEM_UrlW
[] = {'O','E','M',' ','U','r','l',0};
228 static const WCHAR ParametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
229 static const WCHAR PortW
[] = {'P','o','r','t',0};
230 static const WCHAR bs_Ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
231 static const WCHAR Previous_NamesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
232 static const WCHAR Print_ProcessorW
[] = {'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r',0};
233 static const WCHAR Printer_DriverW
[] = {'P','r','i','n','t','e','r',' ','D','r','i','v','e','r',0};
234 static const WCHAR PrinterDriverDataW
[] = {'P','r','i','n','t','e','r','D','r','i','v','e','r','D','a','t','a',0};
235 static const WCHAR ProviderW
[] = {'P','r','o','v','i','d','e','r',0};
236 static const WCHAR Separator_FileW
[] = {'S','e','p','a','r','a','t','o','r',' ','F','i','l','e',0};
237 static const WCHAR Share_NameW
[] = {'S','h','a','r','e',' ','N','a','m','e',0};
238 static const WCHAR VersionW
[] = {'V','e','r','s','i','o','n',0};
239 static const WCHAR WinPrintW
[] = {'W','i','n','P','r','i','n','t',0};
240 static const WCHAR deviceW
[] = {'d','e','v','i','c','e',0};
241 static const WCHAR devicesW
[] = {'d','e','v','i','c','e','s',0};
242 static const WCHAR windowsW
[] = {'w','i','n','d','o','w','s',0};
243 static const WCHAR emptyStringW
[] = {0};
244 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
245 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
247 static const WCHAR May_Delete_Value
[] = {'W','i','n','e','M','a','y','D','e','l','e','t','e','M','e',0};
249 static const WCHAR CUPS_Port
[] = {'C','U','P','S',':',0};
250 static const WCHAR FILE_Port
[] = {'F','I','L','E',':',0};
251 static const WCHAR LPR_Port
[] = {'L','P','R',':',0};
253 static const WCHAR default_doc_title
[] = {'L','o','c','a','l',' ','D','o','w','n','l','e','v','e','l',' ',
254 'D','o','c','u','m','e','n','t',0};
256 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
257 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
258 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
259 0, sizeof(DRIVER_INFO_8W
)};
261 /******************************************************************
262 * validate the user-supplied printing-environment [internal]
265 * env [I] PTR to Environment-String or NULL
269 * Success: PTR to printenv_t
272 * An empty string is handled the same way as NULL.
273 * SetLastEror(ERROR_INVALID_ENVIRONMENT) is called on Failure
277 static const printenv_t
* validate_envW(LPCWSTR env
)
279 static const printenv_t env_x86
= {envname_x86W
, subdir_x86W
,
280 3, Version3_RegPathW
, Version3_SubdirW
};
281 static const printenv_t env_win40
= {envname_win40W
, subdir_win40W
,
282 0, Version0_RegPathW
, Version0_SubdirW
};
284 static const printenv_t
* const all_printenv
[]={&env_x86
, &env_win40
};
286 const printenv_t
*result
= NULL
;
289 TRACE("testing %s\n", debugstr_w(env
));
292 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
294 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
296 result
= all_printenv
[i
];
301 if (result
== NULL
) {
302 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
303 SetLastError(ERROR_INVALID_ENVIRONMENT
);
305 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
309 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
311 TRACE("using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
317 /* RtlCreateUnicodeStringFromAsciiz will return an empty string in the buffer
318 if passed a NULL string. This returns NULLs to the result.
320 static inline PWSTR
asciitounicode( UNICODE_STRING
* usBufferPtr
, LPCSTR src
)
324 RtlCreateUnicodeStringFromAsciiz(usBufferPtr
, src
);
325 return usBufferPtr
->Buffer
;
327 usBufferPtr
->Buffer
= NULL
; /* so that RtlFreeUnicodeString won't barf */
331 static LPWSTR
strdupW(LPCWSTR p
)
337 len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
338 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
343 static LPSTR
strdupWtoA( LPCWSTR str
)
348 if (!str
) return NULL
;
349 len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
350 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
351 if(ret
) WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
355 /******************************************************************
356 * apd_copyfile [internal]
358 * Copy a file from the driverdirectory to the versioned directory
365 static BOOL
apd_copyfile(LPWSTR filename
, apd_data_t
*apd
)
371 apd
->src
[apd
->srclen
] = '\0';
372 apd
->dst
[apd
->dstlen
] = '\0';
374 if (!filename
|| !filename
[0]) {
375 /* nothing to copy */
379 ptr
= strrchrW(filename
, '\\');
388 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
) {
389 /* we have an absolute Path */
395 lstrcatW(srcname
, ptr
);
397 lstrcatW(apd
->dst
, ptr
);
399 TRACE("%s => %s\n", debugstr_w(filename
), debugstr_w(apd
->dst
));
401 /* FIXME: handle APD_COPY_NEW_FILES */
402 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
403 TRACE("got %u with %u\n", res
, GetLastError());
405 /* FIXME: install of wineps.drv must be fixed, before we return the real result
412 /******************************************************************
413 * Return the number of bytes for an multi_sz string.
414 * The result includes all \0s
415 * (specifically the extra \0, that is needed as multi_sz terminator).
417 static int multi_sz_lenW(const WCHAR
*str
)
419 const WCHAR
*ptr
= str
;
423 ptr
+= lstrlenW(ptr
) + 1;
426 return (ptr
- str
+ 1) * sizeof(WCHAR
);
429 /* ################################ */
431 static int multi_sz_lenA(const char *str
)
433 const char *ptr
= str
;
437 ptr
+= lstrlenA(ptr
) + 1;
440 return ptr
- str
+ 1;
444 WINSPOOL_SetDefaultPrinter(const char *devname
, const char *name
, BOOL force
) {
447 /* If forcing, or no profile string entry for device yet, set the entry
449 * The always change entry if not WINEPS yet is discussable.
452 !GetProfileStringA("windows","device","*",qbuf
,sizeof(qbuf
)) ||
454 !strstr(qbuf
,"WINEPS.DRV")
456 char *buf
= HeapAlloc(GetProcessHeap(),0,strlen(name
)+strlen(devname
)+strlen(",WINEPS.DRV,LPR:")+1);
459 sprintf(buf
,"%s,WINEPS.DRV,LPR:%s",devname
,name
);
460 WriteProfileStringA("windows","device",buf
);
461 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_default_reg_key
, &hkey
) == ERROR_SUCCESS
) {
462 RegSetValueExA(hkey
, "Device", 0, REG_SZ
, (LPBYTE
)buf
, strlen(buf
) + 1);
465 HeapFree(GetProcessHeap(),0,buf
);
469 static BOOL
add_printer_driver(const char *name
)
473 static char driver_9x
[] = "wineps16.drv",
474 driver_nt
[] = "wineps.drv",
475 env_9x
[] = "Windows 4.0",
476 env_nt
[] = "Windows NT x86",
477 data_file
[] = "generic.ppd",
478 default_data_type
[] = "RAW";
480 ZeroMemory(&di3a
, sizeof(DRIVER_INFO_3A
));
482 di3a
.pName
= (char *)name
;
483 di3a
.pEnvironment
= env_nt
;
484 di3a
.pDriverPath
= driver_nt
;
485 di3a
.pDataFile
= data_file
;
486 di3a
.pConfigFile
= driver_nt
;
487 di3a
.pDefaultDataType
= default_data_type
;
489 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
))
492 di3a
.pEnvironment
= env_9x
;
493 di3a
.pDriverPath
= driver_9x
;
494 di3a
.pConfigFile
= driver_9x
;
495 if (AddPrinterDriverA(NULL
, 3, (LPBYTE
)&di3a
))
500 ERR("Failed adding driver %s: %u\n", debugstr_a(di3a
.pDriverPath
), GetLastError());
504 #ifdef SONAME_LIBCUPS
505 static typeof(cupsGetDests
) *pcupsGetDests
;
506 static typeof(cupsGetPPD
) *pcupsGetPPD
;
507 static typeof(cupsPrintFile
) *pcupsPrintFile
;
508 static void *cupshandle
;
510 static BOOL
CUPS_LoadPrinters(void)
513 BOOL hadprinter
= FALSE
, haddefault
= FALSE
;
515 PRINTER_INFO_2A pinfo2a
;
517 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
520 cupshandle
= wine_dlopen(SONAME_LIBCUPS
, RTLD_NOW
, loaderror
, sizeof(loaderror
));
522 TRACE("%s\n", loaderror
);
525 TRACE("%p: %s loaded\n", cupshandle
, SONAME_LIBCUPS
);
528 p##x = wine_dlsym(cupshandle, #x, NULL,0); \
529 if (!p##x) return FALSE;
532 DYNCUPS(cupsGetDests
);
533 DYNCUPS(cupsPrintFile
);
536 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
538 ERR("Can't create Printers key\n");
542 nrofdests
= pcupsGetDests(&dests
);
543 TRACE("Found %d CUPS %s:\n", nrofdests
, (nrofdests
== 1) ? "printer" : "printers");
544 for (i
=0;i
<nrofdests
;i
++) {
545 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests
[i
].name
)+1);
546 sprintf(port
,"LPR:%s",dests
[i
].name
);
547 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
548 sprintf(devline
,"WINEPS.DRV,%s",port
);
549 WriteProfileStringA("devices",dests
[i
].name
,devline
);
550 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
551 RegSetValueExA(hkey
, dests
[i
].name
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
554 HeapFree(GetProcessHeap(),0,devline
);
556 TRACE("Printer %d: %s\n", i
, dests
[i
].name
);
557 if(RegOpenKeyA(hkeyPrinters
, dests
[i
].name
, &hkeyPrinter
) == ERROR_SUCCESS
) {
558 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
560 TRACE("Printer already exists\n");
561 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
562 RegCloseKey(hkeyPrinter
);
564 static CHAR data_type
[] = "RAW",
565 print_proc
[] = "WinPrint",
566 comment
[] = "WINEPS Printer using CUPS",
567 location
[] = "<physical location of printer>",
568 params
[] = "<parameters?>",
569 share_name
[] = "<share name?>",
570 sep_file
[] = "<sep file?>";
572 add_printer_driver(dests
[i
].name
);
574 memset(&pinfo2a
,0,sizeof(pinfo2a
));
575 pinfo2a
.pPrinterName
= dests
[i
].name
;
576 pinfo2a
.pDatatype
= data_type
;
577 pinfo2a
.pPrintProcessor
= print_proc
;
578 pinfo2a
.pDriverName
= dests
[i
].name
;
579 pinfo2a
.pComment
= comment
;
580 pinfo2a
.pLocation
= location
;
581 pinfo2a
.pPortName
= port
;
582 pinfo2a
.pParameters
= params
;
583 pinfo2a
.pShareName
= share_name
;
584 pinfo2a
.pSepFile
= sep_file
;
586 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
587 if (GetLastError() != ERROR_PRINTER_ALREADY_EXISTS
)
588 ERR("printer '%s' not added by AddPrinterA (error %d)\n",dests
[i
].name
,GetLastError());
591 HeapFree(GetProcessHeap(),0,port
);
594 if (dests
[i
].is_default
) {
595 WINSPOOL_SetDefaultPrinter(dests
[i
].name
, dests
[i
].name
, TRUE
);
599 if (hadprinter
& !haddefault
)
600 WINSPOOL_SetDefaultPrinter(dests
[0].name
, dests
[0].name
, TRUE
);
601 RegCloseKey(hkeyPrinters
);
607 PRINTCAP_ParseEntry(const char *pent
, BOOL isfirst
) {
608 PRINTER_INFO_2A pinfo2a
;
609 char *e
,*s
,*name
,*prettyname
,*devname
;
610 BOOL ret
= FALSE
, set_default
= FALSE
;
611 char *port
,*devline
,*env_default
;
612 HKEY hkeyPrinter
, hkeyPrinters
, hkey
;
614 while (isspace(*pent
)) pent
++;
615 s
= strchr(pent
,':');
617 name
= HeapAlloc(GetProcessHeap(), 0, strlen(pent
) + 1);
625 TRACE("name=%s entry=%s\n",name
, pent
);
627 if(ispunct(*name
)) { /* a tc entry, not a real printer */
628 TRACE("skipping tc entry\n");
632 if(strstr(pent
,":server")) { /* server only version so skip */
633 TRACE("skipping server entry\n");
637 /* Determine whether this is a postscript printer. */
640 env_default
= getenv("PRINTER");
642 /* Get longest name, usually the one at the right for later display. */
643 while((s
=strchr(prettyname
,'|'))) {
646 while(isspace(*--e
)) *e
= '\0';
647 TRACE("\t%s\n", debugstr_a(prettyname
));
648 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
649 for(prettyname
= s
+1; isspace(*prettyname
); prettyname
++)
652 e
= prettyname
+ strlen(prettyname
);
653 while(isspace(*--e
)) *e
= '\0';
654 TRACE("\t%s\n", debugstr_a(prettyname
));
655 if(env_default
&& !strcasecmp(prettyname
, env_default
)) set_default
= TRUE
;
657 /* prettyname must fit into the dmDeviceName member of DEVMODE struct,
658 * if it is too long, we use it as comment below. */
659 devname
= prettyname
;
660 if (strlen(devname
)>=CCHDEVICENAME
-1)
662 if (strlen(devname
)>=CCHDEVICENAME
-1) {
667 port
= HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name
)+1);
668 sprintf(port
,"LPR:%s",name
);
670 devline
=HeapAlloc(GetProcessHeap(),0,sizeof("WINEPS.DRV,")+strlen(port
));
671 sprintf(devline
,"WINEPS.DRV,%s",port
);
672 WriteProfileStringA("devices",devname
,devline
);
673 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
674 RegSetValueExA(hkey
, devname
, 0, REG_SZ
, (LPBYTE
)devline
, strlen(devline
) + 1);
677 HeapFree(GetProcessHeap(),0,devline
);
679 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
681 ERR("Can't create Printers key\n");
685 if(RegOpenKeyA(hkeyPrinters
, devname
, &hkeyPrinter
) == ERROR_SUCCESS
) {
686 /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
688 TRACE("Printer already exists\n");
689 RegDeleteValueW(hkeyPrinter
, May_Delete_Value
);
690 RegCloseKey(hkeyPrinter
);
692 static CHAR data_type
[] = "RAW",
693 print_proc
[] = "WinPrint",
694 comment
[] = "WINEPS Printer using LPR",
695 params
[] = "<parameters?>",
696 share_name
[] = "<share name?>",
697 sep_file
[] = "<sep file?>";
699 add_printer_driver(devname
);
701 memset(&pinfo2a
,0,sizeof(pinfo2a
));
702 pinfo2a
.pPrinterName
= devname
;
703 pinfo2a
.pDatatype
= data_type
;
704 pinfo2a
.pPrintProcessor
= print_proc
;
705 pinfo2a
.pDriverName
= devname
;
706 pinfo2a
.pComment
= comment
;
707 pinfo2a
.pLocation
= prettyname
;
708 pinfo2a
.pPortName
= port
;
709 pinfo2a
.pParameters
= params
;
710 pinfo2a
.pShareName
= share_name
;
711 pinfo2a
.pSepFile
= sep_file
;
713 if (!AddPrinterA(NULL
,2,(LPBYTE
)&pinfo2a
)) {
714 if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS
)
715 ERR("%s not added by AddPrinterA (%d)\n",name
,GetLastError());
718 RegCloseKey(hkeyPrinters
);
720 if (isfirst
|| set_default
)
721 WINSPOOL_SetDefaultPrinter(devname
,name
,TRUE
);
723 HeapFree(GetProcessHeap(), 0, port
);
725 HeapFree(GetProcessHeap(), 0, name
);
730 PRINTCAP_LoadPrinters(void) {
731 BOOL hadprinter
= FALSE
;
735 BOOL had_bash
= FALSE
;
737 f
= fopen("/etc/printcap","r");
741 while(fgets(buf
,sizeof(buf
),f
)) {
744 end
=strchr(buf
,'\n');
748 while(isspace(*start
)) start
++;
749 if(*start
== '#' || *start
== '\0')
752 if(pent
&& !had_bash
&& *start
!= ':' && *start
!= '|') { /* start of new entry, parse the previous one */
753 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
754 HeapFree(GetProcessHeap(),0,pent
);
758 if (end
&& *--end
== '\\') {
765 pent
=HeapReAlloc(GetProcessHeap(),0,pent
,strlen(pent
)+strlen(start
)+1);
768 pent
=HeapAlloc(GetProcessHeap(),0,strlen(start
)+1);
774 hadprinter
|= PRINTCAP_ParseEntry(pent
,!hadprinter
);
775 HeapFree(GetProcessHeap(),0,pent
);
781 static inline DWORD
set_reg_szW(HKEY hkey
, const WCHAR
*keyname
, const WCHAR
*value
)
784 return RegSetValueExW(hkey
, keyname
, 0, REG_SZ
, (const BYTE
*)value
,
785 (lstrlenW(value
) + 1) * sizeof(WCHAR
));
787 return ERROR_FILE_NOT_FOUND
;
790 /*****************************************************************************
791 * enumerate the local monitors (INTERNAL)
793 * returns the needed size (in bytes) for pMonitors
794 * and *lpreturned is set to number of entries returned in pMonitors
797 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
802 LPMONITOR_INFO_2W mi
;
803 WCHAR buffer
[MAX_PATH
];
804 WCHAR dllname
[MAX_PATH
];
812 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
814 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
815 len
= entrysize
* numentries
;
816 ptr
= (LPWSTR
) &pMonitors
[len
];
819 len
= sizeof(buffer
);
822 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
823 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
824 /* Scan all Monitor-Registry-Keys */
825 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
826 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
827 dllsize
= sizeof(dllname
);
830 /* The Monitor must have a Driver-DLL */
831 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
832 if (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
833 /* We found a valid DLL for this Monitor. */
834 TRACE("using Driver: %s\n", debugstr_w(dllname
));
839 /* Windows returns only Port-Monitors here, but to simplify our code,
840 we do no filtering for Language-Monitors */
844 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
846 /* we install and return only monitors for "Windows NT x86" */
847 needed
+= (lstrlenW(envname_x86W
) +1) * sizeof(WCHAR
);
851 /* required size is calculated. Now fill the user-buffer */
852 if (pMonitors
&& (cbBuf
>= needed
)){
853 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
854 pMonitors
+= entrysize
;
856 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
858 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
859 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
861 mi
->pEnvironment
= ptr
;
862 lstrcpyW(ptr
, envname_x86W
); /* fixed to "Windows NT x86" */
863 ptr
+= (lstrlenW(envname_x86W
)+1);
866 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
867 ptr
+= (dllsize
/ sizeof(WCHAR
));
872 len
= sizeof(buffer
);
877 *lpreturned
= numentries
;
878 TRACE("need %d byte for %d entries\n", needed
, numentries
);
882 /******************************************************************
883 * monitor_unload [internal]
885 * release a printmonitor and unload it from memory, when needed
888 static void monitor_unload(monitor_t
* pm
)
890 if (pm
== NULL
) return;
891 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
893 EnterCriticalSection(&monitor_handles_cs
);
895 if (pm
->refcount
) pm
->refcount
--;
897 if (pm
->refcount
== 0) {
898 list_remove(&pm
->entry
);
899 FreeLibrary(pm
->hdll
);
900 HeapFree(GetProcessHeap(), 0, pm
->name
);
901 HeapFree(GetProcessHeap(), 0, pm
->dllname
);
902 HeapFree(GetProcessHeap(), 0, pm
);
904 LeaveCriticalSection(&monitor_handles_cs
);
907 /******************************************************************
908 * monitor_unloadall [internal]
910 * release all printmonitors and unload them from memory, when needed
913 static void monitor_unloadall(void)
918 EnterCriticalSection(&monitor_handles_cs
);
919 /* iterate through the list, with safety against removal */
920 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
924 LeaveCriticalSection(&monitor_handles_cs
);
927 /******************************************************************
928 * monitor_load [internal]
930 * load a printmonitor, get the dllname from the registry, when needed
931 * initialize the monitor and dump found function-pointers
933 * On failure, SetLastError() is called and NULL is returned
936 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
938 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
939 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
940 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
941 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
942 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
944 monitor_t
* pm
= NULL
;
946 LPWSTR regroot
= NULL
;
947 LPWSTR driver
= dllname
;
949 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
950 /* Is the Monitor already loaded? */
951 EnterCriticalSection(&monitor_handles_cs
);
954 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
956 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
964 pm
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(monitor_t
));
965 if (pm
== NULL
) goto cleanup
;
966 list_add_tail(&monitor_handles
, &pm
->entry
);
970 if (pm
->name
== NULL
) {
971 /* Load the monitor */
972 LPMONITOREX pmonitorEx
;
976 len
= lstrlenW(MonitorsW
) + lstrlenW(name
) + 2;
977 regroot
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
981 lstrcpyW(regroot
, MonitorsW
);
982 lstrcatW(regroot
, name
);
983 /* Get the Driver from the Registry */
984 if (driver
== NULL
) {
987 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
988 if (RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, NULL
,
989 &namesize
) == ERROR_SUCCESS
) {
990 driver
= HeapAlloc(GetProcessHeap(), 0, namesize
);
991 RegQueryValueExW(hroot
, DriverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
998 pm
->name
= strdupW(name
);
999 pm
->dllname
= strdupW(driver
);
1001 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
1003 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1008 pm
->hdll
= LoadLibraryW(driver
);
1009 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
1011 if (pm
->hdll
== NULL
) {
1013 SetLastError(ERROR_MOD_NOT_FOUND
);
1018 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
1019 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
1020 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
1021 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
1022 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
1025 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
1026 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
1027 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
1028 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
1029 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
1031 if (pInitializePrintMonitorUI
!= NULL
) {
1032 pm
->monitorUI
= pInitializePrintMonitorUI();
1033 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
1034 if (pm
->monitorUI
) {
1035 TRACE( "0x%08x: dwMonitorSize (%d)\n",
1036 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
1041 if (pInitializePrintMonitor
&& regroot
) {
1042 pmonitorEx
= pInitializePrintMonitor(regroot
);
1043 TRACE( "%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
1044 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
1047 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
1048 pm
->monitor
= &(pmonitorEx
->Monitor
);
1053 TRACE( "0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
1057 if (!pm
->monitor
&& regroot
) {
1058 if (pInitializePrintMonitor2
!= NULL
) {
1059 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
1061 if (pInitializeMonitorEx
!= NULL
) {
1062 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
1064 if (pInitializeMonitor
!= NULL
) {
1065 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
1068 if (!pm
->monitor
&& !pm
->monitorUI
) {
1070 SetLastError(ERROR_PROC_NOT_FOUND
);
1075 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, LocalPortW
) == 0)) {
1079 LeaveCriticalSection(&monitor_handles_cs
);
1080 if (driver
!= dllname
) HeapFree(GetProcessHeap(), 0, driver
);
1081 HeapFree(GetProcessHeap(), 0, regroot
);
1082 TRACE("=> %p\n", pm
);
1086 /******************************************************************
1087 * monitor_loadall [internal]
1089 * Load all registered monitors
1092 static DWORD
monitor_loadall(void)
1095 DWORD registered
= 0;
1098 WCHAR buffer
[MAX_PATH
];
1101 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
1102 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
1103 NULL
, NULL
, NULL
, NULL
, NULL
);
1105 TRACE("%d monitors registered\n", registered
);
1107 EnterCriticalSection(&monitor_handles_cs
);
1108 while (id
< registered
) {
1110 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
1111 pm
= monitor_load(buffer
, NULL
);
1115 LeaveCriticalSection(&monitor_handles_cs
);
1116 RegCloseKey(hmonitors
);
1118 TRACE("%d monitors loaded\n", loaded
);
1122 /******************************************************************
1123 * monitor_loadui [internal]
1125 * load the userinterface-dll for a given portmonitor
1127 * On failure, NULL is returned
1130 static monitor_t
* monitor_loadui(monitor_t
* pm
)
1132 monitor_t
* pui
= NULL
;
1133 LPWSTR buffer
[MAX_PATH
];
1138 if (pm
== NULL
) return NULL
;
1139 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
1141 /* Try the Portmonitor first; works for many monitors */
1142 if (pm
->monitorUI
) {
1143 EnterCriticalSection(&monitor_handles_cs
);
1145 LeaveCriticalSection(&monitor_handles_cs
);
1149 /* query the userinterface-dllname from the Portmonitor */
1150 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
1151 /* building (",XcvMonitor %s",pm->name) not needed yet */
1152 res
= pm
->monitor
->pfnXcvOpenPort(emptyStringW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
1153 TRACE("got %u with %p\n", res
, hXcv
);
1155 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, MonitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
1156 TRACE("got %u with %s\n", res
, debugstr_w((LPWSTR
) buffer
));
1157 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, (LPWSTR
) buffer
);
1158 pm
->monitor
->pfnXcvClosePort(hXcv
);
1165 /******************************************************************
1166 * monitor_load_by_port [internal]
1168 * load a printmonitor for a given port
1170 * On failure, NULL is returned
1173 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
1178 monitor_t
* pm
= NULL
;
1179 DWORD registered
= 0;
1183 TRACE("(%s)\n", debugstr_w(portname
));
1185 /* Try the Local Monitor first */
1186 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, WinNT_CV_PortsW
, &hroot
) == ERROR_SUCCESS
) {
1187 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
1188 /* found the portname */
1190 return monitor_load(LocalPortW
, NULL
);
1195 len
= MAX_PATH
+ lstrlenW(bs_Ports_bsW
) + lstrlenW(portname
) + 1;
1196 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1197 if (buffer
== NULL
) return NULL
;
1199 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) == ERROR_SUCCESS
) {
1200 EnterCriticalSection(&monitor_handles_cs
);
1201 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1203 while ((pm
== NULL
) && (id
< registered
)) {
1205 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
1206 TRACE("testing %s\n", debugstr_w(buffer
));
1207 len
= lstrlenW(buffer
);
1208 lstrcatW(buffer
, bs_Ports_bsW
);
1209 lstrcatW(buffer
, portname
);
1210 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
1212 buffer
[len
] = '\0'; /* use only the Monitor-Name */
1213 pm
= monitor_load(buffer
, NULL
);
1217 LeaveCriticalSection(&monitor_handles_cs
);
1220 HeapFree(GetProcessHeap(), 0, buffer
);
1224 /******************************************************************
1225 * enumerate the local Ports from all loaded monitors (internal)
1227 * returns the needed size (in bytes) for pPorts
1228 * and *lpreturned is set to number of entries returned in pPorts
1231 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1235 LPPORT_INFO_2W cache
;
1237 LPBYTE pi_buffer
= NULL
;
1238 DWORD pi_allocated
= 0;
1249 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1250 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1252 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1253 needed
= entrysize
* numentries
;
1254 ptr
= (LPWSTR
) &pPorts
[needed
];
1259 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1261 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
1264 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1265 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1266 /* Do not use HeapReAlloc (we do not need the old data in the buffer) */
1267 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1268 pi_buffer
= HeapAlloc(GetProcessHeap(), 0, pi_needed
);
1269 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1270 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1272 TRACE( "(%s) got %d with %d (need %d byte for %d entries)\n",
1273 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1275 numentries
+= pi_returned
;
1276 needed
+= pi_needed
;
1278 /* fill the output-buffer (pPorts), if we have one */
1279 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1281 while (pi_returned
> pi_index
) {
1282 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1283 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1284 out
->pPortName
= ptr
;
1285 lstrcpyW(ptr
, cache
->pPortName
);
1286 ptr
+= (lstrlenW(ptr
)+1);
1288 out
->pMonitorName
= ptr
;
1289 lstrcpyW(ptr
, cache
->pMonitorName
);
1290 ptr
+= (lstrlenW(ptr
)+1);
1292 out
->pDescription
= ptr
;
1293 lstrcpyW(ptr
, cache
->pDescription
);
1294 ptr
+= (lstrlenW(ptr
)+1);
1295 out
->fPortType
= cache
->fPortType
;
1296 out
->Reserved
= cache
->Reserved
;
1304 /* the temporary portinfo-buffer is no longer needed */
1305 HeapFree(GetProcessHeap(), 0, pi_buffer
);
1307 *lpreturned
= numentries
;
1308 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1312 /******************************************************************
1313 * get_servername_from_name (internal)
1315 * for an external server, a copy of the serverpart from the full name is returned
1318 static LPWSTR
get_servername_from_name(LPCWSTR name
)
1322 WCHAR buffer
[MAX_PATH
];
1325 if (name
== NULL
) return NULL
;
1326 if ((name
[0] != '\\') || (name
[1] != '\\')) return NULL
;
1328 server
= strdupW(&name
[2]); /* skip over both backslash */
1329 if (server
== NULL
) return NULL
;
1331 /* strip '\' and the printername */
1332 ptr
= strchrW(server
, '\\');
1333 if (ptr
) ptr
[0] = '\0';
1335 TRACE("found %s\n", debugstr_w(server
));
1337 len
= sizeof(buffer
)/sizeof(buffer
[0]);
1338 if (GetComputerNameW(buffer
, &len
)) {
1339 if (lstrcmpW(buffer
, server
) == 0) {
1340 /* The requested Servername is our computername */
1341 HeapFree(GetProcessHeap(), 0, server
);
1348 /******************************************************************
1349 * get_basename_from_name (internal)
1351 * skip over the serverpart from the full name
1354 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
1356 if (name
== NULL
) return NULL
;
1357 if ((name
[0] == '\\') && (name
[1] == '\\')) {
1358 /* skip over the servername and search for the following '\' */
1359 name
= strchrW(&name
[2], '\\');
1360 if ((name
) && (name
[1])) {
1361 /* found a separator ('\') followed by a name:
1362 skip over the separator and return the rest */
1367 /* no basename present (we found only a servername) */
1374 /******************************************************************
1375 * get_opened_printer_entry
1376 * Get the first place empty in the opened printer table
1379 * - pDefault is ignored
1381 static HANDLE
get_opened_printer_entry(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1383 UINT_PTR handle
= nb_printer_handles
, i
;
1384 jobqueue_t
*queue
= NULL
;
1385 opened_printer_t
*printer
= NULL
;
1387 LPCWSTR printername
;
1392 servername
= get_servername_from_name(name
);
1394 FIXME("server %s not supported\n", debugstr_w(servername
));
1395 HeapFree(GetProcessHeap(), 0, servername
);
1396 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1400 printername
= get_basename_from_name(name
);
1401 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1403 /* an empty printername is invalid */
1404 if (printername
&& (!printername
[0])) {
1405 SetLastError(ERROR_INVALID_PARAMETER
);
1409 EnterCriticalSection(&printer_handles_cs
);
1411 for (i
= 0; i
< nb_printer_handles
; i
++)
1413 if (!printer_handles
[i
])
1415 if(handle
== nb_printer_handles
)
1420 if(!queue
&& (name
) && !lstrcmpW(name
, printer_handles
[i
]->name
))
1421 queue
= printer_handles
[i
]->queue
;
1425 if (handle
>= nb_printer_handles
)
1427 opened_printer_t
**new_array
;
1428 if (printer_handles
)
1429 new_array
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, printer_handles
,
1430 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1432 new_array
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
1433 (nb_printer_handles
+ 16) * sizeof(*new_array
) );
1440 printer_handles
= new_array
;
1441 nb_printer_handles
+= 16;
1444 if (!(printer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*printer
))))
1451 /* clone the base name. This is NULL for the printserver */
1452 printer
->printername
= strdupW(printername
);
1454 /* clone the full name */
1455 printer
->name
= strdupW(name
);
1456 if (name
&& (!printer
->name
)) {
1462 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1463 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1464 /* OpenPrinter(",XcvMonitor " detected */
1465 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1466 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1467 if (printer
->pm
== NULL
) {
1468 SetLastError(ERROR_UNKNOWN_PORT
);
1475 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1476 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1477 /* OpenPrinter(",XcvPort " detected */
1478 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1479 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1480 if (printer
->pm
== NULL
) {
1481 SetLastError(ERROR_UNKNOWN_PORT
);
1489 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1490 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1491 pDefault
? pDefault
->DesiredAccess
: 0,
1494 if (printer
->hXcv
== NULL
) {
1495 SetLastError(ERROR_INVALID_PARAMETER
);
1502 /* Does the Printer exist? */
1503 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1504 ERR("Can't create Printers key\n");
1508 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1509 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1510 RegCloseKey(hkeyPrinters
);
1511 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1515 RegCloseKey(hkeyPrinter
);
1516 RegCloseKey(hkeyPrinters
);
1521 TRACE("using the local printserver\n");
1525 printer
->queue
= queue
;
1528 printer
->queue
= HeapAlloc(GetProcessHeap(), 0, sizeof(*queue
));
1529 if (!printer
->queue
) {
1533 list_init(&printer
->queue
->jobs
);
1534 printer
->queue
->ref
= 0;
1536 InterlockedIncrement(&printer
->queue
->ref
);
1538 printer_handles
[handle
] = printer
;
1541 LeaveCriticalSection(&printer_handles_cs
);
1542 if (!handle
&& printer
) {
1543 /* Something failed: Free all resources */
1544 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1545 monitor_unload(printer
->pm
);
1546 HeapFree(GetProcessHeap(), 0, printer
->printername
);
1547 HeapFree(GetProcessHeap(), 0, printer
->name
);
1548 if (!queue
) HeapFree(GetProcessHeap(), 0, printer
->queue
);
1549 HeapFree(GetProcessHeap(), 0, printer
);
1552 return (HANDLE
)handle
;
1555 /******************************************************************
1556 * get_opened_printer
1557 * Get the pointer to the opened printer referred by the handle
1559 static opened_printer_t
*get_opened_printer(HANDLE hprn
)
1561 UINT_PTR idx
= (UINT_PTR
)hprn
;
1562 opened_printer_t
*ret
= NULL
;
1564 EnterCriticalSection(&printer_handles_cs
);
1566 if ((idx
<= 0) || (idx
> nb_printer_handles
))
1569 ret
= printer_handles
[idx
- 1];
1571 LeaveCriticalSection(&printer_handles_cs
);
1575 /******************************************************************
1576 * get_opened_printer_name
1577 * Get the pointer to the opened printer name referred by the handle
1579 static LPCWSTR
get_opened_printer_name(HANDLE hprn
)
1581 opened_printer_t
*printer
= get_opened_printer(hprn
);
1582 if(!printer
) return NULL
;
1583 return printer
->name
;
1586 /******************************************************************
1587 * WINSPOOL_GetOpenedPrinterRegKey
1590 static DWORD
WINSPOOL_GetOpenedPrinterRegKey(HANDLE hPrinter
, HKEY
*phkey
)
1592 LPCWSTR name
= get_opened_printer_name(hPrinter
);
1596 if(!name
) return ERROR_INVALID_HANDLE
;
1598 if((ret
= RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
)) !=
1602 if(RegOpenKeyW(hkeyPrinters
, name
, phkey
) != ERROR_SUCCESS
)
1604 ERR("Can't find opened printer %s in registry\n",
1606 RegCloseKey(hkeyPrinters
);
1607 return ERROR_INVALID_PRINTER_NAME
; /* ? */
1609 RegCloseKey(hkeyPrinters
);
1610 return ERROR_SUCCESS
;
1613 void WINSPOOL_LoadSystemPrinters(void)
1615 HKEY hkey
, hkeyPrinters
;
1617 DWORD needed
, num
, i
;
1618 WCHAR PrinterName
[256];
1621 /* This ensures that all printer entries have a valid Name value. If causes
1622 problems later if they don't. If one is found to be missed we create one
1623 and set it equal to the name of the key */
1624 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
1625 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &num
, NULL
, NULL
,
1626 NULL
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
1627 for(i
= 0; i
< num
; i
++) {
1628 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) == ERROR_SUCCESS
) {
1629 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkey
) == ERROR_SUCCESS
) {
1630 if(RegQueryValueExW(hkey
, NameW
, 0, 0, 0, &needed
) == ERROR_FILE_NOT_FOUND
) {
1631 set_reg_szW(hkey
, NameW
, PrinterName
);
1638 RegCloseKey(hkeyPrinters
);
1641 /* We want to avoid calling AddPrinter on printers as much as
1642 possible, because on cups printers this will (eventually) lead
1643 to a call to cupsGetPPD which takes forever, even with non-cups
1644 printers AddPrinter takes a while. So we'll tag all printers that
1645 were automatically added last time around, if they still exist
1646 we'll leave them be otherwise we'll delete them. */
1647 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1649 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1650 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1651 for(i
= 0; i
< num
; i
++) {
1652 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1653 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1654 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1656 RegSetValueExW(hkey
, May_Delete_Value
, 0, REG_DWORD
, (LPBYTE
)&dw
, sizeof(dw
));
1664 HeapFree(GetProcessHeap(), 0, pi
);
1668 #ifdef SONAME_LIBCUPS
1669 done
= CUPS_LoadPrinters();
1672 if(!done
) /* If we have any CUPS based printers, skip looking for printcap printers */
1673 PRINTCAP_LoadPrinters();
1675 /* Now enumerate the list again and delete any printers that are still tagged */
1676 EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, NULL
, 0, &needed
, &num
);
1678 PRINTER_INFO_5A
* pi
= HeapAlloc(GetProcessHeap(), 0, needed
);
1679 if(EnumPrintersA(PRINTER_ENUM_LOCAL
, NULL
, 5, (LPBYTE
)pi
, needed
, &needed
, &num
)) {
1680 for(i
= 0; i
< num
; i
++) {
1681 if(pi
[i
].pPortName
== NULL
|| !strncmp(pi
[i
].pPortName
,"CUPS:", 5) || !strncmp(pi
[i
].pPortName
, "LPR:", 4)) {
1682 if(OpenPrinterA(pi
[i
].pPrinterName
, &hprn
, NULL
)) {
1683 BOOL delete_driver
= FALSE
;
1684 if(WINSPOOL_GetOpenedPrinterRegKey(hprn
, &hkey
) == ERROR_SUCCESS
) {
1685 DWORD dw
, type
, size
= sizeof(dw
);
1686 if(RegQueryValueExW(hkey
, May_Delete_Value
, NULL
, &type
, (LPBYTE
)&dw
, &size
) == ERROR_SUCCESS
) {
1687 TRACE("Deleting old printer %s\n", pi
[i
].pPrinterName
);
1688 DeletePrinter(hprn
);
1689 delete_driver
= TRUE
;
1695 DeletePrinterDriverExA(NULL
, NULL
, pi
[i
].pPrinterName
, 0, 0);
1700 HeapFree(GetProcessHeap(), 0, pi
);
1707 /******************************************************************
1710 * Get the pointer to the specified job.
1711 * Should hold the printer_handles_cs before calling.
1713 static job_t
*get_job(HANDLE hprn
, DWORD JobId
)
1715 opened_printer_t
*printer
= get_opened_printer(hprn
);
1718 if(!printer
) return NULL
;
1719 LIST_FOR_EACH_ENTRY(job
, &printer
->queue
->jobs
, job_t
, entry
)
1721 if(job
->job_id
== JobId
)
1727 /***********************************************************
1730 static LPDEVMODEW
DEVMODEcpyAtoW(DEVMODEW
*dmW
, const DEVMODEA
*dmA
)
1733 ptrdiff_t off_formname
= (const char *)dmA
->dmFormName
- (const char *)dmA
;
1736 Formname
= (dmA
->dmSize
> off_formname
);
1737 size
= dmA
->dmSize
+ CCHDEVICENAME
+ (Formname
? CCHFORMNAME
: 0);
1738 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmDeviceName
, -1,
1739 dmW
->dmDeviceName
, CCHDEVICENAME
);
1741 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1742 dmA
->dmSize
- CCHDEVICENAME
);
1744 memcpy(&dmW
->dmSpecVersion
, &dmA
->dmSpecVersion
,
1745 off_formname
- CCHDEVICENAME
);
1746 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)dmA
->dmFormName
, -1,
1747 dmW
->dmFormName
, CCHFORMNAME
);
1748 memcpy(&dmW
->dmLogPixels
, &dmA
->dmLogPixels
, dmA
->dmSize
-
1749 (off_formname
+ CCHFORMNAME
));
1752 memcpy((char *)dmW
+ dmW
->dmSize
, (const char *)dmA
+ dmA
->dmSize
,
1753 dmA
->dmDriverExtra
);
1757 /***********************************************************
1759 * Creates an ascii copy of supplied devmode on heap
1761 static LPDEVMODEA
DEVMODEdupWtoA(HANDLE heap
, const DEVMODEW
*dmW
)
1766 ptrdiff_t off_formname
= (const char *)dmW
->dmFormName
- (const char *)dmW
;
1768 if(!dmW
) return NULL
;
1769 Formname
= (dmW
->dmSize
> off_formname
);
1770 size
= dmW
->dmSize
- CCHDEVICENAME
- (Formname
? CCHFORMNAME
: 0);
1771 dmA
= HeapAlloc(heap
, HEAP_ZERO_MEMORY
, size
+ dmW
->dmDriverExtra
);
1772 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmDeviceName
, -1,
1773 (LPSTR
)dmA
->dmDeviceName
, CCHDEVICENAME
, NULL
, NULL
);
1775 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1776 dmW
->dmSize
- CCHDEVICENAME
* sizeof(WCHAR
));
1778 memcpy(&dmA
->dmSpecVersion
, &dmW
->dmSpecVersion
,
1779 off_formname
- CCHDEVICENAME
* sizeof(WCHAR
));
1780 WideCharToMultiByte(CP_ACP
, 0, dmW
->dmFormName
, -1,
1781 (LPSTR
)dmA
->dmFormName
, CCHFORMNAME
, NULL
, NULL
);
1782 memcpy(&dmA
->dmLogPixels
, &dmW
->dmLogPixels
, dmW
->dmSize
-
1783 (off_formname
+ CCHFORMNAME
* sizeof(WCHAR
)));
1786 memcpy((char *)dmA
+ dmA
->dmSize
, (const char *)dmW
+ dmW
->dmSize
,
1787 dmW
->dmDriverExtra
);
1791 /***********************************************************
1792 * PRINTER_INFO_2AtoW
1793 * Creates a unicode copy of PRINTER_INFO_2A on heap
1795 static LPPRINTER_INFO_2W
PRINTER_INFO_2AtoW(HANDLE heap
, LPPRINTER_INFO_2A piA
)
1797 LPPRINTER_INFO_2W piW
;
1798 UNICODE_STRING usBuffer
;
1800 if(!piA
) return NULL
;
1801 piW
= HeapAlloc(heap
, 0, sizeof(*piW
));
1802 memcpy(piW
, piA
, sizeof(*piW
)); /* copy everything first */
1804 piW
->pServerName
= asciitounicode(&usBuffer
,piA
->pServerName
);
1805 piW
->pPrinterName
= asciitounicode(&usBuffer
,piA
->pPrinterName
);
1806 piW
->pShareName
= asciitounicode(&usBuffer
,piA
->pShareName
);
1807 piW
->pPortName
= asciitounicode(&usBuffer
,piA
->pPortName
);
1808 piW
->pDriverName
= asciitounicode(&usBuffer
,piA
->pDriverName
);
1809 piW
->pComment
= asciitounicode(&usBuffer
,piA
->pComment
);
1810 piW
->pLocation
= asciitounicode(&usBuffer
,piA
->pLocation
);
1811 piW
->pDevMode
= piA
->pDevMode
? GdiConvertToDevmodeW(piA
->pDevMode
) : NULL
;
1812 piW
->pSepFile
= asciitounicode(&usBuffer
,piA
->pSepFile
);
1813 piW
->pPrintProcessor
= asciitounicode(&usBuffer
,piA
->pPrintProcessor
);
1814 piW
->pDatatype
= asciitounicode(&usBuffer
,piA
->pDatatype
);
1815 piW
->pParameters
= asciitounicode(&usBuffer
,piA
->pParameters
);
1819 /***********************************************************
1820 * FREE_PRINTER_INFO_2W
1821 * Free PRINTER_INFO_2W and all strings
1823 static void FREE_PRINTER_INFO_2W(HANDLE heap
, LPPRINTER_INFO_2W piW
)
1827 HeapFree(heap
,0,piW
->pServerName
);
1828 HeapFree(heap
,0,piW
->pPrinterName
);
1829 HeapFree(heap
,0,piW
->pShareName
);
1830 HeapFree(heap
,0,piW
->pPortName
);
1831 HeapFree(heap
,0,piW
->pDriverName
);
1832 HeapFree(heap
,0,piW
->pComment
);
1833 HeapFree(heap
,0,piW
->pLocation
);
1834 HeapFree(heap
,0,piW
->pDevMode
);
1835 HeapFree(heap
,0,piW
->pSepFile
);
1836 HeapFree(heap
,0,piW
->pPrintProcessor
);
1837 HeapFree(heap
,0,piW
->pDatatype
);
1838 HeapFree(heap
,0,piW
->pParameters
);
1839 HeapFree(heap
,0,piW
);
1843 /******************************************************************
1844 * DeviceCapabilities [WINSPOOL.@]
1845 * DeviceCapabilitiesA [WINSPOOL.@]
1848 INT WINAPI
DeviceCapabilitiesA(LPCSTR pDevice
,LPCSTR pPort
, WORD cap
,
1849 LPSTR pOutput
, LPDEVMODEA lpdm
)
1853 if (!GDI_CallDeviceCapabilities16
)
1855 GDI_CallDeviceCapabilities16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1857 if (!GDI_CallDeviceCapabilities16
) return -1;
1859 ret
= GDI_CallDeviceCapabilities16(pDevice
, pPort
, cap
, pOutput
, lpdm
);
1861 /* If DC_PAPERSIZE map POINT16s to POINTs */
1862 if(ret
!= -1 && cap
== DC_PAPERSIZE
&& pOutput
) {
1863 POINT16
*tmp
= HeapAlloc( GetProcessHeap(), 0, ret
* sizeof(POINT16
) );
1864 POINT
*pt
= (POINT
*)pOutput
;
1866 memcpy(tmp
, pOutput
, ret
* sizeof(POINT16
));
1867 for(i
= 0; i
< ret
; i
++, pt
++)
1872 HeapFree( GetProcessHeap(), 0, tmp
);
1878 /*****************************************************************************
1879 * DeviceCapabilitiesW [WINSPOOL.@]
1881 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
1884 INT WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice
, LPCWSTR pPort
,
1885 WORD fwCapability
, LPWSTR pOutput
,
1886 const DEVMODEW
*pDevMode
)
1888 LPDEVMODEA dmA
= DEVMODEdupWtoA(GetProcessHeap(), pDevMode
);
1889 LPSTR pDeviceA
= strdupWtoA(pDevice
);
1890 LPSTR pPortA
= strdupWtoA(pPort
);
1893 if(pOutput
&& (fwCapability
== DC_BINNAMES
||
1894 fwCapability
== DC_FILEDEPENDENCIES
||
1895 fwCapability
== DC_PAPERNAMES
)) {
1896 /* These need A -> W translation */
1899 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, NULL
,
1903 switch(fwCapability
) {
1908 case DC_FILEDEPENDENCIES
:
1912 pOutputA
= HeapAlloc(GetProcessHeap(), 0, size
* ret
);
1913 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
, pOutputA
,
1915 for(i
= 0; i
< ret
; i
++)
1916 MultiByteToWideChar(CP_ACP
, 0, pOutputA
+ (i
* size
), -1,
1917 pOutput
+ (i
* size
), size
);
1918 HeapFree(GetProcessHeap(), 0, pOutputA
);
1920 ret
= DeviceCapabilitiesA(pDeviceA
, pPortA
, fwCapability
,
1921 (LPSTR
)pOutput
, dmA
);
1923 HeapFree(GetProcessHeap(),0,pPortA
);
1924 HeapFree(GetProcessHeap(),0,pDeviceA
);
1925 HeapFree(GetProcessHeap(),0,dmA
);
1929 /******************************************************************
1930 * DocumentPropertiesA [WINSPOOL.@]
1932 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1934 LONG WINAPI
DocumentPropertiesA(HWND hWnd
,HANDLE hPrinter
,
1935 LPSTR pDeviceName
, LPDEVMODEA pDevModeOutput
,
1936 LPDEVMODEA pDevModeInput
,DWORD fMode
)
1938 LPSTR lpName
= pDeviceName
;
1939 static CHAR port
[] = "LPT1:";
1942 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1943 hWnd
,hPrinter
,pDeviceName
,pDevModeOutput
,pDevModeInput
,fMode
1947 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
1949 ERR("no name from hPrinter?\n");
1950 SetLastError(ERROR_INVALID_HANDLE
);
1953 lpName
= strdupWtoA(lpNameW
);
1956 if (!GDI_CallExtDeviceMode16
)
1958 GDI_CallExtDeviceMode16
= (void*)GetProcAddress( GetModuleHandleA("gdi32"),
1960 if (!GDI_CallExtDeviceMode16
) {
1961 ERR("No CallExtDeviceMode16?\n");
1965 ret
= GDI_CallExtDeviceMode16(hWnd
, pDevModeOutput
, lpName
, port
,
1966 pDevModeInput
, NULL
, fMode
);
1969 HeapFree(GetProcessHeap(),0,lpName
);
1974 /*****************************************************************************
1975 * DocumentPropertiesW (WINSPOOL.@)
1977 * FIXME: implement DocumentPropertiesA via DocumentPropertiesW, not vice versa
1979 LONG WINAPI
DocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
,
1981 LPDEVMODEW pDevModeOutput
,
1982 LPDEVMODEW pDevModeInput
, DWORD fMode
)
1985 LPSTR pDeviceNameA
= strdupWtoA(pDeviceName
);
1986 LPDEVMODEA pDevModeInputA
= DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput
);
1987 LPDEVMODEA pDevModeOutputA
= NULL
;
1990 TRACE("(%p,%p,%s,%p,%p,%d)\n",
1991 hWnd
,hPrinter
,debugstr_w(pDeviceName
),pDevModeOutput
,pDevModeInput
,
1993 if(pDevModeOutput
) {
1994 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, NULL
, NULL
, 0);
1995 if(ret
< 0) return ret
;
1996 pDevModeOutputA
= HeapAlloc(GetProcessHeap(), 0, ret
);
1998 ret
= DocumentPropertiesA(hWnd
, hPrinter
, pDeviceNameA
, pDevModeOutputA
,
1999 pDevModeInputA
, fMode
);
2000 if(pDevModeOutput
) {
2001 DEVMODEcpyAtoW(pDevModeOutput
, pDevModeOutputA
);
2002 HeapFree(GetProcessHeap(),0,pDevModeOutputA
);
2004 if(fMode
== 0 && ret
> 0)
2005 ret
+= (CCHDEVICENAME
+ CCHFORMNAME
);
2006 HeapFree(GetProcessHeap(),0,pDevModeInputA
);
2007 HeapFree(GetProcessHeap(),0,pDeviceNameA
);
2011 /******************************************************************
2012 * OpenPrinterA [WINSPOOL.@]
2017 BOOL WINAPI
OpenPrinterA(LPSTR lpPrinterName
,HANDLE
*phPrinter
,
2018 LPPRINTER_DEFAULTSA pDefault
)
2020 UNICODE_STRING lpPrinterNameW
;
2021 UNICODE_STRING usBuffer
;
2022 PRINTER_DEFAULTSW DefaultW
, *pDefaultW
= NULL
;
2023 PWSTR pwstrPrinterNameW
;
2026 pwstrPrinterNameW
= asciitounicode(&lpPrinterNameW
,lpPrinterName
);
2029 DefaultW
.pDatatype
= asciitounicode(&usBuffer
,pDefault
->pDatatype
);
2030 DefaultW
.pDevMode
= pDefault
->pDevMode
? GdiConvertToDevmodeW(pDefault
->pDevMode
) : NULL
;
2031 DefaultW
.DesiredAccess
= pDefault
->DesiredAccess
;
2032 pDefaultW
= &DefaultW
;
2034 ret
= OpenPrinterW(pwstrPrinterNameW
, phPrinter
, pDefaultW
);
2036 RtlFreeUnicodeString(&usBuffer
);
2037 HeapFree(GetProcessHeap(), 0, DefaultW
.pDevMode
);
2039 RtlFreeUnicodeString(&lpPrinterNameW
);
2043 /******************************************************************
2044 * OpenPrinterW [WINSPOOL.@]
2046 * Open a Printer / Printserver or a Printer-Object
2049 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2050 * phPrinter [O] The resulting Handle is stored here
2051 * pDefault [I] PTR to Default Printer Settings or NULL
2058 * lpPrinterName is one of:
2059 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2060 *| Printer: "PrinterName"
2061 *| Printer-Object: "PrinterName,Job xxx"
2062 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2063 *| XcvPort: "Servername,XcvPort PortName"
2066 *| Printer-Object not supported
2067 *| pDefaults is ignored
2070 BOOL WINAPI
OpenPrinterW(LPWSTR lpPrinterName
,HANDLE
*phPrinter
, LPPRINTER_DEFAULTSW pDefault
)
2073 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), phPrinter
, pDefault
);
2075 FIXME("PRINTER_DEFAULTS ignored => %s,%p,0x%08x\n",
2076 debugstr_w(pDefault
->pDatatype
), pDefault
->pDevMode
, pDefault
->DesiredAccess
);
2080 /* NT: FALSE with ERROR_INVALID_PARAMETER, 9x: TRUE */
2081 SetLastError(ERROR_INVALID_PARAMETER
);
2085 /* Get the unique handle of the printer or Printserver */
2086 *phPrinter
= get_opened_printer_entry(lpPrinterName
, pDefault
);
2087 TRACE("returning %d with %u and %p\n", *phPrinter
!= NULL
, GetLastError(), *phPrinter
);
2088 return (*phPrinter
!= 0);
2091 /******************************************************************
2092 * AddMonitorA [WINSPOOL.@]
2097 BOOL WINAPI
AddMonitorA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2099 LPWSTR nameW
= NULL
;
2102 LPMONITOR_INFO_2A mi2a
;
2103 MONITOR_INFO_2W mi2w
;
2105 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
2106 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_a(pName
), Level
, pMonitors
,
2107 mi2a
? debugstr_a(mi2a
->pName
) : NULL
,
2108 mi2a
? debugstr_a(mi2a
->pEnvironment
) : NULL
,
2109 mi2a
? debugstr_a(mi2a
->pDLLName
) : NULL
);
2112 SetLastError(ERROR_INVALID_LEVEL
);
2116 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2122 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2123 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2124 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2127 memset(&mi2w
, 0, sizeof(MONITOR_INFO_2W
));
2129 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, NULL
, 0);
2130 mi2w
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2131 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pName
, -1, mi2w
.pName
, len
);
2133 if (mi2a
->pEnvironment
) {
2134 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, NULL
, 0);
2135 mi2w
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2136 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pEnvironment
, -1, mi2w
.pEnvironment
, len
);
2138 if (mi2a
->pDLLName
) {
2139 len
= MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, NULL
, 0);
2140 mi2w
.pDLLName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2141 MultiByteToWideChar(CP_ACP
, 0, mi2a
->pDLLName
, -1, mi2w
.pDLLName
, len
);
2144 res
= AddMonitorW(nameW
, Level
, (LPBYTE
) &mi2w
);
2146 HeapFree(GetProcessHeap(), 0, mi2w
.pName
);
2147 HeapFree(GetProcessHeap(), 0, mi2w
.pEnvironment
);
2148 HeapFree(GetProcessHeap(), 0, mi2w
.pDLLName
);
2150 HeapFree(GetProcessHeap(), 0, nameW
);
2154 /******************************************************************************
2155 * AddMonitorW [WINSPOOL.@]
2157 * Install a Printmonitor
2160 * pName [I] Servername or NULL (local Computer)
2161 * Level [I] Structure-Level (Must be 2)
2162 * pMonitors [I] PTR to MONITOR_INFO_2
2169 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
2172 BOOL WINAPI
AddMonitorW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
2174 monitor_t
* pm
= NULL
;
2175 LPMONITOR_INFO_2W mi2w
;
2181 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
2182 TRACE("(%s, %d, %p) : %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
2183 mi2w
? debugstr_w(mi2w
->pName
) : NULL
,
2184 mi2w
? debugstr_w(mi2w
->pEnvironment
) : NULL
,
2185 mi2w
? debugstr_w(mi2w
->pDLLName
) : NULL
);
2188 SetLastError(ERROR_INVALID_LEVEL
);
2192 /* XP: unchanged, win9x: ERROR_INVALID_ENVIRONMENT */
2197 if (pName
&& (pName
[0])) {
2198 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2199 SetLastError(ERROR_ACCESS_DENIED
);
2204 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
2205 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
2206 SetLastError(ERROR_INVALID_PARAMETER
);
2209 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, envname_x86W
)) {
2210 WARN("Environment %s requested (we support only %s)\n",
2211 debugstr_w(mi2w
->pEnvironment
), debugstr_w(envname_x86W
));
2212 SetLastError(ERROR_INVALID_ENVIRONMENT
);
2216 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
2217 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
2218 SetLastError(ERROR_INVALID_PARAMETER
);
2222 /* Load and initialize the monitor. SetLastError() is called on failure */
2223 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
2228 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2229 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2233 if(RegCreateKeyExW( hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
2234 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
2235 &disposition
) == ERROR_SUCCESS
) {
2237 /* Some installers set options for the port before calling AddMonitor.
2238 We query the "Driver" entry to verify that the monitor is installed,
2239 before we return an error.
2240 When a user installs two print monitors at the same time with the
2241 same name but with a different driver DLL and a task switch comes
2242 between RegQueryValueExW and RegSetValueExW, a race condition
2243 is possible but silently ignored. */
2247 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
2248 (RegQueryValueExW(hentry
, DriverW
, NULL
, NULL
, NULL
,
2249 &namesize
) == ERROR_SUCCESS
)) {
2250 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
2251 /* NT: ERROR_PRINT_MONITOR_ALREADY_INSTALLED (3006)
2252 9x: ERROR_ALREADY_EXISTS (183) */
2253 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
2258 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
2259 res
= (RegSetValueExW(hentry
, DriverW
, 0,
2260 REG_SZ
, (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
2262 RegCloseKey(hentry
);
2269 /******************************************************************
2270 * DeletePrinterDriverA [WINSPOOL.@]
2273 BOOL WINAPI
DeletePrinterDriverA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pDriverName
)
2275 return DeletePrinterDriverExA(pName
, pEnvironment
, pDriverName
, 0, 0);
2278 /******************************************************************
2279 * DeletePrinterDriverW [WINSPOOL.@]
2282 BOOL WINAPI
DeletePrinterDriverW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pDriverName
)
2284 return DeletePrinterDriverExW(pName
, pEnvironment
, pDriverName
, 0, 0);
2287 /******************************************************************
2288 * DeleteMonitorA [WINSPOOL.@]
2290 * See DeleteMonitorW.
2293 BOOL WINAPI
DeleteMonitorA (LPSTR pName
, LPSTR pEnvironment
, LPSTR pMonitorName
)
2295 LPWSTR nameW
= NULL
;
2296 LPWSTR EnvironmentW
= NULL
;
2297 LPWSTR MonitorNameW
= NULL
;
2302 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2303 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2304 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2308 len
= MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, NULL
, 0);
2309 EnvironmentW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2310 MultiByteToWideChar(CP_ACP
, 0, pEnvironment
, -1, EnvironmentW
, len
);
2313 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
2314 MonitorNameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2315 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, MonitorNameW
, len
);
2318 res
= DeleteMonitorW(nameW
, EnvironmentW
, MonitorNameW
);
2320 HeapFree(GetProcessHeap(), 0, MonitorNameW
);
2321 HeapFree(GetProcessHeap(), 0, EnvironmentW
);
2322 HeapFree(GetProcessHeap(), 0, nameW
);
2326 /******************************************************************
2327 * DeleteMonitorW [WINSPOOL.@]
2329 * Delete a specific Printmonitor from a Printing-Environment
2332 * pName [I] Servername or NULL (local Computer)
2333 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2334 * pMonitorName [I] Name of the Monitor, that should be deleted
2341 * pEnvironment is ignored in Windows for the local Computer.
2345 BOOL WINAPI
DeleteMonitorW (LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2349 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2350 debugstr_w(pMonitorName
));
2352 if (pName
&& (pName
[0])) {
2353 FIXME("for server %s not implemented\n", debugstr_w(pName
));
2354 SetLastError(ERROR_ACCESS_DENIED
);
2358 /* pEnvironment is ignored in Windows for the local Computer */
2360 if (!pMonitorName
|| !pMonitorName
[0]) {
2361 WARN("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2362 SetLastError(ERROR_INVALID_PARAMETER
);
2366 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, MonitorsW
, &hroot
) != ERROR_SUCCESS
) {
2367 ERR("unable to create key %s\n", debugstr_w(MonitorsW
));
2371 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2372 TRACE("monitor %s deleted\n", debugstr_w(pMonitorName
));
2377 WARN("monitor %s does not exist\n", debugstr_w(pMonitorName
));
2380 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2381 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2385 /******************************************************************
2386 * DeletePortA [WINSPOOL.@]
2391 BOOL WINAPI
DeletePortA (LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
2393 LPWSTR nameW
= NULL
;
2394 LPWSTR portW
= NULL
;
2398 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
2400 /* convert servername to unicode */
2402 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
2403 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2404 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
2407 /* convert portname to unicode */
2409 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
2410 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2411 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
2414 res
= DeletePortW(nameW
, hWnd
, portW
);
2415 HeapFree(GetProcessHeap(), 0, nameW
);
2416 HeapFree(GetProcessHeap(), 0, portW
);
2420 /******************************************************************
2421 * DeletePortW [WINSPOOL.@]
2423 * Delete a specific Port
2426 * pName [I] Servername or NULL (local Computer)
2427 * hWnd [I] Handle to parent Window for the Dialog-Box
2428 * pPortName [I] Name of the Port, that should be deleted
2435 BOOL WINAPI
DeletePortW (LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2441 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2443 if (pName
&& pName
[0]) {
2444 SetLastError(ERROR_INVALID_PARAMETER
);
2449 SetLastError(RPC_X_NULL_REF_POINTER
);
2453 /* an empty Portname is Invalid */
2454 if (!pPortName
[0]) {
2455 SetLastError(ERROR_NOT_SUPPORTED
);
2459 pm
= monitor_load_by_port(pPortName
);
2460 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
2461 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2462 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
2463 TRACE("got %d with %u\n", res
, GetLastError());
2467 pui
= monitor_loadui(pm
);
2468 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2469 TRACE("use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2470 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2471 TRACE("got %d with %u\n", res
, GetLastError());
2475 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
2476 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
2478 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
2479 SetLastError(ERROR_NOT_SUPPORTED
);
2482 monitor_unload(pui
);
2486 TRACE("returning %d with %u\n", res
, GetLastError());
2490 /******************************************************************************
2491 * SetPrinterW [WINSPOOL.@]
2493 BOOL WINAPI
SetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
, DWORD Command
)
2495 FIXME("(%p, %d, %p, %d): stub\n", hPrinter
, Level
, pPrinter
, Command
);
2496 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
2500 /******************************************************************************
2501 * WritePrinter [WINSPOOL.@]
2503 BOOL WINAPI
WritePrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
, LPDWORD pcWritten
)
2505 opened_printer_t
*printer
;
2508 TRACE("(%p, %p, %d, %p)\n", hPrinter
, pBuf
, cbBuf
, pcWritten
);
2510 EnterCriticalSection(&printer_handles_cs
);
2511 printer
= get_opened_printer(hPrinter
);
2514 SetLastError(ERROR_INVALID_HANDLE
);
2520 SetLastError(ERROR_SPL_NO_STARTDOC
);
2524 ret
= WriteFile(printer
->doc
->hf
, pBuf
, cbBuf
, pcWritten
, NULL
);
2526 LeaveCriticalSection(&printer_handles_cs
);
2530 /*****************************************************************************
2531 * AddFormA [WINSPOOL.@]
2533 BOOL WINAPI
AddFormA(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2535 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2539 /*****************************************************************************
2540 * AddFormW [WINSPOOL.@]
2542 BOOL WINAPI
AddFormW(HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
)
2544 FIXME("(%p,%d,%p): stub\n", hPrinter
, Level
, pForm
);
2548 /*****************************************************************************
2549 * AddJobA [WINSPOOL.@]
2551 BOOL WINAPI
AddJobA(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2554 BYTE buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
2558 SetLastError(ERROR_INVALID_LEVEL
);
2562 ret
= AddJobW(hPrinter
, Level
, buf
, sizeof(buf
), &needed
);
2565 ADDJOB_INFO_1W
*addjobW
= (ADDJOB_INFO_1W
*)buf
;
2566 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, NULL
, 0, NULL
, NULL
);
2567 *pcbNeeded
= len
+ sizeof(ADDJOB_INFO_1A
);
2568 if(*pcbNeeded
> cbBuf
) {
2569 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2572 ADDJOB_INFO_1A
*addjobA
= (ADDJOB_INFO_1A
*)pData
;
2573 addjobA
->JobId
= addjobW
->JobId
;
2574 addjobA
->Path
= (char *)(addjobA
+ 1);
2575 WideCharToMultiByte(CP_ACP
, 0, addjobW
->Path
, -1, addjobA
->Path
, len
, NULL
, NULL
);
2581 /*****************************************************************************
2582 * AddJobW [WINSPOOL.@]
2584 BOOL WINAPI
AddJobW(HANDLE hPrinter
, DWORD Level
, LPBYTE pData
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2586 opened_printer_t
*printer
;
2589 static const WCHAR spool_path
[] = {'s','p','o','o','l','\\','P','R','I','N','T','E','R','S','\\',0};
2590 static const WCHAR fmtW
[] = {'%','s','%','0','5','d','.','S','P','L',0};
2591 WCHAR path
[MAX_PATH
], filename
[MAX_PATH
];
2593 ADDJOB_INFO_1W
*addjob
;
2595 TRACE("(%p,%d,%p,%d,%p)\n", hPrinter
, Level
, pData
, cbBuf
, pcbNeeded
);
2597 EnterCriticalSection(&printer_handles_cs
);
2599 printer
= get_opened_printer(hPrinter
);
2602 SetLastError(ERROR_INVALID_HANDLE
);
2607 SetLastError(ERROR_INVALID_LEVEL
);
2611 job
= HeapAlloc(GetProcessHeap(), 0, sizeof(*job
));
2615 job
->job_id
= InterlockedIncrement(&next_job_id
);
2617 len
= GetSystemDirectoryW(path
, sizeof(path
) / sizeof(WCHAR
));
2618 if(path
[len
- 1] != '\\')
2620 memcpy(path
+ len
, spool_path
, sizeof(spool_path
));
2621 sprintfW(filename
, fmtW
, path
, job
->job_id
);
2623 len
= strlenW(filename
);
2624 job
->filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
2625 memcpy(job
->filename
, filename
, (len
+ 1) * sizeof(WCHAR
));
2626 job
->document_title
= strdupW(default_doc_title
);
2627 list_add_tail(&printer
->queue
->jobs
, &job
->entry
);
2629 *pcbNeeded
= (len
+ 1) * sizeof(WCHAR
) + sizeof(*addjob
);
2630 if(*pcbNeeded
<= cbBuf
) {
2631 addjob
= (ADDJOB_INFO_1W
*)pData
;
2632 addjob
->JobId
= job
->job_id
;
2633 addjob
->Path
= (WCHAR
*)(addjob
+ 1);
2634 memcpy(addjob
->Path
, filename
, (len
+ 1) * sizeof(WCHAR
));
2637 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2640 LeaveCriticalSection(&printer_handles_cs
);
2644 /*****************************************************************************
2645 * GetPrintProcessorDirectoryA [WINSPOOL.@]
2647 * Return the PATH for the Print-Processors
2649 * See GetPrintProcessorDirectoryW.
2653 BOOL WINAPI
GetPrintProcessorDirectoryA(LPSTR server
, LPSTR env
,
2654 DWORD level
, LPBYTE Info
,
2655 DWORD cbBuf
, LPDWORD pcbNeeded
)
2657 LPWSTR serverW
= NULL
;
2662 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(server
),
2663 debugstr_a(env
), level
, Info
, cbBuf
, pcbNeeded
);
2667 len
= MultiByteToWideChar(CP_ACP
, 0, server
, -1, NULL
, 0);
2668 serverW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2669 MultiByteToWideChar(CP_ACP
, 0, server
, -1, serverW
, len
);
2673 len
= MultiByteToWideChar(CP_ACP
, 0, env
, -1, NULL
, 0);
2674 envW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2675 MultiByteToWideChar(CP_ACP
, 0, env
, -1, envW
, len
);
2678 /* NT requires the buffersize from GetPrintProcessorDirectoryW also
2679 for GetPrintProcessorDirectoryA and WC2MB is done in-place.
2681 ret
= GetPrintProcessorDirectoryW(serverW
, envW
, level
, Info
,
2684 if (ret
) ret
= WideCharToMultiByte(CP_ACP
, 0, (LPWSTR
)Info
, -1, (LPSTR
)Info
,
2685 cbBuf
, NULL
, NULL
) > 0;
2688 TRACE(" required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
2689 HeapFree(GetProcessHeap(), 0, envW
);
2690 HeapFree(GetProcessHeap(), 0, serverW
);
2694 /*****************************************************************************
2695 * GetPrintProcessorDirectoryW [WINSPOOL.@]
2697 * Return the PATH for the Print-Processors
2700 * server [I] Servername (NT only) or NULL (local Computer)
2701 * env [I] Printing-Environment (see below) or NULL (Default)
2702 * level [I] Structure-Level (must be 1)
2703 * Info [O] PTR to Buffer that receives the Result
2704 * cbBuf [I] Size of Buffer at "Info"
2705 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
2706 * required for the Buffer at "Info"
2709 * Success: TRUE and in pcbNeeded the Bytes used in Info
2710 * Failure: FALSE and in pcbNeeded the Bytes required for Info,
2711 * if cbBuf is too small
2713 * Native Values returned in Info on Success:
2714 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2715 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2716 *| win9x(Windows 4.0): "%winsysdir%"
2718 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2721 * Only NULL or "" is supported for server
2724 BOOL WINAPI
GetPrintProcessorDirectoryW(LPWSTR server
, LPWSTR env
,
2725 DWORD level
, LPBYTE Info
,
2726 DWORD cbBuf
, LPDWORD pcbNeeded
)
2729 const printenv_t
* env_t
;
2731 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(server
),
2732 debugstr_w(env
), level
, Info
, cbBuf
, pcbNeeded
);
2734 if(server
!= NULL
&& server
[0]) {
2735 FIXME("server not supported: %s\n", debugstr_w(server
));
2736 SetLastError(ERROR_INVALID_PARAMETER
);
2740 env_t
= validate_envW(env
);
2741 if(!env_t
) return FALSE
; /* environment invalid or unsupported */
2744 WARN("(Level: %d) is ignored in win9x\n", level
);
2745 SetLastError(ERROR_INVALID_LEVEL
);
2749 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2750 needed
= GetSystemDirectoryW(NULL
, 0);
2751 /* add the Size for the Subdirectories */
2752 needed
+= lstrlenW(spoolprtprocsW
);
2753 needed
+= lstrlenW(env_t
->subdir
);
2754 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2756 if(pcbNeeded
) *pcbNeeded
= needed
;
2757 TRACE ("required: 0x%x/%d\n", needed
, needed
);
2758 if (needed
> cbBuf
) {
2759 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2762 if(pcbNeeded
== NULL
) {
2763 /* NT: RPC_X_NULL_REF_POINTER, 9x: ignored */
2764 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
2765 SetLastError(RPC_X_NULL_REF_POINTER
);
2769 /* NT: RPC_X_NULL_REF_POINTER, 9x: ERROR_INVALID_PARAMETER */
2770 SetLastError(RPC_X_NULL_REF_POINTER
);
2774 GetSystemDirectoryW((LPWSTR
) Info
, cbBuf
/sizeof(WCHAR
));
2775 /* add the Subdirectories */
2776 lstrcatW((LPWSTR
) Info
, spoolprtprocsW
);
2777 lstrcatW((LPWSTR
) Info
, env_t
->subdir
);
2778 TRACE(" => %s\n", debugstr_w((LPWSTR
) Info
));
2782 /*****************************************************************************
2783 * WINSPOOL_OpenDriverReg [internal]
2785 * opens the registry for the printer drivers depending on the given input
2786 * variable pEnvironment
2789 * the opened hkey on success
2792 static HKEY
WINSPOOL_OpenDriverReg( LPCVOID pEnvironment
, BOOL unicode
)
2796 const printenv_t
* env
;
2799 (unicode
) ? debugstr_w(pEnvironment
) : debugstr_a(pEnvironment
), unicode
);
2801 if (!pEnvironment
|| unicode
) {
2802 /* pEnvironment was NULL or an Unicode-String: use it direct */
2803 env
= validate_envW(pEnvironment
);
2807 /* pEnvironment was an ANSI-String: convert to unicode first */
2809 INT len
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, NULL
, 0);
2810 buffer
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2811 if (buffer
) MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)pEnvironment
, -1, buffer
, len
);
2812 env
= validate_envW(buffer
);
2813 HeapFree(GetProcessHeap(), 0, buffer
);
2815 if (!env
) return NULL
;
2817 buffer
= HeapAlloc( GetProcessHeap(), 0,
2818 (strlenW(DriversW
) + strlenW(env
->envname
) +
2819 strlenW(env
->versionregpath
) + 1) * sizeof(WCHAR
));
2821 wsprintfW(buffer
, DriversW
, env
->envname
, env
->versionregpath
);
2822 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
2823 HeapFree(GetProcessHeap(), 0, buffer
);
2828 /*****************************************************************************
2829 * AddPrinterW [WINSPOOL.@]
2831 HANDLE WINAPI
AddPrinterW(LPWSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2833 PRINTER_INFO_2W
*pi
= (PRINTER_INFO_2W
*) pPrinter
;
2837 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDriver
, hkeyDrivers
;
2839 static const WCHAR attributesW
[] = {'A','t','t','r','i','b','u','t','e','s',0},
2840 default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0},
2841 priorityW
[] = {'P','r','i','o','r','i','t','y',0},
2842 start_timeW
[] = {'S','t','a','r','t','T','i','m','e',0},
2843 statusW
[] = {'S','t','a','t','u','s',0},
2844 until_timeW
[] = {'U','n','t','i','l','T','i','m','e',0};
2846 TRACE("(%s,%d,%p)\n", debugstr_w(pName
), Level
, pPrinter
);
2849 ERR("pName = %s - unsupported\n", debugstr_w(pName
));
2850 SetLastError(ERROR_INVALID_PARAMETER
);
2854 ERR("Level = %d, unsupported!\n", Level
);
2855 SetLastError(ERROR_INVALID_LEVEL
);
2859 SetLastError(ERROR_INVALID_PARAMETER
);
2862 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
2864 ERR("Can't create Printers key\n");
2867 if(!RegOpenKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
)) {
2868 if (!RegQueryValueW(hkeyPrinter
, attributesW
, NULL
, NULL
)) {
2869 SetLastError(ERROR_PRINTER_ALREADY_EXISTS
);
2870 RegCloseKey(hkeyPrinter
);
2871 RegCloseKey(hkeyPrinters
);
2874 RegCloseKey(hkeyPrinter
);
2876 hkeyDrivers
= WINSPOOL_OpenDriverReg( NULL
, TRUE
);
2878 ERR("Can't create Drivers key\n");
2879 RegCloseKey(hkeyPrinters
);
2882 if(RegOpenKeyW(hkeyDrivers
, pi
->pDriverName
, &hkeyDriver
) !=
2884 WARN("Can't find driver %s\n", debugstr_w(pi
->pDriverName
));
2885 RegCloseKey(hkeyPrinters
);
2886 RegCloseKey(hkeyDrivers
);
2887 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
);
2890 RegCloseKey(hkeyDriver
);
2891 RegCloseKey(hkeyDrivers
);
2893 if(lstrcmpiW(pi
->pPrintProcessor
, WinPrintW
)) { /* FIXME */
2894 FIXME("Can't find processor %s\n", debugstr_w(pi
->pPrintProcessor
));
2895 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR
);
2896 RegCloseKey(hkeyPrinters
);
2900 if(RegCreateKeyW(hkeyPrinters
, pi
->pPrinterName
, &hkeyPrinter
) !=
2902 FIXME("Can't create printer %s\n", debugstr_w(pi
->pPrinterName
));
2903 SetLastError(ERROR_INVALID_PRINTER_NAME
);
2904 RegCloseKey(hkeyPrinters
);
2907 RegSetValueExW(hkeyPrinter
, attributesW
, 0, REG_DWORD
,
2908 (LPBYTE
)&pi
->Attributes
, sizeof(DWORD
));
2909 set_reg_szW(hkeyPrinter
, DatatypeW
, pi
->pDatatype
);
2911 /* See if we can load the driver. We may need the devmode structure anyway
2914 * Note that DocumentPropertiesW will briefly try to open the printer we
2915 * just create to find a DEVMODEA struct (it will use the WINEPS default
2916 * one in case it is not there, so we are ok).
2918 size
= DocumentPropertiesW(0, 0, pi
->pPrinterName
, NULL
, NULL
, 0);
2921 FIXME("DocumentPropertiesW on printer %s fails\n", debugstr_w(pi
->pPrinterName
));
2922 size
= sizeof(DEVMODEW
);
2928 dmW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
2930 if (0>DocumentPropertiesW(0,0,pi
->pPrinterName
,dmW
,NULL
,DM_OUT_BUFFER
))
2932 WARN("DocumentPropertiesW on printer %s failed!\n", debugstr_w(pi
->pPrinterName
));
2933 HeapFree(GetProcessHeap(),0,dmW
);
2938 /* set devmode to printer name */
2939 lstrcpynW(dmW
->dmDeviceName
, pi
->pPrinterName
, CCHDEVICENAME
);
2943 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2944 and we support these drivers. NT writes DEVMODEW so somehow
2945 we'll need to distinguish between these when we support NT
2949 dmA
= DEVMODEdupWtoA(GetProcessHeap(), dmW
);
2950 RegSetValueExW(hkeyPrinter
, default_devmodeW
, 0, REG_BINARY
,
2951 (LPBYTE
)dmA
, dmA
->dmSize
+ dmA
->dmDriverExtra
);
2952 HeapFree(GetProcessHeap(), 0, dmA
);
2954 HeapFree(GetProcessHeap(), 0, dmW
);
2956 set_reg_szW(hkeyPrinter
, DescriptionW
, pi
->pComment
);
2957 set_reg_szW(hkeyPrinter
, LocationW
, pi
->pLocation
);
2958 set_reg_szW(hkeyPrinter
, NameW
, pi
->pPrinterName
);
2959 set_reg_szW(hkeyPrinter
, ParametersW
, pi
->pParameters
);
2961 set_reg_szW(hkeyPrinter
, PortW
, pi
->pPortName
);
2962 set_reg_szW(hkeyPrinter
, Print_ProcessorW
, pi
->pPrintProcessor
);
2963 set_reg_szW(hkeyPrinter
, Printer_DriverW
, pi
->pDriverName
);
2964 RegSetValueExW(hkeyPrinter
, priorityW
, 0, REG_DWORD
,
2965 (LPBYTE
)&pi
->Priority
, sizeof(DWORD
));
2966 set_reg_szW(hkeyPrinter
, Separator_FileW
, pi
->pSepFile
);
2967 set_reg_szW(hkeyPrinter
, Share_NameW
, pi
->pShareName
);
2968 RegSetValueExW(hkeyPrinter
, start_timeW
, 0, REG_DWORD
,
2969 (LPBYTE
)&pi
->StartTime
, sizeof(DWORD
));
2970 RegSetValueExW(hkeyPrinter
, statusW
, 0, REG_DWORD
,
2971 (LPBYTE
)&pi
->Status
, sizeof(DWORD
));
2972 RegSetValueExW(hkeyPrinter
, until_timeW
, 0, REG_DWORD
,
2973 (LPBYTE
)&pi
->UntilTime
, sizeof(DWORD
));
2975 RegCloseKey(hkeyPrinter
);
2976 RegCloseKey(hkeyPrinters
);
2977 if(!OpenPrinterW(pi
->pPrinterName
, &retval
, NULL
)) {
2978 ERR("OpenPrinter failing\n");
2984 /*****************************************************************************
2985 * AddPrinterA [WINSPOOL.@]
2987 HANDLE WINAPI
AddPrinterA(LPSTR pName
, DWORD Level
, LPBYTE pPrinter
)
2989 UNICODE_STRING pNameW
;
2991 PRINTER_INFO_2W
*piW
;
2992 PRINTER_INFO_2A
*piA
= (PRINTER_INFO_2A
*)pPrinter
;
2995 TRACE("(%s,%d,%p): stub\n", debugstr_a(pName
), Level
, pPrinter
);
2997 ERR("Level = %d, unsupported!\n", Level
);
2998 SetLastError(ERROR_INVALID_LEVEL
);
3001 pwstrNameW
= asciitounicode(&pNameW
,pName
);
3002 piW
= PRINTER_INFO_2AtoW(GetProcessHeap(), piA
);
3004 ret
= AddPrinterW(pwstrNameW
, Level
, (LPBYTE
)piW
);
3006 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW
);
3007 RtlFreeUnicodeString(&pNameW
);
3012 /*****************************************************************************
3013 * ClosePrinter [WINSPOOL.@]
3015 BOOL WINAPI
ClosePrinter(HANDLE hPrinter
)
3017 UINT_PTR i
= (UINT_PTR
)hPrinter
;
3018 opened_printer_t
*printer
= NULL
;
3021 TRACE("(%p)\n", hPrinter
);
3023 EnterCriticalSection(&printer_handles_cs
);
3025 if ((i
> 0) && (i
<= nb_printer_handles
))
3026 printer
= printer_handles
[i
- 1];
3031 struct list
*cursor
, *cursor2
;
3033 TRACE("%p: %s (hXcv: %p) for %s (doc: %p)\n", printer
->pm
,
3034 debugstr_w(printer
->pm
? printer
->pm
->dllname
: NULL
),
3035 printer
->hXcv
, debugstr_w(printer
->name
), printer
->doc
);
3038 EndDocPrinter(hPrinter
);
3040 if(InterlockedDecrement(&printer
->queue
->ref
) == 0)
3042 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
3044 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
3045 ScheduleJob(hPrinter
, job
->job_id
);
3047 HeapFree(GetProcessHeap(), 0, printer
->queue
);
3049 if (printer
->hXcv
) printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
3050 monitor_unload(printer
->pm
);
3051 HeapFree(GetProcessHeap(), 0, printer
->printername
);
3052 HeapFree(GetProcessHeap(), 0, printer
->name
);
3053 HeapFree(GetProcessHeap(), 0, printer
);
3054 printer_handles
[i
- 1] = NULL
;
3057 LeaveCriticalSection(&printer_handles_cs
);
3061 /*****************************************************************************
3062 * DeleteFormA [WINSPOOL.@]
3064 BOOL WINAPI
DeleteFormA(HANDLE hPrinter
, LPSTR pFormName
)
3066 FIXME("(%p,%s): stub\n", hPrinter
, pFormName
);
3070 /*****************************************************************************
3071 * DeleteFormW [WINSPOOL.@]
3073 BOOL WINAPI
DeleteFormW(HANDLE hPrinter
, LPWSTR pFormName
)
3075 FIXME("(%p,%s): stub\n", hPrinter
, debugstr_w(pFormName
));
3079 /*****************************************************************************
3080 * DeletePrinter [WINSPOOL.@]
3082 BOOL WINAPI
DeletePrinter(HANDLE hPrinter
)
3084 LPCWSTR lpNameW
= get_opened_printer_name(hPrinter
);
3085 HKEY hkeyPrinters
, hkey
;
3088 SetLastError(ERROR_INVALID_HANDLE
);
3091 if(RegOpenKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) == ERROR_SUCCESS
) {
3092 RegDeleteTreeW(hkeyPrinters
, lpNameW
);
3093 RegCloseKey(hkeyPrinters
);
3095 WriteProfileStringW(devicesW
, lpNameW
, NULL
);
3096 if(RegCreateKeyW(HKEY_CURRENT_USER
, user_printers_reg_key
, &hkey
) == ERROR_SUCCESS
) {
3097 RegDeleteValueW(hkey
, lpNameW
);
3103 /*****************************************************************************
3104 * SetPrinterA [WINSPOOL.@]
3106 BOOL WINAPI
SetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
3109 FIXME("(%p,%d,%p,%d): stub\n",hPrinter
,Level
,pPrinter
,Command
);
3113 /*****************************************************************************
3114 * SetJobA [WINSPOOL.@]
3116 BOOL WINAPI
SetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3117 LPBYTE pJob
, DWORD Command
)
3121 UNICODE_STRING usBuffer
;
3123 TRACE("(%p, %d, %d, %p, %d)\n",hPrinter
, JobId
, Level
, pJob
, Command
);
3125 /* JobId, pPrinterName, pMachineName, pDriverName, Size, Submitted, Time and TotalPages
3126 are all ignored by SetJob, so we don't bother copying them */
3134 JOB_INFO_1W
*info1W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info1W
));
3135 JOB_INFO_1A
*info1A
= (JOB_INFO_1A
*)pJob
;
3137 JobW
= (LPBYTE
)info1W
;
3138 info1W
->pUserName
= asciitounicode(&usBuffer
, info1A
->pUserName
);
3139 info1W
->pDocument
= asciitounicode(&usBuffer
, info1A
->pDocument
);
3140 info1W
->pDatatype
= asciitounicode(&usBuffer
, info1A
->pDatatype
);
3141 info1W
->pStatus
= asciitounicode(&usBuffer
, info1A
->pStatus
);
3142 info1W
->Status
= info1A
->Status
;
3143 info1W
->Priority
= info1A
->Priority
;
3144 info1W
->Position
= info1A
->Position
;
3145 info1W
->PagesPrinted
= info1A
->PagesPrinted
;
3150 JOB_INFO_2W
*info2W
= HeapAlloc(GetProcessHeap(), 0, sizeof(*info2W
));
3151 JOB_INFO_2A
*info2A
= (JOB_INFO_2A
*)pJob
;
3153 JobW
= (LPBYTE
)info2W
;
3154 info2W
->pUserName
= asciitounicode(&usBuffer
, info2A
->pUserName
);
3155 info2W
->pDocument
= asciitounicode(&usBuffer
, info2A
->pDocument
);
3156 info2W
->pNotifyName
= asciitounicode(&usBuffer
, info2A
->pNotifyName
);
3157 info2W
->pDatatype
= asciitounicode(&usBuffer
, info2A
->pDatatype
);
3158 info2W
->pPrintProcessor
= asciitounicode(&usBuffer
, info2A
->pPrintProcessor
);
3159 info2W
->pParameters
= asciitounicode(&usBuffer
, info2A
->pParameters
);
3160 info2W
->pDevMode
= info2A
->pDevMode
? GdiConvertToDevmodeW(info2A
->pDevMode
) : NULL
;
3161 info2W
->pStatus
= asciitounicode(&usBuffer
, info2A
->pStatus
);
3162 info2W
->pSecurityDescriptor
= info2A
->pSecurityDescriptor
;
3163 info2W
->Status
= info2A
->Status
;
3164 info2W
->Priority
= info2A
->Priority
;
3165 info2W
->Position
= info2A
->Position
;
3166 info2W
->StartTime
= info2A
->StartTime
;
3167 info2W
->UntilTime
= info2A
->UntilTime
;
3168 info2W
->PagesPrinted
= info2A
->PagesPrinted
;
3172 JobW
= HeapAlloc(GetProcessHeap(), 0, sizeof(JOB_INFO_3
));
3173 memcpy(JobW
, pJob
, sizeof(JOB_INFO_3
));
3176 SetLastError(ERROR_INVALID_LEVEL
);
3180 ret
= SetJobW(hPrinter
, JobId
, Level
, JobW
, Command
);
3186 JOB_INFO_1W
*info1W
= (JOB_INFO_1W
*)JobW
;
3187 HeapFree(GetProcessHeap(), 0, info1W
->pUserName
);
3188 HeapFree(GetProcessHeap(), 0, info1W
->pDocument
);
3189 HeapFree(GetProcessHeap(), 0, info1W
->pDatatype
);
3190 HeapFree(GetProcessHeap(), 0, info1W
->pStatus
);
3195 JOB_INFO_2W
*info2W
= (JOB_INFO_2W
*)JobW
;
3196 HeapFree(GetProcessHeap(), 0, info2W
->pUserName
);
3197 HeapFree(GetProcessHeap(), 0, info2W
->pDocument
);
3198 HeapFree(GetProcessHeap(), 0, info2W
->pNotifyName
);
3199 HeapFree(GetProcessHeap(), 0, info2W
->pDatatype
);
3200 HeapFree(GetProcessHeap(), 0, info2W
->pPrintProcessor
);
3201 HeapFree(GetProcessHeap(), 0, info2W
->pParameters
);
3202 HeapFree(GetProcessHeap(), 0, info2W
->pDevMode
);
3203 HeapFree(GetProcessHeap(), 0, info2W
->pStatus
);
3207 HeapFree(GetProcessHeap(), 0, JobW
);
3212 /*****************************************************************************
3213 * SetJobW [WINSPOOL.@]
3215 BOOL WINAPI
SetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
,
3216 LPBYTE pJob
, DWORD Command
)
3221 TRACE("(%p, %d, %d, %p, %d)\n", hPrinter
, JobId
, Level
, pJob
, Command
);
3222 FIXME("Ignoring everything other than document title\n");
3224 EnterCriticalSection(&printer_handles_cs
);
3225 job
= get_job(hPrinter
, JobId
);
3235 JOB_INFO_1W
*info1
= (JOB_INFO_1W
*)pJob
;
3236 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3237 job
->document_title
= strdupW(info1
->pDocument
);
3242 JOB_INFO_2W
*info2
= (JOB_INFO_2W
*)pJob
;
3243 HeapFree(GetProcessHeap(), 0, job
->document_title
);
3244 job
->document_title
= strdupW(info2
->pDocument
);
3250 SetLastError(ERROR_INVALID_LEVEL
);
3255 LeaveCriticalSection(&printer_handles_cs
);
3259 /*****************************************************************************
3260 * EndDocPrinter [WINSPOOL.@]
3262 BOOL WINAPI
EndDocPrinter(HANDLE hPrinter
)
3264 opened_printer_t
*printer
;
3266 TRACE("(%p)\n", hPrinter
);
3268 EnterCriticalSection(&printer_handles_cs
);
3270 printer
= get_opened_printer(hPrinter
);
3273 SetLastError(ERROR_INVALID_HANDLE
);
3279 SetLastError(ERROR_SPL_NO_STARTDOC
);
3283 CloseHandle(printer
->doc
->hf
);
3284 ScheduleJob(hPrinter
, printer
->doc
->job_id
);
3285 HeapFree(GetProcessHeap(), 0, printer
->doc
);
3286 printer
->doc
= NULL
;
3289 LeaveCriticalSection(&printer_handles_cs
);
3293 /*****************************************************************************
3294 * EndPagePrinter [WINSPOOL.@]
3296 BOOL WINAPI
EndPagePrinter(HANDLE hPrinter
)
3298 FIXME("(%p): stub\n", hPrinter
);
3302 /*****************************************************************************
3303 * StartDocPrinterA [WINSPOOL.@]
3305 DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3307 UNICODE_STRING usBuffer
;
3309 DOC_INFO_2A
*doc2
= (DOC_INFO_2A
*)pDocInfo
;
3312 /* DOC_INFO_1, 2 and 3 all have the strings in the same place with either two (DOC_INFO_2)
3313 or one (DOC_INFO_3) extra DWORDs */
3317 doc2W
.JobId
= doc2
->JobId
;
3320 doc2W
.dwMode
= doc2
->dwMode
;
3323 doc2W
.pDocName
= asciitounicode(&usBuffer
, doc2
->pDocName
);
3324 doc2W
.pOutputFile
= asciitounicode(&usBuffer
, doc2
->pOutputFile
);
3325 doc2W
.pDatatype
= asciitounicode(&usBuffer
, doc2
->pDatatype
);
3329 SetLastError(ERROR_INVALID_LEVEL
);
3333 ret
= StartDocPrinterW(hPrinter
, Level
, (LPBYTE
)&doc2W
);
3335 HeapFree(GetProcessHeap(), 0, doc2W
.pDatatype
);
3336 HeapFree(GetProcessHeap(), 0, doc2W
.pOutputFile
);
3337 HeapFree(GetProcessHeap(), 0, doc2W
.pDocName
);
3342 /*****************************************************************************
3343 * StartDocPrinterW [WINSPOOL.@]
3345 DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pDocInfo
)
3347 DOC_INFO_2W
*doc
= (DOC_INFO_2W
*)pDocInfo
;
3348 opened_printer_t
*printer
;
3349 BYTE addjob_buf
[MAX_PATH
* sizeof(WCHAR
) + sizeof(ADDJOB_INFO_1W
)];
3350 ADDJOB_INFO_1W
*addjob
= (ADDJOB_INFO_1W
*) addjob_buf
;
3351 JOB_INFO_1W job_info
;
3352 DWORD needed
, ret
= 0;
3356 TRACE("(hPrinter = %p, Level = %d, pDocInfo = %p {pDocName = %s, pOutputFile = %s, pDatatype = %s}):\n",
3357 hPrinter
, Level
, doc
, debugstr_w(doc
->pDocName
), debugstr_w(doc
->pOutputFile
),
3358 debugstr_w(doc
->pDatatype
));
3360 if(Level
< 1 || Level
> 3)
3362 SetLastError(ERROR_INVALID_LEVEL
);
3366 EnterCriticalSection(&printer_handles_cs
);
3367 printer
= get_opened_printer(hPrinter
);
3370 SetLastError(ERROR_INVALID_HANDLE
);
3376 SetLastError(ERROR_INVALID_PRINTER_STATE
);
3380 /* Even if we're printing to a file we still add a print job, we'll
3381 just ignore the spool file name */
3383 if(!AddJobW(hPrinter
, 1, addjob_buf
, sizeof(addjob_buf
), &needed
))
3385 ERR("AddJob failed gle %u\n", GetLastError());
3389 if(doc
->pOutputFile
)
3390 filename
= doc
->pOutputFile
;
3392 filename
= addjob
->Path
;
3394 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3395 if(hf
== INVALID_HANDLE_VALUE
)
3398 memset(&job_info
, 0, sizeof(job_info
));
3399 job_info
.pDocument
= doc
->pDocName
;
3400 SetJobW(hPrinter
, addjob
->JobId
, 1, (LPBYTE
)&job_info
, 0);
3402 printer
->doc
= HeapAlloc(GetProcessHeap(), 0, sizeof(*printer
->doc
));
3403 printer
->doc
->hf
= hf
;
3404 ret
= printer
->doc
->job_id
= addjob
->JobId
;
3406 LeaveCriticalSection(&printer_handles_cs
);
3411 /*****************************************************************************
3412 * StartPagePrinter [WINSPOOL.@]
3414 BOOL WINAPI
StartPagePrinter(HANDLE hPrinter
)
3416 FIXME("(%p): stub\n", hPrinter
);
3420 /*****************************************************************************
3421 * GetFormA [WINSPOOL.@]
3423 BOOL WINAPI
GetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3424 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3426 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,pFormName
,
3427 Level
,pForm
,cbBuf
,pcbNeeded
);
3431 /*****************************************************************************
3432 * GetFormW [WINSPOOL.@]
3434 BOOL WINAPI
GetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3435 LPBYTE pForm
, DWORD cbBuf
, LPDWORD pcbNeeded
)
3437 FIXME("(%p,%s,%d,%p,%d,%p): stub\n",hPrinter
,
3438 debugstr_w(pFormName
),Level
,pForm
,cbBuf
,pcbNeeded
);
3442 /*****************************************************************************
3443 * SetFormA [WINSPOOL.@]
3445 BOOL WINAPI
SetFormA(HANDLE hPrinter
, LPSTR pFormName
, DWORD Level
,
3448 FIXME("(%p,%s,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3452 /*****************************************************************************
3453 * SetFormW [WINSPOOL.@]
3455 BOOL WINAPI
SetFormW(HANDLE hPrinter
, LPWSTR pFormName
, DWORD Level
,
3458 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pFormName
,Level
,pForm
);
3462 /*****************************************************************************
3463 * ReadPrinter [WINSPOOL.@]
3465 BOOL WINAPI
ReadPrinter(HANDLE hPrinter
, LPVOID pBuf
, DWORD cbBuf
,
3466 LPDWORD pNoBytesRead
)
3468 FIXME("(%p,%p,%d,%p): stub\n",hPrinter
,pBuf
,cbBuf
,pNoBytesRead
);
3472 /*****************************************************************************
3473 * ResetPrinterA [WINSPOOL.@]
3475 BOOL WINAPI
ResetPrinterA(HANDLE hPrinter
, LPPRINTER_DEFAULTSA pDefault
)
3477 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3481 /*****************************************************************************
3482 * ResetPrinterW [WINSPOOL.@]
3484 BOOL WINAPI
ResetPrinterW(HANDLE hPrinter
, LPPRINTER_DEFAULTSW pDefault
)
3486 FIXME("(%p, %p): stub\n", hPrinter
, pDefault
);
3490 /*****************************************************************************
3491 * WINSPOOL_GetDWORDFromReg
3493 * Return DWORD associated with ValueName from hkey.
3495 static DWORD
WINSPOOL_GetDWORDFromReg(HKEY hkey
, LPCSTR ValueName
)
3497 DWORD sz
= sizeof(DWORD
), type
, value
= 0;
3500 ret
= RegQueryValueExA(hkey
, ValueName
, 0, &type
, (LPBYTE
)&value
, &sz
);
3502 if(ret
!= ERROR_SUCCESS
) {
3503 WARN("Got ret = %d on name %s\n", ret
, ValueName
);
3506 if(type
!= REG_DWORD
) {
3507 ERR("Got type %d\n", type
);
3514 /*****************************************************************************
3515 * get_filename_from_reg [internal]
3517 * Get ValueName from hkey storing result in out
3518 * when the Value in the registry has only a filename, use driverdir as prefix
3519 * outlen is space left in out
3520 * String is stored either as unicode or ascii
3524 static BOOL
get_filename_from_reg(HKEY hkey
, LPCWSTR driverdir
, DWORD dirlen
, LPCWSTR ValueName
,
3525 LPBYTE out
, DWORD outlen
, LPDWORD needed
, BOOL unicode
)
3527 WCHAR filename
[MAX_PATH
];
3531 LPWSTR buffer
= filename
;
3535 size
= sizeof(filename
);
3537 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3538 if (ret
== ERROR_MORE_DATA
) {
3539 TRACE("need dynamic buffer: %u\n", size
);
3540 buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
3542 /* No Memory is bad */
3546 ret
= RegQueryValueExW(hkey
, ValueName
, NULL
, &type
, (LPBYTE
) buffer
, &size
);
3549 if ((ret
!= ERROR_SUCCESS
) || (!buffer
[0])) {
3550 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3556 /* do we have a full path ? */
3557 ret
= (((buffer
[0] == '\\') && (buffer
[1] == '\\')) ||
3558 (buffer
[0] && (buffer
[1] == ':') && (buffer
[2] == '\\')) );
3561 /* we must build the full Path */
3563 if ((out
) && (outlen
> dirlen
)) {
3565 lstrcpyW((LPWSTR
)out
, driverdir
);
3569 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3578 /* write the filename */
3580 size
= (lstrlenW(ptr
) + 1) * sizeof(WCHAR
);
3581 if ((out
) && (outlen
>= size
)) {
3582 lstrcpyW((LPWSTR
)out
, ptr
);
3591 size
= WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, NULL
, 0, NULL
, NULL
);
3592 if ((out
) && (outlen
>= size
)) {
3593 WideCharToMultiByte(CP_ACP
, 0, ptr
, -1, (LPSTR
)out
, outlen
, NULL
, NULL
);
3601 ptr
+= lstrlenW(ptr
)+1;
3602 if ((type
!= REG_MULTI_SZ
) || (!ptr
[0])) ptr
= NULL
;
3605 if (buffer
!= filename
) HeapFree(GetProcessHeap(), 0, buffer
);
3607 /* write the multisz-termination */
3608 if (type
== REG_MULTI_SZ
) {
3609 size
= (unicode
) ? sizeof(WCHAR
) : 1;
3612 if (out
&& (outlen
>= size
)) {
3613 memset (out
, 0, size
);
3619 /*****************************************************************************
3620 * WINSPOOL_GetStringFromReg
3622 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3623 * String is stored either as unicode or ascii.
3624 * Bit of a hack here to get the ValueName if we want ascii.
3626 static BOOL
WINSPOOL_GetStringFromReg(HKEY hkey
, LPCWSTR ValueName
, LPBYTE ptr
,
3627 DWORD buflen
, DWORD
*needed
,
3630 DWORD sz
= buflen
, type
;
3634 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3636 LPSTR ValueNameA
= strdupWtoA(ValueName
);
3637 ret
= RegQueryValueExA(hkey
, ValueNameA
, 0, &type
, ptr
, &sz
);
3638 HeapFree(GetProcessHeap(),0,ValueNameA
);
3640 if(ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
3641 WARN("Got ret = %d\n", ret
);
3645 /* add space for terminating '\0' */
3646 sz
+= unicode
? sizeof(WCHAR
) : 1;
3650 TRACE("%s: %s\n", debugstr_w(ValueName
), unicode
? debugstr_w((LPCWSTR
)ptr
) : debugstr_a((LPCSTR
)ptr
));
3655 /*****************************************************************************
3656 * WINSPOOL_GetDefaultDevMode
3658 * Get a default DevMode values for wineps.
3662 static void WINSPOOL_GetDefaultDevMode(
3664 DWORD buflen
, DWORD
*needed
,
3668 static const char szwps
[] = "wineps.drv";
3670 /* fill default DEVMODE - should be read from ppd... */
3671 ZeroMemory( &dm
, sizeof(dm
) );
3672 memcpy(dm
.dmDeviceName
,szwps
,sizeof szwps
);
3673 dm
.dmSpecVersion
= DM_SPECVERSION
;
3674 dm
.dmDriverVersion
= 1;
3675 dm
.dmSize
= sizeof(DEVMODEA
);
3676 dm
.dmDriverExtra
= 0;
3678 DM_ORIENTATION
| DM_PAPERSIZE
|
3679 DM_PAPERLENGTH
| DM_PAPERWIDTH
|
3682 DM_DEFAULTSOURCE
| DM_PRINTQUALITY
|
3683 DM_YRESOLUTION
| DM_TTOPTION
;
3685 dm
.u1
.s1
.dmOrientation
= DMORIENT_PORTRAIT
;
3686 dm
.u1
.s1
.dmPaperSize
= DMPAPER_A4
;
3687 dm
.u1
.s1
.dmPaperLength
= 2970;
3688 dm
.u1
.s1
.dmPaperWidth
= 2100;
3692 dm
.dmDefaultSource
= DMBIN_AUTO
;
3693 dm
.dmPrintQuality
= DMRES_MEDIUM
;
3696 dm
.dmYResolution
= 300; /* 300dpi */
3697 dm
.dmTTOption
= DMTT_BITMAP
;
3700 /* dm.dmLogPixels */
3701 /* dm.dmBitsPerPel */
3702 /* dm.dmPelsWidth */
3703 /* dm.dmPelsHeight */
3704 /* dm.dmDisplayFlags */
3705 /* dm.dmDisplayFrequency */
3706 /* dm.dmICMMethod */
3707 /* dm.dmICMIntent */
3708 /* dm.dmMediaType */
3709 /* dm.dmDitherType */
3710 /* dm.dmReserved1 */
3711 /* dm.dmReserved2 */
3712 /* dm.dmPanningWidth */
3713 /* dm.dmPanningHeight */
3716 if(buflen
>= sizeof(DEVMODEW
)) {
3717 DEVMODEW
*pdmW
= GdiConvertToDevmodeW(&dm
);
3718 memcpy(ptr
, pdmW
, sizeof(DEVMODEW
));
3719 HeapFree(GetProcessHeap(),0,pdmW
);
3721 *needed
= sizeof(DEVMODEW
);
3725 if(buflen
>= sizeof(DEVMODEA
)) {
3726 memcpy(ptr
, &dm
, sizeof(DEVMODEA
));
3728 *needed
= sizeof(DEVMODEA
);
3732 /*****************************************************************************
3733 * WINSPOOL_GetDevModeFromReg
3735 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
3736 * DevMode is stored either as unicode or ascii.
3738 static BOOL
WINSPOOL_GetDevModeFromReg(HKEY hkey
, LPCWSTR ValueName
,
3740 DWORD buflen
, DWORD
*needed
,
3743 DWORD sz
= buflen
, type
;
3746 if (ptr
&& buflen
>=sizeof(DEVMODEA
)) memset(ptr
, 0, sizeof(DEVMODEA
));
3747 ret
= RegQueryValueExW(hkey
, ValueName
, 0, &type
, ptr
, &sz
);
3748 if ((ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
)) sz
= 0;
3749 if (sz
< sizeof(DEVMODEA
))
3751 TRACE("corrupted registry for %s ( size %d)\n",debugstr_w(ValueName
),sz
);
3754 /* ensures that dmSize is not erratically bogus if registry is invalid */
3755 if (ptr
&& ((DEVMODEA
*)ptr
)->dmSize
< sizeof(DEVMODEA
))
3756 ((DEVMODEA
*)ptr
)->dmSize
= sizeof(DEVMODEA
);
3758 sz
+= (CCHDEVICENAME
+ CCHFORMNAME
);
3760 DEVMODEW
*dmW
= GdiConvertToDevmodeW((DEVMODEA
*)ptr
);
3761 memcpy(ptr
, dmW
, sz
);
3762 HeapFree(GetProcessHeap(),0,dmW
);
3769 /*********************************************************************
3770 * WINSPOOL_GetPrinter_1
3772 * Fills out a PRINTER_INFO_1A|W struct storing the strings in buf.
3773 * The strings are either stored as unicode or ascii.
3775 static BOOL
WINSPOOL_GetPrinter_1(HKEY hkeyPrinter
, PRINTER_INFO_1W
*pi1
,
3776 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3779 DWORD size
, left
= cbBuf
;
3780 BOOL space
= (cbBuf
> 0);
3785 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3787 if(space
&& size
<= left
) {
3788 pi1
->pName
= (LPWSTR
)ptr
;
3796 /* FIXME: pDescription should be something like "Name,Driver_Name,". */
3797 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3799 if(space
&& size
<= left
) {
3800 pi1
->pDescription
= (LPWSTR
)ptr
;
3808 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3810 if(space
&& size
<= left
) {
3811 pi1
->pComment
= (LPWSTR
)ptr
;
3819 if(pi1
) pi1
->Flags
= PRINTER_ENUM_ICON8
; /* We're a printer */
3821 if(!space
&& pi1
) /* zero out pi1 if we can't completely fill buf */
3822 memset(pi1
, 0, sizeof(*pi1
));
3826 /*********************************************************************
3827 * WINSPOOL_GetPrinter_2
3829 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
3830 * The strings are either stored as unicode or ascii.
3832 static BOOL
WINSPOOL_GetPrinter_2(HKEY hkeyPrinter
, PRINTER_INFO_2W
*pi2
,
3833 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3836 DWORD size
, left
= cbBuf
;
3837 BOOL space
= (cbBuf
> 0);
3842 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3844 if(space
&& size
<= left
) {
3845 pi2
->pPrinterName
= (LPWSTR
)ptr
;
3852 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Share_NameW
, ptr
, left
, &size
,
3854 if(space
&& size
<= left
) {
3855 pi2
->pShareName
= (LPWSTR
)ptr
;
3862 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
3864 if(space
&& size
<= left
) {
3865 pi2
->pPortName
= (LPWSTR
)ptr
;
3872 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Printer_DriverW
, ptr
, left
,
3874 if(space
&& size
<= left
) {
3875 pi2
->pDriverName
= (LPWSTR
)ptr
;
3882 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DescriptionW
, ptr
, left
, &size
,
3884 if(space
&& size
<= left
) {
3885 pi2
->pComment
= (LPWSTR
)ptr
;
3892 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, LocationW
, ptr
, left
, &size
,
3894 if(space
&& size
<= left
) {
3895 pi2
->pLocation
= (LPWSTR
)ptr
;
3902 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter
, Default_DevModeW
, ptr
, left
,
3904 if(space
&& size
<= left
) {
3905 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3914 WINSPOOL_GetDefaultDevMode(ptr
, left
, &size
, unicode
);
3915 if(space
&& size
<= left
) {
3916 pi2
->pDevMode
= (LPDEVMODEW
)ptr
;
3923 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Separator_FileW
, ptr
, left
,
3925 if(space
&& size
<= left
) {
3926 pi2
->pSepFile
= (LPWSTR
)ptr
;
3933 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, Print_ProcessorW
, ptr
, left
,
3935 if(space
&& size
<= left
) {
3936 pi2
->pPrintProcessor
= (LPWSTR
)ptr
;
3943 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, DatatypeW
, ptr
, left
,
3945 if(space
&& size
<= left
) {
3946 pi2
->pDatatype
= (LPWSTR
)ptr
;
3953 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, ParametersW
, ptr
, left
,
3955 if(space
&& size
<= left
) {
3956 pi2
->pParameters
= (LPWSTR
)ptr
;
3964 pi2
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
3965 pi2
->Priority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Priority");
3966 pi2
->DefaultPriority
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
3967 "Default Priority");
3968 pi2
->StartTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "StartTime");
3969 pi2
->UntilTime
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "UntilTime");
3972 if(!space
&& pi2
) /* zero out pi2 if we can't completely fill buf */
3973 memset(pi2
, 0, sizeof(*pi2
));
3978 /*********************************************************************
3979 * WINSPOOL_GetPrinter_4
3981 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
3983 static BOOL
WINSPOOL_GetPrinter_4(HKEY hkeyPrinter
, PRINTER_INFO_4W
*pi4
,
3984 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
3987 DWORD size
, left
= cbBuf
;
3988 BOOL space
= (cbBuf
> 0);
3993 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
3995 if(space
&& size
<= left
) {
3996 pi4
->pPrinterName
= (LPWSTR
)ptr
;
4004 pi4
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4007 if(!space
&& pi4
) /* zero out pi4 if we can't completely fill buf */
4008 memset(pi4
, 0, sizeof(*pi4
));
4013 /*********************************************************************
4014 * WINSPOOL_GetPrinter_5
4016 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
4018 static BOOL
WINSPOOL_GetPrinter_5(HKEY hkeyPrinter
, PRINTER_INFO_5W
*pi5
,
4019 LPBYTE buf
, DWORD cbBuf
, LPDWORD pcbNeeded
,
4022 DWORD size
, left
= cbBuf
;
4023 BOOL space
= (cbBuf
> 0);
4028 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, NameW
, ptr
, left
, &size
,
4030 if(space
&& size
<= left
) {
4031 pi5
->pPrinterName
= (LPWSTR
)ptr
;
4038 if(WINSPOOL_GetStringFromReg(hkeyPrinter
, PortW
, ptr
, left
, &size
,
4040 if(space
&& size
<= left
) {
4041 pi5
->pPortName
= (LPWSTR
)ptr
;
4049 pi5
->Attributes
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
, "Attributes");
4050 pi5
->DeviceNotSelectedTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4052 pi5
->TransmissionRetryTimeout
= WINSPOOL_GetDWORDFromReg(hkeyPrinter
,
4056 if(!space
&& pi5
) /* zero out pi5 if we can't completely fill buf */
4057 memset(pi5
, 0, sizeof(*pi5
));
4062 /*****************************************************************************
4063 * WINSPOOL_GetPrinter
4065 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
4066 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
4067 * just a collection of pointers to strings.
4069 static BOOL
WINSPOOL_GetPrinter(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4070 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
4073 DWORD size
, needed
= 0;
4075 HKEY hkeyPrinter
, hkeyPrinters
;
4078 TRACE("(%p,%d,%p,%d,%p)\n",hPrinter
,Level
,pPrinter
,cbBuf
, pcbNeeded
);
4080 if (!(name
= get_opened_printer_name(hPrinter
))) {
4081 SetLastError(ERROR_INVALID_HANDLE
);
4085 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4087 ERR("Can't create Printers key\n");
4090 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
) != ERROR_SUCCESS
)
4092 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4093 RegCloseKey(hkeyPrinters
);
4094 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4101 PRINTER_INFO_2W
*pi2
= (PRINTER_INFO_2W
*)pPrinter
;
4103 size
= sizeof(PRINTER_INFO_2W
);
4105 ptr
= pPrinter
+ size
;
4107 memset(pPrinter
, 0, size
);
4112 ret
= WINSPOOL_GetPrinter_2(hkeyPrinter
, pi2
, ptr
, cbBuf
, &needed
,
4120 PRINTER_INFO_4W
*pi4
= (PRINTER_INFO_4W
*)pPrinter
;
4122 size
= sizeof(PRINTER_INFO_4W
);
4124 ptr
= pPrinter
+ size
;
4126 memset(pPrinter
, 0, size
);
4131 ret
= WINSPOOL_GetPrinter_4(hkeyPrinter
, pi4
, ptr
, cbBuf
, &needed
,
4140 PRINTER_INFO_5W
*pi5
= (PRINTER_INFO_5W
*)pPrinter
;
4142 size
= sizeof(PRINTER_INFO_5W
);
4144 ptr
= pPrinter
+ size
;
4146 memset(pPrinter
, 0, size
);
4152 ret
= WINSPOOL_GetPrinter_5(hkeyPrinter
, pi5
, ptr
, cbBuf
, &needed
,
4159 FIXME("Unimplemented level %d\n", Level
);
4160 SetLastError(ERROR_INVALID_LEVEL
);
4161 RegCloseKey(hkeyPrinters
);
4162 RegCloseKey(hkeyPrinter
);
4166 RegCloseKey(hkeyPrinter
);
4167 RegCloseKey(hkeyPrinters
);
4169 TRACE("returning %d needed = %d\n", ret
, needed
);
4170 if(pcbNeeded
) *pcbNeeded
= needed
;
4172 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4176 /*****************************************************************************
4177 * GetPrinterW [WINSPOOL.@]
4179 BOOL WINAPI
GetPrinterW(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4180 DWORD cbBuf
, LPDWORD pcbNeeded
)
4182 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4186 /*****************************************************************************
4187 * GetPrinterA [WINSPOOL.@]
4189 BOOL WINAPI
GetPrinterA(HANDLE hPrinter
, DWORD Level
, LPBYTE pPrinter
,
4190 DWORD cbBuf
, LPDWORD pcbNeeded
)
4192 return WINSPOOL_GetPrinter(hPrinter
, Level
, pPrinter
, cbBuf
, pcbNeeded
,
4196 /*****************************************************************************
4197 * WINSPOOL_EnumPrinters
4199 * Implementation of EnumPrintersA|W
4201 static BOOL
WINSPOOL_EnumPrinters(DWORD dwType
, LPWSTR lpszName
,
4202 DWORD dwLevel
, LPBYTE lpbPrinters
,
4203 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4204 LPDWORD lpdwReturned
, BOOL unicode
)
4207 HKEY hkeyPrinters
, hkeyPrinter
;
4208 WCHAR PrinterName
[255];
4209 DWORD needed
= 0, number
= 0;
4210 DWORD used
, i
, left
;
4214 memset(lpbPrinters
, 0, cbBuf
);
4220 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
4221 if(dwType
== PRINTER_ENUM_DEFAULT
)
4224 if (dwType
& PRINTER_ENUM_CONNECTIONS
) {
4225 TRACE("ignoring PRINTER_ENUM_CONNECTIONS\n");
4226 dwType
&= ~PRINTER_ENUM_CONNECTIONS
; /* we don't handle that */
4228 FIXME("We don't handle PRINTER_ENUM_CONNECTIONS\n");
4236 if (!((dwType
& PRINTER_ENUM_LOCAL
) || (dwType
& PRINTER_ENUM_NAME
))) {
4237 FIXME("dwType = %08x\n", dwType
);
4238 SetLastError(ERROR_INVALID_FLAGS
);
4242 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4244 ERR("Can't create Printers key\n");
4248 if(RegQueryInfoKeyA(hkeyPrinters
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
4249 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
4250 RegCloseKey(hkeyPrinters
);
4251 ERR("Can't query Printers key\n");
4254 TRACE("Found %d printers\n", number
);
4258 used
= number
* sizeof(PRINTER_INFO_1W
);
4261 used
= number
* sizeof(PRINTER_INFO_2W
);
4264 used
= number
* sizeof(PRINTER_INFO_4W
);
4267 used
= number
* sizeof(PRINTER_INFO_5W
);
4271 SetLastError(ERROR_INVALID_LEVEL
);
4272 RegCloseKey(hkeyPrinters
);
4275 pi
= (used
<= cbBuf
) ? lpbPrinters
: NULL
;
4277 for(i
= 0; i
< number
; i
++) {
4278 if(RegEnumKeyW(hkeyPrinters
, i
, PrinterName
, sizeof(PrinterName
)) !=
4280 ERR("Can't enum key number %d\n", i
);
4281 RegCloseKey(hkeyPrinters
);
4284 TRACE("Printer %d is %s\n", i
, debugstr_w(PrinterName
));
4285 if(RegOpenKeyW(hkeyPrinters
, PrinterName
, &hkeyPrinter
) !=
4287 ERR("Can't open key %s\n", debugstr_w(PrinterName
));
4288 RegCloseKey(hkeyPrinters
);
4293 buf
= lpbPrinters
+ used
;
4294 left
= cbBuf
- used
;
4302 WINSPOOL_GetPrinter_1(hkeyPrinter
, (PRINTER_INFO_1W
*)pi
, buf
,
4303 left
, &needed
, unicode
);
4305 if(pi
) pi
+= sizeof(PRINTER_INFO_1W
);
4308 WINSPOOL_GetPrinter_2(hkeyPrinter
, (PRINTER_INFO_2W
*)pi
, buf
,
4309 left
, &needed
, unicode
);
4311 if(pi
) pi
+= sizeof(PRINTER_INFO_2W
);
4314 WINSPOOL_GetPrinter_4(hkeyPrinter
, (PRINTER_INFO_4W
*)pi
, buf
,
4315 left
, &needed
, unicode
);
4317 if(pi
) pi
+= sizeof(PRINTER_INFO_4W
);
4320 WINSPOOL_GetPrinter_5(hkeyPrinter
, (PRINTER_INFO_5W
*)pi
, buf
,
4321 left
, &needed
, unicode
);
4323 if(pi
) pi
+= sizeof(PRINTER_INFO_5W
);
4326 ERR("Shouldn't be here!\n");
4327 RegCloseKey(hkeyPrinter
);
4328 RegCloseKey(hkeyPrinters
);
4331 RegCloseKey(hkeyPrinter
);
4333 RegCloseKey(hkeyPrinters
);
4340 memset(lpbPrinters
, 0, cbBuf
);
4341 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4345 *lpdwReturned
= number
;
4346 SetLastError(ERROR_SUCCESS
);
4351 /******************************************************************
4352 * EnumPrintersW [WINSPOOL.@]
4354 * Enumerates the available printers, print servers and print
4355 * providers, depending on the specified flags, name and level.
4359 * If level is set to 1:
4360 * Returns an array of PRINTER_INFO_1 data structures in the
4361 * lpbPrinters buffer.
4363 * If level is set to 2:
4364 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4365 * Returns an array of PRINTER_INFO_2 data structures in the
4366 * lpbPrinters buffer. Note that according to MSDN also an
4367 * OpenPrinter should be performed on every remote printer.
4369 * If level is set to 4 (officially WinNT only):
4370 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
4371 * Fast: Only the registry is queried to retrieve printer names,
4372 * no connection to the driver is made.
4373 * Returns an array of PRINTER_INFO_4 data structures in the
4374 * lpbPrinters buffer.
4376 * If level is set to 5 (officially WinNT4/Win9x only):
4377 * Fast: Only the registry is queried to retrieve printer names,
4378 * no connection to the driver is made.
4379 * Returns an array of PRINTER_INFO_5 data structures in the
4380 * lpbPrinters buffer.
4382 * If level set to 3 or 6+:
4383 * returns zero (failure!)
4385 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
4389 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
4390 * - Only levels 2, 4 and 5 are implemented at the moment.
4391 * - 16-bit printer drivers are not enumerated.
4392 * - Returned amount of bytes used/needed does not match the real Windoze
4393 * implementation (as in this implementation, all strings are part
4394 * of the buffer, whereas Win32 keeps them somewhere else)
4395 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
4398 * - In a regular Wine installation, no registry settings for printers
4399 * exist, which makes this function return an empty list.
4401 BOOL WINAPI
EnumPrintersW(
4402 DWORD dwType
, /* [in] Types of print objects to enumerate */
4403 LPWSTR lpszName
, /* [in] name of objects to enumerate */
4404 DWORD dwLevel
, /* [in] type of printer info structure */
4405 LPBYTE lpbPrinters
, /* [out] buffer which receives info */
4406 DWORD cbBuf
, /* [in] max size of buffer in bytes */
4407 LPDWORD lpdwNeeded
, /* [out] pointer to var: # bytes used/needed */
4408 LPDWORD lpdwReturned
/* [out] number of entries returned */
4411 return WINSPOOL_EnumPrinters(dwType
, lpszName
, dwLevel
, lpbPrinters
, cbBuf
,
4412 lpdwNeeded
, lpdwReturned
, TRUE
);
4415 /******************************************************************
4416 * EnumPrintersA [WINSPOOL.@]
4419 BOOL WINAPI
EnumPrintersA(DWORD dwType
, LPSTR lpszName
,
4420 DWORD dwLevel
, LPBYTE lpbPrinters
,
4421 DWORD cbBuf
, LPDWORD lpdwNeeded
,
4422 LPDWORD lpdwReturned
)
4424 BOOL ret
, unicode
= FALSE
;
4425 UNICODE_STRING lpszNameW
;
4428 pwstrNameW
= asciitounicode(&lpszNameW
,lpszName
);
4429 if(!cbBuf
) unicode
= TRUE
; /* return a buffer that's big enough for the unicode version */
4430 ret
= WINSPOOL_EnumPrinters(dwType
, pwstrNameW
, dwLevel
, lpbPrinters
, cbBuf
,
4431 lpdwNeeded
, lpdwReturned
, unicode
);
4432 RtlFreeUnicodeString(&lpszNameW
);
4436 /*****************************************************************************
4437 * WINSPOOL_GetDriverInfoFromReg [internal]
4439 * Enters the information from the registry into the DRIVER_INFO struct
4442 * zero if the printer driver does not exist in the registry
4443 * (only if Level > 1) otherwise nonzero
4445 static BOOL
WINSPOOL_GetDriverInfoFromReg(
4448 const printenv_t
* env
,
4450 LPBYTE ptr
, /* DRIVER_INFO */
4451 LPBYTE pDriverStrings
, /* strings buffer */
4452 DWORD cbBuf
, /* size of string buffer */
4453 LPDWORD pcbNeeded
, /* space needed for str. */
4454 BOOL unicode
) /* type of strings */
4458 WCHAR driverdir
[MAX_PATH
];
4460 LPBYTE strPtr
= pDriverStrings
;
4461 LPDRIVER_INFO_8W di
= (LPDRIVER_INFO_8W
) ptr
;
4463 TRACE("(%p, %s, %p, %d, %p, %p, %d, %d)\n", hkeyDrivers
,
4464 debugstr_w(DriverName
), env
,
4465 Level
, di
, pDriverStrings
, cbBuf
, unicode
);
4467 if (di
) ZeroMemory(di
, di_sizeof
[Level
]);
4470 *pcbNeeded
= (lstrlenW(DriverName
) + 1) * sizeof(WCHAR
);
4471 if (*pcbNeeded
<= cbBuf
)
4472 strcpyW((LPWSTR
)strPtr
, DriverName
);
4476 *pcbNeeded
= WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, NULL
, 0, NULL
, NULL
);
4477 if (*pcbNeeded
<= cbBuf
)
4478 WideCharToMultiByte(CP_ACP
, 0, DriverName
, -1, (LPSTR
)strPtr
, *pcbNeeded
, NULL
, NULL
);
4481 /* pName for level 1 has a different offset! */
4483 if (di
) ((LPDRIVER_INFO_1W
) di
)->pName
= (LPWSTR
) strPtr
;
4487 /* .cVersion and .pName for level > 1 */
4489 di
->cVersion
= env
->driverversion
;
4490 di
->pName
= (LPWSTR
) strPtr
;
4491 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4494 /* Reserve Space for the largest subdir and a Backslash*/
4495 size
= sizeof(driverdir
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
4496 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1, (LPBYTE
) driverdir
, size
, &size
)) {
4497 /* Should never Fail */
4500 lstrcatW(driverdir
, env
->versionsubdir
);
4501 lstrcatW(driverdir
, backslashW
);
4503 /* dirlen must not include the terminating zero */
4504 dirlen
= (unicode
) ? lstrlenW(driverdir
) * sizeof(WCHAR
) :
4505 WideCharToMultiByte(CP_ACP
, 0, driverdir
, -1, NULL
, 0, NULL
, NULL
) -1;
4507 if (!DriverName
[0] || RegOpenKeyW(hkeyDrivers
, DriverName
, &hkeyDriver
) != ERROR_SUCCESS
) {
4508 ERR("Can't find driver %s in registry\n", debugstr_w(DriverName
));
4509 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER
); /* ? */
4515 size
= (lstrlenW(env
->envname
) + 1) * sizeof(WCHAR
);
4517 size
= WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, NULL
, 0, NULL
, NULL
);
4520 if (*pcbNeeded
<= cbBuf
) {
4522 lstrcpyW((LPWSTR
)strPtr
, env
->envname
);
4526 WideCharToMultiByte(CP_ACP
, 0, env
->envname
, -1, (LPSTR
)strPtr
, size
, NULL
, NULL
);
4528 if (di
) di
->pEnvironment
= (LPWSTR
)strPtr
;
4529 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4532 /* .pDriverPath is the Graphics rendering engine.
4533 The full Path is required to avoid a crash in some apps */
4534 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, 0, &size
, unicode
)) {
4536 if (*pcbNeeded
<= cbBuf
)
4537 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, DriverW
, strPtr
, size
, &tmp
, unicode
);
4539 if (di
) di
->pDriverPath
= (LPWSTR
)strPtr
;
4540 strPtr
= (pDriverStrings
) ? (pDriverStrings
+ (*pcbNeeded
)) : NULL
;
4543 /* .pDataFile: For postscript-drivers, this is the ppd-file */
4544 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, 0, &size
, unicode
)) {
4546 if (*pcbNeeded
<= cbBuf
)
4547 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Data_FileW
, strPtr
, size
, &size
, unicode
);
4549 if (di
) di
->pDataFile
= (LPWSTR
)strPtr
;
4550 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4553 /* .pConfigFile is the Driver user Interface */
4554 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, 0, &size
, unicode
)) {
4556 if (*pcbNeeded
<= cbBuf
)
4557 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Configuration_FileW
, strPtr
, size
, &size
, unicode
);
4559 if (di
) di
->pConfigFile
= (LPWSTR
)strPtr
;
4560 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4564 RegCloseKey(hkeyDriver
);
4565 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4570 RegCloseKey(hkeyDriver
);
4571 FIXME("level 5: incomplete\n");
4576 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, 0, &size
, unicode
)) {
4578 if (*pcbNeeded
<= cbBuf
)
4579 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Help_FileW
, strPtr
, size
, &size
, unicode
);
4581 if (di
) di
->pHelpFile
= (LPWSTR
)strPtr
;
4582 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4585 /* .pDependentFiles */
4586 if (get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, 0, &size
, unicode
)) {
4588 if (*pcbNeeded
<= cbBuf
)
4589 get_filename_from_reg(hkeyDriver
, driverdir
, dirlen
, Dependent_FilesW
, strPtr
, size
, &size
, unicode
);
4591 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4592 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4594 else if (GetVersion() & 0x80000000) {
4595 /* PowerPoint XP expects that pDependentFiles is always valid on win9x */
4596 size
= 2 * ((unicode
) ? sizeof(WCHAR
) : 1);
4598 if ((*pcbNeeded
<= cbBuf
) && strPtr
) ZeroMemory(strPtr
, size
);
4600 if (di
) di
->pDependentFiles
= (LPWSTR
)strPtr
;
4601 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4604 /* .pMonitorName is the optional Language Monitor */
4605 if (WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, 0, &size
, unicode
)) {
4607 if (*pcbNeeded
<= cbBuf
)
4608 WINSPOOL_GetStringFromReg(hkeyDriver
, MonitorW
, strPtr
, size
, &size
, unicode
);
4610 if (di
) di
->pMonitorName
= (LPWSTR
)strPtr
;
4611 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4614 /* .pDefaultDataType */
4615 if (WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, 0, &size
, unicode
)) {
4617 if(*pcbNeeded
<= cbBuf
)
4618 WINSPOOL_GetStringFromReg(hkeyDriver
, DatatypeW
, strPtr
, size
, &size
, unicode
);
4620 if (di
) di
->pDefaultDataType
= (LPWSTR
)strPtr
;
4621 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4625 RegCloseKey(hkeyDriver
);
4626 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4630 /* .pszzPreviousNames */
4631 if (WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, 0, &size
, unicode
)) {
4633 if(*pcbNeeded
<= cbBuf
)
4634 WINSPOOL_GetStringFromReg(hkeyDriver
, Previous_NamesW
, strPtr
, size
, &size
, unicode
);
4636 if (di
) di
->pszzPreviousNames
= (LPWSTR
)strPtr
;
4637 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4641 RegCloseKey(hkeyDriver
);
4642 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4646 /* support is missing, but not important enough for a FIXME */
4647 TRACE("%s: DriverDate + DriverVersion not supported\n", debugstr_w(DriverName
));
4650 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, 0, &size
, unicode
)) {
4652 if(*pcbNeeded
<= cbBuf
)
4653 WINSPOOL_GetStringFromReg(hkeyDriver
, ManufacturerW
, strPtr
, size
, &size
, unicode
);
4655 if (di
) di
->pszMfgName
= (LPWSTR
)strPtr
;
4656 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4660 if (WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, 0, &size
, unicode
)) {
4662 if(*pcbNeeded
<= cbBuf
)
4663 WINSPOOL_GetStringFromReg(hkeyDriver
, OEM_UrlW
, strPtr
, size
, &size
, unicode
);
4665 if (di
) di
->pszOEMUrl
= (LPWSTR
)strPtr
;
4666 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4669 /* .pszHardwareID */
4670 if (WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, 0, &size
, unicode
)) {
4672 if(*pcbNeeded
<= cbBuf
)
4673 WINSPOOL_GetStringFromReg(hkeyDriver
, HardwareIDW
, strPtr
, size
, &size
, unicode
);
4675 if (di
) di
->pszHardwareID
= (LPWSTR
)strPtr
;
4676 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4680 if (WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, 0, &size
, unicode
)) {
4682 if(*pcbNeeded
<= cbBuf
)
4683 WINSPOOL_GetStringFromReg(hkeyDriver
, ProviderW
, strPtr
, size
, &size
, unicode
);
4685 if (di
) di
->pszProvider
= (LPWSTR
)strPtr
;
4686 strPtr
= (pDriverStrings
) ? pDriverStrings
+ (*pcbNeeded
) : NULL
;
4690 RegCloseKey(hkeyDriver
);
4694 /* support is missing, but not important enough for a FIXME */
4695 TRACE("level 8: incomplete\n");
4697 TRACE("buffer space %d required %d\n", cbBuf
, *pcbNeeded
);
4698 RegCloseKey(hkeyDriver
);
4702 /*****************************************************************************
4703 * WINSPOOL_GetPrinterDriver
4705 static BOOL
WINSPOOL_GetPrinterDriver(HANDLE hPrinter
, LPCWSTR pEnvironment
,
4706 DWORD Level
, LPBYTE pDriverInfo
,
4707 DWORD cbBuf
, LPDWORD pcbNeeded
,
4711 WCHAR DriverName
[100];
4712 DWORD ret
, type
, size
, needed
= 0;
4714 HKEY hkeyPrinter
, hkeyPrinters
, hkeyDrivers
;
4715 const printenv_t
* env
;
4717 TRACE("(%p,%s,%d,%p,%d,%p)\n",hPrinter
,debugstr_w(pEnvironment
),
4718 Level
,pDriverInfo
,cbBuf
, pcbNeeded
);
4721 if (!(name
= get_opened_printer_name(hPrinter
))) {
4722 SetLastError(ERROR_INVALID_HANDLE
);
4726 if (Level
< 1 || Level
== 7 || Level
> 8) {
4727 SetLastError(ERROR_INVALID_LEVEL
);
4731 env
= validate_envW(pEnvironment
);
4732 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
4734 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, PrintersW
, &hkeyPrinters
) !=
4736 ERR("Can't create Printers key\n");
4739 if(RegOpenKeyW(hkeyPrinters
, name
, &hkeyPrinter
)
4741 ERR("Can't find opened printer %s in registry\n", debugstr_w(name
));
4742 RegCloseKey(hkeyPrinters
);
4743 SetLastError(ERROR_INVALID_PRINTER_NAME
); /* ? */
4746 size
= sizeof(DriverName
);
4748 ret
= RegQueryValueExW(hkeyPrinter
, Printer_DriverW
, 0, &type
,
4749 (LPBYTE
)DriverName
, &size
);
4750 RegCloseKey(hkeyPrinter
);
4751 RegCloseKey(hkeyPrinters
);
4752 if(ret
!= ERROR_SUCCESS
) {
4753 ERR("Can't get DriverName for printer %s\n", debugstr_w(name
));
4757 hkeyDrivers
= WINSPOOL_OpenDriverReg( pEnvironment
, TRUE
);
4759 ERR("Can't create Drivers key\n");
4763 size
= di_sizeof
[Level
];
4764 if ((size
<= cbBuf
) && pDriverInfo
)
4765 ptr
= pDriverInfo
+ size
;
4767 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverName
,
4768 env
, Level
, pDriverInfo
, ptr
,
4769 (cbBuf
< size
) ? 0 : cbBuf
- size
,
4770 &needed
, unicode
)) {
4771 RegCloseKey(hkeyDrivers
);
4775 RegCloseKey(hkeyDrivers
);
4777 if(pcbNeeded
) *pcbNeeded
= size
+ needed
;
4778 TRACE("buffer space %d required %d\n", cbBuf
, size
+ needed
);
4779 if(cbBuf
>= needed
) return TRUE
;
4780 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4784 /*****************************************************************************
4785 * GetPrinterDriverA [WINSPOOL.@]
4787 BOOL WINAPI
GetPrinterDriverA(HANDLE hPrinter
, LPSTR pEnvironment
,
4788 DWORD Level
, LPBYTE pDriverInfo
,
4789 DWORD cbBuf
, LPDWORD pcbNeeded
)
4792 UNICODE_STRING pEnvW
;
4795 pwstrEnvW
= asciitounicode(&pEnvW
, pEnvironment
);
4796 ret
= WINSPOOL_GetPrinterDriver(hPrinter
, pwstrEnvW
, Level
, pDriverInfo
,
4797 cbBuf
, pcbNeeded
, FALSE
);
4798 RtlFreeUnicodeString(&pEnvW
);
4801 /*****************************************************************************
4802 * GetPrinterDriverW [WINSPOOL.@]
4804 BOOL WINAPI
GetPrinterDriverW(HANDLE hPrinter
, LPWSTR pEnvironment
,
4805 DWORD Level
, LPBYTE pDriverInfo
,
4806 DWORD cbBuf
, LPDWORD pcbNeeded
)
4808 return WINSPOOL_GetPrinterDriver(hPrinter
, pEnvironment
, Level
,
4809 pDriverInfo
, cbBuf
, pcbNeeded
, TRUE
);
4812 /*****************************************************************************
4813 * GetPrinterDriverDirectoryW [WINSPOOL.@]
4815 * Return the PATH for the Printer-Drivers (UNICODE)
4818 * pName [I] Servername (NT only) or NULL (local Computer)
4819 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
4820 * Level [I] Structure-Level (must be 1)
4821 * pDriverDirectory [O] PTR to Buffer that receives the Result
4822 * cbBuf [I] Size of Buffer at pDriverDirectory
4823 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
4824 * required for pDriverDirectory
4827 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
4828 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
4829 * if cbBuf is too small
4831 * Native Values returned in pDriverDirectory on Success:
4832 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
4833 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
4834 *| win9x(Windows 4.0): "%winsysdir%"
4836 * "%winsysdir%" is the Value from GetSystemDirectoryW()
4839 *- Only NULL or "" is supported for pName
4842 BOOL WINAPI
GetPrinterDriverDirectoryW(LPWSTR pName
, LPWSTR pEnvironment
,
4843 DWORD Level
, LPBYTE pDriverDirectory
,
4844 DWORD cbBuf
, LPDWORD pcbNeeded
)
4847 const printenv_t
* env
;
4849 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
4850 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4851 if(pName
!= NULL
&& pName
[0]) {
4852 FIXME("pName unsupported: %s\n", debugstr_w(pName
));
4853 SetLastError(ERROR_INVALID_PARAMETER
);
4857 env
= validate_envW(pEnvironment
);
4858 if(!env
) return FALSE
; /* pEnvironment invalid or unsupported */
4861 WARN("(Level: %d) is ignored in win9x\n", Level
);
4862 SetLastError(ERROR_INVALID_LEVEL
);
4866 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
4867 needed
= GetSystemDirectoryW(NULL
, 0);
4868 /* add the Size for the Subdirectories */
4869 needed
+= lstrlenW(spooldriversW
);
4870 needed
+= lstrlenW(env
->subdir
);
4871 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
4874 *pcbNeeded
= needed
;
4875 TRACE("required: 0x%x/%d\n", needed
, needed
);
4876 if(needed
> cbBuf
) {
4877 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
4880 if(pcbNeeded
== NULL
) {
4881 WARN("(pcbNeeded == NULL) is ignored in win9x\n");
4882 SetLastError(RPC_X_NULL_REF_POINTER
);
4885 if(pDriverDirectory
== NULL
) {
4886 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
4887 SetLastError(ERROR_INVALID_USER_BUFFER
);
4891 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
4892 /* add the Subdirectories */
4893 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
4894 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
4895 TRACE(" => %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
4900 /*****************************************************************************
4901 * GetPrinterDriverDirectoryA [WINSPOOL.@]
4903 * Return the PATH for the Printer-Drivers (ANSI)
4905 * See GetPrinterDriverDirectoryW.
4908 * On NT, pDriverDirectory need the same Size as the Unicode-Version
4911 BOOL WINAPI
GetPrinterDriverDirectoryA(LPSTR pName
, LPSTR pEnvironment
,
4912 DWORD Level
, LPBYTE pDriverDirectory
,
4913 DWORD cbBuf
, LPDWORD pcbNeeded
)
4915 UNICODE_STRING nameW
, environmentW
;
4918 INT len
= cbBuf
* sizeof(WCHAR
)/sizeof(CHAR
);
4919 WCHAR
*driverDirectoryW
= NULL
;
4921 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_a(pName
),
4922 debugstr_a(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
4924 if (len
) driverDirectoryW
= HeapAlloc( GetProcessHeap(), 0, len
);
4926 if(pName
) RtlCreateUnicodeStringFromAsciiz(&nameW
, pName
);
4927 else nameW
.Buffer
= NULL
;
4928 if(pEnvironment
) RtlCreateUnicodeStringFromAsciiz(&environmentW
, pEnvironment
);
4929 else environmentW
.Buffer
= NULL
;
4931 ret
= GetPrinterDriverDirectoryW( nameW
.Buffer
, environmentW
.Buffer
, Level
,
4932 (LPBYTE
)driverDirectoryW
, len
, &pcbNeededW
);
4935 needed
= WideCharToMultiByte( CP_ACP
, 0, driverDirectoryW
, -1,
4936 (LPSTR
)pDriverDirectory
, cbBuf
, NULL
, NULL
);
4938 *pcbNeeded
= needed
;
4939 ret
= (needed
<= cbBuf
) ? TRUE
: FALSE
;
4941 if(pcbNeeded
) *pcbNeeded
= pcbNeededW
* sizeof(CHAR
)/sizeof(WCHAR
);
4943 TRACE("required: 0x%x/%d\n", pcbNeeded
? *pcbNeeded
: 0, pcbNeeded
? *pcbNeeded
: 0);
4945 HeapFree( GetProcessHeap(), 0, driverDirectoryW
);
4946 RtlFreeUnicodeString(&environmentW
);
4947 RtlFreeUnicodeString(&nameW
);
4952 /*****************************************************************************
4953 * AddPrinterDriverA [WINSPOOL.@]
4955 * See AddPrinterDriverW.
4958 BOOL WINAPI
AddPrinterDriverA(LPSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4960 TRACE("(%s, %d, %p)\n", debugstr_a(pName
), level
, pDriverInfo
);
4961 return AddPrinterDriverExA(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4964 /******************************************************************************
4965 * AddPrinterDriverW (WINSPOOL.@)
4967 * Install a Printer Driver
4970 * pName [I] Servername or NULL (local Computer)
4971 * level [I] Level for the supplied DRIVER_INFO_*W struct
4972 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
4979 BOOL WINAPI
AddPrinterDriverW(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
)
4981 TRACE("(%s, %d, %p)\n", debugstr_w(pName
), level
, pDriverInfo
);
4982 return AddPrinterDriverExW(pName
, level
, pDriverInfo
, APD_COPY_NEW_FILES
);
4985 /*****************************************************************************
4986 * AddPrintProcessorA [WINSPOOL.@]
4988 BOOL WINAPI
AddPrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPathName
,
4989 LPSTR pPrintProcessorName
)
4991 FIXME("(%s,%s,%s,%s): stub\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
4992 debugstr_a(pPathName
), debugstr_a(pPrintProcessorName
));
4996 /*****************************************************************************
4997 * AddPrintProcessorW [WINSPOOL.@]
4999 BOOL WINAPI
AddPrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPathName
,
5000 LPWSTR pPrintProcessorName
)
5002 FIXME("(%s,%s,%s,%s): stub\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
5003 debugstr_w(pPathName
), debugstr_w(pPrintProcessorName
));
5007 /*****************************************************************************
5008 * AddPrintProvidorA [WINSPOOL.@]
5010 BOOL WINAPI
AddPrintProvidorA(LPSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5012 FIXME("(%s,0x%08x,%p): stub\n", debugstr_a(pName
), Level
, pProviderInfo
);
5016 /*****************************************************************************
5017 * AddPrintProvidorW [WINSPOOL.@]
5019 BOOL WINAPI
AddPrintProvidorW(LPWSTR pName
, DWORD Level
, LPBYTE pProviderInfo
)
5021 FIXME("(%s,0x%08x,%p): stub\n", debugstr_w(pName
), Level
, pProviderInfo
);
5025 /*****************************************************************************
5026 * AdvancedDocumentPropertiesA [WINSPOOL.@]
5028 LONG WINAPI
AdvancedDocumentPropertiesA(HWND hWnd
, HANDLE hPrinter
, LPSTR pDeviceName
,
5029 PDEVMODEA pDevModeOutput
, PDEVMODEA pDevModeInput
)
5031 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_a(pDeviceName
),
5032 pDevModeOutput
, pDevModeInput
);
5036 /*****************************************************************************
5037 * AdvancedDocumentPropertiesW [WINSPOOL.@]
5039 LONG WINAPI
AdvancedDocumentPropertiesW(HWND hWnd
, HANDLE hPrinter
, LPWSTR pDeviceName
,
5040 PDEVMODEW pDevModeOutput
, PDEVMODEW pDevModeInput
)
5042 FIXME("(%p,%p,%s,%p,%p): stub\n", hWnd
, hPrinter
, debugstr_w(pDeviceName
),
5043 pDevModeOutput
, pDevModeInput
);
5047 /*****************************************************************************
5048 * PrinterProperties [WINSPOOL.@]
5050 * Displays a dialog to set the properties of the printer.
5053 * nonzero on success or zero on failure
5056 * implemented as stub only
5058 BOOL WINAPI
PrinterProperties(HWND hWnd
, /* [in] handle to parent window */
5059 HANDLE hPrinter
/* [in] handle to printer object */
5061 FIXME("(%p,%p): stub\n", hWnd
, hPrinter
);
5062 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5066 /*****************************************************************************
5067 * EnumJobsA [WINSPOOL.@]
5070 BOOL WINAPI
EnumJobsA(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5071 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5074 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5075 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5077 if(pcbNeeded
) *pcbNeeded
= 0;
5078 if(pcReturned
) *pcReturned
= 0;
5083 /*****************************************************************************
5084 * EnumJobsW [WINSPOOL.@]
5087 BOOL WINAPI
EnumJobsW(HANDLE hPrinter
, DWORD FirstJob
, DWORD NoJobs
,
5088 DWORD Level
, LPBYTE pJob
, DWORD cbBuf
, LPDWORD pcbNeeded
,
5091 FIXME("(%p,first=%d,no=%d,level=%d,job=%p,cb=%d,%p,%p), stub!\n",
5092 hPrinter
, FirstJob
, NoJobs
, Level
, pJob
, cbBuf
, pcbNeeded
, pcReturned
5094 if(pcbNeeded
) *pcbNeeded
= 0;
5095 if(pcReturned
) *pcReturned
= 0;
5099 /*****************************************************************************
5100 * WINSPOOL_EnumPrinterDrivers [internal]
5102 * Delivers information about all printer drivers installed on the
5103 * localhost or a given server
5106 * nonzero on success or zero on failure. If the buffer for the returned
5107 * information is too small the function will return an error
5110 * - only implemented for localhost, foreign hosts will return an error
5112 static BOOL
WINSPOOL_EnumPrinterDrivers(LPWSTR pName
, LPCWSTR pEnvironment
,
5113 DWORD Level
, LPBYTE pDriverInfo
,
5114 DWORD cbBuf
, LPDWORD pcbNeeded
,
5115 LPDWORD pcReturned
, BOOL unicode
)
5118 DWORD i
, needed
, number
= 0, size
= 0;
5119 WCHAR DriverNameW
[255];
5121 const printenv_t
* env
;
5123 TRACE("%s,%s,%d,%p,%d,%d\n",
5124 debugstr_w(pName
), debugstr_w(pEnvironment
),
5125 Level
, pDriverInfo
, cbBuf
, unicode
);
5127 /* check for local drivers */
5128 if((pName
) && (pName
[0])) {
5129 FIXME("remote drivers (%s) not supported!\n", debugstr_w(pName
));
5130 SetLastError(ERROR_ACCESS_DENIED
);
5134 env
= validate_envW(pEnvironment
);
5135 if (!env
) return FALSE
; /* SetLastError() is in validate_envW */
5137 /* check input parameter */
5138 if ((Level
< 1) || (Level
== 7) || (Level
> 8)) {
5139 SetLastError(ERROR_INVALID_LEVEL
);
5143 if ((pcbNeeded
== NULL
) || (pcReturned
== NULL
)) {
5144 SetLastError(RPC_X_NULL_REF_POINTER
);
5148 /* initialize return values */
5150 memset( pDriverInfo
, 0, cbBuf
);
5154 hkeyDrivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
5156 ERR("Can't open Drivers key\n");
5160 if(RegQueryInfoKeyA(hkeyDrivers
, NULL
, NULL
, NULL
, &number
, NULL
, NULL
,
5161 NULL
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
) {
5162 RegCloseKey(hkeyDrivers
);
5163 ERR("Can't query Drivers key\n");
5166 TRACE("Found %d Drivers\n", number
);
5168 /* get size of single struct
5169 * unicode and ascii structure have the same size
5171 size
= di_sizeof
[Level
];
5173 /* calculate required buffer size */
5174 *pcbNeeded
= size
* number
;
5176 for( i
= 0, ptr
= (pDriverInfo
&& (cbBuf
>= size
)) ? pDriverInfo
: NULL
;
5178 i
++, ptr
= (ptr
&& (cbBuf
>= size
* i
)) ? ptr
+ size
: NULL
) {
5179 if(RegEnumKeyW(hkeyDrivers
, i
, DriverNameW
, sizeof(DriverNameW
))
5181 ERR("Can't enum key number %d\n", i
);
5182 RegCloseKey(hkeyDrivers
);
5185 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers
, DriverNameW
,
5187 (cbBuf
< *pcbNeeded
) ? NULL
: pDriverInfo
+ *pcbNeeded
,
5188 (cbBuf
< *pcbNeeded
) ? 0 : cbBuf
- *pcbNeeded
,
5189 &needed
, unicode
)) {
5190 RegCloseKey(hkeyDrivers
);
5193 (*pcbNeeded
) += needed
;
5196 RegCloseKey(hkeyDrivers
);
5198 if(cbBuf
< *pcbNeeded
){
5199 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5203 *pcReturned
= number
;
5207 /*****************************************************************************
5208 * EnumPrinterDriversW [WINSPOOL.@]
5210 * see function EnumPrinterDrivers for RETURNS, BUGS
5212 BOOL WINAPI
EnumPrinterDriversW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
5213 LPBYTE pDriverInfo
, DWORD cbBuf
,
5214 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5216 return WINSPOOL_EnumPrinterDrivers(pName
, pEnvironment
, Level
, pDriverInfo
,
5217 cbBuf
, pcbNeeded
, pcReturned
, TRUE
);
5220 /*****************************************************************************
5221 * EnumPrinterDriversA [WINSPOOL.@]
5223 * see function EnumPrinterDrivers for RETURNS, BUGS
5225 BOOL WINAPI
EnumPrinterDriversA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
5226 LPBYTE pDriverInfo
, DWORD cbBuf
,
5227 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5229 UNICODE_STRING pNameW
, pEnvironmentW
;
5230 PWSTR pwstrNameW
, pwstrEnvironmentW
;
5232 pwstrNameW
= asciitounicode(&pNameW
, pName
);
5233 pwstrEnvironmentW
= asciitounicode(&pEnvironmentW
, pEnvironment
);
5235 ret
= WINSPOOL_EnumPrinterDrivers(pwstrNameW
, pwstrEnvironmentW
,
5236 Level
, pDriverInfo
, cbBuf
, pcbNeeded
,
5238 RtlFreeUnicodeString(&pNameW
);
5239 RtlFreeUnicodeString(&pEnvironmentW
);
5244 /******************************************************************************
5245 * EnumPortsA (WINSPOOL.@)
5250 BOOL WINAPI
EnumPortsA( LPSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
5251 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5254 LPBYTE bufferW
= NULL
;
5255 LPWSTR nameW
= NULL
;
5257 DWORD numentries
= 0;
5260 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pPorts
,
5261 cbBuf
, pcbNeeded
, pcReturned
);
5263 /* convert servername to unicode */
5265 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
5266 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5267 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
5269 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
5270 needed
= cbBuf
* sizeof(WCHAR
);
5271 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
5272 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5274 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
5275 if (pcbNeeded
) needed
= *pcbNeeded
;
5276 /* HeapReAlloc return NULL, when bufferW was NULL */
5277 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
5278 HeapAlloc(GetProcessHeap(), 0, needed
);
5280 /* Try again with the large Buffer */
5281 res
= EnumPortsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
5283 needed
= pcbNeeded
? *pcbNeeded
: 0;
5284 numentries
= pcReturned
? *pcReturned
: 0;
5287 W2k require the buffersize from EnumPortsW also for EnumPortsA.
5288 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
5291 /* EnumPortsW collected all Data. Parse them to calculate ANSI-Size */
5292 DWORD entrysize
= 0;
5295 LPPORT_INFO_2W pi2w
;
5296 LPPORT_INFO_2A pi2a
;
5299 entrysize
= (Level
== 1) ? sizeof(PORT_INFO_1A
) : sizeof(PORT_INFO_2A
);
5301 /* First pass: calculate the size for all Entries */
5302 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5303 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5305 while (index
< numentries
) {
5307 needed
+= entrysize
; /* PORT_INFO_?A */
5308 TRACE("%p: parsing #%d (%s)\n", pi2w
, index
, debugstr_w(pi2w
->pPortName
));
5310 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5311 NULL
, 0, NULL
, NULL
);
5313 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5314 NULL
, 0, NULL
, NULL
);
5315 needed
+= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5316 NULL
, 0, NULL
, NULL
);
5318 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5319 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5320 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5323 /* check for errors and quit on failure */
5324 if (cbBuf
< needed
) {
5325 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5329 len
= entrysize
* numentries
; /* room for all PORT_INFO_?A */
5330 ptr
= (LPSTR
) &pPorts
[len
]; /* room for strings */
5331 cbBuf
-= len
; /* free Bytes in the user-Buffer */
5332 pi2w
= (LPPORT_INFO_2W
) bufferW
;
5333 pi2a
= (LPPORT_INFO_2A
) pPorts
;
5335 /* Second Pass: Fill the User Buffer (if we have one) */
5336 while ((index
< numentries
) && pPorts
) {
5338 TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a
, Level
, index
);
5339 pi2a
->pPortName
= ptr
;
5340 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pPortName
, -1,
5341 ptr
, cbBuf
, NULL
, NULL
);
5345 pi2a
->pMonitorName
= ptr
;
5346 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pMonitorName
, -1,
5347 ptr
, cbBuf
, NULL
, NULL
);
5351 pi2a
->pDescription
= ptr
;
5352 len
= WideCharToMultiByte(CP_ACP
, 0, pi2w
->pDescription
, -1,
5353 ptr
, cbBuf
, NULL
, NULL
);
5357 pi2a
->fPortType
= pi2w
->fPortType
;
5358 pi2a
->Reserved
= 0; /* documented: "must be zero" */
5361 /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
5362 pi2w
= (LPPORT_INFO_2W
) (((LPBYTE
)pi2w
) + entrysize
);
5363 pi2a
= (LPPORT_INFO_2A
) (((LPBYTE
)pi2a
) + entrysize
);
5368 if (pcbNeeded
) *pcbNeeded
= needed
;
5369 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5371 HeapFree(GetProcessHeap(), 0, nameW
);
5372 HeapFree(GetProcessHeap(), 0, bufferW
);
5374 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5375 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5381 /******************************************************************************
5382 * EnumPortsW (WINSPOOL.@)
5384 * Enumerate available Ports
5387 * name [I] Servername or NULL (local Computer)
5388 * level [I] Structure-Level (1 or 2)
5389 * buffer [O] PTR to Buffer that receives the Result
5390 * bufsize [I] Size of Buffer at buffer
5391 * bufneeded [O] PTR to DWORD that receives the size in Bytes used / required for buffer
5392 * bufreturned [O] PTR to DWORD that receives the number of Ports in buffer
5396 * Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
5400 BOOL WINAPI
EnumPortsW(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
5403 DWORD numentries
= 0;
5406 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
5407 cbBuf
, pcbNeeded
, pcReturned
);
5409 if (pName
&& (pName
[0])) {
5410 FIXME("not implemented for Server %s\n", debugstr_w(pName
));
5411 SetLastError(ERROR_ACCESS_DENIED
);
5415 /* Level is not checked in win9x */
5416 if (!Level
|| (Level
> 2)) {
5417 WARN("level (%d) is ignored in win9x\n", Level
);
5418 SetLastError(ERROR_INVALID_LEVEL
);
5422 SetLastError(RPC_X_NULL_REF_POINTER
);
5426 EnterCriticalSection(&monitor_handles_cs
);
5429 /* Scan all local Ports */
5431 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
5433 /* we calculated the needed buffersize. now do the error-checks */
5434 if (cbBuf
< needed
) {
5435 monitor_unloadall();
5436 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5437 goto emP_cleanup_cs
;
5439 else if (!pPorts
|| !pcReturned
) {
5440 monitor_unloadall();
5441 SetLastError(RPC_X_NULL_REF_POINTER
);
5442 goto emP_cleanup_cs
;
5445 /* Fill the Buffer */
5446 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
5448 monitor_unloadall();
5451 LeaveCriticalSection(&monitor_handles_cs
);
5454 if (pcbNeeded
) *pcbNeeded
= needed
;
5455 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
5457 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
5458 (res
), GetLastError(), needed
, (res
)? numentries
: 0, numentries
);
5463 /******************************************************************************
5464 * GetDefaultPrinterW (WINSPOOL.@)
5467 * This function must read the value from data 'device' of key
5468 * HCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows
5470 BOOL WINAPI
GetDefaultPrinterW(LPWSTR name
, LPDWORD namesize
)
5474 WCHAR
*buffer
, *ptr
;
5478 SetLastError(ERROR_INVALID_PARAMETER
);
5482 /* make the buffer big enough for the stuff from the profile/registry,
5483 * the content must fit into the local buffer to compute the correct
5484 * size even if the extern buffer is too small or not given.
5485 * (20 for ,driver,port) */
5487 len
= max(100, (insize
+ 20));
5488 buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5490 if (!GetProfileStringW(windowsW
, deviceW
, emptyStringW
, buffer
, len
))
5492 SetLastError (ERROR_FILE_NOT_FOUND
);
5496 TRACE("%s\n", debugstr_w(buffer
));
5498 if ((ptr
= strchrW(buffer
, ',')) == NULL
)
5500 SetLastError(ERROR_INVALID_NAME
);
5506 *namesize
= strlenW(buffer
) + 1;
5507 if(!name
|| (*namesize
> insize
))
5509 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
5513 strcpyW(name
, buffer
);
5516 HeapFree( GetProcessHeap(), 0, buffer
);
5521 /******************************************************************************
5522 * GetDefaultPrinterA (WINSPOOL.@)
5524 BOOL WINAPI
GetDefaultPrinterA(LPSTR name
, LPDWORD namesize
)
5528 WCHAR
*bufferW
= NULL
;
5532 SetLastError(ERROR_INVALID_PARAMETER
);
5536 if(name
&& *namesize
) {
5538 bufferW
= HeapAlloc( GetProcessHeap(), 0, insize
* sizeof(WCHAR
));
5541 if(!GetDefaultPrinterW( bufferW
, namesize
)) {
5546 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, name
, insize
,
5550 *namesize
= WideCharToMultiByte(CP_ACP
, 0, bufferW
, -1, NULL
, 0, NULL
, NULL
);
5553 TRACE("0x%08x/0x%08x:%s\n", *namesize
, insize
, debugstr_w(bufferW
));
5556 HeapFree( GetProcessHeap(), 0, bufferW
);
5561 /******************************************************************************
5562 * SetDefaultPrinterW (WINSPOOL.204)
5564 * Set the Name of the Default Printer
5567 * pszPrinter [I] Name of the Printer or NULL
5574 * When the Parameter is NULL or points to an Empty String and
5575 * a Default Printer was already present, then this Function changes nothing.
5576 * Without a Default Printer and NULL (or an Empty String) as Parameter,
5577 * the First enumerated local Printer is used.
5580 BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter
)
5583 TRACE("(%s)\n", debugstr_w(pszPrinter
));
5585 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5589 /******************************************************************************
5590 * SetDefaultPrinterA (WINSPOOL.202)
5592 * See SetDefaultPrinterW.
5595 BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter
)
5598 TRACE("(%s)\n", debugstr_a(pszPrinter
));
5600 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
5605 /******************************************************************************
5606 * SetPrinterDataExA (WINSPOOL.@)
5608 DWORD WINAPI
SetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5609 LPCSTR pValueName
, DWORD Type
,
5610 LPBYTE pData
, DWORD cbData
)
5612 HKEY hkeyPrinter
, hkeySubkey
;
5615 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_a(pKeyName
),
5616 debugstr_a(pValueName
), Type
, pData
, cbData
);
5618 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5622 if((ret
= RegCreateKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5624 ERR("Can't create subkey %s\n", debugstr_a(pKeyName
));
5625 RegCloseKey(hkeyPrinter
);
5628 ret
= RegSetValueExA(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5629 RegCloseKey(hkeySubkey
);
5630 RegCloseKey(hkeyPrinter
);
5634 /******************************************************************************
5635 * SetPrinterDataExW (WINSPOOL.@)
5637 DWORD WINAPI
SetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5638 LPCWSTR pValueName
, DWORD Type
,
5639 LPBYTE pData
, DWORD cbData
)
5641 HKEY hkeyPrinter
, hkeySubkey
;
5644 TRACE("(%p, %s, %s %08x, %p, %08x)\n", hPrinter
, debugstr_w(pKeyName
),
5645 debugstr_w(pValueName
), Type
, pData
, cbData
);
5647 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5651 if((ret
= RegCreateKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5653 ERR("Can't create subkey %s\n", debugstr_w(pKeyName
));
5654 RegCloseKey(hkeyPrinter
);
5657 ret
= RegSetValueExW(hkeySubkey
, pValueName
, 0, Type
, pData
, cbData
);
5658 RegCloseKey(hkeySubkey
);
5659 RegCloseKey(hkeyPrinter
);
5663 /******************************************************************************
5664 * SetPrinterDataA (WINSPOOL.@)
5666 DWORD WINAPI
SetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, DWORD Type
,
5667 LPBYTE pData
, DWORD cbData
)
5669 return SetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, Type
,
5673 /******************************************************************************
5674 * SetPrinterDataW (WINSPOOL.@)
5676 DWORD WINAPI
SetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, DWORD Type
,
5677 LPBYTE pData
, DWORD cbData
)
5679 return SetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, Type
,
5683 /******************************************************************************
5684 * GetPrinterDataExA (WINSPOOL.@)
5686 DWORD WINAPI
GetPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
5687 LPCSTR pValueName
, LPDWORD pType
,
5688 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5690 HKEY hkeyPrinter
, hkeySubkey
;
5693 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5694 debugstr_a(pKeyName
), debugstr_a(pValueName
), pType
, pData
, nSize
,
5697 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5701 if((ret
= RegOpenKeyA(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5703 WARN("Can't open subkey %s\n", debugstr_a(pKeyName
));
5704 RegCloseKey(hkeyPrinter
);
5708 ret
= RegQueryValueExA(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5709 RegCloseKey(hkeySubkey
);
5710 RegCloseKey(hkeyPrinter
);
5714 /******************************************************************************
5715 * GetPrinterDataExW (WINSPOOL.@)
5717 DWORD WINAPI
GetPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5718 LPCWSTR pValueName
, LPDWORD pType
,
5719 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5721 HKEY hkeyPrinter
, hkeySubkey
;
5724 TRACE("(%p, %s, %s %p, %p, %08x, %p)\n", hPrinter
,
5725 debugstr_w(pKeyName
), debugstr_w(pValueName
), pType
, pData
, nSize
,
5728 if((ret
= WINSPOOL_GetOpenedPrinterRegKey(hPrinter
, &hkeyPrinter
))
5732 if((ret
= RegOpenKeyW(hkeyPrinter
, pKeyName
, &hkeySubkey
))
5734 WARN("Can't open subkey %s\n", debugstr_w(pKeyName
));
5735 RegCloseKey(hkeyPrinter
);
5739 ret
= RegQueryValueExW(hkeySubkey
, pValueName
, 0, pType
, pData
, pcbNeeded
);
5740 RegCloseKey(hkeySubkey
);
5741 RegCloseKey(hkeyPrinter
);
5745 /******************************************************************************
5746 * GetPrinterDataA (WINSPOOL.@)
5748 DWORD WINAPI
GetPrinterDataA(HANDLE hPrinter
, LPSTR pValueName
, LPDWORD pType
,
5749 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5751 return GetPrinterDataExA(hPrinter
, "PrinterDriverData", pValueName
, pType
,
5752 pData
, nSize
, pcbNeeded
);
5755 /******************************************************************************
5756 * GetPrinterDataW (WINSPOOL.@)
5758 DWORD WINAPI
GetPrinterDataW(HANDLE hPrinter
, LPWSTR pValueName
, LPDWORD pType
,
5759 LPBYTE pData
, DWORD nSize
, LPDWORD pcbNeeded
)
5761 return GetPrinterDataExW(hPrinter
, PrinterDriverDataW
, pValueName
, pType
,
5762 pData
, nSize
, pcbNeeded
);
5765 /*******************************************************************************
5766 * EnumPrinterDataExW [WINSPOOL.@]
5768 DWORD WINAPI
EnumPrinterDataExW(HANDLE hPrinter
, LPCWSTR pKeyName
,
5769 LPBYTE pEnumValues
, DWORD cbEnumValues
,
5770 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
5772 HKEY hkPrinter
, hkSubKey
;
5773 DWORD r
, ret
, dwIndex
, cValues
, cbMaxValueNameLen
,
5774 cbValueNameLen
, cbMaxValueLen
, cbValueLen
,
5779 PPRINTER_ENUM_VALUESW ppev
;
5781 TRACE ("%p %s\n", hPrinter
, debugstr_w (pKeyName
));
5783 if (pKeyName
== NULL
|| *pKeyName
== 0)
5784 return ERROR_INVALID_PARAMETER
;
5786 ret
= WINSPOOL_GetOpenedPrinterRegKey (hPrinter
, &hkPrinter
);
5787 if (ret
!= ERROR_SUCCESS
)
5789 TRACE ("WINSPOOL_GetOpenedPrinterRegKey (%p) returned %i\n",
5794 ret
= RegOpenKeyExW (hkPrinter
, pKeyName
, 0, KEY_READ
, &hkSubKey
);
5795 if (ret
!= ERROR_SUCCESS
)
5797 r
= RegCloseKey (hkPrinter
);
5798 if (r
!= ERROR_SUCCESS
)
5799 WARN ("RegCloseKey returned %i\n", r
);
5800 TRACE ("RegOpenKeyExW (%p, %s) returned %i\n", hPrinter
,
5801 debugstr_w (pKeyName
), ret
);
5805 ret
= RegCloseKey (hkPrinter
);
5806 if (ret
!= ERROR_SUCCESS
)
5808 ERR ("RegCloseKey returned %i\n", ret
);
5809 r
= RegCloseKey (hkSubKey
);
5810 if (r
!= ERROR_SUCCESS
)
5811 WARN ("RegCloseKey returned %i\n", r
);
5815 ret
= RegQueryInfoKeyW (hkSubKey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
5816 &cValues
, &cbMaxValueNameLen
, &cbMaxValueLen
, NULL
, NULL
);
5817 if (ret
!= ERROR_SUCCESS
)
5819 r
= RegCloseKey (hkSubKey
);
5820 if (r
!= ERROR_SUCCESS
)
5821 WARN ("RegCloseKey returned %i\n", r
);
5822 TRACE ("RegQueryInfoKeyW (%p) returned %i\n", hkSubKey
, ret
);
5826 TRACE ("RegQueryInfoKeyW returned cValues = %i, cbMaxValueNameLen = %i, "
5827 "cbMaxValueLen = %i\n", cValues
, cbMaxValueNameLen
, cbMaxValueLen
);
5829 if (cValues
== 0) /* empty key */
5831 r
= RegCloseKey (hkSubKey
);
5832 if (r
!= ERROR_SUCCESS
)
5833 WARN ("RegCloseKey returned %i\n", r
);
5834 *pcbEnumValues
= *pnEnumValues
= 0;
5835 return ERROR_SUCCESS
;
5838 ++cbMaxValueNameLen
; /* allow for trailing '\0' */
5840 hHeap
= GetProcessHeap ();
5843 ERR ("GetProcessHeap failed\n");
5844 r
= RegCloseKey (hkSubKey
);
5845 if (r
!= ERROR_SUCCESS
)
5846 WARN ("RegCloseKey returned %i\n", r
);
5847 return ERROR_OUTOFMEMORY
;
5850 lpValueName
= HeapAlloc (hHeap
, 0, cbMaxValueNameLen
* sizeof (WCHAR
));
5851 if (lpValueName
== NULL
)
5853 ERR ("Failed to allocate %i WCHARs from process heap\n", cbMaxValueNameLen
);
5854 r
= RegCloseKey (hkSubKey
);
5855 if (r
!= ERROR_SUCCESS
)
5856 WARN ("RegCloseKey returned %i\n", r
);
5857 return ERROR_OUTOFMEMORY
;
5860 lpValue
= HeapAlloc (hHeap
, 0, cbMaxValueLen
);
5861 if (lpValue
== NULL
)
5863 ERR ("Failed to allocate %i bytes from process heap\n", cbMaxValueLen
);
5864 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5865 WARN ("HeapFree failed with code %i\n", GetLastError ());
5866 r
= RegCloseKey (hkSubKey
);
5867 if (r
!= ERROR_SUCCESS
)
5868 WARN ("RegCloseKey returned %i\n", r
);
5869 return ERROR_OUTOFMEMORY
;
5872 TRACE ("pass 1: calculating buffer required for all names and values\n");
5874 cbBufSize
= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5876 TRACE ("%i bytes required for %i headers\n", cbBufSize
, cValues
);
5878 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5880 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5881 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5882 NULL
, NULL
, lpValue
, &cbValueLen
);
5883 if (ret
!= ERROR_SUCCESS
)
5885 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5886 WARN ("HeapFree failed with code %i\n", GetLastError ());
5887 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5888 WARN ("HeapFree failed with code %i\n", GetLastError ());
5889 r
= RegCloseKey (hkSubKey
);
5890 if (r
!= ERROR_SUCCESS
)
5891 WARN ("RegCloseKey returned %i\n", r
);
5892 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5896 TRACE ("%s [%i]: name needs %i WCHARs, data needs %i bytes\n",
5897 debugstr_w (lpValueName
), dwIndex
,
5898 cbValueNameLen
+ 1, cbValueLen
);
5900 cbBufSize
+= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5901 cbBufSize
+= cbValueLen
;
5904 TRACE ("%i bytes required for all %i values\n", cbBufSize
, cValues
);
5906 *pcbEnumValues
= cbBufSize
;
5907 *pnEnumValues
= cValues
;
5909 if (cbEnumValues
< cbBufSize
) /* buffer too small */
5911 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5912 WARN ("HeapFree failed with code %i\n", GetLastError ());
5913 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5914 WARN ("HeapFree failed with code %i\n", GetLastError ());
5915 r
= RegCloseKey (hkSubKey
);
5916 if (r
!= ERROR_SUCCESS
)
5917 WARN ("RegCloseKey returned %i\n", r
);
5918 TRACE ("%i byte buffer is not large enough\n", cbEnumValues
);
5919 return ERROR_MORE_DATA
;
5922 TRACE ("pass 2: copying all names and values to buffer\n");
5924 ppev
= (PPRINTER_ENUM_VALUESW
) pEnumValues
; /* array of structs */
5925 pEnumValues
+= cValues
* sizeof (PRINTER_ENUM_VALUESW
);
5927 for (dwIndex
= 0; dwIndex
< cValues
; ++dwIndex
)
5929 cbValueNameLen
= cbMaxValueNameLen
; cbValueLen
= cbMaxValueLen
;
5930 ret
= RegEnumValueW (hkSubKey
, dwIndex
, lpValueName
, &cbValueNameLen
,
5931 NULL
, &dwType
, lpValue
, &cbValueLen
);
5932 if (ret
!= ERROR_SUCCESS
)
5934 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5935 WARN ("HeapFree failed with code %i\n", GetLastError ());
5936 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5937 WARN ("HeapFree failed with code %i\n", GetLastError ());
5938 r
= RegCloseKey (hkSubKey
);
5939 if (r
!= ERROR_SUCCESS
)
5940 WARN ("RegCloseKey returned %i\n", r
);
5941 TRACE ("RegEnumValueW (%i) returned %i\n", dwIndex
, ret
);
5945 cbValueNameLen
= (cbValueNameLen
+ 1) * sizeof (WCHAR
);
5946 memcpy (pEnumValues
, lpValueName
, cbValueNameLen
);
5947 ppev
[dwIndex
].pValueName
= (LPWSTR
) pEnumValues
;
5948 pEnumValues
+= cbValueNameLen
;
5950 /* return # of *bytes* (including trailing \0), not # of chars */
5951 ppev
[dwIndex
].cbValueName
= cbValueNameLen
;
5953 ppev
[dwIndex
].dwType
= dwType
;
5955 memcpy (pEnumValues
, lpValue
, cbValueLen
);
5956 ppev
[dwIndex
].pData
= pEnumValues
;
5957 pEnumValues
+= cbValueLen
;
5959 ppev
[dwIndex
].cbData
= cbValueLen
;
5961 TRACE ("%s [%i]: copied name (%i bytes) and data (%i bytes)\n",
5962 debugstr_w (lpValueName
), dwIndex
, cbValueNameLen
, cbValueLen
);
5965 if (HeapFree (hHeap
, 0, lpValue
) == 0)
5967 ret
= GetLastError ();
5968 ERR ("HeapFree failed with code %i\n", ret
);
5969 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5970 WARN ("HeapFree failed with code %i\n", GetLastError ());
5971 r
= RegCloseKey (hkSubKey
);
5972 if (r
!= ERROR_SUCCESS
)
5973 WARN ("RegCloseKey returned %i\n", r
);
5977 if (HeapFree (hHeap
, 0, lpValueName
) == 0)
5979 ret
= GetLastError ();
5980 ERR ("HeapFree failed with code %i\n", ret
);
5981 r
= RegCloseKey (hkSubKey
);
5982 if (r
!= ERROR_SUCCESS
)
5983 WARN ("RegCloseKey returned %i\n", r
);
5987 ret
= RegCloseKey (hkSubKey
);
5988 if (ret
!= ERROR_SUCCESS
)
5990 ERR ("RegCloseKey returned %i\n", ret
);
5994 return ERROR_SUCCESS
;
5997 /*******************************************************************************
5998 * EnumPrinterDataExA [WINSPOOL.@]
6000 * This functions returns value names and REG_SZ, REG_EXPAND_SZ, and
6001 * REG_MULTI_SZ values as ASCII strings in Unicode-sized buffers. This is
6002 * what Windows 2000 SP1 does.
6005 DWORD WINAPI
EnumPrinterDataExA(HANDLE hPrinter
, LPCSTR pKeyName
,
6006 LPBYTE pEnumValues
, DWORD cbEnumValues
,
6007 LPDWORD pcbEnumValues
, LPDWORD pnEnumValues
)
6011 DWORD ret
, dwIndex
, dwBufSize
;
6015 TRACE ("%p %s\n", hPrinter
, pKeyName
);
6017 if (pKeyName
== NULL
|| *pKeyName
== 0)
6018 return ERROR_INVALID_PARAMETER
;
6020 len
= MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, NULL
, 0);
6023 ret
= GetLastError ();
6024 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6028 hHeap
= GetProcessHeap ();
6031 ERR ("GetProcessHeap failed\n");
6032 return ERROR_OUTOFMEMORY
;
6035 pKeyNameW
= HeapAlloc (hHeap
, 0, len
* sizeof (WCHAR
));
6036 if (pKeyNameW
== NULL
)
6038 ERR ("Failed to allocate %i bytes from process heap\n",
6039 (LONG
)(len
* sizeof (WCHAR
)));
6040 return ERROR_OUTOFMEMORY
;
6043 if (MultiByteToWideChar (CP_ACP
, 0, pKeyName
, -1, pKeyNameW
, len
) == 0)
6045 ret
= GetLastError ();
6046 ERR ("MultiByteToWideChar failed with code %i\n", ret
);
6047 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6048 WARN ("HeapFree failed with code %i\n", GetLastError ());
6052 ret
= EnumPrinterDataExW (hPrinter
, pKeyNameW
, pEnumValues
, cbEnumValues
,
6053 pcbEnumValues
, pnEnumValues
);
6054 if (ret
!= ERROR_SUCCESS
)
6056 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6057 WARN ("HeapFree failed with code %i\n", GetLastError ());
6058 TRACE ("EnumPrinterDataExW returned %i\n", ret
);
6062 if (HeapFree (hHeap
, 0, pKeyNameW
) == 0)
6064 ret
= GetLastError ();
6065 ERR ("HeapFree failed with code %i\n", ret
);
6069 if (*pnEnumValues
== 0) /* empty key */
6070 return ERROR_SUCCESS
;
6073 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6075 PPRINTER_ENUM_VALUESW ppev
=
6076 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6078 if (dwBufSize
< ppev
->cbValueName
)
6079 dwBufSize
= ppev
->cbValueName
;
6081 if (dwBufSize
< ppev
->cbData
&& (ppev
->dwType
== REG_SZ
||
6082 ppev
->dwType
== REG_EXPAND_SZ
|| ppev
->dwType
== REG_MULTI_SZ
))
6083 dwBufSize
= ppev
->cbData
;
6086 TRACE ("Largest Unicode name or value is %i bytes\n", dwBufSize
);
6088 pBuffer
= HeapAlloc (hHeap
, 0, dwBufSize
);
6089 if (pBuffer
== NULL
)
6091 ERR ("Failed to allocate %i bytes from process heap\n", dwBufSize
);
6092 return ERROR_OUTOFMEMORY
;
6095 for (dwIndex
= 0; dwIndex
< *pnEnumValues
; ++dwIndex
)
6097 PPRINTER_ENUM_VALUESW ppev
=
6098 &((PPRINTER_ENUM_VALUESW
) pEnumValues
)[dwIndex
];
6100 len
= WideCharToMultiByte (CP_ACP
, 0, ppev
->pValueName
,
6101 ppev
->cbValueName
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
,
6105 ret
= GetLastError ();
6106 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6107 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6108 WARN ("HeapFree failed with code %i\n", GetLastError ());
6112 memcpy (ppev
->pValueName
, pBuffer
, len
);
6114 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6116 if (ppev
->dwType
!= REG_SZ
&& ppev
->dwType
!= REG_EXPAND_SZ
&&
6117 ppev
->dwType
!= REG_MULTI_SZ
)
6120 len
= WideCharToMultiByte (CP_ACP
, 0, (LPWSTR
) ppev
->pData
,
6121 ppev
->cbData
/ sizeof (WCHAR
), pBuffer
, dwBufSize
, NULL
, NULL
);
6124 ret
= GetLastError ();
6125 ERR ("WideCharToMultiByte failed with code %i\n", ret
);
6126 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6127 WARN ("HeapFree failed with code %i\n", GetLastError ());
6131 memcpy (ppev
->pData
, pBuffer
, len
);
6133 TRACE ("Converted '%s' from Unicode to ASCII\n", pBuffer
);
6134 TRACE (" (only first string of REG_MULTI_SZ printed)\n");
6137 if (HeapFree (hHeap
, 0, pBuffer
) == 0)
6139 ret
= GetLastError ();
6140 ERR ("HeapFree failed with code %i\n", ret
);
6144 return ERROR_SUCCESS
;
6147 /******************************************************************************
6148 * AbortPrinter (WINSPOOL.@)
6150 BOOL WINAPI
AbortPrinter( HANDLE hPrinter
)
6152 FIXME("(%p), stub!\n", hPrinter
);
6156 /******************************************************************************
6157 * AddPortA (WINSPOOL.@)
6162 BOOL WINAPI
AddPortA(LPSTR pName
, HWND hWnd
, LPSTR pMonitorName
)
6164 LPWSTR nameW
= NULL
;
6165 LPWSTR monitorW
= NULL
;
6169 TRACE("(%s, %p, %s)\n",debugstr_a(pName
), hWnd
, debugstr_a(pMonitorName
));
6172 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6173 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6174 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6178 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6179 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6180 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6182 res
= AddPortW(nameW
, hWnd
, monitorW
);
6183 HeapFree(GetProcessHeap(), 0, nameW
);
6184 HeapFree(GetProcessHeap(), 0, monitorW
);
6188 /******************************************************************************
6189 * AddPortW (WINSPOOL.@)
6191 * Add a Port for a specific Monitor
6194 * pName [I] Servername or NULL (local Computer)
6195 * hWnd [I] Handle to parent Window for the Dialog-Box
6196 * pMonitorName [I] Name of the Monitor that manage the Port
6203 BOOL WINAPI
AddPortW(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
6209 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
6211 if (pName
&& pName
[0]) {
6212 SetLastError(ERROR_INVALID_PARAMETER
);
6216 if (!pMonitorName
) {
6217 SetLastError(RPC_X_NULL_REF_POINTER
);
6221 /* an empty Monitorname is Invalid */
6222 if (!pMonitorName
[0]) {
6223 SetLastError(ERROR_NOT_SUPPORTED
);
6227 pm
= monitor_load(pMonitorName
, NULL
);
6228 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
6229 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
6230 TRACE("got %d with %u\n", res
, GetLastError());
6235 pui
= monitor_loadui(pm
);
6236 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
6237 TRACE("use %p: %s\n", pui
, debugstr_w(pui
->dllname
));
6238 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
6239 TRACE("got %d with %u\n", res
, GetLastError());
6244 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pMonitorName
),
6245 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6247 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6248 SetLastError(ERROR_NOT_SUPPORTED
);
6251 monitor_unload(pui
);
6254 TRACE("returning %d with %u\n", res
, GetLastError());
6258 /******************************************************************************
6259 * AddPortExA (WINSPOOL.@)
6264 BOOL WINAPI
AddPortExA(LPSTR pName
, DWORD level
, LPBYTE pBuffer
, LPSTR pMonitorName
)
6267 PORT_INFO_2A
* pi2A
;
6268 LPWSTR nameW
= NULL
;
6269 LPWSTR monitorW
= NULL
;
6273 pi2A
= (PORT_INFO_2A
*) pBuffer
;
6275 TRACE("(%s, %d, %p, %s): %s\n", debugstr_a(pName
), level
, pBuffer
,
6276 debugstr_a(pMonitorName
), debugstr_a(pi2A
? pi2A
->pPortName
: NULL
));
6278 if ((level
< 1) || (level
> 2)) {
6279 SetLastError(ERROR_INVALID_LEVEL
);
6284 SetLastError(ERROR_INVALID_PARAMETER
);
6289 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6290 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6291 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6295 len
= MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, NULL
, 0);
6296 monitorW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6297 MultiByteToWideChar(CP_ACP
, 0, pMonitorName
, -1, monitorW
, len
);
6300 ZeroMemory(&pi2W
, sizeof(PORT_INFO_2W
));
6302 if (pi2A
->pPortName
) {
6303 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, NULL
, 0);
6304 pi2W
.pPortName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6305 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pPortName
, -1, pi2W
.pPortName
, len
);
6309 if (pi2A
->pMonitorName
) {
6310 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, NULL
, 0);
6311 pi2W
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6312 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pMonitorName
, -1, pi2W
.pMonitorName
, len
);
6315 if (pi2A
->pDescription
) {
6316 len
= MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, NULL
, 0);
6317 pi2W
.pDescription
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6318 MultiByteToWideChar(CP_ACP
, 0, pi2A
->pDescription
, -1, pi2W
.pDescription
, len
);
6320 pi2W
.fPortType
= pi2A
->fPortType
;
6321 pi2W
.Reserved
= pi2A
->Reserved
;
6324 res
= AddPortExW(nameW
, level
, (LPBYTE
) &pi2W
, monitorW
);
6326 HeapFree(GetProcessHeap(), 0, nameW
);
6327 HeapFree(GetProcessHeap(), 0, monitorW
);
6328 HeapFree(GetProcessHeap(), 0, pi2W
.pPortName
);
6329 HeapFree(GetProcessHeap(), 0, pi2W
.pMonitorName
);
6330 HeapFree(GetProcessHeap(), 0, pi2W
.pDescription
);
6335 /******************************************************************************
6336 * AddPortExW (WINSPOOL.@)
6338 * Add a Port for a specific Monitor, without presenting a user interface
6341 * pName [I] Servername or NULL (local Computer)
6342 * level [I] Structure-Level (1 or 2) for pBuffer
6343 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
6344 * pMonitorName [I] Name of the Monitor that manage the Port
6351 BOOL WINAPI
AddPortExW(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
6357 pi2
= (PORT_INFO_2W
*) pBuffer
;
6359 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
6360 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
6361 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
6362 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
6365 if ((level
< 1) || (level
> 2)) {
6366 SetLastError(ERROR_INVALID_LEVEL
);
6370 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
6371 SetLastError(ERROR_INVALID_PARAMETER
);
6375 /* load the Monitor */
6376 pm
= monitor_load(pMonitorName
, NULL
);
6378 SetLastError(ERROR_INVALID_PARAMETER
);
6382 if (pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
6383 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
6384 TRACE("got %u with %u\n", res
, GetLastError());
6388 FIXME("not implemented for %s (%p)\n", debugstr_w(pMonitorName
), pm
->monitor
);
6394 /******************************************************************************
6395 * AddPrinterConnectionA (WINSPOOL.@)
6397 BOOL WINAPI
AddPrinterConnectionA( LPSTR pName
)
6399 FIXME("%s\n", debugstr_a(pName
));
6403 /******************************************************************************
6404 * AddPrinterConnectionW (WINSPOOL.@)
6406 BOOL WINAPI
AddPrinterConnectionW( LPWSTR pName
)
6408 FIXME("%s\n", debugstr_w(pName
));
6412 /******************************************************************************
6413 * AddPrinterDriverExW (WINSPOOL.@)
6415 * Install a Printer Driver with the Option to upgrade / downgrade the Files
6418 * pName [I] Servername or NULL (local Computer)
6419 * level [I] Level for the supplied DRIVER_INFO_*W struct
6420 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
6421 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
6428 BOOL WINAPI
AddPrinterDriverExW( LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6430 const printenv_t
*env
;
6440 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
6442 if (level
< 2 || level
== 5 || level
== 7 || level
> 8) {
6443 SetLastError(ERROR_INVALID_LEVEL
);
6448 SetLastError(ERROR_INVALID_PARAMETER
);
6452 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
6453 FIXME("Flags 0x%x ignored (Fallback to APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
6456 ptr
= get_servername_from_name(pName
);
6457 HeapFree(GetProcessHeap(), 0, ptr
);
6459 FIXME("not supported for server: %s\n", debugstr_w(pName
));
6460 SetLastError(ERROR_ACCESS_DENIED
);
6464 /* we need to set all entries in the Registry, independent from the Level of
6465 DRIVER_INFO, that the caller supplied */
6467 ZeroMemory(&di
, sizeof(di
));
6468 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
6469 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
6472 /* dump the most used infos */
6473 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
6474 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
6475 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
6476 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
6477 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
6478 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
6479 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
6480 /* dump only the first of the additional Files */
6481 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
6484 /* check environment */
6485 env
= validate_envW(di
.pEnvironment
);
6486 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
6488 /* fill the copy-data / get the driverdir */
6489 len
= sizeof(apd
.src
) - sizeof(Version3_SubdirW
) - sizeof(WCHAR
);
6490 if (!GetPrinterDriverDirectoryW(NULL
, (LPWSTR
) env
->envname
, 1,
6491 (LPBYTE
) apd
.src
, len
, &len
)) {
6492 /* Should never Fail */
6495 memcpy(apd
.dst
, apd
.src
, len
);
6496 lstrcatW(apd
.src
, backslashW
);
6497 apd
.srclen
= lstrlenW(apd
.src
);
6498 lstrcatW(apd
.dst
, env
->versionsubdir
);
6499 lstrcatW(apd
.dst
, backslashW
);
6500 apd
.dstlen
= lstrlenW(apd
.dst
);
6501 apd
.copyflags
= dwFileCopyFlags
;
6502 CreateDirectoryW(apd
.src
, NULL
);
6503 CreateDirectoryW(apd
.dst
, NULL
);
6505 /* Fill the Registry for the Driver */
6506 hroot
= WINSPOOL_OpenDriverReg(env
->envname
, TRUE
);
6508 ERR("Can't create Drivers key\n");
6512 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
6513 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
6514 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
6516 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
6523 if (disposition
== REG_OPENED_EXISTING_KEY
) {
6524 TRACE("driver %s already installed\n", debugstr_w(di
.pName
));
6526 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
6530 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
6531 RegSetValueExW(hdrv
, VersionW
, 0, REG_DWORD
, (LPBYTE
) &env
->driverversion
,
6534 RegSetValueExW(hdrv
, DriverW
, 0, REG_SZ
, (LPBYTE
) di
.pDriverPath
,
6535 (lstrlenW(di
.pDriverPath
)+1)* sizeof(WCHAR
));
6536 apd_copyfile(di
.pDriverPath
, &apd
);
6538 RegSetValueExW(hdrv
, Data_FileW
, 0, REG_SZ
, (LPBYTE
) di
.pDataFile
,
6539 (lstrlenW(di
.pDataFile
)+1)* sizeof(WCHAR
));
6540 apd_copyfile(di
.pDataFile
, &apd
);
6542 RegSetValueExW(hdrv
, Configuration_FileW
, 0, REG_SZ
, (LPBYTE
) di
.pConfigFile
,
6543 (lstrlenW(di
.pConfigFile
)+1)* sizeof(WCHAR
));
6544 apd_copyfile(di
.pConfigFile
, &apd
);
6546 /* settings for level 3 */
6547 RegSetValueExW(hdrv
, Help_FileW
, 0, REG_SZ
, (LPBYTE
) di
.pHelpFile
,
6548 di
.pHelpFile
? (lstrlenW(di
.pHelpFile
)+1)* sizeof(WCHAR
) : 0);
6549 apd_copyfile(di
.pHelpFile
, &apd
);
6552 ptr
= di
.pDependentFiles
;
6553 RegSetValueExW(hdrv
, Dependent_FilesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pDependentFiles
,
6554 di
.pDependentFiles
? multi_sz_lenW(di
.pDependentFiles
) : 0);
6555 while ((ptr
!= NULL
) && (ptr
[0])) {
6556 if (apd_copyfile(ptr
, &apd
)) {
6557 ptr
+= lstrlenW(ptr
) + 1;
6561 WARN("Failed to copy %s\n", debugstr_w(ptr
));
6566 /* The language-Monitor was already copied to "%SystemRoot%\system32" */
6567 RegSetValueExW(hdrv
, MonitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
6568 di
.pMonitorName
? (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
) : 0);
6570 RegSetValueExW(hdrv
, DatatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
6571 di
.pDefaultDataType
? (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
) : 0);
6573 /* settings for level 4 */
6574 RegSetValueExW(hdrv
, Previous_NamesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
6575 di
.pszzPreviousNames
? multi_sz_lenW(di
.pszzPreviousNames
) : 0);
6577 if (level
> 5) FIXME("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
6581 FIXME("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
6584 TRACE("=> TRUE with %u\n", GetLastError());
6589 /******************************************************************************
6590 * AddPrinterDriverExA (WINSPOOL.@)
6592 * See AddPrinterDriverExW.
6595 BOOL WINAPI
AddPrinterDriverExA(LPSTR pName
, DWORD Level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
6597 DRIVER_INFO_8A
*diA
;
6599 LPWSTR nameW
= NULL
;
6604 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_a(pName
), Level
, pDriverInfo
, dwFileCopyFlags
);
6606 diA
= (DRIVER_INFO_8A
*) pDriverInfo
;
6607 ZeroMemory(&diW
, sizeof(diW
));
6609 if (Level
< 2 || Level
== 5 || Level
== 7 || Level
> 8) {
6610 SetLastError(ERROR_INVALID_LEVEL
);
6615 SetLastError(ERROR_INVALID_PARAMETER
);
6619 /* convert servername to unicode */
6621 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6622 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6623 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6627 diW
.cVersion
= diA
->cVersion
;
6630 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, NULL
, 0);
6631 diW
.pName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6632 MultiByteToWideChar(CP_ACP
, 0, diA
->pName
, -1, diW
.pName
, len
);
6635 if (diA
->pEnvironment
) {
6636 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, NULL
, 0);
6637 diW
.pEnvironment
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6638 MultiByteToWideChar(CP_ACP
, 0, diA
->pEnvironment
, -1, diW
.pEnvironment
, len
);
6641 if (diA
->pDriverPath
) {
6642 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, NULL
, 0);
6643 diW
.pDriverPath
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6644 MultiByteToWideChar(CP_ACP
, 0, diA
->pDriverPath
, -1, diW
.pDriverPath
, len
);
6647 if (diA
->pDataFile
) {
6648 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, NULL
, 0);
6649 diW
.pDataFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6650 MultiByteToWideChar(CP_ACP
, 0, diA
->pDataFile
, -1, diW
.pDataFile
, len
);
6653 if (diA
->pConfigFile
) {
6654 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, NULL
, 0);
6655 diW
.pConfigFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6656 MultiByteToWideChar(CP_ACP
, 0, diA
->pConfigFile
, -1, diW
.pConfigFile
, len
);
6659 if ((Level
> 2) && diA
->pDependentFiles
) {
6660 lenA
= multi_sz_lenA(diA
->pDependentFiles
);
6661 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, NULL
, 0);
6662 diW
.pDependentFiles
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6663 MultiByteToWideChar(CP_ACP
, 0, diA
->pDependentFiles
, lenA
, diW
.pDependentFiles
, len
);
6666 if ((Level
> 2) && diA
->pMonitorName
) {
6667 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, NULL
, 0);
6668 diW
.pMonitorName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6669 MultiByteToWideChar(CP_ACP
, 0, diA
->pMonitorName
, -1, diW
.pMonitorName
, len
);
6672 if ((Level
> 3) && diA
->pDefaultDataType
) {
6673 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, NULL
, 0);
6674 diW
.pDefaultDataType
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6675 MultiByteToWideChar(CP_ACP
, 0, diA
->pDefaultDataType
, -1, diW
.pDefaultDataType
, len
);
6678 if ((Level
> 3) && diA
->pszzPreviousNames
) {
6679 lenA
= multi_sz_lenA(diA
->pszzPreviousNames
);
6680 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, NULL
, 0);
6681 diW
.pszzPreviousNames
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6682 MultiByteToWideChar(CP_ACP
, 0, diA
->pszzPreviousNames
, lenA
, diW
.pszzPreviousNames
, len
);
6685 if ((Level
> 5) && diA
->pszMfgName
) {
6686 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, NULL
, 0);
6687 diW
.pszMfgName
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6688 MultiByteToWideChar(CP_ACP
, 0, diA
->pszMfgName
, -1, diW
.pszMfgName
, len
);
6691 if ((Level
> 5) && diA
->pszOEMUrl
) {
6692 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, NULL
, 0);
6693 diW
.pszOEMUrl
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6694 MultiByteToWideChar(CP_ACP
, 0, diA
->pszOEMUrl
, -1, diW
.pszOEMUrl
, len
);
6697 if ((Level
> 5) && diA
->pszHardwareID
) {
6698 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, NULL
, 0);
6699 diW
.pszHardwareID
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6700 MultiByteToWideChar(CP_ACP
, 0, diA
->pszHardwareID
, -1, diW
.pszHardwareID
, len
);
6703 if ((Level
> 5) && diA
->pszProvider
) {
6704 len
= MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, NULL
, 0);
6705 diW
.pszProvider
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6706 MultiByteToWideChar(CP_ACP
, 0, diA
->pszProvider
, -1, diW
.pszProvider
, len
);
6710 FIXME("level %u is incomplete\n", Level
);
6713 res
= AddPrinterDriverExW(nameW
, Level
, (LPBYTE
) &diW
, dwFileCopyFlags
);
6714 TRACE("got %u with %u\n", res
, GetLastError());
6715 HeapFree(GetProcessHeap(), 0, nameW
);
6716 HeapFree(GetProcessHeap(), 0, diW
.pName
);
6717 HeapFree(GetProcessHeap(), 0, diW
.pEnvironment
);
6718 HeapFree(GetProcessHeap(), 0, diW
.pDriverPath
);
6719 HeapFree(GetProcessHeap(), 0, diW
.pDataFile
);
6720 HeapFree(GetProcessHeap(), 0, diW
.pConfigFile
);
6721 HeapFree(GetProcessHeap(), 0, diW
.pDependentFiles
);
6722 HeapFree(GetProcessHeap(), 0, diW
.pMonitorName
);
6723 HeapFree(GetProcessHeap(), 0, diW
.pDefaultDataType
);
6724 HeapFree(GetProcessHeap(), 0, diW
.pszzPreviousNames
);
6725 HeapFree(GetProcessHeap(), 0, diW
.pszMfgName
);
6726 HeapFree(GetProcessHeap(), 0, diW
.pszOEMUrl
);
6727 HeapFree(GetProcessHeap(), 0, diW
.pszHardwareID
);
6728 HeapFree(GetProcessHeap(), 0, diW
.pszProvider
);
6730 TRACE("=> %u with %u\n", res
, GetLastError());
6734 /******************************************************************************
6735 * ConfigurePortA (WINSPOOL.@)
6737 * See ConfigurePortW.
6740 BOOL WINAPI
ConfigurePortA(LPSTR pName
, HWND hWnd
, LPSTR pPortName
)
6742 LPWSTR nameW
= NULL
;
6743 LPWSTR portW
= NULL
;
6747 TRACE("(%s, %p, %s)\n", debugstr_a(pName
), hWnd
, debugstr_a(pPortName
));
6749 /* convert servername to unicode */
6751 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
6752 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6753 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
6756 /* convert portname to unicode */
6758 len
= MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, NULL
, 0);
6759 portW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
6760 MultiByteToWideChar(CP_ACP
, 0, pPortName
, -1, portW
, len
);
6763 res
= ConfigurePortW(nameW
, hWnd
, portW
);
6764 HeapFree(GetProcessHeap(), 0, nameW
);
6765 HeapFree(GetProcessHeap(), 0, portW
);
6769 /******************************************************************************
6770 * ConfigurePortW (WINSPOOL.@)
6772 * Display the Configuration-Dialog for a specific Port
6775 * pName [I] Servername or NULL (local Computer)
6776 * hWnd [I] Handle to parent Window for the Dialog-Box
6777 * pPortName [I] Name of the Port, that should be configured
6784 BOOL WINAPI
ConfigurePortW(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
6790 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
6792 if (pName
&& pName
[0]) {
6793 SetLastError(ERROR_INVALID_PARAMETER
);
6798 SetLastError(RPC_X_NULL_REF_POINTER
);
6802 /* an empty Portname is Invalid, but can popup a Dialog */
6803 if (!pPortName
[0]) {
6804 SetLastError(ERROR_NOT_SUPPORTED
);
6808 pm
= monitor_load_by_port(pPortName
);
6809 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
6810 TRACE("Using %s for %s (%p: %s)\n", debugstr_w(pm
->name
), debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
6811 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
6812 TRACE("got %d with %u\n", res
, GetLastError());
6816 pui
= monitor_loadui(pm
);
6817 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
6818 TRACE("Use %s for %s (%p: %s)\n", debugstr_w(pui
->name
), debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
6819 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
6820 TRACE("got %d with %u\n", res
, GetLastError());
6824 FIXME("not implemented for %s (%p: %s => %p: %s)\n", debugstr_w(pPortName
),
6825 pm
, pm
? debugstr_w(pm
->dllname
) : NULL
, pui
, pui
? debugstr_w(pui
->dllname
) : NULL
);
6827 /* XP: ERROR_NOT_SUPPORTED, NT351,9x: ERROR_INVALID_PARAMETER */
6828 SetLastError(ERROR_NOT_SUPPORTED
);
6831 monitor_unload(pui
);
6835 TRACE("returning %d with %u\n", res
, GetLastError());
6839 /******************************************************************************
6840 * ConnectToPrinterDlg (WINSPOOL.@)
6842 HANDLE WINAPI
ConnectToPrinterDlg( HWND hWnd
, DWORD Flags
)
6844 FIXME("%p %x\n", hWnd
, Flags
);
6848 /******************************************************************************
6849 * DeletePrinterConnectionA (WINSPOOL.@)
6851 BOOL WINAPI
DeletePrinterConnectionA( LPSTR pName
)
6853 FIXME("%s\n", debugstr_a(pName
));
6857 /******************************************************************************
6858 * DeletePrinterConnectionW (WINSPOOL.@)
6860 BOOL WINAPI
DeletePrinterConnectionW( LPWSTR pName
)
6862 FIXME("%s\n", debugstr_w(pName
));
6866 /******************************************************************************
6867 * DeletePrinterDriverExW (WINSPOOL.@)
6869 BOOL WINAPI
DeletePrinterDriverExW( LPWSTR pName
, LPWSTR pEnvironment
,
6870 LPWSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6875 TRACE("%s %s %s %x %x\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6876 debugstr_w(pDriverName
), dwDeleteFlag
, dwVersionFlag
);
6878 if(pName
&& pName
[0])
6880 FIXME("pName = %s - unsupported\n", debugstr_w(pName
));
6881 SetLastError(ERROR_INVALID_PARAMETER
);
6887 FIXME("dwDeleteFlag = %x - unsupported\n", dwDeleteFlag
);
6888 SetLastError(ERROR_INVALID_PARAMETER
);
6892 hkey_drivers
= WINSPOOL_OpenDriverReg(pEnvironment
, TRUE
);
6896 ERR("Can't open drivers key\n");
6900 if(RegDeleteTreeW(hkey_drivers
, pDriverName
) == ERROR_SUCCESS
)
6903 RegCloseKey(hkey_drivers
);
6908 /******************************************************************************
6909 * DeletePrinterDriverExA (WINSPOOL.@)
6911 BOOL WINAPI
DeletePrinterDriverExA( LPSTR pName
, LPSTR pEnvironment
,
6912 LPSTR pDriverName
, DWORD dwDeleteFlag
, DWORD dwVersionFlag
)
6914 UNICODE_STRING NameW
, EnvW
, DriverW
;
6917 asciitounicode(&NameW
, pName
);
6918 asciitounicode(&EnvW
, pEnvironment
);
6919 asciitounicode(&DriverW
, pDriverName
);
6921 ret
= DeletePrinterDriverExW(NameW
.Buffer
, EnvW
.Buffer
, DriverW
.Buffer
, dwDeleteFlag
, dwVersionFlag
);
6923 RtlFreeUnicodeString(&DriverW
);
6924 RtlFreeUnicodeString(&EnvW
);
6925 RtlFreeUnicodeString(&NameW
);
6930 /******************************************************************************
6931 * DeletePrinterDataExW (WINSPOOL.@)
6933 DWORD WINAPI
DeletePrinterDataExW( HANDLE hPrinter
, LPCWSTR pKeyName
,
6936 FIXME("%p %s %s\n", hPrinter
,
6937 debugstr_w(pKeyName
), debugstr_w(pValueName
));
6938 return ERROR_INVALID_PARAMETER
;
6941 /******************************************************************************
6942 * DeletePrinterDataExA (WINSPOOL.@)
6944 DWORD WINAPI
DeletePrinterDataExA( HANDLE hPrinter
, LPCSTR pKeyName
,
6947 FIXME("%p %s %s\n", hPrinter
,
6948 debugstr_a(pKeyName
), debugstr_a(pValueName
));
6949 return ERROR_INVALID_PARAMETER
;
6952 /******************************************************************************
6953 * DeletePrintProcessorA (WINSPOOL.@)
6955 BOOL WINAPI
DeletePrintProcessorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProcessorName
)
6957 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6958 debugstr_a(pPrintProcessorName
));
6962 /******************************************************************************
6963 * DeletePrintProcessorW (WINSPOOL.@)
6965 BOOL WINAPI
DeletePrintProcessorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProcessorName
)
6967 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6968 debugstr_w(pPrintProcessorName
));
6972 /******************************************************************************
6973 * DeletePrintProvidorA (WINSPOOL.@)
6975 BOOL WINAPI
DeletePrintProvidorA(LPSTR pName
, LPSTR pEnvironment
, LPSTR pPrintProviderName
)
6977 FIXME("%s %s %s\n", debugstr_a(pName
), debugstr_a(pEnvironment
),
6978 debugstr_a(pPrintProviderName
));
6982 /******************************************************************************
6983 * DeletePrintProvidorW (WINSPOOL.@)
6985 BOOL WINAPI
DeletePrintProvidorW(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pPrintProviderName
)
6987 FIXME("%s %s %s\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
6988 debugstr_w(pPrintProviderName
));
6992 /******************************************************************************
6993 * EnumFormsA (WINSPOOL.@)
6995 BOOL WINAPI
EnumFormsA( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
6996 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
6998 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
6999 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7003 /******************************************************************************
7004 * EnumFormsW (WINSPOOL.@)
7006 BOOL WINAPI
EnumFormsW( HANDLE hPrinter
, DWORD Level
, LPBYTE pForm
,
7007 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7009 FIXME("%p %x %p %x %p %p\n", hPrinter
, Level
, pForm
, cbBuf
, pcbNeeded
, pcReturned
);
7010 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
7014 /*****************************************************************************
7015 * EnumMonitorsA [WINSPOOL.@]
7017 * See EnumMonitorsW.
7020 BOOL WINAPI
EnumMonitorsA(LPSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7021 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7024 LPBYTE bufferW
= NULL
;
7025 LPWSTR nameW
= NULL
;
7027 DWORD numentries
= 0;
7030 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName
), Level
, pMonitors
,
7031 cbBuf
, pcbNeeded
, pcReturned
);
7033 /* convert servername to unicode */
7035 len
= MultiByteToWideChar(CP_ACP
, 0, pName
, -1, NULL
, 0);
7036 nameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
7037 MultiByteToWideChar(CP_ACP
, 0, pName
, -1, nameW
, len
);
7039 /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the monitors */
7040 needed
= cbBuf
* sizeof(WCHAR
);
7041 if (needed
) bufferW
= HeapAlloc(GetProcessHeap(), 0, needed
);
7042 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7044 if(!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
7045 if (pcbNeeded
) needed
= *pcbNeeded
;
7046 /* HeapReAlloc return NULL, when bufferW was NULL */
7047 bufferW
= (bufferW
) ? HeapReAlloc(GetProcessHeap(), 0, bufferW
, needed
) :
7048 HeapAlloc(GetProcessHeap(), 0, needed
);
7050 /* Try again with the large Buffer */
7051 res
= EnumMonitorsW(nameW
, Level
, bufferW
, needed
, pcbNeeded
, pcReturned
);
7053 numentries
= pcReturned
? *pcReturned
: 0;
7056 W2k require the buffersize from EnumMonitorsW also for EnumMonitorsA.
7057 We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
7060 /* EnumMonitorsW collected all Data. Parse them to calculate ANSI-Size */
7061 DWORD entrysize
= 0;
7064 LPMONITOR_INFO_2W mi2w
;
7065 LPMONITOR_INFO_2A mi2a
;
7067 /* MONITOR_INFO_*W and MONITOR_INFO_*A have the same size */
7068 entrysize
= (Level
== 1) ? sizeof(MONITOR_INFO_1A
) : sizeof(MONITOR_INFO_2A
);
7070 /* First pass: calculate the size for all Entries */
7071 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7072 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7074 while (index
< numentries
) {
7076 needed
+= entrysize
; /* MONITOR_INFO_?A */
7077 TRACE("%p: parsing #%d (%s)\n", mi2w
, index
, debugstr_w(mi2w
->pName
));
7079 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7080 NULL
, 0, NULL
, NULL
);
7082 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7083 NULL
, 0, NULL
, NULL
);
7084 needed
+= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7085 NULL
, 0, NULL
, NULL
);
7087 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7088 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7089 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7092 /* check for errors and quit on failure */
7093 if (cbBuf
< needed
) {
7094 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7098 len
= entrysize
* numentries
; /* room for all MONITOR_INFO_?A */
7099 ptr
= (LPSTR
) &pMonitors
[len
]; /* room for strings */
7100 cbBuf
-= len
; /* free Bytes in the user-Buffer */
7101 mi2w
= (LPMONITOR_INFO_2W
) bufferW
;
7102 mi2a
= (LPMONITOR_INFO_2A
) pMonitors
;
7104 /* Second Pass: Fill the User Buffer (if we have one) */
7105 while ((index
< numentries
) && pMonitors
) {
7107 TRACE("%p: writing MONITOR_INFO_%dA #%d\n", mi2a
, Level
, index
);
7109 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pName
, -1,
7110 ptr
, cbBuf
, NULL
, NULL
);
7114 mi2a
->pEnvironment
= ptr
;
7115 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pEnvironment
, -1,
7116 ptr
, cbBuf
, NULL
, NULL
);
7120 mi2a
->pDLLName
= ptr
;
7121 len
= WideCharToMultiByte(CP_ACP
, 0, mi2w
->pDLLName
, -1,
7122 ptr
, cbBuf
, NULL
, NULL
);
7126 /* use LPBYTE with entrysize to avoid double code (MONITOR_INFO_1 + MONITOR_INFO_2) */
7127 mi2w
= (LPMONITOR_INFO_2W
) (((LPBYTE
)mi2w
) + entrysize
);
7128 mi2a
= (LPMONITOR_INFO_2A
) (((LPBYTE
)mi2a
) + entrysize
);
7132 if (pcbNeeded
) *pcbNeeded
= needed
;
7133 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
7135 HeapFree(GetProcessHeap(), 0, nameW
);
7136 HeapFree(GetProcessHeap(), 0, bufferW
);
7138 TRACE("returning %d with %d (%d byte for %d entries)\n",
7139 (res
), GetLastError(), needed
, numentries
);
7145 /*****************************************************************************
7146 * EnumMonitorsW [WINSPOOL.@]
7148 * Enumerate available Port-Monitors
7151 * pName [I] Servername or NULL (local Computer)
7152 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
7153 * pMonitors [O] PTR to Buffer that receives the Result
7154 * cbBuf [I] Size of Buffer at pMonitors
7155 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
7156 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
7160 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
7163 * Windows reads the Registry once and cache the Results.
7165 *| Language-Monitors are also installed in the same Registry-Location but
7166 *| they are filtered in Windows (not returned by EnumMonitors).
7167 *| We do no filtering to simplify our Code.
7170 BOOL WINAPI
EnumMonitorsW(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
,
7171 DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7174 DWORD numentries
= 0;
7177 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
7178 cbBuf
, pcbNeeded
, pcReturned
);
7180 if (pName
&& (lstrlenW(pName
))) {
7181 FIXME("for Server %s not implemented\n", debugstr_w(pName
));
7182 SetLastError(ERROR_ACCESS_DENIED
);
7186 /* Level is not checked in win9x */
7187 if (!Level
|| (Level
> 2)) {
7188 WARN("level (%d) is ignored in win9x\n", Level
);
7189 SetLastError(ERROR_INVALID_LEVEL
);
7193 SetLastError(RPC_X_NULL_REF_POINTER
);
7197 /* Scan all Monitor-Keys */
7199 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
7201 /* we calculated the needed buffersize. now do the error-checks */
7202 if (cbBuf
< needed
) {
7203 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
7206 else if (!pMonitors
|| !pcReturned
) {
7207 SetLastError(RPC_X_NULL_REF_POINTER
);
7211 /* fill the Buffer with the Monitor-Keys */
7212 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
7216 if (pcbNeeded
) *pcbNeeded
= needed
;
7217 if (pcReturned
) *pcReturned
= numentries
;
7219 TRACE("returning %d with %d (%d byte for %d entries)\n",
7220 res
, GetLastError(), needed
, numentries
);
7225 /******************************************************************************
7226 * XcvDataW (WINSPOOL.@)
7228 * Execute commands in the Printmonitor DLL
7231 * hXcv [i] Handle from OpenPrinter (with XcvMonitor or XcvPort)
7232 * pszDataName [i] Name of the command to execute
7233 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
7234 * cbInputData [i] Size in Bytes of Buffer at pInputData
7235 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
7236 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
7237 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
7238 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
7245 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
7246 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
7248 * Minimal List of commands, that a Printmonitor DLL should support:
7250 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
7251 *| "AddPort" : Add a Port
7252 *| "DeletePort": Delete a Port
7254 * Many Printmonitors support additional commands. Examples for localspl.dll:
7255 * "GetDefaultCommConfig", "SetDefaultCommConfig",
7256 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
7259 BOOL WINAPI
XcvDataW( HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
7260 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
7261 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
7263 opened_printer_t
*printer
;
7265 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
7266 pInputData
, cbInputData
, pOutputData
,
7267 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
7269 printer
= get_opened_printer(hXcv
);
7270 if (!printer
|| (!printer
->hXcv
)) {
7271 SetLastError(ERROR_INVALID_HANDLE
);
7275 if (!pcbOutputNeeded
) {
7276 SetLastError(ERROR_INVALID_PARAMETER
);
7280 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
7281 SetLastError(RPC_X_NULL_REF_POINTER
);
7285 *pcbOutputNeeded
= 0;
7287 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
7288 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
7293 /*****************************************************************************
7294 * EnumPrinterDataA [WINSPOOL.@]
7297 DWORD WINAPI
EnumPrinterDataA( HANDLE hPrinter
, DWORD dwIndex
, LPSTR pValueName
,
7298 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7299 DWORD cbData
, LPDWORD pcbData
)
7301 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7302 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7303 return ERROR_NO_MORE_ITEMS
;
7306 /*****************************************************************************
7307 * EnumPrinterDataW [WINSPOOL.@]
7310 DWORD WINAPI
EnumPrinterDataW( HANDLE hPrinter
, DWORD dwIndex
, LPWSTR pValueName
,
7311 DWORD cbValueName
, LPDWORD pcbValueName
, LPDWORD pType
, LPBYTE pData
,
7312 DWORD cbData
, LPDWORD pcbData
)
7314 FIXME("%p %x %p %x %p %p %p %x %p\n", hPrinter
, dwIndex
, pValueName
,
7315 cbValueName
, pcbValueName
, pType
, pData
, cbData
, pcbData
);
7316 return ERROR_NO_MORE_ITEMS
;
7319 /*****************************************************************************
7320 * EnumPrintProcessorDatatypesA [WINSPOOL.@]
7323 BOOL WINAPI
EnumPrintProcessorDatatypesA(LPSTR pName
, LPSTR pPrintProcessorName
,
7324 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7325 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7327 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_a(pName
),
7328 debugstr_a(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7329 pcbNeeded
, pcReturned
);
7333 /*****************************************************************************
7334 * EnumPrintProcessorDatatypesW [WINSPOOL.@]
7337 BOOL WINAPI
EnumPrintProcessorDatatypesW(LPWSTR pName
, LPWSTR pPrintProcessorName
,
7338 DWORD Level
, LPBYTE pDatatypes
, DWORD cbBuf
,
7339 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
7341 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7342 debugstr_w(pPrintProcessorName
), Level
, pDatatypes
, cbBuf
,
7343 pcbNeeded
, pcReturned
);
7347 /*****************************************************************************
7348 * EnumPrintProcessorsA [WINSPOOL.@]
7351 BOOL WINAPI
EnumPrintProcessorsA(LPSTR pName
, LPSTR pEnvironment
, DWORD Level
,
7352 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7354 FIXME("Stub: %s %s %d %p %d %p %p\n", pName
, pEnvironment
, Level
,
7355 pPrintProcessorInfo
, cbBuf
, pcbNeeded
, pcbReturned
);
7359 /*****************************************************************************
7360 * EnumPrintProcessorsW [WINSPOOL.@]
7363 BOOL WINAPI
EnumPrintProcessorsW(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
7364 LPBYTE pPrintProcessorInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcbReturned
)
7366 FIXME("Stub: %s %s %d %p %d %p %p\n", debugstr_w(pName
),
7367 debugstr_w(pEnvironment
), Level
, pPrintProcessorInfo
,
7368 cbBuf
, pcbNeeded
, pcbReturned
);
7372 /*****************************************************************************
7373 * ExtDeviceMode [WINSPOOL.@]
7376 LONG WINAPI
ExtDeviceMode( HWND hWnd
, HANDLE hInst
, LPDEVMODEA pDevModeOutput
,
7377 LPSTR pDeviceName
, LPSTR pPort
, LPDEVMODEA pDevModeInput
, LPSTR pProfile
,
7380 FIXME("Stub: %p %p %p %s %s %p %s %x\n", hWnd
, hInst
, pDevModeOutput
,
7381 debugstr_a(pDeviceName
), debugstr_a(pPort
), pDevModeInput
,
7382 debugstr_a(pProfile
), fMode
);
7386 /*****************************************************************************
7387 * FindClosePrinterChangeNotification [WINSPOOL.@]
7390 BOOL WINAPI
FindClosePrinterChangeNotification( HANDLE hChange
)
7392 FIXME("Stub: %p\n", hChange
);
7396 /*****************************************************************************
7397 * FindFirstPrinterChangeNotification [WINSPOOL.@]
7400 HANDLE WINAPI
FindFirstPrinterChangeNotification( HANDLE hPrinter
,
7401 DWORD fdwFlags
, DWORD fdwOptions
, LPVOID pPrinterNotifyOptions
)
7403 FIXME("Stub: %p %x %x %p\n",
7404 hPrinter
, fdwFlags
, fdwOptions
, pPrinterNotifyOptions
);
7405 return INVALID_HANDLE_VALUE
;
7408 /*****************************************************************************
7409 * FindNextPrinterChangeNotification [WINSPOOL.@]
7412 BOOL WINAPI
FindNextPrinterChangeNotification( HANDLE hChange
, PDWORD pdwChange
,
7413 LPVOID pPrinterNotifyOptions
, LPVOID
*ppPrinterNotifyInfo
)
7415 FIXME("Stub: %p %p %p %p\n",
7416 hChange
, pdwChange
, pPrinterNotifyOptions
, ppPrinterNotifyInfo
);
7420 /*****************************************************************************
7421 * FreePrinterNotifyInfo [WINSPOOL.@]
7424 BOOL WINAPI
FreePrinterNotifyInfo( PPRINTER_NOTIFY_INFO pPrinterNotifyInfo
)
7426 FIXME("Stub: %p\n", pPrinterNotifyInfo
);
7430 /*****************************************************************************
7433 * Copies a unicode string into a buffer. The buffer will either contain unicode or
7434 * ansi depending on the unicode parameter.
7436 static BOOL
string_to_buf(LPCWSTR str
, LPBYTE ptr
, DWORD cb
, DWORD
*size
, BOOL unicode
)
7446 *size
= (strlenW(str
) + 1) * sizeof(WCHAR
);
7449 memcpy(ptr
, str
, *size
);
7456 *size
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
7459 WideCharToMultiByte(CP_ACP
, 0, str
, -1, (LPSTR
)ptr
, *size
, NULL
, NULL
);
7466 /*****************************************************************************
7469 static BOOL
get_job_info_1(job_t
*job
, JOB_INFO_1W
*ji1
, LPBYTE buf
, DWORD cbBuf
,
7470 LPDWORD pcbNeeded
, BOOL unicode
)
7472 DWORD size
, left
= cbBuf
;
7473 BOOL space
= (cbBuf
> 0);
7480 ji1
->JobId
= job
->job_id
;
7483 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7484 if(space
&& size
<= left
)
7486 ji1
->pDocument
= (LPWSTR
)ptr
;
7497 /*****************************************************************************
7500 static BOOL
get_job_info_2(job_t
*job
, JOB_INFO_2W
*ji2
, LPBYTE buf
, DWORD cbBuf
,
7501 LPDWORD pcbNeeded
, BOOL unicode
)
7503 DWORD size
, left
= cbBuf
;
7504 BOOL space
= (cbBuf
> 0);
7511 ji2
->JobId
= job
->job_id
;
7514 string_to_buf(job
->document_title
, ptr
, left
, &size
, unicode
);
7515 if(space
&& size
<= left
)
7517 ji2
->pDocument
= (LPWSTR
)ptr
;
7528 /*****************************************************************************
7531 static BOOL
get_job_info(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7532 DWORD cbBuf
, LPDWORD pcbNeeded
, BOOL unicode
)
7535 DWORD needed
= 0, size
;
7539 TRACE("%p %d %d %p %d %p\n", hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
);
7541 EnterCriticalSection(&printer_handles_cs
);
7542 job
= get_job(hPrinter
, JobId
);
7549 size
= sizeof(JOB_INFO_1W
);
7554 memset(pJob
, 0, size
);
7558 ret
= get_job_info_1(job
, (JOB_INFO_1W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7563 size
= sizeof(JOB_INFO_2W
);
7568 memset(pJob
, 0, size
);
7572 ret
= get_job_info_2(job
, (JOB_INFO_2W
*)pJob
, ptr
, cbBuf
, &needed
, unicode
);
7577 size
= sizeof(JOB_INFO_3
);
7581 memset(pJob
, 0, size
);
7590 SetLastError(ERROR_INVALID_LEVEL
);
7594 *pcbNeeded
= needed
;
7596 LeaveCriticalSection(&printer_handles_cs
);
7600 /*****************************************************************************
7601 * GetJobA [WINSPOOL.@]
7604 BOOL WINAPI
GetJobA(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7605 DWORD cbBuf
, LPDWORD pcbNeeded
)
7607 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, FALSE
);
7610 /*****************************************************************************
7611 * GetJobW [WINSPOOL.@]
7614 BOOL WINAPI
GetJobW(HANDLE hPrinter
, DWORD JobId
, DWORD Level
, LPBYTE pJob
,
7615 DWORD cbBuf
, LPDWORD pcbNeeded
)
7617 return get_job_info(hPrinter
, JobId
, Level
, pJob
, cbBuf
, pcbNeeded
, TRUE
);
7620 /*****************************************************************************
7623 static BOOL
schedule_lpr(LPCWSTR printer_name
, LPCWSTR filename
)
7625 char *unixname
, *queue
, *cmd
;
7626 char fmt
[] = "lpr -P%s %s";
7629 if(!(unixname
= wine_get_unix_file_name(filename
)))
7632 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7633 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7634 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7636 cmd
= HeapAlloc(GetProcessHeap(), 0, strlen(unixname
) + len
+ sizeof(fmt
) - 5);
7637 sprintf(cmd
, fmt
, queue
, unixname
);
7639 TRACE("printing with: %s\n", cmd
);
7642 HeapFree(GetProcessHeap(), 0, cmd
);
7643 HeapFree(GetProcessHeap(), 0, queue
);
7644 HeapFree(GetProcessHeap(), 0, unixname
);
7648 /*****************************************************************************
7651 static BOOL
schedule_cups(LPCWSTR printer_name
, LPCWSTR filename
, LPCWSTR document_title
)
7653 #ifdef SONAME_LIBCUPS
7656 char *unixname
, *queue
, *doc_titleA
;
7660 if(!(unixname
= wine_get_unix_file_name(filename
)))
7663 len
= WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, NULL
, 0, NULL
, NULL
);
7664 queue
= HeapAlloc(GetProcessHeap(), 0, len
);
7665 WideCharToMultiByte(CP_ACP
, 0, printer_name
, -1, queue
, len
, NULL
, NULL
);
7667 len
= WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, NULL
, 0, NULL
, NULL
);
7668 doc_titleA
= HeapAlloc(GetProcessHeap(), 0, len
);
7669 WideCharToMultiByte(CP_ACP
, 0, document_title
, -1, doc_titleA
, len
, NULL
, NULL
);
7671 TRACE("printing via cups\n");
7672 ret
= pcupsPrintFile(queue
, unixname
, doc_titleA
, 0, NULL
);
7673 HeapFree(GetProcessHeap(), 0, doc_titleA
);
7674 HeapFree(GetProcessHeap(), 0, queue
);
7675 HeapFree(GetProcessHeap(), 0, unixname
);
7681 return schedule_lpr(printer_name
, filename
);
7685 INT_PTR CALLBACK
file_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
7692 SetWindowLongPtrW(hwnd
, DWLP_USER
, lparam
);
7696 if(HIWORD(wparam
) == BN_CLICKED
)
7698 if(LOWORD(wparam
) == IDOK
)
7701 DWORD len
= SendDlgItemMessageW(hwnd
, EDITBOX
, WM_GETTEXTLENGTH
, 0, 0);
7704 filename
= HeapAlloc(GetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
));
7705 GetDlgItemTextW(hwnd
, EDITBOX
, filename
, len
+ 1);
7707 if(GetFileAttributesW(filename
) != INVALID_FILE_ATTRIBUTES
)
7709 WCHAR caption
[200], message
[200];
7712 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7713 LoadStringW(WINSPOOL_hInstance
, IDS_FILE_EXISTS
, message
, sizeof(message
) / sizeof(WCHAR
));
7714 mb_ret
= MessageBoxW(hwnd
, message
, caption
, MB_OKCANCEL
| MB_ICONEXCLAMATION
);
7715 if(mb_ret
== IDCANCEL
)
7717 HeapFree(GetProcessHeap(), 0, filename
);
7721 hf
= CreateFileW(filename
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
7722 if(hf
== INVALID_HANDLE_VALUE
)
7724 WCHAR caption
[200], message
[200];
7726 LoadStringW(WINSPOOL_hInstance
, IDS_CAPTION
, caption
, sizeof(caption
) / sizeof(WCHAR
));
7727 LoadStringW(WINSPOOL_hInstance
, IDS_CANNOT_OPEN
, message
, sizeof(message
) / sizeof(WCHAR
));
7728 MessageBoxW(hwnd
, message
, caption
, MB_OK
| MB_ICONEXCLAMATION
);
7729 HeapFree(GetProcessHeap(), 0, filename
);
7733 DeleteFileW(filename
);
7734 output
= (LPWSTR
*)GetWindowLongPtrW(hwnd
, DWLP_USER
);
7736 EndDialog(hwnd
, IDOK
);
7739 if(LOWORD(wparam
) == IDCANCEL
)
7741 EndDialog(hwnd
, IDCANCEL
);
7750 /*****************************************************************************
7753 static BOOL
get_filename(LPWSTR
*filename
)
7755 return DialogBoxParamW(WINSPOOL_hInstance
, MAKEINTRESOURCEW(FILENAME_DIALOG
), GetForegroundWindow(),
7756 file_dlg_proc
, (LPARAM
)filename
) == IDOK
;
7759 /*****************************************************************************
7762 static BOOL
schedule_file(LPCWSTR filename
)
7764 LPWSTR output
= NULL
;
7766 if(get_filename(&output
))
7768 TRACE("copy to %s\n", debugstr_w(output
));
7769 CopyFileW(filename
, output
, FALSE
);
7770 HeapFree(GetProcessHeap(), 0, output
);
7776 /*****************************************************************************
7779 static BOOL
schedule_pipe(LPCWSTR cmd
, LPCWSTR filename
)
7782 char *unixname
, *cmdA
;
7784 int fds
[2] = {-1, -1}, file_fd
= -1, no_read
;
7788 if(!(unixname
= wine_get_unix_file_name(filename
)))
7791 len
= WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, NULL
, 0, NULL
, NULL
);
7792 cmdA
= HeapAlloc(GetProcessHeap(), 0, len
);
7793 WideCharToMultiByte(CP_ACP
, 0, cmd
, -1, cmdA
, len
, NULL
, NULL
);
7795 TRACE("printing with: %s\n", cmdA
);
7797 if((file_fd
= open(unixname
, O_RDONLY
)) == -1)
7802 ERR("pipe() failed!\n");
7812 /* reset signals that we previously set to SIG_IGN */
7813 signal(SIGPIPE
, SIG_DFL
);
7814 signal(SIGCHLD
, SIG_DFL
);
7816 execl("/bin/sh", "/bin/sh", "-c", cmdA
, (char*)0);
7820 while((no_read
= read(file_fd
, buf
, sizeof(buf
))) > 0)
7821 write(fds
[1], buf
, no_read
);
7826 if(file_fd
!= -1) close(file_fd
);
7827 if(fds
[0] != -1) close(fds
[0]);
7828 if(fds
[1] != -1) close(fds
[1]);
7830 HeapFree(GetProcessHeap(), 0, cmdA
);
7831 HeapFree(GetProcessHeap(), 0, unixname
);
7838 /*****************************************************************************
7841 static BOOL
schedule_unixfile(LPCWSTR output
, LPCWSTR filename
)
7843 int in_fd
, out_fd
, no_read
;
7846 char *unixname
, *outputA
;
7849 if(!(unixname
= wine_get_unix_file_name(filename
)))
7852 len
= WideCharToMultiByte(CP_ACP
, 0, output
, -1, NULL
, 0, NULL
, NULL
);
7853 outputA
= HeapAlloc(GetProcessHeap(), 0, len
);
7854 WideCharToMultiByte(CP_ACP
, 0, output
, -1, outputA
, len
, NULL
, NULL
);
7856 out_fd
= open(outputA
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
7857 in_fd
= open(unixname
, O_RDONLY
);
7858 if(out_fd
== -1 || in_fd
== -1)
7861 while((no_read
= read(in_fd
, buf
, sizeof(buf
))) > 0)
7862 write(out_fd
, buf
, no_read
);
7866 if(in_fd
!= -1) close(in_fd
);
7867 if(out_fd
!= -1) close(out_fd
);
7868 HeapFree(GetProcessHeap(), 0, outputA
);
7869 HeapFree(GetProcessHeap(), 0, unixname
);
7873 /*****************************************************************************
7874 * ScheduleJob [WINSPOOL.@]
7877 BOOL WINAPI
ScheduleJob( HANDLE hPrinter
, DWORD dwJobID
)
7879 opened_printer_t
*printer
;
7881 struct list
*cursor
, *cursor2
;
7883 TRACE("(%p, %x)\n", hPrinter
, dwJobID
);
7884 EnterCriticalSection(&printer_handles_cs
);
7885 printer
= get_opened_printer(hPrinter
);
7889 LIST_FOR_EACH_SAFE(cursor
, cursor2
, &printer
->queue
->jobs
)
7891 job_t
*job
= LIST_ENTRY(cursor
, job_t
, entry
);
7894 if(job
->job_id
!= dwJobID
) continue;
7896 hf
= CreateFileW(job
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
7897 if(hf
!= INVALID_HANDLE_VALUE
)
7899 PRINTER_INFO_5W
*pi5
;
7903 static const WCHAR spooler_key
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\',
7904 'P','r','i','n','t','i','n','g','\\','S','p','o','o','l','e','r',0};
7906 GetPrinterW(hPrinter
, 5, NULL
, 0, &needed
);
7907 pi5
= HeapAlloc(GetProcessHeap(), 0, needed
);
7908 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, needed
, &needed
);
7909 TRACE("need to schedule job %d filename %s to port %s\n", job
->job_id
, debugstr_w(job
->filename
),
7910 debugstr_w(pi5
->pPortName
));
7914 /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */
7915 if(RegOpenKeyW(HKEY_CURRENT_USER
, spooler_key
, &hkey
) == ERROR_SUCCESS
)
7917 DWORD type
, count
= sizeof(output
);
7918 RegQueryValueExW(hkey
, pi5
->pPortName
, NULL
, &type
, (LPBYTE
)output
, &count
);
7921 if(output
[0] == '|')
7923 schedule_pipe(output
+ 1, job
->filename
);
7927 schedule_unixfile(output
, job
->filename
);
7929 else if(!strncmpW(pi5
->pPortName
, LPR_Port
, strlenW(LPR_Port
)))
7931 schedule_lpr(pi5
->pPortName
+ strlenW(LPR_Port
), job
->filename
);
7933 else if(!strncmpW(pi5
->pPortName
, CUPS_Port
, strlenW(CUPS_Port
)))
7935 schedule_cups(pi5
->pPortName
+ strlenW(CUPS_Port
), job
->filename
, job
->document_title
);
7937 else if(!strncmpW(pi5
->pPortName
, FILE_Port
, strlenW(FILE_Port
)))
7939 schedule_file(job
->filename
);
7943 FIXME("can't schedule to port %s\n", debugstr_w(pi5
->pPortName
));
7945 HeapFree(GetProcessHeap(), 0, pi5
);
7947 DeleteFileW(job
->filename
);
7949 list_remove(cursor
);
7950 HeapFree(GetProcessHeap(), 0, job
->document_title
);
7951 HeapFree(GetProcessHeap(), 0, job
->filename
);
7952 HeapFree(GetProcessHeap(), 0, job
);
7957 LeaveCriticalSection(&printer_handles_cs
);
7961 /*****************************************************************************
7962 * StartDocDlgA [WINSPOOL.@]
7964 LPSTR WINAPI
StartDocDlgA( HANDLE hPrinter
, DOCINFOA
*doc
)
7966 UNICODE_STRING usBuffer
;
7969 LPWSTR docnameW
= NULL
, outputW
= NULL
, datatypeW
= NULL
;
7972 docW
.cbSize
= sizeof(docW
);
7973 if (doc
->lpszDocName
)
7975 docnameW
= asciitounicode(&usBuffer
, doc
->lpszDocName
);
7976 if (!(docW
.lpszDocName
= docnameW
)) return NULL
;
7978 if (doc
->lpszOutput
)
7980 outputW
= asciitounicode(&usBuffer
, doc
->lpszOutput
);
7981 if (!(docW
.lpszOutput
= outputW
)) return NULL
;
7983 if (doc
->lpszDatatype
)
7985 datatypeW
= asciitounicode(&usBuffer
, doc
->lpszDatatype
);
7986 if (!(docW
.lpszDatatype
= datatypeW
)) return NULL
;
7988 docW
.fwType
= doc
->fwType
;
7990 retW
= StartDocDlgW(hPrinter
, &docW
);
7994 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, retW
, -1, NULL
, 0, NULL
, NULL
);
7995 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
7996 WideCharToMultiByte(CP_ACP
, 0, retW
, -1, ret
, len
, NULL
, NULL
);
7997 HeapFree(GetProcessHeap(), 0, retW
);
8000 HeapFree(GetProcessHeap(), 0, datatypeW
);
8001 HeapFree(GetProcessHeap(), 0, outputW
);
8002 HeapFree(GetProcessHeap(), 0, docnameW
);
8007 /*****************************************************************************
8008 * StartDocDlgW [WINSPOOL.@]
8010 * Undocumented: Apparently used by gdi32:StartDocW() to popup the file dialog
8011 * when lpszOutput is "FILE:" or if lpszOutput is NULL and the default printer
8012 * port is "FILE:". Also returns the full path if passed a relative path.
8014 * The caller should free the returned string from the process heap.
8016 LPWSTR WINAPI
StartDocDlgW( HANDLE hPrinter
, DOCINFOW
*doc
)
8021 if(doc
->lpszOutput
== NULL
) /* Check whether default port is FILE: */
8023 PRINTER_INFO_5W
*pi5
;
8024 GetPrinterW(hPrinter
, 5, NULL
, 0, &len
);
8025 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
8027 pi5
= HeapAlloc(GetProcessHeap(), 0, len
);
8028 GetPrinterW(hPrinter
, 5, (LPBYTE
)pi5
, len
, &len
);
8029 if(!pi5
->pPortName
|| strcmpW(pi5
->pPortName
, FILE_Port
))
8031 HeapFree(GetProcessHeap(), 0, pi5
);
8034 HeapFree(GetProcessHeap(), 0, pi5
);
8037 if(doc
->lpszOutput
== NULL
|| !strcmpW(doc
->lpszOutput
, FILE_Port
))
8041 if (get_filename(&name
))
8043 if(!(len
= GetFullPathNameW(name
, 0, NULL
, NULL
)))
8045 HeapFree(GetProcessHeap(), 0, name
);
8048 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8049 GetFullPathNameW(name
, len
, ret
, NULL
);
8050 HeapFree(GetProcessHeap(), 0, name
);
8055 if(!(len
= GetFullPathNameW(doc
->lpszOutput
, 0, NULL
, NULL
)))
8058 ret
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
8059 GetFullPathNameW(doc
->lpszOutput
, len
, ret
, NULL
);
8061 attr
= GetFileAttributesW(ret
);
8062 if(attr
!= INVALID_FILE_ATTRIBUTES
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
))
8064 HeapFree(GetProcessHeap(), 0, ret
);