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
31 #include "ddk/winddiui.h"
32 #include "ddk/winsplp.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/list.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 dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
103 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
104 static const WCHAR emptyW
[] = {0};
105 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
106 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
107 'c','o','n','t','r','o','l','\\',
108 'P','r','i','n','t','\\',
109 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
110 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
111 static const WCHAR fmt_printprocessorsW
[] = { 'S','y','s','t','e','m','\\',
112 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
113 'C','o','n','t','r','o','l','\\',
114 'P','r','i','n','t','\\',
115 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
116 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
117 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
118 static const WCHAR ia64_envnameW
[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
119 static const WCHAR ia64_subdirW
[] = {'i','a','6','4',0};
120 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
121 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
122 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
123 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
124 'C','o','n','t','r','o','l','\\',
125 'P','r','i','n','t','\\',
126 'M','o','n','i','t','o','r','s','\\',0};
127 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
128 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
129 static const WCHAR printersW
[] = {'S','y','s','t','e','m','\\',
130 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'C','o','n','t','r','o','l','\\',
132 'P','r','i','n','t','\\',
133 'P','r','i','n','t','e','r','s',0};
134 static const WCHAR spoolW
[] = {'\\','s','p','o','o','l',0};
135 static const WCHAR driversW
[] = {'\\','d','r','i','v','e','r','s','\\',0};
136 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
137 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
138 static const WCHAR version0_subdirW
[] = {'\\','0',0};
139 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
140 static const WCHAR version3_subdirW
[] = {'\\','3',0};
141 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
142 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
143 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
144 static const WCHAR winnt_cv_portsW
[] = {'S','o','f','t','w','a','r','e','\\',
145 'M','i','c','r','o','s','o','f','t','\\',
146 'W','i','n','d','o','w','s',' ','N','T','\\',
147 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
148 'P','o','r','t','s',0};
149 static const WCHAR winprintW
[] = {'w','i','n','p','r','i','n','t',0};
150 static const WCHAR x64_envnameW
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
151 static const WCHAR x64_subdirW
[] = {'x','6','4',0};
152 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
153 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
154 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
155 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
158 static const printenv_t env_ia64
= {ia64_envnameW
, ia64_subdirW
, 3,
159 version3_regpathW
, version3_subdirW
};
161 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
162 version3_regpathW
, version3_subdirW
};
164 static const printenv_t env_x64
= {x64_envnameW
, x64_subdirW
, 3,
165 version3_regpathW
, version3_subdirW
};
167 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
168 version0_regpathW
, version0_subdirW
};
170 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_win40
};
173 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
174 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
175 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
176 0, sizeof(DRIVER_INFO_8W
)};
179 /******************************************************************
182 * create a copy of a unicode-string
185 static LPWSTR
strdupW(LPCWSTR p
)
191 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
192 ret
= heap_alloc(len
);
193 if (ret
) memcpy(ret
, p
, len
);
197 /******************************************************************
198 * apd_copyfile [internal]
200 * Copy a file from the driverdirectory to the versioned directory
207 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
212 apd
->src
[apd
->srclen
] = '\0';
213 apd
->dst
[apd
->dstlen
] = '\0';
215 if (!pathname
|| !pathname
[0]) {
216 /* nothing to copy */
220 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
225 strcatW( srcname
, file_part
);
227 strcatW( apd
->dst
, file_part
);
229 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
231 /* FIXME: handle APD_COPY_NEW_FILES */
232 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
233 TRACE("got %d with %u\n", res
, GetLastError());
235 return apd
->lazy
|| res
;
238 /******************************************************************
239 * copy_servername_from_name (internal)
241 * for an external server, the serverpart from the name is copied.
244 * the length (in WCHAR) of the serverpart (0 for the local computer)
245 * (-length), when the name is too long
248 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
252 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
256 if (target
) *target
= '\0';
258 if (name
== NULL
) return 0;
259 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
262 /* skip over both backslash, find separator '\' */
263 ptr
= strchrW(server
, '\\');
264 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
266 /* servername is empty */
267 if (serverlen
== 0) return 0;
269 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
271 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
274 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
275 target
[serverlen
] = '\0';
278 len
= sizeof(buffer
) / sizeof(buffer
[0]);
279 if (GetComputerNameW(buffer
, &len
)) {
280 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
281 /* The requested Servername is our computername */
288 /******************************************************************
289 * get_basename_from_name (internal)
291 * skip over the serverpart from the full name
294 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
296 if (name
== NULL
) return NULL
;
297 if ((name
[0] == '\\') && (name
[1] == '\\')) {
298 /* skip over the servername and search for the following '\' */
299 name
= strchrW(&name
[2], '\\');
300 if ((name
) && (name
[1])) {
301 /* found a separator ('\') followed by a name:
302 skip over the separator and return the rest */
307 /* no basename present (we found only a servername) */
314 /******************************************************************
315 * monitor_unload [internal]
317 * release a printmonitor and unload it from memory, when needed
320 static void monitor_unload(monitor_t
* pm
)
322 if (pm
== NULL
) return;
323 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
325 EnterCriticalSection(&monitor_handles_cs
);
327 if (pm
->refcount
) pm
->refcount
--;
329 if (pm
->refcount
== 0) {
330 list_remove(&pm
->entry
);
331 FreeLibrary(pm
->hdll
);
333 heap_free(pm
->dllname
);
336 LeaveCriticalSection(&monitor_handles_cs
);
339 /******************************************************************
340 * monitor_unloadall [internal]
342 * release all registered printmonitors and unload them from memory, when needed
346 static void monitor_unloadall(void)
351 EnterCriticalSection(&monitor_handles_cs
);
352 /* iterate through the list, with safety against removal */
353 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
355 /* skip monitorui dlls */
356 if (pm
->monitor
) monitor_unload(pm
);
358 LeaveCriticalSection(&monitor_handles_cs
);
361 /******************************************************************
362 * monitor_load [internal]
364 * load a printmonitor, get the dllname from the registry, when needed
365 * initialize the monitor and dump found function-pointers
367 * On failure, SetLastError() is called and NULL is returned
370 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
372 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
373 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
374 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
375 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
376 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
378 monitor_t
* pm
= NULL
;
380 LPWSTR regroot
= NULL
;
381 LPWSTR driver
= dllname
;
383 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
384 /* Is the Monitor already loaded? */
385 EnterCriticalSection(&monitor_handles_cs
);
388 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
390 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
398 pm
= heap_alloc_zero(sizeof(monitor_t
));
399 if (pm
== NULL
) goto cleanup
;
400 list_add_tail(&monitor_handles
, &pm
->entry
);
404 if (pm
->name
== NULL
) {
405 /* Load the monitor */
406 LPMONITOREX pmonitorEx
;
410 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
411 regroot
= heap_alloc(len
* sizeof(WCHAR
));
415 lstrcpyW(regroot
, monitorsW
);
416 lstrcatW(regroot
, name
);
417 /* Get the Driver from the Registry */
418 if (driver
== NULL
) {
421 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
422 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
423 &namesize
) == ERROR_SUCCESS
) {
424 driver
= heap_alloc(namesize
);
425 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
432 pm
->name
= strdupW(name
);
433 pm
->dllname
= strdupW(driver
);
435 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
437 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
442 pm
->hdll
= LoadLibraryW(driver
);
443 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
445 if (pm
->hdll
== NULL
) {
447 SetLastError(ERROR_MOD_NOT_FOUND
);
452 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
453 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
454 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
455 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
456 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
459 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
460 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
461 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
462 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
463 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
465 if (pInitializePrintMonitorUI
!= NULL
) {
466 pm
->monitorUI
= pInitializePrintMonitorUI();
467 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
469 TRACE("0x%08x: dwMonitorSize (%d)\n",
470 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
475 if (pInitializePrintMonitor
&& regroot
) {
476 pmonitorEx
= pInitializePrintMonitor(regroot
);
477 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
478 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
481 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
482 pm
->monitor
= &(pmonitorEx
->Monitor
);
487 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
491 if (!pm
->monitor
&& regroot
) {
492 if (pInitializePrintMonitor2
!= NULL
) {
493 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
495 if (pInitializeMonitorEx
!= NULL
) {
496 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
498 if (pInitializeMonitor
!= NULL
) {
499 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
502 if (!pm
->monitor
&& !pm
->monitorUI
) {
504 SetLastError(ERROR_PROC_NOT_FOUND
);
509 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
513 LeaveCriticalSection(&monitor_handles_cs
);
514 if (driver
!= dllname
) heap_free(driver
);
516 TRACE("=> %p\n", pm
);
520 /******************************************************************
521 * monitor_loadall [internal]
523 * Load all registered monitors
526 static DWORD
monitor_loadall(void)
529 DWORD registered
= 0;
532 WCHAR buffer
[MAX_PATH
];
535 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
536 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
537 NULL
, NULL
, NULL
, NULL
, NULL
);
539 TRACE("%d monitors registered\n", registered
);
541 while (id
< registered
) {
543 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
544 pm
= monitor_load(buffer
, NULL
);
548 RegCloseKey(hmonitors
);
550 TRACE("%d monitors loaded\n", loaded
);
554 /******************************************************************
555 * monitor_loadui [internal]
557 * load the userinterface-dll for a given portmonitor
559 * On failure, NULL is returned
561 static monitor_t
* monitor_loadui(monitor_t
* pm
)
563 monitor_t
* pui
= NULL
;
564 WCHAR buffer
[MAX_PATH
];
569 if (pm
== NULL
) return NULL
;
570 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
572 /* Try the Portmonitor first; works for many monitors */
574 EnterCriticalSection(&monitor_handles_cs
);
576 LeaveCriticalSection(&monitor_handles_cs
);
580 /* query the userinterface-dllname from the Portmonitor */
581 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
582 /* building (",XcvMonitor %s",pm->name) not needed yet */
583 res
= pm
->monitor
->pfnXcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
584 TRACE("got %u with %p\n", res
, hXcv
);
586 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
587 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
588 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
589 pm
->monitor
->pfnXcvClosePort(hXcv
);
595 /******************************************************************
596 * monitor_load_by_port [internal]
598 * load a printmonitor for a given port
600 * On failure, NULL is returned
603 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
608 monitor_t
* pm
= NULL
;
609 DWORD registered
= 0;
613 TRACE("(%s)\n", debugstr_w(portname
));
615 /* Try the Local Monitor first */
616 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
617 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
618 /* found the portname */
620 return monitor_load(localportW
, NULL
);
625 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
626 buffer
= heap_alloc(len
* sizeof(WCHAR
));
627 if (buffer
== NULL
) return NULL
;
629 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
630 EnterCriticalSection(&monitor_handles_cs
);
631 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
633 while ((pm
== NULL
) && (id
< registered
)) {
635 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
636 TRACE("testing %s\n", debugstr_w(buffer
));
637 len
= lstrlenW(buffer
);
638 lstrcatW(buffer
, bs_ports_bsW
);
639 lstrcatW(buffer
, portname
);
640 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
642 buffer
[len
] = '\0'; /* use only the Monitor-Name */
643 pm
= monitor_load(buffer
, NULL
);
647 LeaveCriticalSection(&monitor_handles_cs
);
654 /******************************************************************
655 * Return the number of bytes for an multi_sz string.
656 * The result includes all \0s
657 * (specifically the extra \0, that is needed as multi_sz terminator).
659 static int multi_sz_lenW(const WCHAR
*str
)
661 const WCHAR
*ptr
= str
;
665 ptr
+= lstrlenW(ptr
) + 1;
668 return (ptr
- str
+ 1) * sizeof(WCHAR
);
671 /******************************************************************
672 * validate_envW [internal]
674 * validate the user-supplied printing-environment
677 * env [I] PTR to Environment-String or NULL
680 * Success: PTR to printenv_t
681 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
684 * An empty string is handled the same way as NULL.
688 static const printenv_t
* validate_envW(LPCWSTR env
)
690 const printenv_t
*result
= NULL
;
693 TRACE("(%s)\n", debugstr_w(env
));
696 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
698 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
700 result
= all_printenv
[i
];
704 if (result
== NULL
) {
705 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
706 SetLastError(ERROR_INVALID_ENVIRONMENT
);
708 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
712 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
715 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
719 /*****************************************************************************
720 * enumerate the local monitors (INTERNAL)
722 * returns the needed size (in bytes) for pMonitors
723 * and *lpreturned is set to number of entries returned in pMonitors
725 * Language-Monitors are also installed in the same Registry-Location but
726 * they are filtered in Windows (not returned by EnumMonitors).
727 * We do no filtering to simplify our Code.
730 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
735 LPMONITOR_INFO_2W mi
;
736 WCHAR buffer
[MAX_PATH
];
737 WCHAR dllname
[MAX_PATH
];
745 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
747 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
748 len
= entrysize
* numentries
;
749 ptr
= (LPWSTR
) &pMonitors
[len
];
752 len
= sizeof(buffer
)/sizeof(buffer
[0]);
755 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
756 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
757 /* Scan all Monitor-Registry-Keys */
758 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
759 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
760 dllsize
= sizeof(dllname
);
763 /* The Monitor must have a Driver-DLL */
764 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
765 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
766 /* We found a valid DLL for this Monitor. */
767 TRACE("using Driver: %s\n", debugstr_w(dllname
));
772 /* Windows returns only Port-Monitors here, but to simplify our code,
773 we do no filtering for Language-Monitors */
777 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
779 /* we install and return only monitors for "Windows NT x86" */
780 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
784 /* required size is calculated. Now fill the user-buffer */
785 if (pMonitors
&& (cbBuf
>= needed
)){
786 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
787 pMonitors
+= entrysize
;
789 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
791 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
792 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
794 mi
->pEnvironment
= ptr
;
795 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
796 ptr
+= (lstrlenW(x86_envnameW
)+1);
799 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
800 ptr
+= (dllsize
/ sizeof(WCHAR
));
805 len
= sizeof(buffer
)/sizeof(buffer
[0]);
810 *lpreturned
= numentries
;
811 TRACE("need %d byte for %d entries\n", needed
, numentries
);
815 /*****************************************************************************
816 * enumerate the local print processors (INTERNAL)
818 * returns the needed size (in bytes) for pPPInfo
819 * and *lpreturned is set to number of entries returned in pPPInfo
822 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
827 PPRINTPROCESSOR_INFO_1W ppi
;
828 WCHAR buffer
[MAX_PATH
];
829 WCHAR dllname
[MAX_PATH
];
836 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
837 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
838 ptr
= (LPWSTR
) &pPPInfo
[len
];
841 len
= sizeof(buffer
)/sizeof(buffer
[0]);
844 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
845 /* add "winprint" first */
847 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(winprintW
);
848 if (pPPInfo
&& (cbBuf
>= needed
)){
849 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
850 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
852 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
854 lstrcpyW(ptr
, winprintW
); /* Name of the Print Processor */
855 ptr
+= sizeof(winprintW
) / sizeof(WCHAR
);
858 /* Scan all Printprocessor Keys */
859 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
860 (lstrcmpiW(buffer
, winprintW
) != 0)) {
861 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
862 dllsize
= sizeof(dllname
);
865 /* The Print Processor must have a Driver-DLL */
866 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
867 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
868 /* We found a valid DLL for this Print Processor */
869 TRACE("using Driver: %s\n", debugstr_w(dllname
));
876 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
877 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
879 /* required size is calculated. Now fill the user-buffer */
880 if (pPPInfo
&& (cbBuf
>= needed
)){
881 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
882 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
884 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
886 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
887 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
891 len
= sizeof(buffer
)/sizeof(buffer
[0]);
896 *lpreturned
= numentries
;
897 TRACE("need %d byte for %d entries\n", needed
, numentries
);
901 /******************************************************************
902 * enumerate the local Ports from all loaded monitors (internal)
904 * returns the needed size (in bytes) for pPorts
905 * and *lpreturned is set to number of entries returned in pPorts
908 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
912 LPPORT_INFO_2W cache
;
914 LPBYTE pi_buffer
= NULL
;
915 DWORD pi_allocated
= 0;
926 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
927 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
929 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
930 needed
= entrysize
* numentries
;
931 ptr
= (LPWSTR
) &pPorts
[needed
];
936 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
938 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
941 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
942 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
943 /* Do not use heap_realloc (we do not need the old data in the buffer) */
944 heap_free(pi_buffer
);
945 pi_buffer
= heap_alloc(pi_needed
);
946 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
947 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
949 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
950 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
952 numentries
+= pi_returned
;
955 /* fill the output-buffer (pPorts), if we have one */
956 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
958 while (pi_returned
> pi_index
) {
959 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
960 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
961 out
->pPortName
= ptr
;
962 lstrcpyW(ptr
, cache
->pPortName
);
963 ptr
+= (lstrlenW(ptr
)+1);
965 out
->pMonitorName
= ptr
;
966 lstrcpyW(ptr
, cache
->pMonitorName
);
967 ptr
+= (lstrlenW(ptr
)+1);
969 out
->pDescription
= ptr
;
970 lstrcpyW(ptr
, cache
->pDescription
);
971 ptr
+= (lstrlenW(ptr
)+1);
972 out
->fPortType
= cache
->fPortType
;
973 out
->Reserved
= cache
->Reserved
;
981 /* the temporary portinfo-buffer is no longer needed */
982 heap_free(pi_buffer
);
984 *lpreturned
= numentries
;
985 TRACE("need %d byte for %d entries\n", needed
, numentries
);
990 /*****************************************************************************
991 * open_driver_reg [internal]
993 * opens the registry for the printer drivers depending on the given input
994 * variable pEnvironment
997 * Success: the opened hkey
1000 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1004 const printenv_t
* env
;
1006 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1008 env
= validate_envW(pEnvironment
);
1009 if (!env
) return NULL
;
1011 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
1012 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
1015 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1016 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1017 HeapFree(GetProcessHeap(), 0, buffer
);
1022 /*****************************************************************************
1023 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1025 * Return the PATH for the Printer-Drivers
1028 * pName [I] Servername (NT only) or NULL (local Computer)
1029 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1030 * Level [I] Structure-Level (must be 1)
1031 * pDriverDirectory [O] PTR to Buffer that receives the Result
1032 * cbBuf [I] Size of Buffer at pDriverDirectory
1033 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1034 * required for pDriverDirectory
1037 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1038 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1039 * if cbBuf is too small
1041 * Native Values returned in pDriverDirectory on Success:
1042 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1043 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1044 *| win9x(Windows 4.0): "%winsysdir%"
1046 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1049 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1050 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1053 const printenv_t
* env
;
1054 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1056 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1057 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1059 if (pName
!= NULL
&& pName
[0]) {
1060 FIXME("server %s not supported\n", debugstr_w(pName
));
1061 SetLastError(ERROR_INVALID_PARAMETER
);
1065 env
= validate_envW(pEnvironment
);
1066 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1069 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1070 needed
= GetSystemDirectoryW(NULL
, 0);
1071 /* add the Size for the Subdirectories */
1072 needed
+= lstrlenW(spoolW
);
1073 needed
+= lstrlenW(driversW
);
1074 needed
+= lstrlenW(env
->subdir
);
1075 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1077 *pcbNeeded
= needed
;
1079 if (needed
> cbBuf
) {
1080 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1085 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1086 SetLastError(ERROR_INVALID_USER_BUFFER
);
1090 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1091 /* add the Subdirectories */
1092 lstrcatW( dir
, spoolW
);
1093 CreateDirectoryW( dir
, NULL
);
1094 lstrcatW( dir
, driversW
);
1095 CreateDirectoryW( dir
, NULL
);
1096 lstrcatW( dir
, env
->subdir
);
1097 CreateDirectoryW( dir
, NULL
);
1099 TRACE( "=> %s\n", debugstr_w( dir
) );
1103 /******************************************************************
1104 * driver_load [internal]
1106 * load a driver user interface dll
1108 * On failure, NULL is returned
1112 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1114 WCHAR fullname
[MAX_PATH
];
1118 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1120 /* build the driverdir */
1121 len
= sizeof(fullname
) -
1122 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1124 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1125 (LPBYTE
) fullname
, len
, &len
)) {
1126 /* Should never fail */
1127 SetLastError(ERROR_BUFFER_OVERFLOW
);
1131 lstrcatW(fullname
, env
->versionsubdir
);
1132 lstrcatW(fullname
, backslashW
);
1133 lstrcatW(fullname
, dllname
);
1135 hui
= LoadLibraryW(fullname
);
1136 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1141 /******************************************************************
1143 * free the data pointer of an opened printer
1145 static VOID
printer_free(printer_t
* printer
)
1148 printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1150 monitor_unload(printer
->pm
);
1152 heap_free(printer
->printername
);
1153 heap_free(printer
->name
);
1157 /******************************************************************
1158 * printer_alloc_handle
1159 * alloc a printer handle and remember the data pointer in the printer handle table
1162 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1164 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1165 printer_t
*printer
= NULL
;
1166 LPCWSTR printername
;
1171 if (copy_servername_from_name(name
, servername
)) {
1172 FIXME("server %s not supported\n", debugstr_w(servername
));
1173 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1177 printername
= get_basename_from_name(name
);
1178 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1180 /* an empty printername is invalid */
1181 if (printername
&& (!printername
[0])) {
1182 SetLastError(ERROR_INVALID_PARAMETER
);
1186 printer
= heap_alloc_zero(sizeof(printer_t
));
1187 if (!printer
) goto end
;
1189 /* clone the base name. This is NULL for the printserver */
1190 printer
->printername
= strdupW(printername
);
1192 /* clone the full name */
1193 printer
->name
= strdupW(name
);
1194 if (name
&& (!printer
->name
)) {
1195 printer_free(printer
);
1199 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1200 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1201 /* OpenPrinter(",XcvMonitor ", ...) detected */
1202 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1203 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1204 if (printer
->pm
== NULL
) {
1205 printer_free(printer
);
1206 SetLastError(ERROR_UNKNOWN_PORT
);
1213 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1214 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1215 /* OpenPrinter(",XcvPort ", ...) detected */
1216 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1217 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1218 if (printer
->pm
== NULL
) {
1219 printer_free(printer
);
1220 SetLastError(ERROR_UNKNOWN_PORT
);
1228 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1229 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1230 pDefault
? pDefault
->DesiredAccess
: 0,
1233 if (printer
->hXcv
== NULL
) {
1234 printer_free(printer
);
1235 SetLastError(ERROR_INVALID_PARAMETER
);
1242 /* Does the Printer exist? */
1243 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1244 ERR("Can't create Printers key\n");
1245 printer_free(printer
);
1246 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1250 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1251 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1252 RegCloseKey(hkeyPrinters
);
1253 printer_free(printer
);
1254 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1258 RegCloseKey(hkeyPrinter
);
1259 RegCloseKey(hkeyPrinters
);
1264 TRACE("using the local printserver\n");
1269 TRACE("==> %p\n", printer
);
1270 return (HANDLE
)printer
;
1273 static inline WCHAR
*get_file_part( WCHAR
*name
)
1275 WCHAR
*ptr
= strrchrW( name
, '\\' );
1276 if (ptr
) return ptr
+ 1;
1280 /******************************************************************************
1281 * myAddPrinterDriverEx [internal]
1283 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1284 * and a special mode with lazy error checking.
1287 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1289 const printenv_t
*env
;
1292 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1302 /* we need to set all entries in the Registry, independent from the Level of
1303 DRIVER_INFO, that the caller supplied */
1305 ZeroMemory(&di
, sizeof(di
));
1306 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
1307 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1310 /* dump the most used infos */
1311 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1312 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1313 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1314 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1315 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1316 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1317 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1318 /* dump only the first of the additional Files */
1319 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1322 /* check environment */
1323 env
= validate_envW(di
.pEnvironment
);
1324 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1326 /* fill the copy-data / get the driverdir */
1327 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1328 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1329 (LPBYTE
) apd
.src
, len
, &len
)) {
1330 /* Should never fail */
1333 memcpy(apd
.dst
, apd
.src
, len
);
1334 lstrcatW(apd
.src
, backslashW
);
1335 apd
.srclen
= lstrlenW(apd
.src
);
1336 lstrcatW(apd
.dst
, env
->versionsubdir
);
1337 lstrcatW(apd
.dst
, backslashW
);
1338 apd
.dstlen
= lstrlenW(apd
.dst
);
1339 apd
.copyflags
= dwFileCopyFlags
;
1341 CreateDirectoryW(apd
.src
, NULL
);
1342 CreateDirectoryW(apd
.dst
, NULL
);
1344 hroot
= open_driver_reg(env
->envname
);
1346 ERR("Can't create Drivers key\n");
1350 /* Fill the Registry for the Driver */
1351 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1352 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1353 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1355 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1362 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1363 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1366 file
= get_file_part( di
.pDriverPath
);
1367 RegSetValueExW( hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1368 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1370 file
= get_file_part( di
.pDataFile
);
1371 RegSetValueExW( hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1372 apd_copyfile( di
.pDataFile
, file
, &apd
);
1374 file
= get_file_part( di
.pConfigFile
);
1375 RegSetValueExW( hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1376 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1378 /* settings for level 3 */
1381 file
= get_file_part( di
.pHelpFile
);
1382 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1383 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1386 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
) );
1388 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1390 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1391 reg
= reg_ptr
= HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di
.pDependentFiles
) );
1393 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= strlenW( in_ptr
) + 1)
1395 file
= get_file_part( in_ptr
);
1396 len
= strlenW( file
) + 1;
1397 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1399 apd_copyfile( in_ptr
, file
, &apd
);
1403 RegSetValueExW( hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
1404 HeapFree( GetProcessHeap(), 0, reg
);
1407 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1409 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1410 if (di
.pMonitorName
)
1411 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1412 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1414 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1416 if (di
.pDefaultDataType
)
1417 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1418 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1420 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1422 /* settings for level 4 */
1423 if (di
.pszzPreviousNames
)
1424 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1425 multi_sz_lenW(di
.pszzPreviousNames
));
1427 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1429 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1432 hui
= driver_load(env
, di
.pConfigFile
);
1433 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1434 if (hui
&& pDrvDriverEvent
) {
1436 /* Support for DrvDriverEvent is optional */
1437 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1438 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1439 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1440 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1444 TRACE("=> TRUE with %u\n", GetLastError());
1449 /******************************************************************************
1450 * fpAddMonitor [exported through PRINTPROVIDOR]
1452 * Install a Printmonitor
1455 * pName [I] Servername or NULL (local Computer)
1456 * Level [I] Structure-Level (Must be 2)
1457 * pMonitors [I] PTR to MONITOR_INFO_2
1464 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1467 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1469 const printenv_t
* env
;
1470 monitor_t
* pm
= NULL
;
1471 LPMONITOR_INFO_2W mi2w
;
1477 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1478 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1479 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1480 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1481 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1483 if (copy_servername_from_name(pName
, NULL
)) {
1484 FIXME("server %s not supported\n", debugstr_w(pName
));
1485 SetLastError(ERROR_ACCESS_DENIED
);
1489 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1490 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1491 SetLastError(ERROR_INVALID_PARAMETER
);
1495 env
= validate_envW(mi2w
->pEnvironment
);
1497 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1499 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1500 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1501 SetLastError(ERROR_INVALID_PARAMETER
);
1505 /* Load and initialize the monitor. SetLastError() is called on failure */
1506 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
1511 SetLastError(ERROR_SUCCESS
); /* Monitor installer depends on this */
1513 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1514 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1518 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1519 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1520 &disposition
) == ERROR_SUCCESS
) {
1522 /* Some installers set options for the port before calling AddMonitor.
1523 We query the "Driver" entry to verify that the monitor is installed,
1524 before we return an error.
1525 When a user installs two print monitors at the same time with the
1526 same name, a race condition is possible but silently ignored. */
1530 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1531 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1532 &namesize
) == ERROR_SUCCESS
)) {
1533 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1534 /* 9x use ERROR_ALREADY_EXISTS */
1535 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1540 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1541 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1542 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1544 RegCloseKey(hentry
);
1551 /******************************************************************************
1552 * fpAddPort [exported through PRINTPROVIDOR]
1554 * Add a Port for a specific Monitor
1557 * pName [I] Servername or NULL (local Computer)
1558 * hWnd [I] Handle to parent Window for the Dialog-Box
1559 * pMonitorName [I] Name of the Monitor that manage the Port
1566 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1573 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1575 lres
= copy_servername_from_name(pName
, NULL
);
1577 FIXME("server %s not supported\n", debugstr_w(pName
));
1578 SetLastError(ERROR_INVALID_PARAMETER
);
1582 /* an empty Monitorname is Invalid */
1583 if (!pMonitorName
[0]) {
1584 SetLastError(ERROR_NOT_SUPPORTED
);
1588 pm
= monitor_load(pMonitorName
, NULL
);
1589 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1590 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1591 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1595 pui
= monitor_loadui(pm
);
1596 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1597 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1598 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1602 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1603 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1604 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1606 SetLastError(ERROR_NOT_SUPPORTED
);
1609 monitor_unload(pui
);
1613 TRACE("returning %d with %u\n", res
, GetLastError());
1617 /******************************************************************************
1618 * fpAddPortEx [exported through PRINTPROVIDOR]
1620 * Add a Port for a specific Monitor, without presenting a user interface
1623 * pName [I] Servername or NULL (local Computer)
1624 * level [I] Structure-Level (1 or 2) for pBuffer
1625 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1626 * pMonitorName [I] Name of the Monitor that manage the Port
1633 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1640 pi2
= (PORT_INFO_2W
*) pBuffer
;
1642 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1643 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1644 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1645 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1647 lres
= copy_servername_from_name(pName
, NULL
);
1649 FIXME("server %s not supported\n", debugstr_w(pName
));
1650 SetLastError(ERROR_INVALID_PARAMETER
);
1654 if ((level
< 1) || (level
> 2)) {
1655 SetLastError(ERROR_INVALID_LEVEL
);
1659 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1660 SetLastError(ERROR_INVALID_PARAMETER
);
1664 /* load the Monitor */
1665 pm
= monitor_load(pMonitorName
, NULL
);
1666 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1667 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1668 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1672 FIXME("not implemented for %s (monitor %p: %s)\n",
1673 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1674 SetLastError(ERROR_INVALID_PARAMETER
);
1681 /******************************************************************************
1682 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1684 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1687 * pName [I] Servername or NULL (local Computer)
1688 * level [I] Level for the supplied DRIVER_INFO_*W struct
1689 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1690 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1697 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1701 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1702 lres
= copy_servername_from_name(pName
, NULL
);
1704 FIXME("server %s not supported\n", debugstr_w(pName
));
1705 SetLastError(ERROR_ACCESS_DENIED
);
1709 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1710 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1713 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1716 /******************************************************************************
1717 * fpClosePrinter [exported through PRINTPROVIDOR]
1719 * Close a printer handle and free associated resources
1722 * hPrinter [I] Printerhandle to close
1729 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1731 printer_t
*printer
= (printer_t
*) hPrinter
;
1733 TRACE("(%p)\n", hPrinter
);
1736 printer_free(printer
);
1742 /******************************************************************************
1743 * fpConfigurePort [exported through PRINTPROVIDOR]
1745 * Display the Configuration-Dialog for a specific Port
1748 * pName [I] Servername or NULL (local Computer)
1749 * hWnd [I] Handle to parent Window for the Dialog-Box
1750 * pPortName [I] Name of the Port, that should be configured
1757 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1764 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1766 lres
= copy_servername_from_name(pName
, NULL
);
1768 FIXME("server %s not supported\n", debugstr_w(pName
));
1769 SetLastError(ERROR_INVALID_NAME
);
1773 /* an empty Portname is Invalid, but can popup a Dialog */
1774 if (!pPortName
[0]) {
1775 SetLastError(ERROR_NOT_SUPPORTED
);
1779 pm
= monitor_load_by_port(pPortName
);
1780 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1781 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1782 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1783 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1784 TRACE("got %d with %u\n", res
, GetLastError());
1788 pui
= monitor_loadui(pm
);
1789 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1790 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1791 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1792 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1793 TRACE("got %d with %u\n", res
, GetLastError());
1797 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1798 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1799 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1801 SetLastError(ERROR_NOT_SUPPORTED
);
1804 monitor_unload(pui
);
1808 TRACE("returning %d with %u\n", res
, GetLastError());
1812 /******************************************************************
1813 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1815 * Delete a specific Printmonitor from a Printing-Environment
1818 * pName [I] Servername or NULL (local Computer)
1819 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1820 * pMonitorName [I] Name of the Monitor, that should be deleted
1827 * pEnvironment is ignored in Windows for the local Computer.
1831 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1836 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1837 debugstr_w(pMonitorName
));
1839 lres
= copy_servername_from_name(pName
, NULL
);
1841 FIXME("server %s not supported\n", debugstr_w(pName
));
1842 SetLastError(ERROR_INVALID_NAME
);
1846 /* pEnvironment is ignored in Windows for the local Computer */
1847 if (!pMonitorName
|| !pMonitorName
[0]) {
1848 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1849 SetLastError(ERROR_INVALID_PARAMETER
);
1853 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1854 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1858 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1859 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1864 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1867 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1868 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1872 /*****************************************************************************
1873 * fpDeletePort [exported through PRINTPROVIDOR]
1875 * Delete a specific Port
1878 * pName [I] Servername or NULL (local Computer)
1879 * hWnd [I] Handle to parent Window for the Dialog-Box
1880 * pPortName [I] Name of the Port, that should be deleted
1887 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1894 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1896 lres
= copy_servername_from_name(pName
, NULL
);
1898 FIXME("server %s not supported\n", debugstr_w(pName
));
1899 SetLastError(ERROR_INVALID_NAME
);
1903 /* an empty Portname is Invalid */
1904 if (!pPortName
[0]) {
1905 SetLastError(ERROR_NOT_SUPPORTED
);
1909 pm
= monitor_load_by_port(pPortName
);
1910 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1911 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1912 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1913 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1914 TRACE("got %d with %u\n", res
, GetLastError());
1918 pui
= monitor_loadui(pm
);
1919 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1920 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1921 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1922 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1923 TRACE("got %d with %u\n", res
, GetLastError());
1927 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1928 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1929 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1931 SetLastError(ERROR_NOT_SUPPORTED
);
1934 monitor_unload(pui
);
1938 TRACE("returning %d with %u\n", res
, GetLastError());
1942 /*****************************************************************************
1943 * fpEnumMonitors [exported through PRINTPROVIDOR]
1945 * Enumerate available Port-Monitors
1948 * pName [I] Servername or NULL (local Computer)
1949 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1950 * pMonitors [O] PTR to Buffer that receives the Result
1951 * cbBuf [I] Size of Buffer at pMonitors
1952 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1953 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1957 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1960 * Windows reads the Registry once and cache the Results.
1963 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1964 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1966 DWORD numentries
= 0;
1971 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1972 cbBuf
, pcbNeeded
, pcReturned
);
1974 lres
= copy_servername_from_name(pName
, NULL
);
1976 FIXME("server %s not supported\n", debugstr_w(pName
));
1977 SetLastError(ERROR_INVALID_NAME
);
1981 if (!Level
|| (Level
> 2)) {
1982 WARN("level (%d) is ignored in win9x\n", Level
);
1983 SetLastError(ERROR_INVALID_LEVEL
);
1987 /* Scan all Monitor-Keys */
1989 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1991 /* we calculated the needed buffersize. now do more error-checks */
1992 if (cbBuf
< needed
) {
1993 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1997 /* fill the Buffer with the Monitor-Keys */
1998 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2002 if (pcbNeeded
) *pcbNeeded
= needed
;
2003 if (pcReturned
) *pcReturned
= numentries
;
2005 TRACE("returning %d with %d (%d byte for %d entries)\n",
2006 res
, GetLastError(), needed
, numentries
);
2011 /******************************************************************************
2012 * fpEnumPorts [exported through PRINTPROVIDOR]
2014 * Enumerate available Ports
2017 * pName [I] Servername or NULL (local Computer)
2018 * Level [I] Structure-Level (1 or 2)
2019 * pPorts [O] PTR to Buffer that receives the Result
2020 * cbBuf [I] Size of Buffer at pPorts
2021 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2022 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2026 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2029 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2030 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2033 DWORD numentries
= 0;
2037 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2038 cbBuf
, pcbNeeded
, pcReturned
);
2040 lres
= copy_servername_from_name(pName
, NULL
);
2042 FIXME("server %s not supported\n", debugstr_w(pName
));
2043 SetLastError(ERROR_INVALID_NAME
);
2047 if (!Level
|| (Level
> 2)) {
2048 SetLastError(ERROR_INVALID_LEVEL
);
2052 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2053 SetLastError(RPC_X_NULL_REF_POINTER
);
2057 EnterCriticalSection(&monitor_handles_cs
);
2060 /* Scan all local Ports */
2062 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2064 /* we calculated the needed buffersize. now do the error-checks */
2065 if (cbBuf
< needed
) {
2066 monitor_unloadall();
2067 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2068 goto emP_cleanup_cs
;
2070 else if (!pPorts
|| !pcReturned
) {
2071 monitor_unloadall();
2072 SetLastError(RPC_X_NULL_REF_POINTER
);
2073 goto emP_cleanup_cs
;
2076 /* Fill the Buffer */
2077 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2079 monitor_unloadall();
2082 LeaveCriticalSection(&monitor_handles_cs
);
2085 if (pcbNeeded
) *pcbNeeded
= needed
;
2086 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2088 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2089 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2094 /*****************************************************************************
2095 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2097 * Enumerate available Print Processors
2100 * pName [I] Servername or NULL (local Computer)
2101 * pEnvironment [I] Printing-Environment or NULL (Default)
2102 * Level [I] Structure-Level (Only 1 is allowed)
2103 * pPPInfo [O] PTR to Buffer that receives the Result
2104 * cbBuf [I] Size of Buffer at pMonitors
2105 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2106 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2110 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2113 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2114 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2116 const printenv_t
* env
;
2117 LPWSTR regpathW
= NULL
;
2118 DWORD numentries
= 0;
2123 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2124 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2126 lres
= copy_servername_from_name(pName
, NULL
);
2128 FIXME("server %s not supported\n", debugstr_w(pName
));
2129 SetLastError(ERROR_INVALID_NAME
);
2134 SetLastError(ERROR_INVALID_LEVEL
);
2138 env
= validate_envW(pEnvironment
);
2140 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2142 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2143 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2148 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2150 /* Scan all Printprocessor-Keys */
2152 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2154 /* we calculated the needed buffersize. now do more error-checks */
2155 if (cbBuf
< needed
) {
2156 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2160 /* fill the Buffer with the Printprocessor Infos */
2161 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2165 heap_free(regpathW
);
2166 if (pcbNeeded
) *pcbNeeded
= needed
;
2167 if (pcReturned
) *pcReturned
= numentries
;
2169 TRACE("returning %d with %d (%d byte for %d entries)\n",
2170 res
, GetLastError(), needed
, numentries
);
2175 /******************************************************************************
2176 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2178 * Return the PATH for the Print-Processors
2181 * pName [I] Servername or NULL (this computer)
2182 * pEnvironment [I] Printing-Environment or NULL (Default)
2183 * level [I] Structure-Level (must be 1)
2184 * pPPInfo [O] PTR to Buffer that receives the Result
2185 * cbBuf [I] Size of Buffer at pPPInfo
2186 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2190 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2192 * Native Values returned in pPPInfo on Success for this computer:
2193 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2194 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2195 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2197 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2200 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2201 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2203 const printenv_t
* env
;
2207 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2208 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2211 lres
= copy_servername_from_name(pName
, NULL
);
2213 FIXME("server %s not supported\n", debugstr_w(pName
));
2214 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2218 env
= validate_envW(pEnvironment
);
2220 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2222 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2223 needed
= GetSystemDirectoryW(NULL
, 0);
2224 /* add the Size for the Subdirectories */
2225 needed
+= lstrlenW(spoolprtprocsW
);
2226 needed
+= lstrlenW(env
->subdir
);
2227 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2229 *pcbNeeded
= needed
;
2231 if (needed
> cbBuf
) {
2232 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2236 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2237 /* add the Subdirectories */
2238 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2239 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2240 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2244 /******************************************************************************
2245 * fpOpenPrinter [exported through PRINTPROVIDOR]
2247 * Open a Printer / Printserver or a Printer-Object
2250 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2251 * pPrinter [O] The resulting Handle is stored here
2252 * pDefaults [I] PTR to Default Printer Settings or NULL
2259 * lpPrinterName is one of:
2260 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2261 *| Printer: "PrinterName"
2262 *| Printer-Object: "PrinterName,Job xxx"
2263 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2264 *| XcvPort: "Servername,XcvPort PortName"
2268 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2269 LPPRINTER_DEFAULTSW pDefaults
)
2272 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2274 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2276 return (*pPrinter
!= 0);
2279 /******************************************************************************
2280 * fpXcvData [exported through PRINTPROVIDOR]
2282 * Execute commands in the Printmonitor DLL
2285 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2286 * pszDataName [i] Name of the command to execute
2287 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2288 * cbInputData [i] Size in Bytes of Buffer at pInputData
2289 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2290 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2291 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2292 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2299 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2300 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2302 * Minimal List of commands, that a Printmonitor DLL should support:
2304 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2305 *| "AddPort" : Add a Port
2306 *| "DeletePort": Delete a Port
2308 * Many Printmonitors support additional commands. Examples for localspl.dll:
2309 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2310 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2313 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2314 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2315 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2317 printer_t
*printer
= (printer_t
* ) hXcv
;
2319 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2320 pInputData
, cbInputData
, pOutputData
,
2321 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2323 if (!printer
|| (!printer
->hXcv
)) {
2324 SetLastError(ERROR_INVALID_HANDLE
);
2328 if (!pcbOutputNeeded
) {
2329 SetLastError(ERROR_INVALID_PARAMETER
);
2333 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2334 SetLastError(RPC_X_NULL_REF_POINTER
);
2338 *pcbOutputNeeded
= 0;
2340 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2341 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2346 /*****************************************************
2347 * setup_provider [internal]
2349 void setup_provider(void)
2351 static const PRINTPROVIDOR backend
= {
2353 NULL
, /* fpSetJob */
2354 NULL
, /* fpGetJob */
2355 NULL
, /* fpEnumJobs */
2356 NULL
, /* fpAddPrinter */
2357 NULL
, /* fpDeletePrinter */
2358 NULL
, /* fpSetPrinter */
2359 NULL
, /* fpGetPrinter */
2360 NULL
, /* fpEnumPrinters */
2361 NULL
, /* fpAddPrinterDriver */
2362 NULL
, /* fpEnumPrinterDrivers */
2363 NULL
, /* fpGetPrinterDriver */
2364 fpGetPrinterDriverDirectory
,
2365 NULL
, /* fpDeletePrinterDriver */
2366 NULL
, /* fpAddPrintProcessor */
2367 fpEnumPrintProcessors
,
2368 fpGetPrintProcessorDirectory
,
2369 NULL
, /* fpDeletePrintProcessor */
2370 NULL
, /* fpEnumPrintProcessorDatatypes */
2371 NULL
, /* fpStartDocPrinter */
2372 NULL
, /* fpStartPagePrinter */
2373 NULL
, /* fpWritePrinter */
2374 NULL
, /* fpEndPagePrinter */
2375 NULL
, /* fpAbortPrinter */
2376 NULL
, /* fpReadPrinter */
2377 NULL
, /* fpEndDocPrinter */
2378 NULL
, /* fpAddJob */
2379 NULL
, /* fpScheduleJob */
2380 NULL
, /* fpGetPrinterData */
2381 NULL
, /* fpSetPrinterData */
2382 NULL
, /* fpWaitForPrinterChange */
2384 NULL
, /* fpAddForm */
2385 NULL
, /* fpDeleteForm */
2386 NULL
, /* fpGetForm */
2387 NULL
, /* fpSetForm */
2388 NULL
, /* fpEnumForms */
2394 NULL
, /* fpCreatePrinterIC */
2395 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2396 NULL
, /* fpDeletePrinterIC */
2397 NULL
, /* fpAddPrinterConnection */
2398 NULL
, /* fpDeletePrinterConnection */
2399 NULL
, /* fpPrinterMessageBox */
2402 NULL
, /* fpResetPrinter */
2403 NULL
, /* fpGetPrinterDriverEx */
2404 NULL
, /* fpFindFirstPrinterChangeNotification */
2405 NULL
, /* fpFindClosePrinterChangeNotification */
2407 NULL
, /* fpShutDown */
2408 NULL
, /* fpRefreshPrinterChangeNotification */
2409 NULL
, /* fpOpenPrinterEx */
2410 NULL
, /* fpAddPrinterEx */
2411 NULL
, /* fpSetPort */
2412 NULL
, /* fpEnumPrinterData */
2413 NULL
, /* fpDeletePrinterData */
2414 NULL
, /* fpClusterSplOpen */
2415 NULL
, /* fpClusterSplClose */
2416 NULL
, /* fpClusterSplIsAlive */
2417 NULL
, /* fpSetPrinterDataEx */
2418 NULL
, /* fpGetPrinterDataEx */
2419 NULL
, /* fpEnumPrinterDataEx */
2420 NULL
, /* fpEnumPrinterKey */
2421 NULL
, /* fpDeletePrinterDataEx */
2422 NULL
, /* fpDeletePrinterKey */
2423 NULL
, /* fpSeekPrinter */
2424 NULL
, /* fpDeletePrinterDriverEx */
2425 NULL
, /* fpAddPerMachineConnection */
2426 NULL
, /* fpDeletePerMachineConnection */
2427 NULL
, /* fpEnumPerMachineConnections */
2429 fpAddPrinterDriverEx
,
2430 NULL
, /* fpSplReadPrinter */
2431 NULL
, /* fpDriverUnloadComplete */
2432 NULL
, /* fpGetSpoolFileInfo */
2433 NULL
, /* fpCommitSpoolData */
2434 NULL
, /* fpCloseSpoolFileHandle */
2435 NULL
, /* fpFlushPrinter */
2436 NULL
, /* fpSendRecvBidiData */
2437 NULL
/* fpAddDriverCatalog */
2439 pprovider
= &backend
;
2443 /*****************************************************
2444 * InitializePrintProvidor (localspl.@)
2446 * Initialize the Printprovider
2449 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2450 * cbPrintProvidor [I] Size of Buffer in Bytes
2451 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2454 * Success: TRUE and pPrintProvidor filled
2458 * The RegistryPath should be:
2459 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2460 * but this Parameter is ignored in "localspl.dll".
2464 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2465 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2468 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2469 memcpy(pPrintProvidor
, pprovider
,
2470 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));