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( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
220 apd
->src
[apd
->srclen
] = '\0';
221 apd
->dst
[apd
->dstlen
] = '\0';
223 if (!pathname
|| !pathname
[0]) {
224 /* nothing to copy */
228 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
233 strcatW( srcname
, file_part
);
235 strcatW( apd
->dst
, file_part
);
237 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
239 /* FIXME: handle APD_COPY_NEW_FILES */
240 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
241 TRACE("got %u with %u\n", res
, GetLastError());
243 return (apd
->lazy
) ? TRUE
: res
;
246 /******************************************************************
247 * copy_servername_from_name (internal)
249 * for an external server, the serverpart from the name is copied.
252 * the length (in WCHAR) of the serverpart (0 for the local computer)
253 * (-length), when the name is to long
256 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
260 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
264 if (target
) *target
= '\0';
266 if (name
== NULL
) return 0;
267 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
270 /* skip over both backslash, find separator '\' */
271 ptr
= strchrW(server
, '\\');
272 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
274 /* servername is empty */
275 if (serverlen
== 0) return 0;
277 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
279 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
282 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
283 target
[serverlen
] = '\0';
286 len
= sizeof(buffer
) / sizeof(buffer
[0]);
287 if (GetComputerNameW(buffer
, &len
)) {
288 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
289 /* The requested Servername is our computername */
296 /******************************************************************
297 * get_basename_from_name (internal)
299 * skip over the serverpart from the full name
302 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
304 if (name
== NULL
) return NULL
;
305 if ((name
[0] == '\\') && (name
[1] == '\\')) {
306 /* skip over the servername and search for the following '\' */
307 name
= strchrW(&name
[2], '\\');
308 if ((name
) && (name
[1])) {
309 /* found a separator ('\') followed by a name:
310 skip over the separator and return the rest */
315 /* no basename present (we found only a servername) */
322 /******************************************************************
323 * monitor_unload [internal]
325 * release a printmonitor and unload it from memory, when needed
328 static void monitor_unload(monitor_t
* pm
)
330 if (pm
== NULL
) return;
331 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
333 EnterCriticalSection(&monitor_handles_cs
);
335 if (pm
->refcount
) pm
->refcount
--;
337 if (pm
->refcount
== 0) {
338 list_remove(&pm
->entry
);
339 FreeLibrary(pm
->hdll
);
341 heap_free(pm
->dllname
);
344 LeaveCriticalSection(&monitor_handles_cs
);
347 /******************************************************************
348 * monitor_unloadall [internal]
350 * release all registered printmonitors and unload them from memory, when needed
354 static void monitor_unloadall(void)
359 EnterCriticalSection(&monitor_handles_cs
);
360 /* iterate through the list, with safety against removal */
361 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
363 /* skip monitorui dlls */
364 if (pm
->monitor
) monitor_unload(pm
);
366 LeaveCriticalSection(&monitor_handles_cs
);
369 /******************************************************************
370 * monitor_load [internal]
372 * load a printmonitor, get the dllname from the registry, when needed
373 * initialize the monitor and dump found function-pointers
375 * On failure, SetLastError() is called and NULL is returned
378 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
380 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
381 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
382 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
383 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
384 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
386 monitor_t
* pm
= NULL
;
388 LPWSTR regroot
= NULL
;
389 LPWSTR driver
= dllname
;
391 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
392 /* Is the Monitor already loaded? */
393 EnterCriticalSection(&monitor_handles_cs
);
396 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
398 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
406 pm
= heap_alloc_zero(sizeof(monitor_t
));
407 if (pm
== NULL
) goto cleanup
;
408 list_add_tail(&monitor_handles
, &pm
->entry
);
412 if (pm
->name
== NULL
) {
413 /* Load the monitor */
414 LPMONITOREX pmonitorEx
;
418 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
419 regroot
= heap_alloc(len
* sizeof(WCHAR
));
423 lstrcpyW(regroot
, monitorsW
);
424 lstrcatW(regroot
, name
);
425 /* Get the Driver from the Registry */
426 if (driver
== NULL
) {
429 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
430 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
431 &namesize
) == ERROR_SUCCESS
) {
432 driver
= heap_alloc(namesize
);
433 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
440 pm
->name
= strdupW(name
);
441 pm
->dllname
= strdupW(driver
);
443 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
445 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
450 pm
->hdll
= LoadLibraryW(driver
);
451 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
453 if (pm
->hdll
== NULL
) {
455 SetLastError(ERROR_MOD_NOT_FOUND
);
460 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
461 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
462 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
463 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
464 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
467 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
468 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
469 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
470 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
471 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
473 if (pInitializePrintMonitorUI
!= NULL
) {
474 pm
->monitorUI
= pInitializePrintMonitorUI();
475 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
477 TRACE("0x%08x: dwMonitorSize (%d)\n",
478 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
483 if (pInitializePrintMonitor
&& regroot
) {
484 pmonitorEx
= pInitializePrintMonitor(regroot
);
485 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
486 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
489 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
490 pm
->monitor
= &(pmonitorEx
->Monitor
);
495 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
499 if (!pm
->monitor
&& regroot
) {
500 if (pInitializePrintMonitor2
!= NULL
) {
501 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
503 if (pInitializeMonitorEx
!= NULL
) {
504 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
506 if (pInitializeMonitor
!= NULL
) {
507 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
510 if (!pm
->monitor
&& !pm
->monitorUI
) {
512 SetLastError(ERROR_PROC_NOT_FOUND
);
517 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
521 LeaveCriticalSection(&monitor_handles_cs
);
522 if (driver
!= dllname
) heap_free(driver
);
524 TRACE("=> %p\n", pm
);
528 /******************************************************************
529 * monitor_loadall [internal]
531 * Load all registered monitors
534 static DWORD
monitor_loadall(void)
537 DWORD registered
= 0;
540 WCHAR buffer
[MAX_PATH
];
543 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
544 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
545 NULL
, NULL
, NULL
, NULL
, NULL
);
547 TRACE("%d monitors registered\n", registered
);
549 while (id
< registered
) {
551 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
552 pm
= monitor_load(buffer
, NULL
);
556 RegCloseKey(hmonitors
);
558 TRACE("%d monitors loaded\n", loaded
);
562 /******************************************************************
563 * monitor_loadui [internal]
565 * load the userinterface-dll for a given portmonitor
567 * On failure, NULL is returned
569 static monitor_t
* monitor_loadui(monitor_t
* pm
)
571 monitor_t
* pui
= NULL
;
572 WCHAR buffer
[MAX_PATH
];
577 if (pm
== NULL
) return NULL
;
578 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
580 /* Try the Portmonitor first; works for many monitors */
582 EnterCriticalSection(&monitor_handles_cs
);
584 LeaveCriticalSection(&monitor_handles_cs
);
588 /* query the userinterface-dllname from the Portmonitor */
589 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
590 /* building (",XcvMonitor %s",pm->name) not needed yet */
591 res
= pm
->monitor
->pfnXcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
592 TRACE("got %u with %p\n", res
, hXcv
);
594 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
595 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
596 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
597 pm
->monitor
->pfnXcvClosePort(hXcv
);
603 /******************************************************************
604 * monitor_load_by_port [internal]
606 * load a printmonitor for a given port
608 * On failure, NULL is returned
611 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
616 monitor_t
* pm
= NULL
;
617 DWORD registered
= 0;
621 TRACE("(%s)\n", debugstr_w(portname
));
623 /* Try the Local Monitor first */
624 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
625 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
626 /* found the portname */
628 return monitor_load(localportW
, NULL
);
633 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
634 buffer
= heap_alloc(len
* sizeof(WCHAR
));
635 if (buffer
== NULL
) return NULL
;
637 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
638 EnterCriticalSection(&monitor_handles_cs
);
639 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
641 while ((pm
== NULL
) && (id
< registered
)) {
643 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
644 TRACE("testing %s\n", debugstr_w(buffer
));
645 len
= lstrlenW(buffer
);
646 lstrcatW(buffer
, bs_ports_bsW
);
647 lstrcatW(buffer
, portname
);
648 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
650 buffer
[len
] = '\0'; /* use only the Monitor-Name */
651 pm
= monitor_load(buffer
, NULL
);
655 LeaveCriticalSection(&monitor_handles_cs
);
662 /******************************************************************
663 * Return the number of bytes for an multi_sz string.
664 * The result includes all \0s
665 * (specifically the extra \0, that is needed as multi_sz terminator).
667 static int multi_sz_lenW(const WCHAR
*str
)
669 const WCHAR
*ptr
= str
;
673 ptr
+= lstrlenW(ptr
) + 1;
676 return (ptr
- str
+ 1) * sizeof(WCHAR
);
679 /******************************************************************
680 * validate_envW [internal]
682 * validate the user-supplied printing-environment
685 * env [I] PTR to Environment-String or NULL
688 * Success: PTR to printenv_t
689 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
692 * An empty string is handled the same way as NULL.
696 static const printenv_t
* validate_envW(LPCWSTR env
)
698 const printenv_t
*result
= NULL
;
701 TRACE("(%s)\n", debugstr_w(env
));
704 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
706 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
708 result
= all_printenv
[i
];
712 if (result
== NULL
) {
713 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
714 SetLastError(ERROR_INVALID_ENVIRONMENT
);
716 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
720 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
723 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
727 /*****************************************************************************
728 * enumerate the local monitors (INTERNAL)
730 * returns the needed size (in bytes) for pMonitors
731 * and *lpreturned is set to number of entries returned in pMonitors
733 * Language-Monitors are also installed in the same Registry-Location but
734 * they are filtered in Windows (not returned by EnumMonitors).
735 * We do no filtering to simplify our Code.
738 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
743 LPMONITOR_INFO_2W mi
;
744 WCHAR buffer
[MAX_PATH
];
745 WCHAR dllname
[MAX_PATH
];
753 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
755 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
756 len
= entrysize
* numentries
;
757 ptr
= (LPWSTR
) &pMonitors
[len
];
760 len
= sizeof(buffer
)/sizeof(buffer
[0]);
763 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
764 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
765 /* Scan all Monitor-Registry-Keys */
766 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
767 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
768 dllsize
= sizeof(dllname
);
771 /* The Monitor must have a Driver-DLL */
772 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
773 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
774 /* We found a valid DLL for this Monitor. */
775 TRACE("using Driver: %s\n", debugstr_w(dllname
));
780 /* Windows returns only Port-Monitors here, but to simplify our code,
781 we do no filtering for Language-Monitors */
785 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
787 /* we install and return only monitors for "Windows NT x86" */
788 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
792 /* required size is calculated. Now fill the user-buffer */
793 if (pMonitors
&& (cbBuf
>= needed
)){
794 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
795 pMonitors
+= entrysize
;
797 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
799 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
800 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
802 mi
->pEnvironment
= ptr
;
803 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
804 ptr
+= (lstrlenW(x86_envnameW
)+1);
807 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
808 ptr
+= (dllsize
/ sizeof(WCHAR
));
813 len
= sizeof(buffer
)/sizeof(buffer
[0]);
818 *lpreturned
= numentries
;
819 TRACE("need %d byte for %d entries\n", needed
, numentries
);
823 /*****************************************************************************
824 * enumerate the local print processors (INTERNAL)
826 * returns the needed size (in bytes) for pPPInfo
827 * and *lpreturned is set to number of entries returned in pPPInfo
830 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
835 PPRINTPROCESSOR_INFO_1W ppi
;
836 WCHAR buffer
[MAX_PATH
];
837 WCHAR dllname
[MAX_PATH
];
844 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
845 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
846 ptr
= (LPWSTR
) &pPPInfo
[len
];
849 len
= sizeof(buffer
)/sizeof(buffer
[0]);
852 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
853 /* add "winprint" first */
855 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(winprintW
);
856 if (pPPInfo
&& (cbBuf
>= needed
)){
857 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
858 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
860 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
862 lstrcpyW(ptr
, winprintW
); /* Name of the Print Processor */
863 ptr
+= sizeof(winprintW
) / sizeof(WCHAR
);
866 /* Scan all Printprocessor Keys */
867 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
868 (lstrcmpiW(buffer
, winprintW
) != 0)) {
869 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
870 dllsize
= sizeof(dllname
);
873 /* The Print Processor must have a Driver-DLL */
874 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
875 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
876 /* We found a valid DLL for this Print Processor */
877 TRACE("using Driver: %s\n", debugstr_w(dllname
));
884 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
885 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
887 /* required size is calculated. Now fill the user-buffer */
888 if (pPPInfo
&& (cbBuf
>= needed
)){
889 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
890 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
892 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
894 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
895 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
899 len
= sizeof(buffer
)/sizeof(buffer
[0]);
904 *lpreturned
= numentries
;
905 TRACE("need %d byte for %d entries\n", needed
, numentries
);
909 /******************************************************************
910 * enumerate the local Ports from all loaded monitors (internal)
912 * returns the needed size (in bytes) for pPorts
913 * and *lpreturned is set to number of entries returned in pPorts
916 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
920 LPPORT_INFO_2W cache
;
922 LPBYTE pi_buffer
= NULL
;
923 DWORD pi_allocated
= 0;
934 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
935 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
937 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
938 needed
= entrysize
* numentries
;
939 ptr
= (LPWSTR
) &pPorts
[needed
];
944 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
946 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
949 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
950 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
951 /* Do not use heap_realloc (we do not need the old data in the buffer) */
952 heap_free(pi_buffer
);
953 pi_buffer
= heap_alloc(pi_needed
);
954 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
955 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
957 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
958 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
960 numentries
+= pi_returned
;
963 /* fill the output-buffer (pPorts), if we have one */
964 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
966 while (pi_returned
> pi_index
) {
967 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
968 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
969 out
->pPortName
= ptr
;
970 lstrcpyW(ptr
, cache
->pPortName
);
971 ptr
+= (lstrlenW(ptr
)+1);
973 out
->pMonitorName
= ptr
;
974 lstrcpyW(ptr
, cache
->pMonitorName
);
975 ptr
+= (lstrlenW(ptr
)+1);
977 out
->pDescription
= ptr
;
978 lstrcpyW(ptr
, cache
->pDescription
);
979 ptr
+= (lstrlenW(ptr
)+1);
980 out
->fPortType
= cache
->fPortType
;
981 out
->Reserved
= cache
->Reserved
;
989 /* the temporary portinfo-buffer is no longer needed */
990 heap_free(pi_buffer
);
992 *lpreturned
= numentries
;
993 TRACE("need %d byte for %d entries\n", needed
, numentries
);
998 /*****************************************************************************
999 * open_driver_reg [internal]
1001 * opens the registry for the printer drivers depending on the given input
1002 * variable pEnvironment
1005 * Success: the opened hkey
1008 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1012 const printenv_t
* env
;
1014 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1016 env
= validate_envW(pEnvironment
);
1017 if (!env
) return NULL
;
1019 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
1020 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
1023 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1024 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1025 HeapFree(GetProcessHeap(), 0, buffer
);
1030 /*****************************************************************************
1031 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1033 * Return the PATH for the Printer-Drivers
1036 * pName [I] Servername (NT only) or NULL (local Computer)
1037 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1038 * Level [I] Structure-Level (must be 1)
1039 * pDriverDirectory [O] PTR to Buffer that receives the Result
1040 * cbBuf [I] Size of Buffer at pDriverDirectory
1041 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1042 * required for pDriverDirectory
1045 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1046 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1047 * if cbBuf is too small
1049 * Native Values returned in pDriverDirectory on Success:
1050 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1051 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1052 *| win9x(Windows 4.0): "%winsysdir%"
1054 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1057 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1058 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1061 const printenv_t
* env
;
1063 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1064 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1066 if (pName
!= NULL
&& pName
[0]) {
1067 FIXME("server %s not supported\n", debugstr_w(pName
));
1068 SetLastError(ERROR_INVALID_PARAMETER
);
1072 env
= validate_envW(pEnvironment
);
1073 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1076 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1077 needed
= GetSystemDirectoryW(NULL
, 0);
1078 /* add the Size for the Subdirectories */
1079 needed
+= lstrlenW(spooldriversW
);
1080 needed
+= lstrlenW(env
->subdir
);
1081 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1083 *pcbNeeded
= needed
;
1085 if (needed
> cbBuf
) {
1086 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1090 if (pDriverDirectory
== NULL
) {
1091 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1092 SetLastError(ERROR_INVALID_USER_BUFFER
);
1096 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
1097 /* add the Subdirectories */
1098 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
1099 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
1101 TRACE("=> %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
1105 /******************************************************************
1106 * driver_load [internal]
1108 * load a driver user interface dll
1110 * On failure, NULL is returned
1114 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1116 WCHAR fullname
[MAX_PATH
];
1120 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1122 /* build the driverdir */
1123 len
= sizeof(fullname
) -
1124 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1126 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1127 (LPBYTE
) fullname
, len
, &len
)) {
1128 /* Should never Fail */
1129 SetLastError(ERROR_BUFFER_OVERFLOW
);
1133 lstrcatW(fullname
, env
->versionsubdir
);
1134 lstrcatW(fullname
, backslashW
);
1135 lstrcatW(fullname
, dllname
);
1137 hui
= LoadLibraryW(fullname
);
1138 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1143 /******************************************************************
1145 * free the data pointer of an opened printer
1147 static VOID
printer_free(printer_t
* printer
)
1150 printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1152 monitor_unload(printer
->pm
);
1154 heap_free(printer
->printername
);
1155 heap_free(printer
->name
);
1159 /******************************************************************
1160 * printer_alloc_handle
1161 * alloc a printer handle and remember the data pointer in the printer handle table
1164 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1166 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1167 printer_t
*printer
= NULL
;
1168 LPCWSTR printername
;
1173 if (copy_servername_from_name(name
, servername
)) {
1174 FIXME("server %s not supported\n", debugstr_w(servername
));
1175 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1179 printername
= get_basename_from_name(name
);
1180 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1182 /* an empty printername is invalid */
1183 if (printername
&& (!printername
[0])) {
1184 SetLastError(ERROR_INVALID_PARAMETER
);
1188 printer
= heap_alloc_zero(sizeof(printer_t
));
1189 if (!printer
) goto end
;
1191 /* clone the base name. This is NULL for the printserver */
1192 printer
->printername
= strdupW(printername
);
1194 /* clone the full name */
1195 printer
->name
= strdupW(name
);
1196 if (name
&& (!printer
->name
)) {
1197 printer_free(printer
);
1201 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1202 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1203 /* OpenPrinter(",XcvMonitor ", ...) detected */
1204 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1205 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1206 if (printer
->pm
== NULL
) {
1207 printer_free(printer
);
1208 SetLastError(ERROR_UNKNOWN_PORT
);
1215 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1216 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1217 /* OpenPrinter(",XcvPort ", ...) detected */
1218 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1219 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1220 if (printer
->pm
== NULL
) {
1221 printer_free(printer
);
1222 SetLastError(ERROR_UNKNOWN_PORT
);
1230 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1231 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1232 pDefault
? pDefault
->DesiredAccess
: 0,
1235 if (printer
->hXcv
== NULL
) {
1236 printer_free(printer
);
1237 SetLastError(ERROR_INVALID_PARAMETER
);
1244 /* Does the Printer exist? */
1245 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1246 ERR("Can't create Printers key\n");
1247 printer_free(printer
);
1248 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1252 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1253 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1254 RegCloseKey(hkeyPrinters
);
1255 printer_free(printer
);
1256 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1260 RegCloseKey(hkeyPrinter
);
1261 RegCloseKey(hkeyPrinters
);
1266 TRACE("using the local printserver\n");
1271 TRACE("==> %p\n", printer
);
1272 return (HANDLE
)printer
;
1275 static inline WCHAR
*get_file_part( WCHAR
*name
)
1277 WCHAR
*ptr
= strrchrW( name
, '\\' );
1278 if (ptr
) return ptr
+ 1;
1282 /******************************************************************************
1283 * myAddPrinterDriverEx [internal]
1285 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1286 * and a special mode with lazy error checking.
1289 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1291 const printenv_t
*env
;
1294 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1304 /* we need to set all entries in the Registry, independent from the Level of
1305 DRIVER_INFO, that the caller supplied */
1307 ZeroMemory(&di
, sizeof(di
));
1308 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
1309 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1312 /* dump the most used infos */
1313 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1314 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1315 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1316 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1317 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1318 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1319 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1320 /* dump only the first of the additional Files */
1321 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1324 /* check environment */
1325 env
= validate_envW(di
.pEnvironment
);
1326 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1328 /* fill the copy-data / get the driverdir */
1329 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1330 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1331 (LPBYTE
) apd
.src
, len
, &len
)) {
1332 /* Should never Fail */
1335 memcpy(apd
.dst
, apd
.src
, len
);
1336 lstrcatW(apd
.src
, backslashW
);
1337 apd
.srclen
= lstrlenW(apd
.src
);
1338 lstrcatW(apd
.dst
, env
->versionsubdir
);
1339 lstrcatW(apd
.dst
, backslashW
);
1340 apd
.dstlen
= lstrlenW(apd
.dst
);
1341 apd
.copyflags
= dwFileCopyFlags
;
1343 CreateDirectoryW(apd
.src
, NULL
);
1344 CreateDirectoryW(apd
.dst
, NULL
);
1346 hroot
= open_driver_reg(env
->envname
);
1348 ERR("Can't create Drivers key\n");
1352 /* Fill the Registry for the Driver */
1353 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1354 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1355 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1357 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1364 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1365 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1368 file
= get_file_part( di
.pDriverPath
);
1369 RegSetValueExW( hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1370 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1372 file
= get_file_part( di
.pDataFile
);
1373 RegSetValueExW( hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1374 apd_copyfile( di
.pDataFile
, file
, &apd
);
1376 file
= get_file_part( di
.pConfigFile
);
1377 RegSetValueExW( hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1378 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1380 /* settings for level 3 */
1383 file
= get_file_part( di
.pHelpFile
);
1384 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1385 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1388 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
) );
1390 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1392 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1393 reg
= reg_ptr
= HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di
.pDependentFiles
) );
1395 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= strlenW( in_ptr
) + 1)
1397 file
= get_file_part( in_ptr
);
1398 len
= strlenW( file
) + 1;
1399 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1401 apd_copyfile( in_ptr
, file
, &apd
);
1405 RegSetValueExW( hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
1406 HeapFree( GetProcessHeap(), 0, reg
);
1409 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1411 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1412 if (di
.pMonitorName
)
1413 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1414 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1416 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1418 if (di
.pDefaultDataType
)
1419 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1420 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1422 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1424 /* settings for level 4 */
1425 if (di
.pszzPreviousNames
)
1426 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1427 multi_sz_lenW(di
.pszzPreviousNames
));
1429 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1431 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1434 hui
= driver_load(env
, di
.pConfigFile
);
1435 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1436 if (hui
&& pDrvDriverEvent
) {
1438 /* Support for DrvDriverEvent is optional */
1439 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1440 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1441 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1442 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1446 TRACE("=> TRUE with %u\n", GetLastError());
1451 /******************************************************************************
1452 * fpAddMonitor [exported through PRINTPROVIDOR]
1454 * Install a Printmonitor
1457 * pName [I] Servername or NULL (local Computer)
1458 * Level [I] Structure-Level (Must be 2)
1459 * pMonitors [I] PTR to MONITOR_INFO_2
1466 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1469 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1471 monitor_t
* pm
= NULL
;
1472 LPMONITOR_INFO_2W mi2w
;
1478 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1479 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1480 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1481 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1482 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1484 if (copy_servername_from_name(pName
, NULL
)) {
1485 FIXME("server %s not supported\n", debugstr_w(pName
));
1486 SetLastError(ERROR_ACCESS_DENIED
);
1490 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1491 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1492 SetLastError(ERROR_INVALID_PARAMETER
);
1495 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
1496 WARN("Environment %s requested (we support only %s)\n",
1497 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
1498 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1502 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1503 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1504 SetLastError(ERROR_INVALID_PARAMETER
);
1508 /* Load and initialize the monitor. SetLastError() is called on failure */
1509 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
1514 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1515 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1519 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1520 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1521 &disposition
) == ERROR_SUCCESS
) {
1523 /* Some installers set options for the port before calling AddMonitor.
1524 We query the "Driver" entry to verify that the monitor is installed,
1525 before we return an error.
1526 When a user installs two print monitors at the same time with the
1527 same name, a race condition is possible but silently ignored. */
1531 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1532 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1533 &namesize
) == ERROR_SUCCESS
)) {
1534 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1535 /* 9x use ERROR_ALREADY_EXISTS */
1536 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1541 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1542 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1543 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1545 RegCloseKey(hentry
);
1552 /******************************************************************************
1553 * fpAddPort [exported through PRINTPROVIDOR]
1555 * Add a Port for a specific Monitor
1558 * pName [I] Servername or NULL (local Computer)
1559 * hWnd [I] Handle to parent Window for the Dialog-Box
1560 * pMonitorName [I] Name of the Monitor that manage the Port
1567 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1574 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1576 lres
= copy_servername_from_name(pName
, NULL
);
1578 FIXME("server %s not supported\n", debugstr_w(pName
));
1579 SetLastError(ERROR_INVALID_PARAMETER
);
1583 /* an empty Monitorname is Invalid */
1584 if (!pMonitorName
[0]) {
1585 SetLastError(ERROR_NOT_SUPPORTED
);
1589 pm
= monitor_load(pMonitorName
, NULL
);
1590 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1591 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1592 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1596 pui
= monitor_loadui(pm
);
1597 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1598 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1599 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1603 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1604 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1605 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1607 SetLastError(ERROR_NOT_SUPPORTED
);
1610 monitor_unload(pui
);
1614 TRACE("returning %d with %u\n", res
, GetLastError());
1618 /******************************************************************************
1619 * fpAddPortEx [exported through PRINTPROVIDOR]
1621 * Add a Port for a specific Monitor, without presenting a user interface
1624 * pName [I] Servername or NULL (local Computer)
1625 * level [I] Structure-Level (1 or 2) for pBuffer
1626 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1627 * pMonitorName [I] Name of the Monitor that manage the Port
1634 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1641 pi2
= (PORT_INFO_2W
*) pBuffer
;
1643 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1644 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1645 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1646 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1648 lres
= copy_servername_from_name(pName
, NULL
);
1650 FIXME("server %s not supported\n", debugstr_w(pName
));
1651 SetLastError(ERROR_INVALID_PARAMETER
);
1655 if ((level
< 1) || (level
> 2)) {
1656 SetLastError(ERROR_INVALID_LEVEL
);
1660 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1661 SetLastError(ERROR_INVALID_PARAMETER
);
1665 /* load the Monitor */
1666 pm
= monitor_load(pMonitorName
, NULL
);
1667 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1668 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1669 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1673 FIXME("not implemented for %s (monitor %p: %s)\n",
1674 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1675 SetLastError(ERROR_INVALID_PARAMETER
);
1682 /******************************************************************************
1683 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1685 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1688 * pName [I] Servername or NULL (local Computer)
1689 * level [I] Level for the supplied DRIVER_INFO_*W struct
1690 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1691 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1698 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1702 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1703 lres
= copy_servername_from_name(pName
, NULL
);
1705 FIXME("server %s not supported\n", debugstr_w(pName
));
1706 SetLastError(ERROR_ACCESS_DENIED
);
1710 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1711 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1714 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1717 /******************************************************************************
1718 * fpClosePrinter [exported through PRINTPROVIDOR]
1720 * Close a printer handle and free associated resources
1723 * hPrinter [I] Printerhandle to close
1730 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1732 printer_t
*printer
= (printer_t
*) hPrinter
;
1734 TRACE("(%p)\n", hPrinter
);
1737 printer_free(printer
);
1743 /******************************************************************************
1744 * fpConfigurePort [exported through PRINTPROVIDOR]
1746 * Display the Configuration-Dialog for a specific Port
1749 * pName [I] Servername or NULL (local Computer)
1750 * hWnd [I] Handle to parent Window for the Dialog-Box
1751 * pPortName [I] Name of the Port, that should be configured
1758 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1765 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1767 lres
= copy_servername_from_name(pName
, NULL
);
1769 FIXME("server %s not supported\n", debugstr_w(pName
));
1770 SetLastError(ERROR_INVALID_NAME
);
1774 /* an empty Portname is Invalid, but can popup a Dialog */
1775 if (!pPortName
[0]) {
1776 SetLastError(ERROR_NOT_SUPPORTED
);
1780 pm
= monitor_load_by_port(pPortName
);
1781 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1782 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1783 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1784 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1785 TRACE("got %d with %u\n", res
, GetLastError());
1789 pui
= monitor_loadui(pm
);
1790 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1791 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1792 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1793 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1794 TRACE("got %d with %u\n", res
, GetLastError());
1798 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1799 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1800 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1802 SetLastError(ERROR_NOT_SUPPORTED
);
1805 monitor_unload(pui
);
1809 TRACE("returning %d with %u\n", res
, GetLastError());
1813 /******************************************************************
1814 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1816 * Delete a specific Printmonitor from a Printing-Environment
1819 * pName [I] Servername or NULL (local Computer)
1820 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1821 * pMonitorName [I] Name of the Monitor, that should be deleted
1828 * pEnvironment is ignored in Windows for the local Computer.
1832 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1837 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1838 debugstr_w(pMonitorName
));
1840 lres
= copy_servername_from_name(pName
, NULL
);
1842 FIXME("server %s not supported\n", debugstr_w(pName
));
1843 SetLastError(ERROR_INVALID_NAME
);
1847 /* pEnvironment is ignored in Windows for the local Computer */
1848 if (!pMonitorName
|| !pMonitorName
[0]) {
1849 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1850 SetLastError(ERROR_INVALID_PARAMETER
);
1854 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1855 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1859 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1860 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1865 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1868 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1869 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1873 /*****************************************************************************
1874 * fpDeletePort [exported through PRINTPROVIDOR]
1876 * Delete a specific Port
1879 * pName [I] Servername or NULL (local Computer)
1880 * hWnd [I] Handle to parent Window for the Dialog-Box
1881 * pPortName [I] Name of the Port, that should be deleted
1888 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1895 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1897 lres
= copy_servername_from_name(pName
, NULL
);
1899 FIXME("server %s not supported\n", debugstr_w(pName
));
1900 SetLastError(ERROR_INVALID_NAME
);
1904 /* an empty Portname is Invalid */
1905 if (!pPortName
[0]) {
1906 SetLastError(ERROR_NOT_SUPPORTED
);
1910 pm
= monitor_load_by_port(pPortName
);
1911 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1912 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1913 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1914 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1915 TRACE("got %d with %u\n", res
, GetLastError());
1919 pui
= monitor_loadui(pm
);
1920 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1921 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1922 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1923 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1924 TRACE("got %d with %u\n", res
, GetLastError());
1928 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1929 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1930 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1932 SetLastError(ERROR_NOT_SUPPORTED
);
1935 monitor_unload(pui
);
1939 TRACE("returning %d with %u\n", res
, GetLastError());
1943 /*****************************************************************************
1944 * fpEnumMonitors [exported through PRINTPROVIDOR]
1946 * Enumerate available Port-Monitors
1949 * pName [I] Servername or NULL (local Computer)
1950 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1951 * pMonitors [O] PTR to Buffer that receives the Result
1952 * cbBuf [I] Size of Buffer at pMonitors
1953 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1954 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1958 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1961 * Windows reads the Registry once and cache the Results.
1964 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1965 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1967 DWORD numentries
= 0;
1972 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1973 cbBuf
, pcbNeeded
, pcReturned
);
1975 lres
= copy_servername_from_name(pName
, NULL
);
1977 FIXME("server %s not supported\n", debugstr_w(pName
));
1978 SetLastError(ERROR_INVALID_NAME
);
1982 if (!Level
|| (Level
> 2)) {
1983 WARN("level (%d) is ignored in win9x\n", Level
);
1984 SetLastError(ERROR_INVALID_LEVEL
);
1988 /* Scan all Monitor-Keys */
1990 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1992 /* we calculated the needed buffersize. now do more error-checks */
1993 if (cbBuf
< needed
) {
1994 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1998 /* fill the Buffer with the Monitor-Keys */
1999 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2003 if (pcbNeeded
) *pcbNeeded
= needed
;
2004 if (pcReturned
) *pcReturned
= numentries
;
2006 TRACE("returning %d with %d (%d byte for %d entries)\n",
2007 res
, GetLastError(), needed
, numentries
);
2012 /******************************************************************************
2013 * fpEnumPorts [exported through PRINTPROVIDOR]
2015 * Enumerate available Ports
2018 * pName [I] Servername or NULL (local Computer)
2019 * Level [I] Structure-Level (1 or 2)
2020 * pPorts [O] PTR to Buffer that receives the Result
2021 * cbBuf [I] Size of Buffer at pPorts
2022 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2023 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2027 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2030 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2031 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2034 DWORD numentries
= 0;
2038 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2039 cbBuf
, pcbNeeded
, pcReturned
);
2041 lres
= copy_servername_from_name(pName
, NULL
);
2043 FIXME("server %s not supported\n", debugstr_w(pName
));
2044 SetLastError(ERROR_INVALID_NAME
);
2048 if (!Level
|| (Level
> 2)) {
2049 SetLastError(ERROR_INVALID_LEVEL
);
2053 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2054 SetLastError(RPC_X_NULL_REF_POINTER
);
2058 EnterCriticalSection(&monitor_handles_cs
);
2061 /* Scan all local Ports */
2063 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2065 /* we calculated the needed buffersize. now do the error-checks */
2066 if (cbBuf
< needed
) {
2067 monitor_unloadall();
2068 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2069 goto emP_cleanup_cs
;
2071 else if (!pPorts
|| !pcReturned
) {
2072 monitor_unloadall();
2073 SetLastError(RPC_X_NULL_REF_POINTER
);
2074 goto emP_cleanup_cs
;
2077 /* Fill the Buffer */
2078 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2080 monitor_unloadall();
2083 LeaveCriticalSection(&monitor_handles_cs
);
2086 if (pcbNeeded
) *pcbNeeded
= needed
;
2087 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2089 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2090 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2095 /*****************************************************************************
2096 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2098 * Enumerate available Print Processors
2101 * pName [I] Servername or NULL (local Computer)
2102 * pEnvironment [I] Printing-Environment or NULL (Default)
2103 * Level [I] Structure-Level (Only 1 is allowed)
2104 * pPPInfo [O] PTR to Buffer that receives the Result
2105 * cbBuf [I] Size of Buffer at pMonitors
2106 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2107 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2111 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2114 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2115 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2117 const printenv_t
* env
;
2118 LPWSTR regpathW
= NULL
;
2119 DWORD numentries
= 0;
2124 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2125 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2127 lres
= copy_servername_from_name(pName
, NULL
);
2129 FIXME("server %s not supported\n", debugstr_w(pName
));
2130 SetLastError(ERROR_INVALID_NAME
);
2135 SetLastError(ERROR_INVALID_LEVEL
);
2139 env
= validate_envW(pEnvironment
);
2141 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2143 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2144 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2149 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2151 /* Scan all Printprocessor-Keys */
2153 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2155 /* we calculated the needed buffersize. now do more error-checks */
2156 if (cbBuf
< needed
) {
2157 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2161 /* fill the Buffer with the Printprocessor Infos */
2162 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2166 heap_free(regpathW
);
2167 if (pcbNeeded
) *pcbNeeded
= needed
;
2168 if (pcReturned
) *pcReturned
= numentries
;
2170 TRACE("returning %d with %d (%d byte for %d entries)\n",
2171 res
, GetLastError(), needed
, numentries
);
2176 /******************************************************************************
2177 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2179 * Return the PATH for the Print-Processors
2182 * pName [I] Servername or NULL (this computer)
2183 * pEnvironment [I] Printing-Environment or NULL (Default)
2184 * level [I] Structure-Level (must be 1)
2185 * pPPInfo [O] PTR to Buffer that receives the Result
2186 * cbBuf [I] Size of Buffer at pPPInfo
2187 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2191 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2193 * Native Values returned in pPPInfo on Success for this computer:
2194 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2195 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2196 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2198 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2201 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2202 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2204 const printenv_t
* env
;
2208 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2209 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2212 lres
= copy_servername_from_name(pName
, NULL
);
2214 FIXME("server %s not supported\n", debugstr_w(pName
));
2215 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2219 env
= validate_envW(pEnvironment
);
2221 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2223 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2224 needed
= GetSystemDirectoryW(NULL
, 0);
2225 /* add the Size for the Subdirectories */
2226 needed
+= lstrlenW(spoolprtprocsW
);
2227 needed
+= lstrlenW(env
->subdir
);
2228 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2230 *pcbNeeded
= needed
;
2232 if (needed
> cbBuf
) {
2233 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2237 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2238 /* add the Subdirectories */
2239 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2240 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2241 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2245 /******************************************************************************
2246 * fpOpenPrinter [exported through PRINTPROVIDOR]
2248 * Open a Printer / Printserver or a Printer-Object
2251 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2252 * pPrinter [O] The resulting Handle is stored here
2253 * pDefaults [I] PTR to Default Printer Settings or NULL
2260 * lpPrinterName is one of:
2261 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2262 *| Printer: "PrinterName"
2263 *| Printer-Object: "PrinterName,Job xxx"
2264 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2265 *| XcvPort: "Servername,XcvPort PortName"
2269 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2270 LPPRINTER_DEFAULTSW pDefaults
)
2273 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2275 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2277 return (*pPrinter
!= 0);
2280 /******************************************************************************
2281 * fpXcvData [exported through PRINTPROVIDOR]
2283 * Execute commands in the Printmonitor DLL
2286 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2287 * pszDataName [i] Name of the command to execute
2288 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2289 * cbInputData [i] Size in Bytes of Buffer at pInputData
2290 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2291 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2292 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2293 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2300 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2301 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2303 * Minimal List of commands, that a Printmonitor DLL should support:
2305 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2306 *| "AddPort" : Add a Port
2307 *| "DeletePort": Delete a Port
2309 * Many Printmonitors support additional commands. Examples for localspl.dll:
2310 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2311 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2314 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2315 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2316 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2318 printer_t
*printer
= (printer_t
* ) hXcv
;
2320 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2321 pInputData
, cbInputData
, pOutputData
,
2322 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2324 if (!printer
|| (!printer
->hXcv
)) {
2325 SetLastError(ERROR_INVALID_HANDLE
);
2329 if (!pcbOutputNeeded
) {
2330 SetLastError(ERROR_INVALID_PARAMETER
);
2334 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2335 SetLastError(RPC_X_NULL_REF_POINTER
);
2339 *pcbOutputNeeded
= 0;
2341 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2342 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2347 /*****************************************************
2348 * setup_provider [internal]
2350 void setup_provider(void)
2352 static const PRINTPROVIDOR backend
= {
2354 NULL
, /* fpSetJob */
2355 NULL
, /* fpGetJob */
2356 NULL
, /* fpEnumJobs */
2357 NULL
, /* fpAddPrinter */
2358 NULL
, /* fpDeletePrinter */
2359 NULL
, /* fpSetPrinter */
2360 NULL
, /* fpGetPrinter */
2361 NULL
, /* fpEnumPrinters */
2362 NULL
, /* fpAddPrinterDriver */
2363 NULL
, /* fpEnumPrinterDrivers */
2364 NULL
, /* fpGetPrinterDriver */
2365 fpGetPrinterDriverDirectory
,
2366 NULL
, /* fpDeletePrinterDriver */
2367 NULL
, /* fpAddPrintProcessor */
2368 fpEnumPrintProcessors
,
2369 fpGetPrintProcessorDirectory
,
2370 NULL
, /* fpDeletePrintProcessor */
2371 NULL
, /* fpEnumPrintProcessorDatatypes */
2372 NULL
, /* fpStartDocPrinter */
2373 NULL
, /* fpStartPagePrinter */
2374 NULL
, /* fpWritePrinter */
2375 NULL
, /* fpEndPagePrinter */
2376 NULL
, /* fpAbortPrinter */
2377 NULL
, /* fpReadPrinter */
2378 NULL
, /* fpEndDocPrinter */
2379 NULL
, /* fpAddJob */
2380 NULL
, /* fpScheduleJob */
2381 NULL
, /* fpGetPrinterData */
2382 NULL
, /* fpSetPrinterData */
2383 NULL
, /* fpWaitForPrinterChange */
2385 NULL
, /* fpAddForm */
2386 NULL
, /* fpDeleteForm */
2387 NULL
, /* fpGetForm */
2388 NULL
, /* fpSetForm */
2389 NULL
, /* fpEnumForms */
2395 NULL
, /* fpCreatePrinterIC */
2396 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2397 NULL
, /* fpDeletePrinterIC */
2398 NULL
, /* fpAddPrinterConnection */
2399 NULL
, /* fpDeletePrinterConnection */
2400 NULL
, /* fpPrinterMessageBox */
2403 NULL
, /* fpResetPrinter */
2404 NULL
, /* fpGetPrinterDriverEx */
2405 NULL
, /* fpFindFirstPrinterChangeNotification */
2406 NULL
, /* fpFindClosePrinterChangeNotification */
2408 NULL
, /* fpShutDown */
2409 NULL
, /* fpRefreshPrinterChangeNotification */
2410 NULL
, /* fpOpenPrinterEx */
2411 NULL
, /* fpAddPrinterEx */
2412 NULL
, /* fpSetPort */
2413 NULL
, /* fpEnumPrinterData */
2414 NULL
, /* fpDeletePrinterData */
2415 NULL
, /* fpClusterSplOpen */
2416 NULL
, /* fpClusterSplClose */
2417 NULL
, /* fpClusterSplIsAlive */
2418 NULL
, /* fpSetPrinterDataEx */
2419 NULL
, /* fpGetPrinterDataEx */
2420 NULL
, /* fpEnumPrinterDataEx */
2421 NULL
, /* fpEnumPrinterKey */
2422 NULL
, /* fpDeletePrinterDataEx */
2423 NULL
, /* fpDeletePrinterKey */
2424 NULL
, /* fpSeekPrinter */
2425 NULL
, /* fpDeletePrinterDriverEx */
2426 NULL
, /* fpAddPerMachineConnection */
2427 NULL
, /* fpDeletePerMachineConnection */
2428 NULL
, /* fpEnumPerMachineConnections */
2430 fpAddPrinterDriverEx
,
2431 NULL
, /* fpSplReadPrinter */
2432 NULL
, /* fpDriverUnloadComplete */
2433 NULL
, /* fpGetSpoolFileInfo */
2434 NULL
, /* fpCommitSpoolData */
2435 NULL
, /* fpCloseSpoolFileHandle */
2436 NULL
, /* fpFlushPrinter */
2437 NULL
, /* fpSendRecvBidiData */
2438 NULL
/* fpAddDriverCatalog */
2440 pprovider
= &backend
;
2444 /*****************************************************
2445 * InitializePrintProvidor (localspl.@)
2447 * Initialize the Printprovider
2450 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2451 * cbPrintProvidor [I] Size of Buffer in Bytes
2452 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2455 * Success: TRUE and pPrintProvidor filled
2459 * The RegistryPath should be:
2460 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2461 * but this Parameter is ignored in "localspl.dll".
2465 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2466 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2469 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2470 memcpy(pPrintProvidor
, pprovider
,
2471 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));