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/list.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "localspl_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(localspl
);
41 /* ############################### */
43 static CRITICAL_SECTION monitor_handles_cs
;
44 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
46 0, 0, &monitor_handles_cs
,
47 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
48 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
50 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
52 /* ############################### */
55 WCHAR src
[MAX_PATH
+MAX_PATH
];
56 WCHAR dst
[MAX_PATH
+MAX_PATH
];
78 LPCWSTR versionregpath
;
79 LPCWSTR versionsubdir
;
89 /* ############################### */
91 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
92 static monitor_t
* pm_localport
;
94 static const PRINTPROVIDOR
* pprovider
= NULL
;
96 static const WCHAR backslashW
[] = {'\\',0};
97 static const WCHAR bs_ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
98 static const WCHAR configuration_fileW
[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
99 static const WCHAR datatypeW
[] = {'D','a','t','a','t','y','p','e',0};
100 static const WCHAR data_fileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
101 static const WCHAR dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
102 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
103 static const WCHAR emptyW
[] = {0};
104 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
105 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
106 'c','o','n','t','r','o','l','\\',
107 'P','r','i','n','t','\\',
108 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
109 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
110 static const WCHAR fmt_printprocessorsW
[] = { 'S','y','s','t','e','m','\\',
111 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
112 'C','o','n','t','r','o','l','\\',
113 'P','r','i','n','t','\\',
114 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
115 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
116 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
117 static const WCHAR ia64_envnameW
[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
118 static const WCHAR ia64_subdirW
[] = {'i','a','6','4',0};
119 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
120 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
121 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
122 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
123 'C','o','n','t','r','o','l','\\',
124 'P','r','i','n','t','\\',
125 'M','o','n','i','t','o','r','s','\\',0};
126 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
127 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
128 static const WCHAR printersW
[] = {'S','y','s','t','e','m','\\',
129 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
130 'C','o','n','t','r','o','l','\\',
131 'P','r','i','n','t','\\',
132 'P','r','i','n','t','e','r','s',0};
133 static const WCHAR spoolW
[] = {'\\','s','p','o','o','l',0};
134 static const WCHAR driversW
[] = {'\\','d','r','i','v','e','r','s','\\',0};
135 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
136 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
137 static const WCHAR version0_subdirW
[] = {'\\','0',0};
138 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
139 static const WCHAR version3_subdirW
[] = {'\\','3',0};
140 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
141 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
142 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
143 static const WCHAR winnt_cv_portsW
[] = {'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'P','o','r','t','s',0};
148 static const WCHAR winprintW
[] = {'w','i','n','p','r','i','n','t',0};
149 static const WCHAR x64_envnameW
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
150 static const WCHAR x64_subdirW
[] = {'x','6','4',0};
151 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
152 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
153 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
154 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
157 static const printenv_t env_ia64
= {ia64_envnameW
, ia64_subdirW
, 3,
158 version3_regpathW
, version3_subdirW
};
160 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
161 version3_regpathW
, version3_subdirW
};
163 static const printenv_t env_x64
= {x64_envnameW
, x64_subdirW
, 3,
164 version3_regpathW
, version3_subdirW
};
166 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
167 version0_regpathW
, version0_subdirW
};
169 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_win40
};
172 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
173 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
174 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
175 0, sizeof(DRIVER_INFO_8W
)};
178 /******************************************************************
181 * create a copy of a unicode-string
184 static LPWSTR
strdupW(LPCWSTR p
)
190 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
191 ret
= heap_alloc(len
);
192 if (ret
) memcpy(ret
, p
, len
);
196 /******************************************************************
197 * apd_copyfile [internal]
199 * Copy a file from the driverdirectory to the versioned directory
206 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
211 apd
->src
[apd
->srclen
] = '\0';
212 apd
->dst
[apd
->dstlen
] = '\0';
214 if (!pathname
|| !pathname
[0]) {
215 /* nothing to copy */
219 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
224 strcatW( srcname
, file_part
);
226 strcatW( apd
->dst
, file_part
);
228 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
230 /* FIXME: handle APD_COPY_NEW_FILES */
231 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
232 TRACE("got %d with %u\n", res
, GetLastError());
234 return apd
->lazy
|| res
;
237 /******************************************************************
238 * copy_servername_from_name (internal)
240 * for an external server, the serverpart from the name is copied.
243 * the length (in WCHAR) of the serverpart (0 for the local computer)
244 * (-length), when the name is too long
247 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
251 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
255 if (target
) *target
= '\0';
257 if (name
== NULL
) return 0;
258 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
261 /* skip over both backslash, find separator '\' */
262 ptr
= strchrW(server
, '\\');
263 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
265 /* servername is empty */
266 if (serverlen
== 0) return 0;
268 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
270 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
273 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
274 target
[serverlen
] = '\0';
277 len
= sizeof(buffer
) / sizeof(buffer
[0]);
278 if (GetComputerNameW(buffer
, &len
)) {
279 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
280 /* The requested Servername is our computername */
287 /******************************************************************
288 * get_basename_from_name (internal)
290 * skip over the serverpart from the full name
293 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
295 if (name
== NULL
) return NULL
;
296 if ((name
[0] == '\\') && (name
[1] == '\\')) {
297 /* skip over the servername and search for the following '\' */
298 name
= strchrW(&name
[2], '\\');
299 if ((name
) && (name
[1])) {
300 /* found a separator ('\') followed by a name:
301 skip over the separator and return the rest */
306 /* no basename present (we found only a servername) */
313 /******************************************************************
314 * monitor_unload [internal]
316 * release a printmonitor and unload it from memory, when needed
319 static void monitor_unload(monitor_t
* pm
)
321 if (pm
== NULL
) return;
322 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
324 EnterCriticalSection(&monitor_handles_cs
);
326 if (pm
->refcount
) pm
->refcount
--;
328 if (pm
->refcount
== 0) {
329 list_remove(&pm
->entry
);
330 FreeLibrary(pm
->hdll
);
332 heap_free(pm
->dllname
);
335 LeaveCriticalSection(&monitor_handles_cs
);
338 /******************************************************************
339 * monitor_unloadall [internal]
341 * release all registered printmonitors and unload them from memory, when needed
345 static void monitor_unloadall(void)
350 EnterCriticalSection(&monitor_handles_cs
);
351 /* iterate through the list, with safety against removal */
352 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
354 /* skip monitorui dlls */
355 if (pm
->monitor
) monitor_unload(pm
);
357 LeaveCriticalSection(&monitor_handles_cs
);
360 /******************************************************************
361 * monitor_load [internal]
363 * load a printmonitor, get the dllname from the registry, when needed
364 * initialize the monitor and dump found function-pointers
366 * On failure, SetLastError() is called and NULL is returned
369 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
371 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
372 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
373 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
374 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
375 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
377 monitor_t
* pm
= NULL
;
379 LPWSTR regroot
= NULL
;
380 LPWSTR driver
= dllname
;
382 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
383 /* Is the Monitor already loaded? */
384 EnterCriticalSection(&monitor_handles_cs
);
387 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
389 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
397 pm
= heap_alloc_zero(sizeof(monitor_t
));
398 if (pm
== NULL
) goto cleanup
;
399 list_add_tail(&monitor_handles
, &pm
->entry
);
403 if (pm
->name
== NULL
) {
404 /* Load the monitor */
405 LPMONITOREX pmonitorEx
;
409 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
410 regroot
= heap_alloc(len
* sizeof(WCHAR
));
414 lstrcpyW(regroot
, monitorsW
);
415 lstrcatW(regroot
, name
);
416 /* Get the Driver from the Registry */
417 if (driver
== NULL
) {
420 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
421 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
422 &namesize
) == ERROR_SUCCESS
) {
423 driver
= heap_alloc(namesize
);
424 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
431 pm
->name
= strdupW(name
);
432 pm
->dllname
= strdupW(driver
);
434 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
436 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
441 pm
->hdll
= LoadLibraryW(driver
);
442 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
444 if (pm
->hdll
== NULL
) {
446 SetLastError(ERROR_MOD_NOT_FOUND
);
451 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
452 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
453 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
454 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
455 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
458 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
459 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
460 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
461 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
462 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
464 if (pInitializePrintMonitorUI
!= NULL
) {
465 pm
->monitorUI
= pInitializePrintMonitorUI();
466 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
468 TRACE("0x%08x: dwMonitorSize (%d)\n",
469 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
474 if (pInitializePrintMonitor
&& regroot
) {
475 pmonitorEx
= pInitializePrintMonitor(regroot
);
476 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
477 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
480 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
481 pm
->monitor
= &(pmonitorEx
->Monitor
);
486 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
490 if (!pm
->monitor
&& regroot
) {
491 if (pInitializePrintMonitor2
!= NULL
) {
492 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
494 if (pInitializeMonitorEx
!= NULL
) {
495 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
497 if (pInitializeMonitor
!= NULL
) {
498 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
501 if (!pm
->monitor
&& !pm
->monitorUI
) {
503 SetLastError(ERROR_PROC_NOT_FOUND
);
508 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
512 LeaveCriticalSection(&monitor_handles_cs
);
513 if (driver
!= dllname
) heap_free(driver
);
515 TRACE("=> %p\n", pm
);
519 /******************************************************************
520 * monitor_loadall [internal]
522 * Load all registered monitors
525 static DWORD
monitor_loadall(void)
528 DWORD registered
= 0;
531 WCHAR buffer
[MAX_PATH
];
534 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
535 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
536 NULL
, NULL
, NULL
, NULL
, NULL
);
538 TRACE("%d monitors registered\n", registered
);
540 while (id
< registered
) {
542 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
543 pm
= monitor_load(buffer
, NULL
);
547 RegCloseKey(hmonitors
);
549 TRACE("%d monitors loaded\n", loaded
);
553 /******************************************************************
554 * monitor_loadui [internal]
556 * load the userinterface-dll for a given portmonitor
558 * On failure, NULL is returned
560 static monitor_t
* monitor_loadui(monitor_t
* pm
)
562 monitor_t
* pui
= NULL
;
563 WCHAR buffer
[MAX_PATH
];
568 if (pm
== NULL
) return NULL
;
569 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
571 /* Try the Portmonitor first; works for many monitors */
573 EnterCriticalSection(&monitor_handles_cs
);
575 LeaveCriticalSection(&monitor_handles_cs
);
579 /* query the userinterface-dllname from the Portmonitor */
580 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
581 /* building (",XcvMonitor %s",pm->name) not needed yet */
582 res
= pm
->monitor
->pfnXcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
583 TRACE("got %u with %p\n", res
, hXcv
);
585 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
586 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
587 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
588 pm
->monitor
->pfnXcvClosePort(hXcv
);
594 /******************************************************************
595 * monitor_load_by_port [internal]
597 * load a printmonitor for a given port
599 * On failure, NULL is returned
602 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
607 monitor_t
* pm
= NULL
;
608 DWORD registered
= 0;
612 TRACE("(%s)\n", debugstr_w(portname
));
614 /* Try the Local Monitor first */
615 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
616 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
617 /* found the portname */
619 return monitor_load(localportW
, NULL
);
624 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
625 buffer
= heap_alloc(len
* sizeof(WCHAR
));
626 if (buffer
== NULL
) return NULL
;
628 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
629 EnterCriticalSection(&monitor_handles_cs
);
630 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
632 while ((pm
== NULL
) && (id
< registered
)) {
634 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
635 TRACE("testing %s\n", debugstr_w(buffer
));
636 len
= lstrlenW(buffer
);
637 lstrcatW(buffer
, bs_ports_bsW
);
638 lstrcatW(buffer
, portname
);
639 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
641 buffer
[len
] = '\0'; /* use only the Monitor-Name */
642 pm
= monitor_load(buffer
, NULL
);
646 LeaveCriticalSection(&monitor_handles_cs
);
653 /******************************************************************
654 * Return the number of bytes for an multi_sz string.
655 * The result includes all \0s
656 * (specifically the extra \0, that is needed as multi_sz terminator).
658 static int multi_sz_lenW(const WCHAR
*str
)
660 const WCHAR
*ptr
= str
;
664 ptr
+= lstrlenW(ptr
) + 1;
667 return (ptr
- str
+ 1) * sizeof(WCHAR
);
670 /******************************************************************
671 * validate_envW [internal]
673 * validate the user-supplied printing-environment
676 * env [I] PTR to Environment-String or NULL
679 * Success: PTR to printenv_t
680 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
683 * An empty string is handled the same way as NULL.
687 static const printenv_t
* validate_envW(LPCWSTR env
)
689 const printenv_t
*result
= NULL
;
692 TRACE("(%s)\n", debugstr_w(env
));
695 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
697 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
699 result
= all_printenv
[i
];
703 if (result
== NULL
) {
704 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
705 SetLastError(ERROR_INVALID_ENVIRONMENT
);
707 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
711 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
714 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
718 /*****************************************************************************
719 * enumerate the local monitors (INTERNAL)
721 * returns the needed size (in bytes) for pMonitors
722 * and *lpreturned is set to number of entries returned in pMonitors
724 * Language-Monitors are also installed in the same Registry-Location but
725 * they are filtered in Windows (not returned by EnumMonitors).
726 * We do no filtering to simplify our Code.
729 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
734 LPMONITOR_INFO_2W mi
;
735 WCHAR buffer
[MAX_PATH
];
736 WCHAR dllname
[MAX_PATH
];
744 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
746 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
747 len
= entrysize
* numentries
;
748 ptr
= (LPWSTR
) &pMonitors
[len
];
751 len
= sizeof(buffer
)/sizeof(buffer
[0]);
754 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
755 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
756 /* Scan all Monitor-Registry-Keys */
757 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
758 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
759 dllsize
= sizeof(dllname
);
762 /* The Monitor must have a Driver-DLL */
763 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
764 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
765 /* We found a valid DLL for this Monitor. */
766 TRACE("using Driver: %s\n", debugstr_w(dllname
));
771 /* Windows returns only Port-Monitors here, but to simplify our code,
772 we do no filtering for Language-Monitors */
776 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
778 /* we install and return only monitors for "Windows NT x86" */
779 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
783 /* required size is calculated. Now fill the user-buffer */
784 if (pMonitors
&& (cbBuf
>= needed
)){
785 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
786 pMonitors
+= entrysize
;
788 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
790 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
791 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
793 mi
->pEnvironment
= ptr
;
794 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
795 ptr
+= (lstrlenW(x86_envnameW
)+1);
798 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
799 ptr
+= (dllsize
/ sizeof(WCHAR
));
804 len
= sizeof(buffer
)/sizeof(buffer
[0]);
809 *lpreturned
= numentries
;
810 TRACE("need %d byte for %d entries\n", needed
, numentries
);
814 /*****************************************************************************
815 * enumerate the local print processors (INTERNAL)
817 * returns the needed size (in bytes) for pPPInfo
818 * and *lpreturned is set to number of entries returned in pPPInfo
821 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
826 PPRINTPROCESSOR_INFO_1W ppi
;
827 WCHAR buffer
[MAX_PATH
];
828 WCHAR dllname
[MAX_PATH
];
835 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
836 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
837 ptr
= (LPWSTR
) &pPPInfo
[len
];
840 len
= sizeof(buffer
)/sizeof(buffer
[0]);
843 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
844 /* add "winprint" first */
846 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(winprintW
);
847 if (pPPInfo
&& (cbBuf
>= needed
)){
848 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
849 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
851 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
853 lstrcpyW(ptr
, winprintW
); /* Name of the Print Processor */
854 ptr
+= sizeof(winprintW
) / sizeof(WCHAR
);
857 /* Scan all Printprocessor Keys */
858 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
859 (lstrcmpiW(buffer
, winprintW
) != 0)) {
860 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
861 dllsize
= sizeof(dllname
);
864 /* The Print Processor must have a Driver-DLL */
865 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
866 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
867 /* We found a valid DLL for this Print Processor */
868 TRACE("using Driver: %s\n", debugstr_w(dllname
));
875 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
876 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
878 /* required size is calculated. Now fill the user-buffer */
879 if (pPPInfo
&& (cbBuf
>= needed
)){
880 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
881 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
883 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
885 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
886 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
890 len
= sizeof(buffer
)/sizeof(buffer
[0]);
895 *lpreturned
= numentries
;
896 TRACE("need %d byte for %d entries\n", needed
, numentries
);
900 /******************************************************************
901 * enumerate the local Ports from all loaded monitors (internal)
903 * returns the needed size (in bytes) for pPorts
904 * and *lpreturned is set to number of entries returned in pPorts
907 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
911 LPPORT_INFO_2W cache
;
913 LPBYTE pi_buffer
= NULL
;
914 DWORD pi_allocated
= 0;
925 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
926 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
928 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
929 needed
= entrysize
* numentries
;
930 ptr
= (LPWSTR
) &pPorts
[needed
];
935 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
937 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
940 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
941 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
942 /* Do not use heap_realloc (we do not need the old data in the buffer) */
943 heap_free(pi_buffer
);
944 pi_buffer
= heap_alloc(pi_needed
);
945 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
946 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
948 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
949 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
951 numentries
+= pi_returned
;
954 /* fill the output-buffer (pPorts), if we have one */
955 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
957 while (pi_returned
> pi_index
) {
958 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
959 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
960 out
->pPortName
= ptr
;
961 lstrcpyW(ptr
, cache
->pPortName
);
962 ptr
+= (lstrlenW(ptr
)+1);
964 out
->pMonitorName
= ptr
;
965 lstrcpyW(ptr
, cache
->pMonitorName
);
966 ptr
+= (lstrlenW(ptr
)+1);
968 out
->pDescription
= ptr
;
969 lstrcpyW(ptr
, cache
->pDescription
);
970 ptr
+= (lstrlenW(ptr
)+1);
971 out
->fPortType
= cache
->fPortType
;
972 out
->Reserved
= cache
->Reserved
;
980 /* the temporary portinfo-buffer is no longer needed */
981 heap_free(pi_buffer
);
983 *lpreturned
= numentries
;
984 TRACE("need %d byte for %d entries\n", needed
, numentries
);
989 /*****************************************************************************
990 * open_driver_reg [internal]
992 * opens the registry for the printer drivers depending on the given input
993 * variable pEnvironment
996 * Success: the opened hkey
999 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1003 const printenv_t
* env
;
1005 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1007 env
= validate_envW(pEnvironment
);
1008 if (!env
) return NULL
;
1010 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
1011 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
1014 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1015 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1016 HeapFree(GetProcessHeap(), 0, buffer
);
1021 /*****************************************************************************
1022 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1024 * Return the PATH for the Printer-Drivers
1027 * pName [I] Servername (NT only) or NULL (local Computer)
1028 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1029 * Level [I] Structure-Level (must be 1)
1030 * pDriverDirectory [O] PTR to Buffer that receives the Result
1031 * cbBuf [I] Size of Buffer at pDriverDirectory
1032 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1033 * required for pDriverDirectory
1036 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1037 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1038 * if cbBuf is too small
1040 * Native Values returned in pDriverDirectory on Success:
1041 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1042 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1043 *| win9x(Windows 4.0): "%winsysdir%"
1045 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1048 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1049 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1052 const printenv_t
* env
;
1053 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1055 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1056 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1058 if (pName
!= NULL
&& pName
[0]) {
1059 FIXME("server %s not supported\n", debugstr_w(pName
));
1060 SetLastError(ERROR_INVALID_PARAMETER
);
1064 env
= validate_envW(pEnvironment
);
1065 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1068 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1069 needed
= GetSystemDirectoryW(NULL
, 0);
1070 /* add the Size for the Subdirectories */
1071 needed
+= lstrlenW(spoolW
);
1072 needed
+= lstrlenW(driversW
);
1073 needed
+= lstrlenW(env
->subdir
);
1074 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1076 *pcbNeeded
= needed
;
1078 if (needed
> cbBuf
) {
1079 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1084 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1085 SetLastError(ERROR_INVALID_USER_BUFFER
);
1089 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1090 /* add the Subdirectories */
1091 lstrcatW( dir
, spoolW
);
1092 CreateDirectoryW( dir
, NULL
);
1093 lstrcatW( dir
, driversW
);
1094 CreateDirectoryW( dir
, NULL
);
1095 lstrcatW( dir
, env
->subdir
);
1096 CreateDirectoryW( dir
, NULL
);
1098 TRACE( "=> %s\n", debugstr_w( dir
) );
1102 /******************************************************************
1103 * driver_load [internal]
1105 * load a driver user interface dll
1107 * On failure, NULL is returned
1111 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1113 WCHAR fullname
[MAX_PATH
];
1117 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1119 /* build the driverdir */
1120 len
= sizeof(fullname
) -
1121 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1123 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1124 (LPBYTE
) fullname
, len
, &len
)) {
1125 /* Should never fail */
1126 SetLastError(ERROR_BUFFER_OVERFLOW
);
1130 lstrcatW(fullname
, env
->versionsubdir
);
1131 lstrcatW(fullname
, backslashW
);
1132 lstrcatW(fullname
, dllname
);
1134 hui
= LoadLibraryW(fullname
);
1135 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1140 /******************************************************************
1142 * free the data pointer of an opened printer
1144 static VOID
printer_free(printer_t
* printer
)
1147 printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1149 monitor_unload(printer
->pm
);
1151 heap_free(printer
->printername
);
1152 heap_free(printer
->name
);
1156 /******************************************************************
1157 * printer_alloc_handle
1158 * alloc a printer handle and remember the data pointer in the printer handle table
1161 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1163 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1164 printer_t
*printer
= NULL
;
1165 LPCWSTR printername
;
1170 if (copy_servername_from_name(name
, servername
)) {
1171 FIXME("server %s not supported\n", debugstr_w(servername
));
1172 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1176 printername
= get_basename_from_name(name
);
1177 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1179 /* an empty printername is invalid */
1180 if (printername
&& (!printername
[0])) {
1181 SetLastError(ERROR_INVALID_PARAMETER
);
1185 printer
= heap_alloc_zero(sizeof(printer_t
));
1186 if (!printer
) goto end
;
1188 /* clone the base name. This is NULL for the printserver */
1189 printer
->printername
= strdupW(printername
);
1191 /* clone the full name */
1192 printer
->name
= strdupW(name
);
1193 if (name
&& (!printer
->name
)) {
1194 printer_free(printer
);
1198 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1199 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1200 /* OpenPrinter(",XcvMonitor ", ...) detected */
1201 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1202 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1203 if (printer
->pm
== NULL
) {
1204 printer_free(printer
);
1205 SetLastError(ERROR_UNKNOWN_PORT
);
1212 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1213 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1214 /* OpenPrinter(",XcvPort ", ...) detected */
1215 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1216 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1217 if (printer
->pm
== NULL
) {
1218 printer_free(printer
);
1219 SetLastError(ERROR_UNKNOWN_PORT
);
1227 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1228 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1229 pDefault
? pDefault
->DesiredAccess
: 0,
1232 if (printer
->hXcv
== NULL
) {
1233 printer_free(printer
);
1234 SetLastError(ERROR_INVALID_PARAMETER
);
1241 /* Does the Printer exist? */
1242 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1243 ERR("Can't create Printers key\n");
1244 printer_free(printer
);
1245 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1249 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1250 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1251 RegCloseKey(hkeyPrinters
);
1252 printer_free(printer
);
1253 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1257 RegCloseKey(hkeyPrinter
);
1258 RegCloseKey(hkeyPrinters
);
1263 TRACE("using the local printserver\n");
1268 TRACE("==> %p\n", printer
);
1269 return (HANDLE
)printer
;
1272 static inline WCHAR
*get_file_part( WCHAR
*name
)
1274 WCHAR
*ptr
= strrchrW( name
, '\\' );
1275 if (ptr
) return ptr
+ 1;
1279 /******************************************************************************
1280 * myAddPrinterDriverEx [internal]
1282 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1283 * and a special mode with lazy error checking.
1286 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1288 const printenv_t
*env
;
1291 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1301 /* we need to set all entries in the Registry, independent from the Level of
1302 DRIVER_INFO, that the caller supplied */
1304 ZeroMemory(&di
, sizeof(di
));
1305 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
1306 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1309 /* dump the most used infos */
1310 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1311 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1312 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1313 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1314 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1315 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1316 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1317 /* dump only the first of the additional Files */
1318 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1321 /* check environment */
1322 env
= validate_envW(di
.pEnvironment
);
1323 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1325 /* fill the copy-data / get the driverdir */
1326 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1327 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1328 (LPBYTE
) apd
.src
, len
, &len
)) {
1329 /* Should never fail */
1332 memcpy(apd
.dst
, apd
.src
, len
);
1333 lstrcatW(apd
.src
, backslashW
);
1334 apd
.srclen
= lstrlenW(apd
.src
);
1335 lstrcatW(apd
.dst
, env
->versionsubdir
);
1336 lstrcatW(apd
.dst
, backslashW
);
1337 apd
.dstlen
= lstrlenW(apd
.dst
);
1338 apd
.copyflags
= dwFileCopyFlags
;
1340 CreateDirectoryW(apd
.src
, NULL
);
1341 CreateDirectoryW(apd
.dst
, NULL
);
1343 hroot
= open_driver_reg(env
->envname
);
1345 ERR("Can't create Drivers key\n");
1349 /* Fill the Registry for the Driver */
1350 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1351 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1352 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1354 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1361 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1362 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1365 file
= get_file_part( di
.pDriverPath
);
1366 RegSetValueExW( hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1367 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1369 file
= get_file_part( di
.pDataFile
);
1370 RegSetValueExW( hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1371 apd_copyfile( di
.pDataFile
, file
, &apd
);
1373 file
= get_file_part( di
.pConfigFile
);
1374 RegSetValueExW( hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1375 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1377 /* settings for level 3 */
1380 file
= get_file_part( di
.pHelpFile
);
1381 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1382 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1385 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
) );
1387 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1389 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1390 reg
= reg_ptr
= HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di
.pDependentFiles
) );
1392 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= strlenW( in_ptr
) + 1)
1394 file
= get_file_part( in_ptr
);
1395 len
= strlenW( file
) + 1;
1396 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1398 apd_copyfile( in_ptr
, file
, &apd
);
1402 RegSetValueExW( hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
1403 HeapFree( GetProcessHeap(), 0, reg
);
1406 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1408 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1409 if (di
.pMonitorName
)
1410 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1411 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1413 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1415 if (di
.pDefaultDataType
)
1416 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1417 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1419 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1421 /* settings for level 4 */
1422 if (di
.pszzPreviousNames
)
1423 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1424 multi_sz_lenW(di
.pszzPreviousNames
));
1426 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1428 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1431 hui
= driver_load(env
, di
.pConfigFile
);
1432 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1433 if (hui
&& pDrvDriverEvent
) {
1435 /* Support for DrvDriverEvent is optional */
1436 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1437 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1438 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1439 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1443 TRACE("=> TRUE with %u\n", GetLastError());
1448 /******************************************************************************
1449 * fpAddMonitor [exported through PRINTPROVIDOR]
1451 * Install a Printmonitor
1454 * pName [I] Servername or NULL (local Computer)
1455 * Level [I] Structure-Level (Must be 2)
1456 * pMonitors [I] PTR to MONITOR_INFO_2
1463 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1466 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1468 const printenv_t
* env
;
1469 monitor_t
* pm
= NULL
;
1470 LPMONITOR_INFO_2W mi2w
;
1476 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1477 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1478 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1479 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1480 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1482 if (copy_servername_from_name(pName
, NULL
)) {
1483 FIXME("server %s not supported\n", debugstr_w(pName
));
1484 SetLastError(ERROR_ACCESS_DENIED
);
1488 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1489 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1490 SetLastError(ERROR_INVALID_PARAMETER
);
1494 env
= validate_envW(mi2w
->pEnvironment
);
1496 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1498 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1499 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1500 SetLastError(ERROR_INVALID_PARAMETER
);
1504 /* Load and initialize the monitor. SetLastError() is called on failure */
1505 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
1510 SetLastError(ERROR_SUCCESS
); /* Monitor installer depends on this */
1512 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1513 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1517 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1518 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1519 &disposition
) == ERROR_SUCCESS
) {
1521 /* Some installers set options for the port before calling AddMonitor.
1522 We query the "Driver" entry to verify that the monitor is installed,
1523 before we return an error.
1524 When a user installs two print monitors at the same time with the
1525 same name, a race condition is possible but silently ignored. */
1529 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1530 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1531 &namesize
) == ERROR_SUCCESS
)) {
1532 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1533 /* 9x use ERROR_ALREADY_EXISTS */
1534 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1539 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1540 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1541 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1543 RegCloseKey(hentry
);
1550 /******************************************************************************
1551 * fpAddPort [exported through PRINTPROVIDOR]
1553 * Add a Port for a specific Monitor
1556 * pName [I] Servername or NULL (local Computer)
1557 * hWnd [I] Handle to parent Window for the Dialog-Box
1558 * pMonitorName [I] Name of the Monitor that manage the Port
1565 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1572 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1574 lres
= copy_servername_from_name(pName
, NULL
);
1576 FIXME("server %s not supported\n", debugstr_w(pName
));
1577 SetLastError(ERROR_INVALID_PARAMETER
);
1581 /* an empty Monitorname is Invalid */
1582 if (!pMonitorName
[0]) {
1583 SetLastError(ERROR_NOT_SUPPORTED
);
1587 pm
= monitor_load(pMonitorName
, NULL
);
1588 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1589 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1590 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1594 pui
= monitor_loadui(pm
);
1595 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1596 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1597 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1601 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1602 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1603 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1605 SetLastError(ERROR_NOT_SUPPORTED
);
1608 monitor_unload(pui
);
1612 TRACE("returning %d with %u\n", res
, GetLastError());
1616 /******************************************************************************
1617 * fpAddPortEx [exported through PRINTPROVIDOR]
1619 * Add a Port for a specific Monitor, without presenting a user interface
1622 * pName [I] Servername or NULL (local Computer)
1623 * level [I] Structure-Level (1 or 2) for pBuffer
1624 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1625 * pMonitorName [I] Name of the Monitor that manage the Port
1632 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1639 pi2
= (PORT_INFO_2W
*) pBuffer
;
1641 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1642 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1643 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1644 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1646 lres
= copy_servername_from_name(pName
, NULL
);
1648 FIXME("server %s not supported\n", debugstr_w(pName
));
1649 SetLastError(ERROR_INVALID_PARAMETER
);
1653 if ((level
< 1) || (level
> 2)) {
1654 SetLastError(ERROR_INVALID_LEVEL
);
1658 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1659 SetLastError(ERROR_INVALID_PARAMETER
);
1663 /* load the Monitor */
1664 pm
= monitor_load(pMonitorName
, NULL
);
1665 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1666 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1667 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1671 FIXME("not implemented for %s (monitor %p: %s)\n",
1672 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1673 SetLastError(ERROR_INVALID_PARAMETER
);
1680 /******************************************************************************
1681 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1683 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1686 * pName [I] Servername or NULL (local Computer)
1687 * level [I] Level for the supplied DRIVER_INFO_*W struct
1688 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1689 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1696 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1700 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1701 lres
= copy_servername_from_name(pName
, NULL
);
1703 FIXME("server %s not supported\n", debugstr_w(pName
));
1704 SetLastError(ERROR_ACCESS_DENIED
);
1708 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1709 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1712 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1715 /******************************************************************************
1716 * fpClosePrinter [exported through PRINTPROVIDOR]
1718 * Close a printer handle and free associated resources
1721 * hPrinter [I] Printerhandle to close
1728 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1730 printer_t
*printer
= (printer_t
*) hPrinter
;
1732 TRACE("(%p)\n", hPrinter
);
1735 printer_free(printer
);
1741 /******************************************************************************
1742 * fpConfigurePort [exported through PRINTPROVIDOR]
1744 * Display the Configuration-Dialog for a specific Port
1747 * pName [I] Servername or NULL (local Computer)
1748 * hWnd [I] Handle to parent Window for the Dialog-Box
1749 * pPortName [I] Name of the Port, that should be configured
1756 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1763 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1765 lres
= copy_servername_from_name(pName
, NULL
);
1767 FIXME("server %s not supported\n", debugstr_w(pName
));
1768 SetLastError(ERROR_INVALID_NAME
);
1772 /* an empty Portname is Invalid, but can popup a Dialog */
1773 if (!pPortName
[0]) {
1774 SetLastError(ERROR_NOT_SUPPORTED
);
1778 pm
= monitor_load_by_port(pPortName
);
1779 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1780 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1781 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1782 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1783 TRACE("got %d with %u\n", res
, GetLastError());
1787 pui
= monitor_loadui(pm
);
1788 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1789 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1790 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1791 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1792 TRACE("got %d with %u\n", res
, GetLastError());
1796 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1797 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1798 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1800 SetLastError(ERROR_NOT_SUPPORTED
);
1803 monitor_unload(pui
);
1807 TRACE("returning %d with %u\n", res
, GetLastError());
1811 /******************************************************************
1812 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1814 * Delete a specific Printmonitor from a Printing-Environment
1817 * pName [I] Servername or NULL (local Computer)
1818 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1819 * pMonitorName [I] Name of the Monitor, that should be deleted
1826 * pEnvironment is ignored in Windows for the local Computer.
1830 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1835 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1836 debugstr_w(pMonitorName
));
1838 lres
= copy_servername_from_name(pName
, NULL
);
1840 FIXME("server %s not supported\n", debugstr_w(pName
));
1841 SetLastError(ERROR_INVALID_NAME
);
1845 /* pEnvironment is ignored in Windows for the local Computer */
1846 if (!pMonitorName
|| !pMonitorName
[0]) {
1847 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1848 SetLastError(ERROR_INVALID_PARAMETER
);
1852 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1853 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1857 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1858 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1863 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1866 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1867 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1871 /*****************************************************************************
1872 * fpDeletePort [exported through PRINTPROVIDOR]
1874 * Delete a specific Port
1877 * pName [I] Servername or NULL (local Computer)
1878 * hWnd [I] Handle to parent Window for the Dialog-Box
1879 * pPortName [I] Name of the Port, that should be deleted
1886 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1893 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1895 lres
= copy_servername_from_name(pName
, NULL
);
1897 FIXME("server %s not supported\n", debugstr_w(pName
));
1898 SetLastError(ERROR_INVALID_NAME
);
1902 /* an empty Portname is Invalid */
1903 if (!pPortName
[0]) {
1904 SetLastError(ERROR_NOT_SUPPORTED
);
1908 pm
= monitor_load_by_port(pPortName
);
1909 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1910 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1911 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1912 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1913 TRACE("got %d with %u\n", res
, GetLastError());
1917 pui
= monitor_loadui(pm
);
1918 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1919 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1920 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1921 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1922 TRACE("got %d with %u\n", res
, GetLastError());
1926 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1927 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1928 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1930 SetLastError(ERROR_NOT_SUPPORTED
);
1933 monitor_unload(pui
);
1937 TRACE("returning %d with %u\n", res
, GetLastError());
1941 /*****************************************************************************
1942 * fpEnumMonitors [exported through PRINTPROVIDOR]
1944 * Enumerate available Port-Monitors
1947 * pName [I] Servername or NULL (local Computer)
1948 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1949 * pMonitors [O] PTR to Buffer that receives the Result
1950 * cbBuf [I] Size of Buffer at pMonitors
1951 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1952 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1956 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1959 * Windows reads the Registry once and cache the Results.
1962 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1963 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1965 DWORD numentries
= 0;
1970 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1971 cbBuf
, pcbNeeded
, pcReturned
);
1973 lres
= copy_servername_from_name(pName
, NULL
);
1975 FIXME("server %s not supported\n", debugstr_w(pName
));
1976 SetLastError(ERROR_INVALID_NAME
);
1980 if (!Level
|| (Level
> 2)) {
1981 WARN("level (%d) is ignored in win9x\n", Level
);
1982 SetLastError(ERROR_INVALID_LEVEL
);
1986 /* Scan all Monitor-Keys */
1988 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1990 /* we calculated the needed buffersize. now do more error-checks */
1991 if (cbBuf
< needed
) {
1992 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1996 /* fill the Buffer with the Monitor-Keys */
1997 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2001 if (pcbNeeded
) *pcbNeeded
= needed
;
2002 if (pcReturned
) *pcReturned
= numentries
;
2004 TRACE("returning %d with %d (%d byte for %d entries)\n",
2005 res
, GetLastError(), needed
, numentries
);
2010 /******************************************************************************
2011 * fpEnumPorts [exported through PRINTPROVIDOR]
2013 * Enumerate available Ports
2016 * pName [I] Servername or NULL (local Computer)
2017 * Level [I] Structure-Level (1 or 2)
2018 * pPorts [O] PTR to Buffer that receives the Result
2019 * cbBuf [I] Size of Buffer at pPorts
2020 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2021 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2025 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2028 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2029 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2032 DWORD numentries
= 0;
2036 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2037 cbBuf
, pcbNeeded
, pcReturned
);
2039 lres
= copy_servername_from_name(pName
, NULL
);
2041 FIXME("server %s not supported\n", debugstr_w(pName
));
2042 SetLastError(ERROR_INVALID_NAME
);
2046 if (!Level
|| (Level
> 2)) {
2047 SetLastError(ERROR_INVALID_LEVEL
);
2051 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2052 SetLastError(RPC_X_NULL_REF_POINTER
);
2056 EnterCriticalSection(&monitor_handles_cs
);
2059 /* Scan all local Ports */
2061 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2063 /* we calculated the needed buffersize. now do the error-checks */
2064 if (cbBuf
< needed
) {
2065 monitor_unloadall();
2066 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2067 goto emP_cleanup_cs
;
2069 else if (!pPorts
|| !pcReturned
) {
2070 monitor_unloadall();
2071 SetLastError(RPC_X_NULL_REF_POINTER
);
2072 goto emP_cleanup_cs
;
2075 /* Fill the Buffer */
2076 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2078 monitor_unloadall();
2081 LeaveCriticalSection(&monitor_handles_cs
);
2084 if (pcbNeeded
) *pcbNeeded
= needed
;
2085 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2087 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2088 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2093 /*****************************************************************************
2094 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2096 * Enumerate available Print Processors
2099 * pName [I] Servername or NULL (local Computer)
2100 * pEnvironment [I] Printing-Environment or NULL (Default)
2101 * Level [I] Structure-Level (Only 1 is allowed)
2102 * pPPInfo [O] PTR to Buffer that receives the Result
2103 * cbBuf [I] Size of Buffer at pMonitors
2104 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2105 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2109 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2112 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2113 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2115 const printenv_t
* env
;
2116 LPWSTR regpathW
= NULL
;
2117 DWORD numentries
= 0;
2122 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2123 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2125 lres
= copy_servername_from_name(pName
, NULL
);
2127 FIXME("server %s not supported\n", debugstr_w(pName
));
2128 SetLastError(ERROR_INVALID_NAME
);
2133 SetLastError(ERROR_INVALID_LEVEL
);
2137 env
= validate_envW(pEnvironment
);
2139 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2141 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2142 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2147 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2149 /* Scan all Printprocessor-Keys */
2151 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2153 /* we calculated the needed buffersize. now do more error-checks */
2154 if (cbBuf
< needed
) {
2155 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2159 /* fill the Buffer with the Printprocessor Infos */
2160 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2164 heap_free(regpathW
);
2165 if (pcbNeeded
) *pcbNeeded
= needed
;
2166 if (pcReturned
) *pcReturned
= numentries
;
2168 TRACE("returning %d with %d (%d byte for %d entries)\n",
2169 res
, GetLastError(), needed
, numentries
);
2174 /******************************************************************************
2175 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2177 * Return the PATH for the Print-Processors
2180 * pName [I] Servername or NULL (this computer)
2181 * pEnvironment [I] Printing-Environment or NULL (Default)
2182 * level [I] Structure-Level (must be 1)
2183 * pPPInfo [O] PTR to Buffer that receives the Result
2184 * cbBuf [I] Size of Buffer at pPPInfo
2185 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2189 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2191 * Native Values returned in pPPInfo on Success for this computer:
2192 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2193 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2194 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2196 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2199 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2200 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2202 const printenv_t
* env
;
2206 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2207 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2210 lres
= copy_servername_from_name(pName
, NULL
);
2212 FIXME("server %s not supported\n", debugstr_w(pName
));
2213 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2217 env
= validate_envW(pEnvironment
);
2219 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2221 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2222 needed
= GetSystemDirectoryW(NULL
, 0);
2223 /* add the Size for the Subdirectories */
2224 needed
+= lstrlenW(spoolprtprocsW
);
2225 needed
+= lstrlenW(env
->subdir
);
2226 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2228 *pcbNeeded
= needed
;
2230 if (needed
> cbBuf
) {
2231 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2235 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2236 /* add the Subdirectories */
2237 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2238 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2239 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2243 /******************************************************************************
2244 * fpOpenPrinter [exported through PRINTPROVIDOR]
2246 * Open a Printer / Printserver or a Printer-Object
2249 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2250 * pPrinter [O] The resulting Handle is stored here
2251 * pDefaults [I] PTR to Default Printer Settings or NULL
2258 * lpPrinterName is one of:
2259 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2260 *| Printer: "PrinterName"
2261 *| Printer-Object: "PrinterName,Job xxx"
2262 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2263 *| XcvPort: "Servername,XcvPort PortName"
2267 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2268 LPPRINTER_DEFAULTSW pDefaults
)
2271 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2273 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2275 return (*pPrinter
!= 0);
2278 /******************************************************************************
2279 * fpXcvData [exported through PRINTPROVIDOR]
2281 * Execute commands in the Printmonitor DLL
2284 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2285 * pszDataName [i] Name of the command to execute
2286 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2287 * cbInputData [i] Size in Bytes of Buffer at pInputData
2288 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2289 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2290 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2291 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2298 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2299 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2301 * Minimal List of commands, that a Printmonitor DLL should support:
2303 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2304 *| "AddPort" : Add a Port
2305 *| "DeletePort": Delete a Port
2307 * Many Printmonitors support additional commands. Examples for localspl.dll:
2308 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2309 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2312 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2313 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2314 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2316 printer_t
*printer
= (printer_t
* ) hXcv
;
2318 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2319 pInputData
, cbInputData
, pOutputData
,
2320 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2322 if (!printer
|| (!printer
->hXcv
)) {
2323 SetLastError(ERROR_INVALID_HANDLE
);
2327 if (!pcbOutputNeeded
) {
2328 SetLastError(ERROR_INVALID_PARAMETER
);
2332 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2333 SetLastError(RPC_X_NULL_REF_POINTER
);
2337 *pcbOutputNeeded
= 0;
2339 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2340 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2345 /*****************************************************
2346 * setup_provider [internal]
2348 void setup_provider(void)
2350 static const PRINTPROVIDOR backend
= {
2352 NULL
, /* fpSetJob */
2353 NULL
, /* fpGetJob */
2354 NULL
, /* fpEnumJobs */
2355 NULL
, /* fpAddPrinter */
2356 NULL
, /* fpDeletePrinter */
2357 NULL
, /* fpSetPrinter */
2358 NULL
, /* fpGetPrinter */
2359 NULL
, /* fpEnumPrinters */
2360 NULL
, /* fpAddPrinterDriver */
2361 NULL
, /* fpEnumPrinterDrivers */
2362 NULL
, /* fpGetPrinterDriver */
2363 fpGetPrinterDriverDirectory
,
2364 NULL
, /* fpDeletePrinterDriver */
2365 NULL
, /* fpAddPrintProcessor */
2366 fpEnumPrintProcessors
,
2367 fpGetPrintProcessorDirectory
,
2368 NULL
, /* fpDeletePrintProcessor */
2369 NULL
, /* fpEnumPrintProcessorDatatypes */
2370 NULL
, /* fpStartDocPrinter */
2371 NULL
, /* fpStartPagePrinter */
2372 NULL
, /* fpWritePrinter */
2373 NULL
, /* fpEndPagePrinter */
2374 NULL
, /* fpAbortPrinter */
2375 NULL
, /* fpReadPrinter */
2376 NULL
, /* fpEndDocPrinter */
2377 NULL
, /* fpAddJob */
2378 NULL
, /* fpScheduleJob */
2379 NULL
, /* fpGetPrinterData */
2380 NULL
, /* fpSetPrinterData */
2381 NULL
, /* fpWaitForPrinterChange */
2383 NULL
, /* fpAddForm */
2384 NULL
, /* fpDeleteForm */
2385 NULL
, /* fpGetForm */
2386 NULL
, /* fpSetForm */
2387 NULL
, /* fpEnumForms */
2393 NULL
, /* fpCreatePrinterIC */
2394 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2395 NULL
, /* fpDeletePrinterIC */
2396 NULL
, /* fpAddPrinterConnection */
2397 NULL
, /* fpDeletePrinterConnection */
2398 NULL
, /* fpPrinterMessageBox */
2401 NULL
, /* fpResetPrinter */
2402 NULL
, /* fpGetPrinterDriverEx */
2403 NULL
, /* fpFindFirstPrinterChangeNotification */
2404 NULL
, /* fpFindClosePrinterChangeNotification */
2406 NULL
, /* fpShutDown */
2407 NULL
, /* fpRefreshPrinterChangeNotification */
2408 NULL
, /* fpOpenPrinterEx */
2409 NULL
, /* fpAddPrinterEx */
2410 NULL
, /* fpSetPort */
2411 NULL
, /* fpEnumPrinterData */
2412 NULL
, /* fpDeletePrinterData */
2413 NULL
, /* fpClusterSplOpen */
2414 NULL
, /* fpClusterSplClose */
2415 NULL
, /* fpClusterSplIsAlive */
2416 NULL
, /* fpSetPrinterDataEx */
2417 NULL
, /* fpGetPrinterDataEx */
2418 NULL
, /* fpEnumPrinterDataEx */
2419 NULL
, /* fpEnumPrinterKey */
2420 NULL
, /* fpDeletePrinterDataEx */
2421 NULL
, /* fpDeletePrinterKey */
2422 NULL
, /* fpSeekPrinter */
2423 NULL
, /* fpDeletePrinterDriverEx */
2424 NULL
, /* fpAddPerMachineConnection */
2425 NULL
, /* fpDeletePerMachineConnection */
2426 NULL
, /* fpEnumPerMachineConnections */
2428 fpAddPrinterDriverEx
,
2429 NULL
, /* fpSplReadPrinter */
2430 NULL
, /* fpDriverUnloadComplete */
2431 NULL
, /* fpGetSpoolFileInfo */
2432 NULL
, /* fpCommitSpoolData */
2433 NULL
, /* fpCloseSpoolFileHandle */
2434 NULL
, /* fpFlushPrinter */
2435 NULL
, /* fpSendRecvBidiData */
2436 NULL
/* fpAddDriverCatalog */
2438 pprovider
= &backend
;
2442 /*****************************************************
2443 * InitializePrintProvidor (localspl.@)
2445 * Initialize the Printprovider
2448 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2449 * cbPrintProvidor [I] Size of Buffer in Bytes
2450 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2453 * Success: TRUE and pPrintProvidor filled
2457 * The RegistryPath should be:
2458 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2459 * but this Parameter is ignored in "localspl.dll".
2463 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2464 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2467 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2468 memcpy(pPrintProvidor
, pprovider
,
2469 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));