2 * Implementation of the Local Printprovider
4 * Copyright 2006-2009 Detlef Riekenberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define NONAMELESSUNION
32 #include "ddk/winddiui.h"
33 #include "ddk/winsplp.h"
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "localspl_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl
);
42 /* ############################### */
44 static CRITICAL_SECTION monitor_handles_cs
;
45 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
47 0, 0, &monitor_handles_cs
,
48 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
49 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
51 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
53 /* ############################### */
56 WCHAR src
[MAX_PATH
+MAX_PATH
];
57 WCHAR dst
[MAX_PATH
+MAX_PATH
];
79 LPCWSTR versionregpath
;
80 LPCWSTR versionsubdir
;
90 /* ############################### */
92 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
93 static monitor_t
* pm_localport
;
95 static const PRINTPROVIDOR
* pprovider
= NULL
;
97 static const WCHAR backslashW
[] = {'\\',0};
98 static const WCHAR bs_ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
99 static const WCHAR configuration_fileW
[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
100 static const WCHAR datatypeW
[] = {'D','a','t','a','t','y','p','e',0};
101 static const WCHAR data_fileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
102 static const WCHAR default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
103 static const WCHAR dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
104 static const WCHAR descriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
105 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
106 static const WCHAR emptyW
[] = {0};
107 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
108 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
109 'c','o','n','t','r','o','l','\\',
110 'P','r','i','n','t','\\',
111 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
112 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
113 static const WCHAR fmt_printprocessorsW
[] = { 'S','y','s','t','e','m','\\',
114 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
115 'C','o','n','t','r','o','l','\\',
116 'P','r','i','n','t','\\',
117 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
118 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
119 static const WCHAR hardwareidW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
120 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
121 static const WCHAR ia64_envnameW
[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
122 static const WCHAR ia64_subdirW
[] = {'i','a','6','4',0};
123 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
124 static const WCHAR locationW
[] = {'L','o','c','a','t','i','o','n',0};
125 static const WCHAR manufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
126 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
127 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
128 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129 'C','o','n','t','r','o','l','\\',
130 'P','r','i','n','t','\\',
131 'M','o','n','i','t','o','r','s','\\',0};
132 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
133 static const WCHAR nameW
[] = {'N','a','m','e',0};
134 static const WCHAR oem_urlW
[] = {'O','E','M',' ','U','r','l',0};
135 static const WCHAR parametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
136 static const WCHAR portW
[] = {'P','o','r','t',0};
137 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
138 static const WCHAR printersW
[] = {'S','y','s','t','e','m','\\',
139 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
140 'C','o','n','t','r','o','l','\\',
141 'P','r','i','n','t','\\',
142 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
144 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
145 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
146 static const WCHAR version0_subdirW
[] = {'\\','0',0};
147 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
148 static const WCHAR version3_subdirW
[] = {'\\','3',0};
149 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
150 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
151 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
152 static const WCHAR winnt_cv_portsW
[] = {'S','o','f','t','w','a','r','e','\\',
153 'M','i','c','r','o','s','o','f','t','\\',
154 'W','i','n','d','o','w','s',' ','N','T','\\',
155 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
156 'P','o','r','t','s',0};
157 static const WCHAR winprintW
[] = {'w','i','n','p','r','i','n','t',0};
158 static const WCHAR x64_envnameW
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
159 static const WCHAR x64_subdirW
[] = {'x','6','4',0};
160 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
161 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
162 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
163 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
166 static const printenv_t env_ia64
= {ia64_envnameW
, ia64_subdirW
, 3,
167 version3_regpathW
, version3_subdirW
};
169 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
170 version3_regpathW
, version3_subdirW
};
172 static const printenv_t env_x64
= {x64_envnameW
, x64_subdirW
, 3,
173 version3_regpathW
, version3_subdirW
};
175 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
176 version0_regpathW
, version0_subdirW
};
178 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_win40
};
181 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
182 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
183 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
184 0, sizeof(DRIVER_INFO_8W
)};
187 /******************************************************************
190 * create a copy of a unicode-string
193 static LPWSTR
strdupW(LPCWSTR p
)
199 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
200 ret
= heap_alloc(len
);
201 if (ret
) memcpy(ret
, p
, len
);
205 /******************************************************************
206 * apd_copyfile [internal]
208 * Copy a file from the driverdirectory to the versioned directory
215 static BOOL
apd_copyfile(LPWSTR filename
, apd_data_t
*apd
)
221 apd
->src
[apd
->srclen
] = '\0';
222 apd
->dst
[apd
->dstlen
] = '\0';
224 if (!filename
|| !filename
[0]) {
225 /* nothing to copy */
229 ptr
= strrchrW(filename
, '\\');
238 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
) {
239 /* we have an absolute Path */
245 lstrcatW(srcname
, ptr
);
247 lstrcatW(apd
->dst
, ptr
);
249 TRACE("%s => %s\n", debugstr_w(filename
), debugstr_w(apd
->dst
));
251 /* FIXME: handle APD_COPY_NEW_FILES */
252 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
253 TRACE("got %u with %u\n", res
, GetLastError());
255 return (apd
->lazy
) ? TRUE
: res
;
258 /******************************************************************
259 * copy_servername_from_name (internal)
261 * for an external server, the serverpart from the name is copied.
264 * the length (in WCHAR) of the serverpart (0 for the local computer)
265 * (-length), when the name is to long
268 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
272 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
276 if (target
) *target
= '\0';
278 if (name
== NULL
) return 0;
279 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
282 /* skip over both backslash, find separator '\' */
283 ptr
= strchrW(server
, '\\');
284 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
286 /* servername is empty */
287 if (serverlen
== 0) return 0;
289 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
291 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
294 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
295 target
[serverlen
] = '\0';
298 len
= sizeof(buffer
) / sizeof(buffer
[0]);
299 if (GetComputerNameW(buffer
, &len
)) {
300 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
301 /* The requested Servername is our computername */
308 /******************************************************************
309 * get_basename_from_name (internal)
311 * skip over the serverpart from the full name
314 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
316 if (name
== NULL
) return NULL
;
317 if ((name
[0] == '\\') && (name
[1] == '\\')) {
318 /* skip over the servername and search for the following '\' */
319 name
= strchrW(&name
[2], '\\');
320 if ((name
) && (name
[1])) {
321 /* found a separator ('\') followed by a name:
322 skip over the separator and return the rest */
327 /* no basename present (we found only a servername) */
334 /******************************************************************
335 * monitor_unload [internal]
337 * release a printmonitor and unload it from memory, when needed
340 static void monitor_unload(monitor_t
* pm
)
342 if (pm
== NULL
) return;
343 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
345 EnterCriticalSection(&monitor_handles_cs
);
347 if (pm
->refcount
) pm
->refcount
--;
349 if (pm
->refcount
== 0) {
350 list_remove(&pm
->entry
);
351 FreeLibrary(pm
->hdll
);
353 heap_free(pm
->dllname
);
356 LeaveCriticalSection(&monitor_handles_cs
);
359 /******************************************************************
360 * monitor_unloadall [internal]
362 * release all registered printmonitors and unload them from memory, when needed
366 static void monitor_unloadall(void)
371 EnterCriticalSection(&monitor_handles_cs
);
372 /* iterate through the list, with safety against removal */
373 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
375 /* skip monitorui dlls */
376 if (pm
->monitor
) monitor_unload(pm
);
378 LeaveCriticalSection(&monitor_handles_cs
);
381 /******************************************************************
382 * monitor_load [internal]
384 * load a printmonitor, get the dllname from the registry, when needed
385 * initialize the monitor and dump found function-pointers
387 * On failure, SetLastError() is called and NULL is returned
390 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
392 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
393 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
394 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
395 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
396 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
398 monitor_t
* pm
= NULL
;
400 LPWSTR regroot
= NULL
;
401 LPWSTR driver
= dllname
;
403 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
404 /* Is the Monitor already loaded? */
405 EnterCriticalSection(&monitor_handles_cs
);
408 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
410 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
418 pm
= heap_alloc_zero(sizeof(monitor_t
));
419 if (pm
== NULL
) goto cleanup
;
420 list_add_tail(&monitor_handles
, &pm
->entry
);
424 if (pm
->name
== NULL
) {
425 /* Load the monitor */
426 LPMONITOREX pmonitorEx
;
430 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
431 regroot
= heap_alloc(len
* sizeof(WCHAR
));
435 lstrcpyW(regroot
, monitorsW
);
436 lstrcatW(regroot
, name
);
437 /* Get the Driver from the Registry */
438 if (driver
== NULL
) {
441 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
442 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
443 &namesize
) == ERROR_SUCCESS
) {
444 driver
= heap_alloc(namesize
);
445 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
452 pm
->name
= strdupW(name
);
453 pm
->dllname
= strdupW(driver
);
455 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
457 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
462 pm
->hdll
= LoadLibraryW(driver
);
463 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
465 if (pm
->hdll
== NULL
) {
467 SetLastError(ERROR_MOD_NOT_FOUND
);
472 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
473 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
474 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
475 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
476 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
479 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
480 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
481 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
482 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
483 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
485 if (pInitializePrintMonitorUI
!= NULL
) {
486 pm
->monitorUI
= pInitializePrintMonitorUI();
487 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
489 TRACE("0x%08x: dwMonitorSize (%d)\n",
490 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
495 if (pInitializePrintMonitor
&& regroot
) {
496 pmonitorEx
= pInitializePrintMonitor(regroot
);
497 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
498 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
501 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
502 pm
->monitor
= &(pmonitorEx
->Monitor
);
507 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
511 if (!pm
->monitor
&& regroot
) {
512 if (pInitializePrintMonitor2
!= NULL
) {
513 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
515 if (pInitializeMonitorEx
!= NULL
) {
516 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
518 if (pInitializeMonitor
!= NULL
) {
519 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
522 if (!pm
->monitor
&& !pm
->monitorUI
) {
524 SetLastError(ERROR_PROC_NOT_FOUND
);
529 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
533 LeaveCriticalSection(&monitor_handles_cs
);
534 if (driver
!= dllname
) heap_free(driver
);
536 TRACE("=> %p\n", pm
);
540 /******************************************************************
541 * monitor_loadall [internal]
543 * Load all registered monitors
546 static DWORD
monitor_loadall(void)
549 DWORD registered
= 0;
552 WCHAR buffer
[MAX_PATH
];
555 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
556 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
557 NULL
, NULL
, NULL
, NULL
, NULL
);
559 TRACE("%d monitors registered\n", registered
);
561 while (id
< registered
) {
563 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
564 pm
= monitor_load(buffer
, NULL
);
568 RegCloseKey(hmonitors
);
570 TRACE("%d monitors loaded\n", loaded
);
574 /******************************************************************
575 * monitor_loadui [internal]
577 * load the userinterface-dll for a given portmonitor
579 * On failure, NULL is returned
581 static monitor_t
* monitor_loadui(monitor_t
* pm
)
583 monitor_t
* pui
= NULL
;
584 WCHAR buffer
[MAX_PATH
];
589 if (pm
== NULL
) return NULL
;
590 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
592 /* Try the Portmonitor first; works for many monitors */
594 EnterCriticalSection(&monitor_handles_cs
);
596 LeaveCriticalSection(&monitor_handles_cs
);
600 /* query the userinterface-dllname from the Portmonitor */
601 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
602 /* building (",XcvMonitor %s",pm->name) not needed yet */
603 res
= pm
->monitor
->pfnXcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
604 TRACE("got %u with %p\n", res
, hXcv
);
606 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
607 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
608 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
609 pm
->monitor
->pfnXcvClosePort(hXcv
);
615 /******************************************************************
616 * monitor_load_by_port [internal]
618 * load a printmonitor for a given port
620 * On failure, NULL is returned
623 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
628 monitor_t
* pm
= NULL
;
629 DWORD registered
= 0;
633 TRACE("(%s)\n", debugstr_w(portname
));
635 /* Try the Local Monitor first */
636 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
637 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
638 /* found the portname */
640 return monitor_load(localportW
, NULL
);
645 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
646 buffer
= heap_alloc(len
* sizeof(WCHAR
));
647 if (buffer
== NULL
) return NULL
;
649 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
650 EnterCriticalSection(&monitor_handles_cs
);
651 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
653 while ((pm
== NULL
) && (id
< registered
)) {
655 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
656 TRACE("testing %s\n", debugstr_w(buffer
));
657 len
= lstrlenW(buffer
);
658 lstrcatW(buffer
, bs_ports_bsW
);
659 lstrcatW(buffer
, portname
);
660 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
662 buffer
[len
] = '\0'; /* use only the Monitor-Name */
663 pm
= monitor_load(buffer
, NULL
);
667 LeaveCriticalSection(&monitor_handles_cs
);
674 /******************************************************************
675 * Return the number of bytes for an multi_sz string.
676 * The result includes all \0s
677 * (specifically the extra \0, that is needed as multi_sz terminator).
679 static int multi_sz_lenW(const WCHAR
*str
)
681 const WCHAR
*ptr
= str
;
685 ptr
+= lstrlenW(ptr
) + 1;
688 return (ptr
- str
+ 1) * sizeof(WCHAR
);
691 /******************************************************************
692 * validate_envW [internal]
694 * validate the user-supplied printing-environment
697 * env [I] PTR to Environment-String or NULL
700 * Success: PTR to printenv_t
701 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
704 * An empty string is handled the same way as NULL.
708 static const printenv_t
* validate_envW(LPCWSTR env
)
710 const printenv_t
*result
= NULL
;
713 TRACE("(%s)\n", debugstr_w(env
));
716 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
718 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
720 result
= all_printenv
[i
];
724 if (result
== NULL
) {
725 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
726 SetLastError(ERROR_INVALID_ENVIRONMENT
);
728 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
732 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
735 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
739 /*****************************************************************************
740 * enumerate the local monitors (INTERNAL)
742 * returns the needed size (in bytes) for pMonitors
743 * and *lpreturned is set to number of entries returned in pMonitors
745 * Language-Monitors are also installed in the same Registry-Location but
746 * they are filtered in Windows (not returned by EnumMonitors).
747 * We do no filtering to simplify our Code.
750 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
755 LPMONITOR_INFO_2W mi
;
756 WCHAR buffer
[MAX_PATH
];
757 WCHAR dllname
[MAX_PATH
];
765 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
767 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
768 len
= entrysize
* numentries
;
769 ptr
= (LPWSTR
) &pMonitors
[len
];
772 len
= sizeof(buffer
)/sizeof(buffer
[0]);
775 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
776 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
777 /* Scan all Monitor-Registry-Keys */
778 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
779 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
780 dllsize
= sizeof(dllname
);
783 /* The Monitor must have a Driver-DLL */
784 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
785 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
786 /* We found a valid DLL for this Monitor. */
787 TRACE("using Driver: %s\n", debugstr_w(dllname
));
792 /* Windows returns only Port-Monitors here, but to simplify our code,
793 we do no filtering for Language-Monitors */
797 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
799 /* we install and return only monitors for "Windows NT x86" */
800 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
804 /* required size is calculated. Now fill the user-buffer */
805 if (pMonitors
&& (cbBuf
>= needed
)){
806 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
807 pMonitors
+= entrysize
;
809 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
811 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
812 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
814 mi
->pEnvironment
= ptr
;
815 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
816 ptr
+= (lstrlenW(x86_envnameW
)+1);
819 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
820 ptr
+= (dllsize
/ sizeof(WCHAR
));
825 len
= sizeof(buffer
)/sizeof(buffer
[0]);
830 *lpreturned
= numentries
;
831 TRACE("need %d byte for %d entries\n", needed
, numentries
);
835 /*****************************************************************************
836 * enumerate the local print processors (INTERNAL)
838 * returns the needed size (in bytes) for pPPInfo
839 * and *lpreturned is set to number of entries returned in pPPInfo
842 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
847 PPRINTPROCESSOR_INFO_1W ppi
;
848 WCHAR buffer
[MAX_PATH
];
849 WCHAR dllname
[MAX_PATH
];
856 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
857 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
858 ptr
= (LPWSTR
) &pPPInfo
[len
];
861 len
= sizeof(buffer
)/sizeof(buffer
[0]);
864 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
865 /* add "winprint" first */
867 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(winprintW
);
868 if (pPPInfo
&& (cbBuf
>= needed
)){
869 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
870 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
872 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
874 lstrcpyW(ptr
, winprintW
); /* Name of the Print Processor */
875 ptr
+= sizeof(winprintW
) / sizeof(WCHAR
);
878 /* Scan all Printprocessor Keys */
879 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
880 (lstrcmpiW(buffer
, winprintW
) != 0)) {
881 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
882 dllsize
= sizeof(dllname
);
885 /* The Print Processor must have a Driver-DLL */
886 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
887 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
888 /* We found a valid DLL for this Print Processor */
889 TRACE("using Driver: %s\n", debugstr_w(dllname
));
896 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
897 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
899 /* required size is calculated. Now fill the user-buffer */
900 if (pPPInfo
&& (cbBuf
>= needed
)){
901 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
902 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
904 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
906 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
907 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
911 len
= sizeof(buffer
)/sizeof(buffer
[0]);
916 *lpreturned
= numentries
;
917 TRACE("need %d byte for %d entries\n", needed
, numentries
);
921 /******************************************************************
922 * enumerate the local Ports from all loaded monitors (internal)
924 * returns the needed size (in bytes) for pPorts
925 * and *lpreturned is set to number of entries returned in pPorts
928 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
932 LPPORT_INFO_2W cache
;
934 LPBYTE pi_buffer
= NULL
;
935 DWORD pi_allocated
= 0;
946 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
947 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
949 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
950 needed
= entrysize
* numentries
;
951 ptr
= (LPWSTR
) &pPorts
[needed
];
956 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
958 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
961 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
962 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
963 /* Do not use heap_realloc (we do not need the old data in the buffer) */
964 heap_free(pi_buffer
);
965 pi_buffer
= heap_alloc(pi_needed
);
966 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
967 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
969 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
970 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
972 numentries
+= pi_returned
;
975 /* fill the output-buffer (pPorts), if we have one */
976 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
978 while (pi_returned
> pi_index
) {
979 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
980 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
981 out
->pPortName
= ptr
;
982 lstrcpyW(ptr
, cache
->pPortName
);
983 ptr
+= (lstrlenW(ptr
)+1);
985 out
->pMonitorName
= ptr
;
986 lstrcpyW(ptr
, cache
->pMonitorName
);
987 ptr
+= (lstrlenW(ptr
)+1);
989 out
->pDescription
= ptr
;
990 lstrcpyW(ptr
, cache
->pDescription
);
991 ptr
+= (lstrlenW(ptr
)+1);
992 out
->fPortType
= cache
->fPortType
;
993 out
->Reserved
= cache
->Reserved
;
1001 /* the temporary portinfo-buffer is no longer needed */
1002 heap_free(pi_buffer
);
1004 *lpreturned
= numentries
;
1005 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1010 /*****************************************************************************
1011 * open_driver_reg [internal]
1013 * opens the registry for the printer drivers depending on the given input
1014 * variable pEnvironment
1017 * Success: the opened hkey
1020 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1024 const printenv_t
* env
;
1026 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1028 env
= validate_envW(pEnvironment
);
1029 if (!env
) return NULL
;
1031 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
1032 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
1035 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1036 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1037 HeapFree(GetProcessHeap(), 0, buffer
);
1042 /*****************************************************************************
1043 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1045 * Return the PATH for the Printer-Drivers
1048 * pName [I] Servername (NT only) or NULL (local Computer)
1049 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1050 * Level [I] Structure-Level (must be 1)
1051 * pDriverDirectory [O] PTR to Buffer that receives the Result
1052 * cbBuf [I] Size of Buffer at pDriverDirectory
1053 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1054 * required for pDriverDirectory
1057 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1058 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1059 * if cbBuf is too small
1061 * Native Values returned in pDriverDirectory on Success:
1062 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1063 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1064 *| win9x(Windows 4.0): "%winsysdir%"
1066 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1069 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1070 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1073 const printenv_t
* env
;
1075 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1076 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1078 if (pName
!= NULL
&& pName
[0]) {
1079 FIXME("server %s not supported\n", debugstr_w(pName
));
1080 SetLastError(ERROR_INVALID_PARAMETER
);
1084 env
= validate_envW(pEnvironment
);
1085 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1088 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1089 needed
= GetSystemDirectoryW(NULL
, 0);
1090 /* add the Size for the Subdirectories */
1091 needed
+= lstrlenW(spooldriversW
);
1092 needed
+= lstrlenW(env
->subdir
);
1093 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1095 *pcbNeeded
= needed
;
1097 if (needed
> cbBuf
) {
1098 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1102 if (pDriverDirectory
== NULL
) {
1103 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1104 SetLastError(ERROR_INVALID_USER_BUFFER
);
1108 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
1109 /* add the Subdirectories */
1110 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
1111 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
1113 TRACE("=> %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
1117 /******************************************************************
1118 * driver_load [internal]
1120 * load a driver user interface dll
1122 * On failure, NULL is returned
1126 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1128 WCHAR fullname
[MAX_PATH
];
1132 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1134 /* build the driverdir */
1135 len
= sizeof(fullname
) -
1136 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1138 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1139 (LPBYTE
) fullname
, len
, &len
)) {
1140 /* Should never Fail */
1141 SetLastError(ERROR_BUFFER_OVERFLOW
);
1145 lstrcatW(fullname
, env
->versionsubdir
);
1146 lstrcatW(fullname
, backslashW
);
1147 lstrcatW(fullname
, dllname
);
1149 hui
= LoadLibraryW(fullname
);
1150 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1155 /******************************************************************
1157 * free the data pointer of an opened printer
1159 static VOID
printer_free(printer_t
* printer
)
1162 printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1164 monitor_unload(printer
->pm
);
1166 heap_free(printer
->printername
);
1167 heap_free(printer
->name
);
1171 /******************************************************************
1172 * printer_alloc_handle
1173 * alloc a printer handle and remember the data pointer in the printer handle table
1176 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1178 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1179 printer_t
*printer
= NULL
;
1180 LPCWSTR printername
;
1185 if (copy_servername_from_name(name
, servername
)) {
1186 FIXME("server %s not supported\n", debugstr_w(servername
));
1187 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1191 printername
= get_basename_from_name(name
);
1192 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1194 /* an empty printername is invalid */
1195 if (printername
&& (!printername
[0])) {
1196 SetLastError(ERROR_INVALID_PARAMETER
);
1200 printer
= heap_alloc_zero(sizeof(printer_t
));
1201 if (!printer
) goto end
;
1203 /* clone the base name. This is NULL for the printserver */
1204 printer
->printername
= strdupW(printername
);
1206 /* clone the full name */
1207 printer
->name
= strdupW(name
);
1208 if (name
&& (!printer
->name
)) {
1209 printer_free(printer
);
1213 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1214 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1215 /* OpenPrinter(",XcvMonitor ", ...) detected */
1216 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1217 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1218 if (printer
->pm
== NULL
) {
1219 printer_free(printer
);
1220 SetLastError(ERROR_UNKNOWN_PORT
);
1227 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1228 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1229 /* OpenPrinter(",XcvPort ", ...) detected */
1230 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1231 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1232 if (printer
->pm
== NULL
) {
1233 printer_free(printer
);
1234 SetLastError(ERROR_UNKNOWN_PORT
);
1242 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1243 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1244 pDefault
? pDefault
->DesiredAccess
: 0,
1247 if (printer
->hXcv
== NULL
) {
1248 printer_free(printer
);
1249 SetLastError(ERROR_INVALID_PARAMETER
);
1256 /* Does the Printer exist? */
1257 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1258 ERR("Can't create Printers key\n");
1259 printer_free(printer
);
1260 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1264 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1265 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1266 RegCloseKey(hkeyPrinters
);
1267 printer_free(printer
);
1268 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1272 RegCloseKey(hkeyPrinter
);
1273 RegCloseKey(hkeyPrinters
);
1278 TRACE("using the local printserver\n");
1283 TRACE("==> %p\n", printer
);
1284 return (HANDLE
)printer
;
1288 /******************************************************************************
1289 * myAddPrinterDriverEx [internal]
1291 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1292 * and a special mode with lazy error checking.
1295 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1297 const printenv_t
*env
;
1300 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1310 /* we need to set all entries in the Registry, independent from the Level of
1311 DRIVER_INFO, that the caller supplied */
1313 ZeroMemory(&di
, sizeof(di
));
1314 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
1315 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1318 /* dump the most used infos */
1319 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1320 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1321 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1322 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1323 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1324 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1325 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1326 /* dump only the first of the additional Files */
1327 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1330 /* check environment */
1331 env
= validate_envW(di
.pEnvironment
);
1332 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1334 /* fill the copy-data / get the driverdir */
1335 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1336 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1337 (LPBYTE
) apd
.src
, len
, &len
)) {
1338 /* Should never Fail */
1341 memcpy(apd
.dst
, apd
.src
, len
);
1342 lstrcatW(apd
.src
, backslashW
);
1343 apd
.srclen
= lstrlenW(apd
.src
);
1344 lstrcatW(apd
.dst
, env
->versionsubdir
);
1345 lstrcatW(apd
.dst
, backslashW
);
1346 apd
.dstlen
= lstrlenW(apd
.dst
);
1347 apd
.copyflags
= dwFileCopyFlags
;
1349 CreateDirectoryW(apd
.src
, NULL
);
1350 CreateDirectoryW(apd
.dst
, NULL
);
1352 hroot
= open_driver_reg(env
->envname
);
1354 ERR("Can't create Drivers key\n");
1358 /* Fill the Registry for the Driver */
1359 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1360 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1361 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1363 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1370 if (disposition
== REG_OPENED_EXISTING_KEY
) {
1371 TRACE("driver %s already installed\n", debugstr_w(di
.pName
));
1373 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
1377 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1378 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1381 RegSetValueExW(hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
) di
.pDriverPath
,
1382 (lstrlenW(di
.pDriverPath
)+1)* sizeof(WCHAR
));
1383 apd_copyfile(di
.pDriverPath
, &apd
);
1385 RegSetValueExW(hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pDataFile
,
1386 (lstrlenW(di
.pDataFile
)+1)* sizeof(WCHAR
));
1387 apd_copyfile(di
.pDataFile
, &apd
);
1389 RegSetValueExW(hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pConfigFile
,
1390 (lstrlenW(di
.pConfigFile
)+1)* sizeof(WCHAR
));
1391 apd_copyfile(di
.pConfigFile
, &apd
);
1393 /* settings for level 3 */
1395 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pHelpFile
,
1396 (lstrlenW(di
.pHelpFile
)+1)* sizeof(WCHAR
));
1398 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1399 apd_copyfile(di
.pHelpFile
, &apd
);
1402 ptr
= di
.pDependentFiles
;
1404 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pDependentFiles
,
1405 multi_sz_lenW(di
.pDependentFiles
));
1407 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1408 while ((ptr
!= NULL
) && (ptr
[0])) {
1409 if (apd_copyfile(ptr
, &apd
)) {
1410 ptr
+= lstrlenW(ptr
) + 1;
1414 WARN("Failed to copy %s\n", debugstr_w(ptr
));
1418 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1419 if (di
.pMonitorName
)
1420 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1421 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1423 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1425 if (di
.pDefaultDataType
)
1426 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1427 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1429 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1431 /* settings for level 4 */
1432 if (di
.pszzPreviousNames
)
1433 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1434 multi_sz_lenW(di
.pszzPreviousNames
));
1436 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1438 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1441 hui
= driver_load(env
, di
.pConfigFile
);
1442 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1443 if (hui
&& pDrvDriverEvent
) {
1445 /* Support for DrvDriverEvent is optional */
1446 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1447 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1448 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1449 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1453 TRACE("=> TRUE with %u\n", GetLastError());
1458 /******************************************************************************
1459 * fpAddMonitor [exported through PRINTPROVIDOR]
1461 * Install a Printmonitor
1464 * pName [I] Servername or NULL (local Computer)
1465 * Level [I] Structure-Level (Must be 2)
1466 * pMonitors [I] PTR to MONITOR_INFO_2
1473 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1476 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1478 monitor_t
* pm
= NULL
;
1479 LPMONITOR_INFO_2W mi2w
;
1485 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1486 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1487 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1488 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1489 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1491 if (copy_servername_from_name(pName
, NULL
)) {
1492 FIXME("server %s not supported\n", debugstr_w(pName
));
1493 SetLastError(ERROR_ACCESS_DENIED
);
1497 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1498 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1499 SetLastError(ERROR_INVALID_PARAMETER
);
1502 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
1503 WARN("Environment %s requested (we support only %s)\n",
1504 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
1505 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1509 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1510 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1511 SetLastError(ERROR_INVALID_PARAMETER
);
1515 /* Load and initialize the monitor. SetLastError() is called on failure */
1516 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
1521 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1522 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1526 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1527 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1528 &disposition
) == ERROR_SUCCESS
) {
1530 /* Some installers set options for the port before calling AddMonitor.
1531 We query the "Driver" entry to verify that the monitor is installed,
1532 before we return an error.
1533 When a user installs two print monitors at the same time with the
1534 same name, a race condition is possible but silently ignored. */
1538 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1539 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1540 &namesize
) == ERROR_SUCCESS
)) {
1541 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1542 /* 9x use ERROR_ALREADY_EXISTS */
1543 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1548 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1549 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1550 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1552 RegCloseKey(hentry
);
1559 /******************************************************************************
1560 * fpAddPort [exported through PRINTPROVIDOR]
1562 * Add a Port for a specific Monitor
1565 * pName [I] Servername or NULL (local Computer)
1566 * hWnd [I] Handle to parent Window for the Dialog-Box
1567 * pMonitorName [I] Name of the Monitor that manage the Port
1574 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1581 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1583 lres
= copy_servername_from_name(pName
, NULL
);
1585 FIXME("server %s not supported\n", debugstr_w(pName
));
1586 SetLastError(ERROR_INVALID_PARAMETER
);
1590 /* an empty Monitorname is Invalid */
1591 if (!pMonitorName
[0]) {
1592 SetLastError(ERROR_NOT_SUPPORTED
);
1596 pm
= monitor_load(pMonitorName
, NULL
);
1597 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1598 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1599 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1603 pui
= monitor_loadui(pm
);
1604 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1605 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1606 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1610 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1611 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1612 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1614 SetLastError(ERROR_NOT_SUPPORTED
);
1617 monitor_unload(pui
);
1621 TRACE("returning %d with %u\n", res
, GetLastError());
1625 /******************************************************************************
1626 * fpAddPortEx [exported through PRINTPROVIDOR]
1628 * Add a Port for a specific Monitor, without presenting a user interface
1631 * pName [I] Servername or NULL (local Computer)
1632 * level [I] Structure-Level (1 or 2) for pBuffer
1633 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1634 * pMonitorName [I] Name of the Monitor that manage the Port
1641 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1648 pi2
= (PORT_INFO_2W
*) pBuffer
;
1650 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1651 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1652 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1653 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1655 lres
= copy_servername_from_name(pName
, NULL
);
1657 FIXME("server %s not supported\n", debugstr_w(pName
));
1658 SetLastError(ERROR_INVALID_PARAMETER
);
1662 if ((level
< 1) || (level
> 2)) {
1663 SetLastError(ERROR_INVALID_LEVEL
);
1667 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1668 SetLastError(ERROR_INVALID_PARAMETER
);
1672 /* load the Monitor */
1673 pm
= monitor_load(pMonitorName
, NULL
);
1674 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1675 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1676 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1680 FIXME("not implemented for %s (monitor %p: %s)\n",
1681 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : NULL
);
1682 SetLastError(ERROR_INVALID_PARAMETER
);
1689 /******************************************************************************
1690 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1692 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1695 * pName [I] Servername or NULL (local Computer)
1696 * level [I] Level for the supplied DRIVER_INFO_*W struct
1697 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1698 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1705 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1709 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1710 lres
= copy_servername_from_name(pName
, NULL
);
1712 FIXME("server %s not supported\n", debugstr_w(pName
));
1713 SetLastError(ERROR_ACCESS_DENIED
);
1717 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1718 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1721 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1724 /******************************************************************************
1725 * fpClosePrinter [exported through PRINTPROVIDOR]
1727 * Close a printer handle and free associated resources
1730 * hPrinter [I] Printerhandle to close
1737 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1739 printer_t
*printer
= (printer_t
*) hPrinter
;
1741 TRACE("(%p)\n", hPrinter
);
1744 printer_free(printer
);
1750 /******************************************************************************
1751 * fpConfigurePort [exported through PRINTPROVIDOR]
1753 * Display the Configuration-Dialog for a specific Port
1756 * pName [I] Servername or NULL (local Computer)
1757 * hWnd [I] Handle to parent Window for the Dialog-Box
1758 * pPortName [I] Name of the Port, that should be configured
1765 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1772 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1774 lres
= copy_servername_from_name(pName
, NULL
);
1776 FIXME("server %s not supported\n", debugstr_w(pName
));
1777 SetLastError(ERROR_INVALID_NAME
);
1781 /* an empty Portname is Invalid, but can popup a Dialog */
1782 if (!pPortName
[0]) {
1783 SetLastError(ERROR_NOT_SUPPORTED
);
1787 pm
= monitor_load_by_port(pPortName
);
1788 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1789 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1790 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1791 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1792 TRACE("got %d with %u\n", res
, GetLastError());
1796 pui
= monitor_loadui(pm
);
1797 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1798 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1799 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1800 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1801 TRACE("got %d with %u\n", res
, GetLastError());
1805 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1806 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1807 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1809 SetLastError(ERROR_NOT_SUPPORTED
);
1812 monitor_unload(pui
);
1816 TRACE("returning %d with %u\n", res
, GetLastError());
1820 /******************************************************************
1821 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1823 * Delete a specific Printmonitor from a Printing-Environment
1826 * pName [I] Servername or NULL (local Computer)
1827 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1828 * pMonitorName [I] Name of the Monitor, that should be deleted
1835 * pEnvironment is ignored in Windows for the local Computer.
1839 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1844 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1845 debugstr_w(pMonitorName
));
1847 lres
= copy_servername_from_name(pName
, NULL
);
1849 FIXME("server %s not supported\n", debugstr_w(pName
));
1850 SetLastError(ERROR_INVALID_NAME
);
1854 /* pEnvironment is ignored in Windows for the local Computer */
1855 if (!pMonitorName
|| !pMonitorName
[0]) {
1856 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1857 SetLastError(ERROR_INVALID_PARAMETER
);
1861 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1862 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1866 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1867 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1872 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1875 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1876 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1880 /*****************************************************************************
1881 * fpDeletePort [exported through PRINTPROVIDOR]
1883 * Delete a specific Port
1886 * pName [I] Servername or NULL (local Computer)
1887 * hWnd [I] Handle to parent Window for the Dialog-Box
1888 * pPortName [I] Name of the Port, that should be deleted
1895 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1902 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1904 lres
= copy_servername_from_name(pName
, NULL
);
1906 FIXME("server %s not supported\n", debugstr_w(pName
));
1907 SetLastError(ERROR_INVALID_NAME
);
1911 /* an empty Portname is Invalid */
1912 if (!pPortName
[0]) {
1913 SetLastError(ERROR_NOT_SUPPORTED
);
1917 pm
= monitor_load_by_port(pPortName
);
1918 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1919 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1920 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1921 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1922 TRACE("got %d with %u\n", res
, GetLastError());
1926 pui
= monitor_loadui(pm
);
1927 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1928 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1929 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1930 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1931 TRACE("got %d with %u\n", res
, GetLastError());
1935 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1936 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1937 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1939 SetLastError(ERROR_NOT_SUPPORTED
);
1942 monitor_unload(pui
);
1946 TRACE("returning %d with %u\n", res
, GetLastError());
1950 /*****************************************************************************
1951 * fpEnumMonitors [exported through PRINTPROVIDOR]
1953 * Enumerate available Port-Monitors
1956 * pName [I] Servername or NULL (local Computer)
1957 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1958 * pMonitors [O] PTR to Buffer that receives the Result
1959 * cbBuf [I] Size of Buffer at pMonitors
1960 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1961 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1965 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1968 * Windows reads the Registry once and cache the Results.
1971 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1972 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1974 DWORD numentries
= 0;
1979 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1980 cbBuf
, pcbNeeded
, pcReturned
);
1982 lres
= copy_servername_from_name(pName
, NULL
);
1984 FIXME("server %s not supported\n", debugstr_w(pName
));
1985 SetLastError(ERROR_INVALID_NAME
);
1989 if (!Level
|| (Level
> 2)) {
1990 WARN("level (%d) is ignored in win9x\n", Level
);
1991 SetLastError(ERROR_INVALID_LEVEL
);
1995 /* Scan all Monitor-Keys */
1997 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1999 /* we calculated the needed buffersize. now do more error-checks */
2000 if (cbBuf
< needed
) {
2001 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2005 /* fill the Buffer with the Monitor-Keys */
2006 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2010 if (pcbNeeded
) *pcbNeeded
= needed
;
2011 if (pcReturned
) *pcReturned
= numentries
;
2013 TRACE("returning %d with %d (%d byte for %d entries)\n",
2014 res
, GetLastError(), needed
, numentries
);
2019 /******************************************************************************
2020 * fpEnumPorts [exported through PRINTPROVIDOR]
2022 * Enumerate available Ports
2025 * pName [I] Servername or NULL (local Computer)
2026 * Level [I] Structure-Level (1 or 2)
2027 * pPorts [O] PTR to Buffer that receives the Result
2028 * cbBuf [I] Size of Buffer at pPorts
2029 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2030 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2034 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2037 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2038 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2041 DWORD numentries
= 0;
2045 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2046 cbBuf
, pcbNeeded
, pcReturned
);
2048 lres
= copy_servername_from_name(pName
, NULL
);
2050 FIXME("server %s not supported\n", debugstr_w(pName
));
2051 SetLastError(ERROR_INVALID_NAME
);
2055 if (!Level
|| (Level
> 2)) {
2056 SetLastError(ERROR_INVALID_LEVEL
);
2060 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2061 SetLastError(RPC_X_NULL_REF_POINTER
);
2065 EnterCriticalSection(&monitor_handles_cs
);
2068 /* Scan all local Ports */
2070 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2072 /* we calculated the needed buffersize. now do the error-checks */
2073 if (cbBuf
< needed
) {
2074 monitor_unloadall();
2075 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2076 goto emP_cleanup_cs
;
2078 else if (!pPorts
|| !pcReturned
) {
2079 monitor_unloadall();
2080 SetLastError(RPC_X_NULL_REF_POINTER
);
2081 goto emP_cleanup_cs
;
2084 /* Fill the Buffer */
2085 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2087 monitor_unloadall();
2090 LeaveCriticalSection(&monitor_handles_cs
);
2093 if (pcbNeeded
) *pcbNeeded
= needed
;
2094 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2096 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2097 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2102 /*****************************************************************************
2103 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2105 * Enumerate available Print Processors
2108 * pName [I] Servername or NULL (local Computer)
2109 * pEnvironment [I] Printing-Environment or NULL (Default)
2110 * Level [I] Structure-Level (Only 1 is allowed)
2111 * pPPInfo [O] PTR to Buffer that receives the Result
2112 * cbBuf [I] Size of Buffer at pMonitors
2113 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2114 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2118 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2121 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2122 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2124 const printenv_t
* env
;
2125 LPWSTR regpathW
= NULL
;
2126 DWORD numentries
= 0;
2131 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2132 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2134 lres
= copy_servername_from_name(pName
, NULL
);
2136 FIXME("server %s not supported\n", debugstr_w(pName
));
2137 SetLastError(ERROR_INVALID_NAME
);
2142 SetLastError(ERROR_INVALID_LEVEL
);
2146 env
= validate_envW(pEnvironment
);
2148 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2150 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2151 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2156 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2158 /* Scan all Printprocessor-Keys */
2160 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2162 /* we calculated the needed buffersize. now do more error-checks */
2163 if (cbBuf
< needed
) {
2164 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2168 /* fill the Buffer with the Printprocessor Infos */
2169 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2173 heap_free(regpathW
);
2174 if (pcbNeeded
) *pcbNeeded
= needed
;
2175 if (pcReturned
) *pcReturned
= numentries
;
2177 TRACE("returning %d with %d (%d byte for %d entries)\n",
2178 res
, GetLastError(), needed
, numentries
);
2183 /******************************************************************************
2184 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2186 * Return the PATH for the Print-Processors
2189 * pName [I] Servername or NULL (this computer)
2190 * pEnvironment [I] Printing-Environment or NULL (Default)
2191 * level [I] Structure-Level (must be 1)
2192 * pPPInfo [O] PTR to Buffer that receives the Result
2193 * cbBuf [I] Size of Buffer at pPPInfo
2194 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2198 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2200 * Native Values returned in pPPInfo on Success for this computer:
2201 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2202 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2203 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2205 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2208 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2209 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2211 const printenv_t
* env
;
2215 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2216 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2219 lres
= copy_servername_from_name(pName
, NULL
);
2221 FIXME("server %s not supported\n", debugstr_w(pName
));
2222 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2226 env
= validate_envW(pEnvironment
);
2228 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2230 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2231 needed
= GetSystemDirectoryW(NULL
, 0);
2232 /* add the Size for the Subdirectories */
2233 needed
+= lstrlenW(spoolprtprocsW
);
2234 needed
+= lstrlenW(env
->subdir
);
2235 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2237 *pcbNeeded
= needed
;
2239 if (needed
> cbBuf
) {
2240 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2244 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2245 /* add the Subdirectories */
2246 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2247 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2248 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2252 /******************************************************************************
2253 * fpOpenPrinter [exported through PRINTPROVIDOR]
2255 * Open a Printer / Printserver or a Printer-Object
2258 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2259 * pPrinter [O] The resulting Handle is stored here
2260 * pDefaults [I] PTR to Default Printer Settings or NULL
2267 * lpPrinterName is one of:
2268 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2269 *| Printer: "PrinterName"
2270 *| Printer-Object: "PrinterName,Job xxx"
2271 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2272 *| XcvPort: "Servername,XcvPort PortName"
2276 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2277 LPPRINTER_DEFAULTSW pDefaults
)
2280 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2282 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2284 return (*pPrinter
!= 0);
2287 /******************************************************************************
2288 * fpXcvData [exported through PRINTPROVIDOR]
2290 * Execute commands in the Printmonitor DLL
2293 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2294 * pszDataName [i] Name of the command to execute
2295 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2296 * cbInputData [i] Size in Bytes of Buffer at pInputData
2297 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2298 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2299 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2300 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2307 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2308 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2310 * Minimal List of commands, that a Printmonitor DLL should support:
2312 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2313 *| "AddPort" : Add a Port
2314 *| "DeletePort": Delete a Port
2316 * Many Printmonitors support additional commands. Examples for localspl.dll:
2317 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2318 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2321 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2322 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2323 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2325 printer_t
*printer
= (printer_t
* ) hXcv
;
2327 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2328 pInputData
, cbInputData
, pOutputData
,
2329 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2331 if (!printer
|| (!printer
->hXcv
)) {
2332 SetLastError(ERROR_INVALID_HANDLE
);
2336 if (!pcbOutputNeeded
) {
2337 SetLastError(ERROR_INVALID_PARAMETER
);
2341 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2342 SetLastError(RPC_X_NULL_REF_POINTER
);
2346 *pcbOutputNeeded
= 0;
2348 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2349 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2354 /*****************************************************
2355 * setup_provider [internal]
2357 void setup_provider(void)
2359 static const PRINTPROVIDOR backend
= {
2361 NULL
, /* fpSetJob */
2362 NULL
, /* fpGetJob */
2363 NULL
, /* fpEnumJobs */
2364 NULL
, /* fpAddPrinter */
2365 NULL
, /* fpDeletePrinter */
2366 NULL
, /* fpSetPrinter */
2367 NULL
, /* fpGetPrinter */
2368 NULL
, /* fpEnumPrinters */
2369 NULL
, /* fpAddPrinterDriver */
2370 NULL
, /* fpEnumPrinterDrivers */
2371 NULL
, /* fpGetPrinterDriver */
2372 fpGetPrinterDriverDirectory
,
2373 NULL
, /* fpDeletePrinterDriver */
2374 NULL
, /* fpAddPrintProcessor */
2375 fpEnumPrintProcessors
,
2376 fpGetPrintProcessorDirectory
,
2377 NULL
, /* fpDeletePrintProcessor */
2378 NULL
, /* fpEnumPrintProcessorDatatypes */
2379 NULL
, /* fpStartDocPrinter */
2380 NULL
, /* fpStartPagePrinter */
2381 NULL
, /* fpWritePrinter */
2382 NULL
, /* fpEndPagePrinter */
2383 NULL
, /* fpAbortPrinter */
2384 NULL
, /* fpReadPrinter */
2385 NULL
, /* fpEndDocPrinter */
2386 NULL
, /* fpAddJob */
2387 NULL
, /* fpScheduleJob */
2388 NULL
, /* fpGetPrinterData */
2389 NULL
, /* fpSetPrinterData */
2390 NULL
, /* fpWaitForPrinterChange */
2392 NULL
, /* fpAddForm */
2393 NULL
, /* fpDeleteForm */
2394 NULL
, /* fpGetForm */
2395 NULL
, /* fpSetForm */
2396 NULL
, /* fpEnumForms */
2402 NULL
, /* fpCreatePrinterIC */
2403 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2404 NULL
, /* fpDeletePrinterIC */
2405 NULL
, /* fpAddPrinterConnection */
2406 NULL
, /* fpDeletePrinterConnection */
2407 NULL
, /* fpPrinterMessageBox */
2410 NULL
, /* fpResetPrinter */
2411 NULL
, /* fpGetPrinterDriverEx */
2412 NULL
, /* fpFindFirstPrinterChangeNotification */
2413 NULL
, /* fpFindClosePrinterChangeNotification */
2415 NULL
, /* fpShutDown */
2416 NULL
, /* fpRefreshPrinterChangeNotification */
2417 NULL
, /* fpOpenPrinterEx */
2418 NULL
, /* fpAddPrinterEx */
2419 NULL
, /* fpSetPort */
2420 NULL
, /* fpEnumPrinterData */
2421 NULL
, /* fpDeletePrinterData */
2422 NULL
, /* fpClusterSplOpen */
2423 NULL
, /* fpClusterSplClose */
2424 NULL
, /* fpClusterSplIsAlive */
2425 NULL
, /* fpSetPrinterDataEx */
2426 NULL
, /* fpGetPrinterDataEx */
2427 NULL
, /* fpEnumPrinterDataEx */
2428 NULL
, /* fpEnumPrinterKey */
2429 NULL
, /* fpDeletePrinterDataEx */
2430 NULL
, /* fpDeletePrinterKey */
2431 NULL
, /* fpSeekPrinter */
2432 NULL
, /* fpDeletePrinterDriverEx */
2433 NULL
, /* fpAddPerMachineConnection */
2434 NULL
, /* fpDeletePerMachineConnection */
2435 NULL
, /* fpEnumPerMachineConnections */
2437 fpAddPrinterDriverEx
,
2438 NULL
, /* fpSplReadPrinter */
2439 NULL
, /* fpDriverUnloadComplete */
2440 NULL
, /* fpGetSpoolFileInfo */
2441 NULL
, /* fpCommitSpoolData */
2442 NULL
, /* fpCloseSpoolFileHandle */
2443 NULL
, /* fpFlushPrinter */
2444 NULL
, /* fpSendRecvBidiData */
2445 NULL
/* fpAddDriverCatalog */
2447 pprovider
= &backend
;
2451 /*****************************************************
2452 * InitializePrintProvidor (localspl.@)
2454 * Initialize the Printprovider
2457 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2458 * cbPrintProvidor [I] Size of Buffer in Bytes
2459 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2462 * Success: TRUE and pPrintProvidor filled
2466 * The RegistryPath should be:
2467 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2468 * but this Parameter is ignored in "localspl.dll".
2472 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2473 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2476 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2477 memcpy(pPrintProvidor
, pprovider
,
2478 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));