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 monitor_t
* pm
= NULL
;
1469 LPMONITOR_INFO_2W mi2w
;
1475 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1476 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1477 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1478 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1479 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1481 if (copy_servername_from_name(pName
, NULL
)) {
1482 FIXME("server %s not supported\n", debugstr_w(pName
));
1483 SetLastError(ERROR_ACCESS_DENIED
);
1487 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1488 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1489 SetLastError(ERROR_INVALID_PARAMETER
);
1492 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
1493 WARN("Environment %s requested (we support only %s)\n",
1494 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
1495 SetLastError(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 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1512 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1516 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1517 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1518 &disposition
) == ERROR_SUCCESS
) {
1520 /* Some installers set options for the port before calling AddMonitor.
1521 We query the "Driver" entry to verify that the monitor is installed,
1522 before we return an error.
1523 When a user installs two print monitors at the same time with the
1524 same name, a race condition is possible but silently ignored. */
1528 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1529 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1530 &namesize
) == ERROR_SUCCESS
)) {
1531 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1532 /* 9x use ERROR_ALREADY_EXISTS */
1533 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1538 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1539 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1540 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1542 RegCloseKey(hentry
);
1549 /******************************************************************************
1550 * fpAddPort [exported through PRINTPROVIDOR]
1552 * Add a Port for a specific Monitor
1555 * pName [I] Servername or NULL (local Computer)
1556 * hWnd [I] Handle to parent Window for the Dialog-Box
1557 * pMonitorName [I] Name of the Monitor that manage the Port
1564 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1571 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1573 lres
= copy_servername_from_name(pName
, NULL
);
1575 FIXME("server %s not supported\n", debugstr_w(pName
));
1576 SetLastError(ERROR_INVALID_PARAMETER
);
1580 /* an empty Monitorname is Invalid */
1581 if (!pMonitorName
[0]) {
1582 SetLastError(ERROR_NOT_SUPPORTED
);
1586 pm
= monitor_load(pMonitorName
, NULL
);
1587 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1588 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1589 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1593 pui
= monitor_loadui(pm
);
1594 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1595 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1596 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1600 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1601 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1602 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1604 SetLastError(ERROR_NOT_SUPPORTED
);
1607 monitor_unload(pui
);
1611 TRACE("returning %d with %u\n", res
, GetLastError());
1615 /******************************************************************************
1616 * fpAddPortEx [exported through PRINTPROVIDOR]
1618 * Add a Port for a specific Monitor, without presenting a user interface
1621 * pName [I] Servername or NULL (local Computer)
1622 * level [I] Structure-Level (1 or 2) for pBuffer
1623 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1624 * pMonitorName [I] Name of the Monitor that manage the Port
1631 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1638 pi2
= (PORT_INFO_2W
*) pBuffer
;
1640 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1641 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1642 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1643 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1645 lres
= copy_servername_from_name(pName
, NULL
);
1647 FIXME("server %s not supported\n", debugstr_w(pName
));
1648 SetLastError(ERROR_INVALID_PARAMETER
);
1652 if ((level
< 1) || (level
> 2)) {
1653 SetLastError(ERROR_INVALID_LEVEL
);
1657 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1658 SetLastError(ERROR_INVALID_PARAMETER
);
1662 /* load the Monitor */
1663 pm
= monitor_load(pMonitorName
, NULL
);
1664 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1665 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1666 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1670 FIXME("not implemented for %s (monitor %p: %s)\n",
1671 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1672 SetLastError(ERROR_INVALID_PARAMETER
);
1679 /******************************************************************************
1680 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1682 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1685 * pName [I] Servername or NULL (local Computer)
1686 * level [I] Level for the supplied DRIVER_INFO_*W struct
1687 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1688 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1695 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1699 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1700 lres
= copy_servername_from_name(pName
, NULL
);
1702 FIXME("server %s not supported\n", debugstr_w(pName
));
1703 SetLastError(ERROR_ACCESS_DENIED
);
1707 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1708 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1711 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1714 /******************************************************************************
1715 * fpClosePrinter [exported through PRINTPROVIDOR]
1717 * Close a printer handle and free associated resources
1720 * hPrinter [I] Printerhandle to close
1727 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1729 printer_t
*printer
= (printer_t
*) hPrinter
;
1731 TRACE("(%p)\n", hPrinter
);
1734 printer_free(printer
);
1740 /******************************************************************************
1741 * fpConfigurePort [exported through PRINTPROVIDOR]
1743 * Display the Configuration-Dialog for a specific Port
1746 * pName [I] Servername or NULL (local Computer)
1747 * hWnd [I] Handle to parent Window for the Dialog-Box
1748 * pPortName [I] Name of the Port, that should be configured
1755 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1762 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1764 lres
= copy_servername_from_name(pName
, NULL
);
1766 FIXME("server %s not supported\n", debugstr_w(pName
));
1767 SetLastError(ERROR_INVALID_NAME
);
1771 /* an empty Portname is Invalid, but can popup a Dialog */
1772 if (!pPortName
[0]) {
1773 SetLastError(ERROR_NOT_SUPPORTED
);
1777 pm
= monitor_load_by_port(pPortName
);
1778 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1779 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1780 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1781 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1782 TRACE("got %d with %u\n", res
, GetLastError());
1786 pui
= monitor_loadui(pm
);
1787 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1788 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1789 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1790 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1791 TRACE("got %d with %u\n", res
, GetLastError());
1795 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1796 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1797 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1799 SetLastError(ERROR_NOT_SUPPORTED
);
1802 monitor_unload(pui
);
1806 TRACE("returning %d with %u\n", res
, GetLastError());
1810 /******************************************************************
1811 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1813 * Delete a specific Printmonitor from a Printing-Environment
1816 * pName [I] Servername or NULL (local Computer)
1817 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1818 * pMonitorName [I] Name of the Monitor, that should be deleted
1825 * pEnvironment is ignored in Windows for the local Computer.
1829 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1834 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1835 debugstr_w(pMonitorName
));
1837 lres
= copy_servername_from_name(pName
, NULL
);
1839 FIXME("server %s not supported\n", debugstr_w(pName
));
1840 SetLastError(ERROR_INVALID_NAME
);
1844 /* pEnvironment is ignored in Windows for the local Computer */
1845 if (!pMonitorName
|| !pMonitorName
[0]) {
1846 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1847 SetLastError(ERROR_INVALID_PARAMETER
);
1851 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1852 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1856 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1857 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1862 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1865 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1866 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1870 /*****************************************************************************
1871 * fpDeletePort [exported through PRINTPROVIDOR]
1873 * Delete a specific Port
1876 * pName [I] Servername or NULL (local Computer)
1877 * hWnd [I] Handle to parent Window for the Dialog-Box
1878 * pPortName [I] Name of the Port, that should be deleted
1885 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1892 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1894 lres
= copy_servername_from_name(pName
, NULL
);
1896 FIXME("server %s not supported\n", debugstr_w(pName
));
1897 SetLastError(ERROR_INVALID_NAME
);
1901 /* an empty Portname is Invalid */
1902 if (!pPortName
[0]) {
1903 SetLastError(ERROR_NOT_SUPPORTED
);
1907 pm
= monitor_load_by_port(pPortName
);
1908 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1909 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1910 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1911 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1912 TRACE("got %d with %u\n", res
, GetLastError());
1916 pui
= monitor_loadui(pm
);
1917 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1918 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1919 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1920 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1921 TRACE("got %d with %u\n", res
, GetLastError());
1925 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1926 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1927 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1929 SetLastError(ERROR_NOT_SUPPORTED
);
1932 monitor_unload(pui
);
1936 TRACE("returning %d with %u\n", res
, GetLastError());
1940 /*****************************************************************************
1941 * fpEnumMonitors [exported through PRINTPROVIDOR]
1943 * Enumerate available Port-Monitors
1946 * pName [I] Servername or NULL (local Computer)
1947 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1948 * pMonitors [O] PTR to Buffer that receives the Result
1949 * cbBuf [I] Size of Buffer at pMonitors
1950 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1951 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1955 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1958 * Windows reads the Registry once and cache the Results.
1961 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1962 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1964 DWORD numentries
= 0;
1969 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1970 cbBuf
, pcbNeeded
, pcReturned
);
1972 lres
= copy_servername_from_name(pName
, NULL
);
1974 FIXME("server %s not supported\n", debugstr_w(pName
));
1975 SetLastError(ERROR_INVALID_NAME
);
1979 if (!Level
|| (Level
> 2)) {
1980 WARN("level (%d) is ignored in win9x\n", Level
);
1981 SetLastError(ERROR_INVALID_LEVEL
);
1985 /* Scan all Monitor-Keys */
1987 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1989 /* we calculated the needed buffersize. now do more error-checks */
1990 if (cbBuf
< needed
) {
1991 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1995 /* fill the Buffer with the Monitor-Keys */
1996 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2000 if (pcbNeeded
) *pcbNeeded
= needed
;
2001 if (pcReturned
) *pcReturned
= numentries
;
2003 TRACE("returning %d with %d (%d byte for %d entries)\n",
2004 res
, GetLastError(), needed
, numentries
);
2009 /******************************************************************************
2010 * fpEnumPorts [exported through PRINTPROVIDOR]
2012 * Enumerate available Ports
2015 * pName [I] Servername or NULL (local Computer)
2016 * Level [I] Structure-Level (1 or 2)
2017 * pPorts [O] PTR to Buffer that receives the Result
2018 * cbBuf [I] Size of Buffer at pPorts
2019 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2020 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2024 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2027 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2028 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2031 DWORD numentries
= 0;
2035 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2036 cbBuf
, pcbNeeded
, pcReturned
);
2038 lres
= copy_servername_from_name(pName
, NULL
);
2040 FIXME("server %s not supported\n", debugstr_w(pName
));
2041 SetLastError(ERROR_INVALID_NAME
);
2045 if (!Level
|| (Level
> 2)) {
2046 SetLastError(ERROR_INVALID_LEVEL
);
2050 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2051 SetLastError(RPC_X_NULL_REF_POINTER
);
2055 EnterCriticalSection(&monitor_handles_cs
);
2058 /* Scan all local Ports */
2060 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2062 /* we calculated the needed buffersize. now do the error-checks */
2063 if (cbBuf
< needed
) {
2064 monitor_unloadall();
2065 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2066 goto emP_cleanup_cs
;
2068 else if (!pPorts
|| !pcReturned
) {
2069 monitor_unloadall();
2070 SetLastError(RPC_X_NULL_REF_POINTER
);
2071 goto emP_cleanup_cs
;
2074 /* Fill the Buffer */
2075 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2077 monitor_unloadall();
2080 LeaveCriticalSection(&monitor_handles_cs
);
2083 if (pcbNeeded
) *pcbNeeded
= needed
;
2084 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2086 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2087 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2092 /*****************************************************************************
2093 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2095 * Enumerate available Print Processors
2098 * pName [I] Servername or NULL (local Computer)
2099 * pEnvironment [I] Printing-Environment or NULL (Default)
2100 * Level [I] Structure-Level (Only 1 is allowed)
2101 * pPPInfo [O] PTR to Buffer that receives the Result
2102 * cbBuf [I] Size of Buffer at pMonitors
2103 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2104 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2108 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2111 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2112 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2114 const printenv_t
* env
;
2115 LPWSTR regpathW
= NULL
;
2116 DWORD numentries
= 0;
2121 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2122 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2124 lres
= copy_servername_from_name(pName
, NULL
);
2126 FIXME("server %s not supported\n", debugstr_w(pName
));
2127 SetLastError(ERROR_INVALID_NAME
);
2132 SetLastError(ERROR_INVALID_LEVEL
);
2136 env
= validate_envW(pEnvironment
);
2138 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2140 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2141 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2146 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2148 /* Scan all Printprocessor-Keys */
2150 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2152 /* we calculated the needed buffersize. now do more error-checks */
2153 if (cbBuf
< needed
) {
2154 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2158 /* fill the Buffer with the Printprocessor Infos */
2159 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2163 heap_free(regpathW
);
2164 if (pcbNeeded
) *pcbNeeded
= needed
;
2165 if (pcReturned
) *pcReturned
= numentries
;
2167 TRACE("returning %d with %d (%d byte for %d entries)\n",
2168 res
, GetLastError(), needed
, numentries
);
2173 /******************************************************************************
2174 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2176 * Return the PATH for the Print-Processors
2179 * pName [I] Servername or NULL (this computer)
2180 * pEnvironment [I] Printing-Environment or NULL (Default)
2181 * level [I] Structure-Level (must be 1)
2182 * pPPInfo [O] PTR to Buffer that receives the Result
2183 * cbBuf [I] Size of Buffer at pPPInfo
2184 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2188 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2190 * Native Values returned in pPPInfo on Success for this computer:
2191 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2192 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2193 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2195 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2198 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2199 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2201 const printenv_t
* env
;
2205 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2206 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2209 lres
= copy_servername_from_name(pName
, NULL
);
2211 FIXME("server %s not supported\n", debugstr_w(pName
));
2212 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2216 env
= validate_envW(pEnvironment
);
2218 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2220 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2221 needed
= GetSystemDirectoryW(NULL
, 0);
2222 /* add the Size for the Subdirectories */
2223 needed
+= lstrlenW(spoolprtprocsW
);
2224 needed
+= lstrlenW(env
->subdir
);
2225 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2227 *pcbNeeded
= needed
;
2229 if (needed
> cbBuf
) {
2230 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2234 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2235 /* add the Subdirectories */
2236 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2237 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2238 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2242 /******************************************************************************
2243 * fpOpenPrinter [exported through PRINTPROVIDOR]
2245 * Open a Printer / Printserver or a Printer-Object
2248 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2249 * pPrinter [O] The resulting Handle is stored here
2250 * pDefaults [I] PTR to Default Printer Settings or NULL
2257 * lpPrinterName is one of:
2258 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2259 *| Printer: "PrinterName"
2260 *| Printer-Object: "PrinterName,Job xxx"
2261 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2262 *| XcvPort: "Servername,XcvPort PortName"
2266 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2267 LPPRINTER_DEFAULTSW pDefaults
)
2270 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2272 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2274 return (*pPrinter
!= 0);
2277 /******************************************************************************
2278 * fpXcvData [exported through PRINTPROVIDOR]
2280 * Execute commands in the Printmonitor DLL
2283 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2284 * pszDataName [i] Name of the command to execute
2285 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2286 * cbInputData [i] Size in Bytes of Buffer at pInputData
2287 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2288 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2289 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2290 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2297 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2298 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2300 * Minimal List of commands, that a Printmonitor DLL should support:
2302 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2303 *| "AddPort" : Add a Port
2304 *| "DeletePort": Delete a Port
2306 * Many Printmonitors support additional commands. Examples for localspl.dll:
2307 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2308 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2311 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2312 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2313 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2315 printer_t
*printer
= (printer_t
* ) hXcv
;
2317 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2318 pInputData
, cbInputData
, pOutputData
,
2319 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2321 if (!printer
|| (!printer
->hXcv
)) {
2322 SetLastError(ERROR_INVALID_HANDLE
);
2326 if (!pcbOutputNeeded
) {
2327 SetLastError(ERROR_INVALID_PARAMETER
);
2331 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2332 SetLastError(RPC_X_NULL_REF_POINTER
);
2336 *pcbOutputNeeded
= 0;
2338 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2339 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2344 /*****************************************************
2345 * setup_provider [internal]
2347 void setup_provider(void)
2349 static const PRINTPROVIDOR backend
= {
2351 NULL
, /* fpSetJob */
2352 NULL
, /* fpGetJob */
2353 NULL
, /* fpEnumJobs */
2354 NULL
, /* fpAddPrinter */
2355 NULL
, /* fpDeletePrinter */
2356 NULL
, /* fpSetPrinter */
2357 NULL
, /* fpGetPrinter */
2358 NULL
, /* fpEnumPrinters */
2359 NULL
, /* fpAddPrinterDriver */
2360 NULL
, /* fpEnumPrinterDrivers */
2361 NULL
, /* fpGetPrinterDriver */
2362 fpGetPrinterDriverDirectory
,
2363 NULL
, /* fpDeletePrinterDriver */
2364 NULL
, /* fpAddPrintProcessor */
2365 fpEnumPrintProcessors
,
2366 fpGetPrintProcessorDirectory
,
2367 NULL
, /* fpDeletePrintProcessor */
2368 NULL
, /* fpEnumPrintProcessorDatatypes */
2369 NULL
, /* fpStartDocPrinter */
2370 NULL
, /* fpStartPagePrinter */
2371 NULL
, /* fpWritePrinter */
2372 NULL
, /* fpEndPagePrinter */
2373 NULL
, /* fpAbortPrinter */
2374 NULL
, /* fpReadPrinter */
2375 NULL
, /* fpEndDocPrinter */
2376 NULL
, /* fpAddJob */
2377 NULL
, /* fpScheduleJob */
2378 NULL
, /* fpGetPrinterData */
2379 NULL
, /* fpSetPrinterData */
2380 NULL
, /* fpWaitForPrinterChange */
2382 NULL
, /* fpAddForm */
2383 NULL
, /* fpDeleteForm */
2384 NULL
, /* fpGetForm */
2385 NULL
, /* fpSetForm */
2386 NULL
, /* fpEnumForms */
2392 NULL
, /* fpCreatePrinterIC */
2393 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2394 NULL
, /* fpDeletePrinterIC */
2395 NULL
, /* fpAddPrinterConnection */
2396 NULL
, /* fpDeletePrinterConnection */
2397 NULL
, /* fpPrinterMessageBox */
2400 NULL
, /* fpResetPrinter */
2401 NULL
, /* fpGetPrinterDriverEx */
2402 NULL
, /* fpFindFirstPrinterChangeNotification */
2403 NULL
, /* fpFindClosePrinterChangeNotification */
2405 NULL
, /* fpShutDown */
2406 NULL
, /* fpRefreshPrinterChangeNotification */
2407 NULL
, /* fpOpenPrinterEx */
2408 NULL
, /* fpAddPrinterEx */
2409 NULL
, /* fpSetPort */
2410 NULL
, /* fpEnumPrinterData */
2411 NULL
, /* fpDeletePrinterData */
2412 NULL
, /* fpClusterSplOpen */
2413 NULL
, /* fpClusterSplClose */
2414 NULL
, /* fpClusterSplIsAlive */
2415 NULL
, /* fpSetPrinterDataEx */
2416 NULL
, /* fpGetPrinterDataEx */
2417 NULL
, /* fpEnumPrinterDataEx */
2418 NULL
, /* fpEnumPrinterKey */
2419 NULL
, /* fpDeletePrinterDataEx */
2420 NULL
, /* fpDeletePrinterKey */
2421 NULL
, /* fpSeekPrinter */
2422 NULL
, /* fpDeletePrinterDriverEx */
2423 NULL
, /* fpAddPerMachineConnection */
2424 NULL
, /* fpDeletePerMachineConnection */
2425 NULL
, /* fpEnumPerMachineConnections */
2427 fpAddPrinterDriverEx
,
2428 NULL
, /* fpSplReadPrinter */
2429 NULL
, /* fpDriverUnloadComplete */
2430 NULL
, /* fpGetSpoolFileInfo */
2431 NULL
, /* fpCommitSpoolData */
2432 NULL
, /* fpCloseSpoolFileHandle */
2433 NULL
, /* fpFlushPrinter */
2434 NULL
, /* fpSendRecvBidiData */
2435 NULL
/* fpAddDriverCatalog */
2437 pprovider
= &backend
;
2441 /*****************************************************
2442 * InitializePrintProvidor (localspl.@)
2444 * Initialize the Printprovider
2447 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2448 * cbPrintProvidor [I] Size of Buffer in Bytes
2449 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2452 * Success: TRUE and pPrintProvidor filled
2456 * The RegistryPath should be:
2457 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2458 * but this Parameter is ignored in "localspl.dll".
2462 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2463 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2466 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2467 memcpy(pPrintProvidor
, pprovider
,
2468 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));