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
21 #include "localspl_private.h"
24 #include <ddk/winddiui.h>
26 /* ############################### */
28 static CRITICAL_SECTION monitor_handles_cs
;
29 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
31 0, 0, &monitor_handles_cs
,
32 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
33 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
35 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
37 /* ############################### */
40 WCHAR src
[MAX_PATH
+MAX_PATH
];
41 WCHAR dst
[MAX_PATH
+MAX_PATH
];
63 LPCWSTR versionregpath
;
64 LPCWSTR versionsubdir
;
74 /* ############################### */
76 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
77 static monitor_t
* pm_localport
;
79 static const PRINTPROVIDOR
* pprovider
= NULL
;
81 static const WCHAR backslashW
[] = {'\\',0};
82 static const WCHAR bs_ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
83 static const WCHAR configuration_fileW
[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
84 static const WCHAR datatypeW
[] = {'D','a','t','a','t','y','p','e',0};
85 static const WCHAR data_fileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
86 static const WCHAR default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
87 static const WCHAR dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
88 static const WCHAR descriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
89 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
90 static const WCHAR emptyW
[] = {0};
91 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
92 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
93 'c','o','n','t','r','o','l','\\',
94 'P','r','i','n','t','\\',
95 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
96 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
97 static const WCHAR fmt_printprocessorsW
[] = { 'S','y','s','t','e','m','\\',
98 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
99 'C','o','n','t','r','o','l','\\',
100 'P','r','i','n','t','\\',
101 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
102 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
103 static const WCHAR hardwareidW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
104 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
105 static const WCHAR ia64_envnameW
[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
106 static const WCHAR ia64_subdirW
[] = {'i','a','6','4',0};
107 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
108 static const WCHAR locationW
[] = {'L','o','c','a','t','i','o','n',0};
109 static const WCHAR manufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
110 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
111 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
112 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
113 'C','o','n','t','r','o','l','\\',
114 'P','r','i','n','t','\\',
115 'M','o','n','i','t','o','r','s','\\',0};
116 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
117 static const WCHAR nameW
[] = {'N','a','m','e',0};
118 static const WCHAR oem_urlW
[] = {'O','E','M',' ','U','r','l',0};
119 static const WCHAR parametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
120 static const WCHAR portW
[] = {'P','o','r','t',0};
121 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
122 static const WCHAR printersW
[] = {'S','y','s','t','e','m','\\',
123 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
124 'C','o','n','t','r','o','l','\\',
125 'P','r','i','n','t','\\',
126 'P','r','i','n','t','e','r','s',0};
127 static const WCHAR spoolW
[] = {'\\','s','p','o','o','l',0};
128 static const WCHAR driversW
[] = {'\\','d','r','i','v','e','r','s','\\',0};
129 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
130 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
131 static const WCHAR version0_subdirW
[] = {'\\','0',0};
132 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
133 static const WCHAR version3_subdirW
[] = {'\\','3',0};
134 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
135 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
136 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
137 static const WCHAR winnt_cv_portsW
[] = {'S','o','f','t','w','a','r','e','\\',
138 'M','i','c','r','o','s','o','f','t','\\',
139 'W','i','n','d','o','w','s',' ','N','T','\\',
140 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
141 'P','o','r','t','s',0};
142 static const WCHAR winprintW
[] = {'w','i','n','p','r','i','n','t',0};
143 static const WCHAR x64_envnameW
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
144 static const WCHAR x64_subdirW
[] = {'x','6','4',0};
145 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
146 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
147 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
148 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
151 static const printenv_t env_ia64
= {ia64_envnameW
, ia64_subdirW
, 3,
152 version3_regpathW
, version3_subdirW
};
154 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
155 version3_regpathW
, version3_subdirW
};
157 static const printenv_t env_x64
= {x64_envnameW
, x64_subdirW
, 3,
158 version3_regpathW
, version3_subdirW
};
160 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
161 version0_regpathW
, version0_subdirW
};
163 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_win40
};
166 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
167 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
168 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
169 0, sizeof(DRIVER_INFO_8W
)};
172 /******************************************************************
175 * create a copy of a unicode-string
178 static LPWSTR
strdupW(LPCWSTR p
)
184 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
185 ret
= heap_alloc(len
);
186 if (ret
) memcpy(ret
, p
, len
);
190 /******************************************************************
191 * apd_copyfile [internal]
193 * Copy a file from the driverdirectory to the versioned directory
200 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
205 apd
->src
[apd
->srclen
] = '\0';
206 apd
->dst
[apd
->dstlen
] = '\0';
208 if (!pathname
|| !pathname
[0]) {
209 /* nothing to copy */
213 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
218 strcatW( srcname
, file_part
);
220 strcatW( apd
->dst
, file_part
);
222 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
224 /* FIXME: handle APD_COPY_NEW_FILES */
225 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
226 TRACE("got %d with %u\n", res
, GetLastError());
228 return apd
->lazy
|| res
;
231 /******************************************************************
232 * copy_servername_from_name (internal)
234 * for an external server, the serverpart from the name is copied.
237 * the length (in WCHAR) of the serverpart (0 for the local computer)
238 * (-length), when the name is too long
241 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
245 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
249 if (target
) *target
= '\0';
251 if (name
== NULL
) return 0;
252 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
255 /* skip over both backslash, find separator '\' */
256 ptr
= strchrW(server
, '\\');
257 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
259 /* servername is empty */
260 if (serverlen
== 0) return 0;
262 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
264 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
267 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
268 target
[serverlen
] = '\0';
271 len
= sizeof(buffer
) / sizeof(buffer
[0]);
272 if (GetComputerNameW(buffer
, &len
)) {
273 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
274 /* The requested Servername is our computername */
281 /******************************************************************
282 * get_basename_from_name (internal)
284 * skip over the serverpart from the full name
287 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
289 if (name
== NULL
) return NULL
;
290 if ((name
[0] == '\\') && (name
[1] == '\\')) {
291 /* skip over the servername and search for the following '\' */
292 name
= strchrW(&name
[2], '\\');
293 if ((name
) && (name
[1])) {
294 /* found a separator ('\') followed by a name:
295 skip over the separator and return the rest */
300 /* no basename present (we found only a servername) */
307 /******************************************************************
308 * monitor_unload [internal]
310 * release a printmonitor and unload it from memory, when needed
313 static void monitor_unload(monitor_t
* pm
)
315 if (pm
== NULL
) return;
316 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
318 EnterCriticalSection(&monitor_handles_cs
);
320 if (pm
->refcount
) pm
->refcount
--;
322 if (pm
->refcount
== 0) {
323 list_remove(&pm
->entry
);
324 FreeLibrary(pm
->hdll
);
326 heap_free(pm
->dllname
);
329 LeaveCriticalSection(&monitor_handles_cs
);
332 /******************************************************************
333 * monitor_unloadall [internal]
335 * release all registered printmonitors and unload them from memory, when needed
339 static void monitor_unloadall(void)
344 EnterCriticalSection(&monitor_handles_cs
);
345 /* iterate through the list, with safety against removal */
346 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
348 /* skip monitorui dlls */
349 if (pm
->monitor
) monitor_unload(pm
);
351 LeaveCriticalSection(&monitor_handles_cs
);
354 /******************************************************************
355 * monitor_load [internal]
357 * load a printmonitor, get the dllname from the registry, when needed
358 * initialize the monitor and dump found function-pointers
360 * On failure, SetLastError() is called and NULL is returned
363 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
365 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
366 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
367 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
368 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
369 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
371 monitor_t
* pm
= NULL
;
373 LPWSTR regroot
= NULL
;
374 LPWSTR driver
= dllname
;
376 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
377 /* Is the Monitor already loaded? */
378 EnterCriticalSection(&monitor_handles_cs
);
381 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
383 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
391 pm
= heap_alloc_zero(sizeof(monitor_t
));
392 if (pm
== NULL
) goto cleanup
;
393 list_add_tail(&monitor_handles
, &pm
->entry
);
397 if (pm
->name
== NULL
) {
398 /* Load the monitor */
399 LPMONITOREX pmonitorEx
;
403 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
404 regroot
= heap_alloc(len
* sizeof(WCHAR
));
408 lstrcpyW(regroot
, monitorsW
);
409 lstrcatW(regroot
, name
);
410 /* Get the Driver from the Registry */
411 if (driver
== NULL
) {
414 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
415 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
416 &namesize
) == ERROR_SUCCESS
) {
417 driver
= heap_alloc(namesize
);
418 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
425 pm
->name
= strdupW(name
);
426 pm
->dllname
= strdupW(driver
);
428 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
430 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
435 pm
->hdll
= LoadLibraryW(driver
);
436 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
438 if (pm
->hdll
== NULL
) {
440 SetLastError(ERROR_MOD_NOT_FOUND
);
445 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
446 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
447 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
448 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
449 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
452 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
453 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
454 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
455 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
456 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
458 if (pInitializePrintMonitorUI
!= NULL
) {
459 pm
->monitorUI
= pInitializePrintMonitorUI();
460 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
462 TRACE("0x%08x: dwMonitorSize (%d)\n",
463 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
468 if (pInitializePrintMonitor
&& regroot
) {
469 pmonitorEx
= pInitializePrintMonitor(regroot
);
470 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
471 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
474 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
475 pm
->monitor
= &(pmonitorEx
->Monitor
);
480 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
484 if (!pm
->monitor
&& regroot
) {
485 if (pInitializePrintMonitor2
!= NULL
) {
486 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
488 if (pInitializeMonitorEx
!= NULL
) {
489 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
491 if (pInitializeMonitor
!= NULL
) {
492 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
495 if (!pm
->monitor
&& !pm
->monitorUI
) {
497 SetLastError(ERROR_PROC_NOT_FOUND
);
502 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
506 LeaveCriticalSection(&monitor_handles_cs
);
507 if (driver
!= dllname
) heap_free(driver
);
509 TRACE("=> %p\n", pm
);
513 /******************************************************************
514 * monitor_loadall [internal]
516 * Load all registered monitors
519 static DWORD
monitor_loadall(void)
522 DWORD registered
= 0;
525 WCHAR buffer
[MAX_PATH
];
528 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
529 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
530 NULL
, NULL
, NULL
, NULL
, NULL
);
532 TRACE("%d monitors registered\n", registered
);
534 while (id
< registered
) {
536 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
537 pm
= monitor_load(buffer
, NULL
);
541 RegCloseKey(hmonitors
);
543 TRACE("%d monitors loaded\n", loaded
);
547 /******************************************************************
548 * monitor_loadui [internal]
550 * load the userinterface-dll for a given portmonitor
552 * On failure, NULL is returned
554 static monitor_t
* monitor_loadui(monitor_t
* pm
)
556 monitor_t
* pui
= NULL
;
557 WCHAR buffer
[MAX_PATH
];
562 if (pm
== NULL
) return NULL
;
563 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
565 /* Try the Portmonitor first; works for many monitors */
567 EnterCriticalSection(&monitor_handles_cs
);
569 LeaveCriticalSection(&monitor_handles_cs
);
573 /* query the userinterface-dllname from the Portmonitor */
574 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
575 /* building (",XcvMonitor %s",pm->name) not needed yet */
576 res
= pm
->monitor
->pfnXcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
577 TRACE("got %u with %p\n", res
, hXcv
);
579 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
580 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
581 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
582 pm
->monitor
->pfnXcvClosePort(hXcv
);
588 /******************************************************************
589 * monitor_load_by_port [internal]
591 * load a printmonitor for a given port
593 * On failure, NULL is returned
596 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
601 monitor_t
* pm
= NULL
;
602 DWORD registered
= 0;
606 TRACE("(%s)\n", debugstr_w(portname
));
608 /* Try the Local Monitor first */
609 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
610 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
611 /* found the portname */
613 return monitor_load(localportW
, NULL
);
618 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
619 buffer
= heap_alloc(len
* sizeof(WCHAR
));
620 if (buffer
== NULL
) return NULL
;
622 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
623 EnterCriticalSection(&monitor_handles_cs
);
624 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
626 while ((pm
== NULL
) && (id
< registered
)) {
628 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
629 TRACE("testing %s\n", debugstr_w(buffer
));
630 len
= lstrlenW(buffer
);
631 lstrcatW(buffer
, bs_ports_bsW
);
632 lstrcatW(buffer
, portname
);
633 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
635 buffer
[len
] = '\0'; /* use only the Monitor-Name */
636 pm
= monitor_load(buffer
, NULL
);
640 LeaveCriticalSection(&monitor_handles_cs
);
647 /******************************************************************
648 * Return the number of bytes for an multi_sz string.
649 * The result includes all \0s
650 * (specifically the extra \0, that is needed as multi_sz terminator).
652 static int multi_sz_lenW(const WCHAR
*str
)
654 const WCHAR
*ptr
= str
;
658 ptr
+= lstrlenW(ptr
) + 1;
661 return (ptr
- str
+ 1) * sizeof(WCHAR
);
664 /******************************************************************
665 * validate_envW [internal]
667 * validate the user-supplied printing-environment
670 * env [I] PTR to Environment-String or NULL
673 * Success: PTR to printenv_t
674 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
677 * An empty string is handled the same way as NULL.
681 static const printenv_t
* validate_envW(LPCWSTR env
)
683 const printenv_t
*result
= NULL
;
686 TRACE("(%s)\n", debugstr_w(env
));
689 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
691 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
693 result
= all_printenv
[i
];
697 if (result
== NULL
) {
698 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
699 SetLastError(ERROR_INVALID_ENVIRONMENT
);
701 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
705 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
708 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
712 /*****************************************************************************
713 * enumerate the local monitors (INTERNAL)
715 * returns the needed size (in bytes) for pMonitors
716 * and *lpreturned is set to number of entries returned in pMonitors
718 * Language-Monitors are also installed in the same Registry-Location but
719 * they are filtered in Windows (not returned by EnumMonitors).
720 * We do no filtering to simplify our Code.
723 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
728 LPMONITOR_INFO_2W mi
;
729 WCHAR buffer
[MAX_PATH
];
730 WCHAR dllname
[MAX_PATH
];
738 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
740 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
741 len
= entrysize
* numentries
;
742 ptr
= (LPWSTR
) &pMonitors
[len
];
745 len
= sizeof(buffer
)/sizeof(buffer
[0]);
748 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
749 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
750 /* Scan all Monitor-Registry-Keys */
751 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
752 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
753 dllsize
= sizeof(dllname
);
756 /* The Monitor must have a Driver-DLL */
757 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
758 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
759 /* We found a valid DLL for this Monitor. */
760 TRACE("using Driver: %s\n", debugstr_w(dllname
));
765 /* Windows returns only Port-Monitors here, but to simplify our code,
766 we do no filtering for Language-Monitors */
770 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
772 /* we install and return only monitors for "Windows NT x86" */
773 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
777 /* required size is calculated. Now fill the user-buffer */
778 if (pMonitors
&& (cbBuf
>= needed
)){
779 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
780 pMonitors
+= entrysize
;
782 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
784 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
785 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
787 mi
->pEnvironment
= ptr
;
788 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
789 ptr
+= (lstrlenW(x86_envnameW
)+1);
792 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
793 ptr
+= (dllsize
/ sizeof(WCHAR
));
798 len
= sizeof(buffer
)/sizeof(buffer
[0]);
803 *lpreturned
= numentries
;
804 TRACE("need %d byte for %d entries\n", needed
, numentries
);
808 /*****************************************************************************
809 * enumerate the local print processors (INTERNAL)
811 * returns the needed size (in bytes) for pPPInfo
812 * and *lpreturned is set to number of entries returned in pPPInfo
815 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
820 PPRINTPROCESSOR_INFO_1W ppi
;
821 WCHAR buffer
[MAX_PATH
];
822 WCHAR dllname
[MAX_PATH
];
829 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
830 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
831 ptr
= (LPWSTR
) &pPPInfo
[len
];
834 len
= sizeof(buffer
)/sizeof(buffer
[0]);
837 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
838 /* add "winprint" first */
840 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(winprintW
);
841 if (pPPInfo
&& (cbBuf
>= needed
)){
842 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
843 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
845 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
847 lstrcpyW(ptr
, winprintW
); /* Name of the Print Processor */
848 ptr
+= sizeof(winprintW
) / sizeof(WCHAR
);
851 /* Scan all Printprocessor Keys */
852 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
853 (lstrcmpiW(buffer
, winprintW
) != 0)) {
854 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
855 dllsize
= sizeof(dllname
);
858 /* The Print Processor must have a Driver-DLL */
859 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
860 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
861 /* We found a valid DLL for this Print Processor */
862 TRACE("using Driver: %s\n", debugstr_w(dllname
));
869 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
870 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
872 /* required size is calculated. Now fill the user-buffer */
873 if (pPPInfo
&& (cbBuf
>= needed
)){
874 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
875 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
877 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
879 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
880 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
884 len
= sizeof(buffer
)/sizeof(buffer
[0]);
889 *lpreturned
= numentries
;
890 TRACE("need %d byte for %d entries\n", needed
, numentries
);
894 /******************************************************************
895 * enumerate the local Ports from all loaded monitors (internal)
897 * returns the needed size (in bytes) for pPorts
898 * and *lpreturned is set to number of entries returned in pPorts
901 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
905 LPPORT_INFO_2W cache
;
907 LPBYTE pi_buffer
= NULL
;
908 DWORD pi_allocated
= 0;
919 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
920 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
922 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
923 needed
= entrysize
* numentries
;
924 ptr
= (LPWSTR
) &pPorts
[needed
];
929 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
931 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
934 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
935 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
936 /* Do not use heap_realloc (we do not need the old data in the buffer) */
937 heap_free(pi_buffer
);
938 pi_buffer
= heap_alloc(pi_needed
);
939 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
940 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
942 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
943 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
945 numentries
+= pi_returned
;
948 /* fill the output-buffer (pPorts), if we have one */
949 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
951 while (pi_returned
> pi_index
) {
952 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
953 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
954 out
->pPortName
= ptr
;
955 lstrcpyW(ptr
, cache
->pPortName
);
956 ptr
+= (lstrlenW(ptr
)+1);
958 out
->pMonitorName
= ptr
;
959 lstrcpyW(ptr
, cache
->pMonitorName
);
960 ptr
+= (lstrlenW(ptr
)+1);
962 out
->pDescription
= ptr
;
963 lstrcpyW(ptr
, cache
->pDescription
);
964 ptr
+= (lstrlenW(ptr
)+1);
965 out
->fPortType
= cache
->fPortType
;
966 out
->Reserved
= cache
->Reserved
;
974 /* the temporary portinfo-buffer is no longer needed */
975 heap_free(pi_buffer
);
977 *lpreturned
= numentries
;
978 TRACE("need %d byte for %d entries\n", needed
, numentries
);
983 /*****************************************************************************
984 * open_driver_reg [internal]
986 * opens the registry for the printer drivers depending on the given input
987 * variable pEnvironment
990 * Success: the opened hkey
993 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
997 const printenv_t
* env
;
999 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1001 env
= validate_envW(pEnvironment
);
1002 if (!env
) return NULL
;
1004 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
1005 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
1008 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1009 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1010 HeapFree(GetProcessHeap(), 0, buffer
);
1015 /*****************************************************************************
1016 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1018 * Return the PATH for the Printer-Drivers
1021 * pName [I] Servername (NT only) or NULL (local Computer)
1022 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1023 * Level [I] Structure-Level (must be 1)
1024 * pDriverDirectory [O] PTR to Buffer that receives the Result
1025 * cbBuf [I] Size of Buffer at pDriverDirectory
1026 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1027 * required for pDriverDirectory
1030 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1031 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1032 * if cbBuf is too small
1034 * Native Values returned in pDriverDirectory on Success:
1035 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1036 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1037 *| win9x(Windows 4.0): "%winsysdir%"
1039 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1042 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1043 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1046 const printenv_t
* env
;
1047 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1049 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1050 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1052 if (pName
!= NULL
&& pName
[0]) {
1053 FIXME("server %s not supported\n", debugstr_w(pName
));
1054 SetLastError(ERROR_INVALID_PARAMETER
);
1058 env
= validate_envW(pEnvironment
);
1059 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1062 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1063 needed
= GetSystemDirectoryW(NULL
, 0);
1064 /* add the Size for the Subdirectories */
1065 needed
+= lstrlenW(spoolW
);
1066 needed
+= lstrlenW(driversW
);
1067 needed
+= lstrlenW(env
->subdir
);
1068 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1070 *pcbNeeded
= needed
;
1072 if (needed
> cbBuf
) {
1073 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1078 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1079 SetLastError(ERROR_INVALID_USER_BUFFER
);
1083 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1084 /* add the Subdirectories */
1085 lstrcatW( dir
, spoolW
);
1086 CreateDirectoryW( dir
, NULL
);
1087 lstrcatW( dir
, driversW
);
1088 CreateDirectoryW( dir
, NULL
);
1089 lstrcatW( dir
, env
->subdir
);
1090 CreateDirectoryW( dir
, NULL
);
1092 TRACE( "=> %s\n", debugstr_w( dir
) );
1096 /******************************************************************
1097 * driver_load [internal]
1099 * load a driver user interface dll
1101 * On failure, NULL is returned
1105 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1107 WCHAR fullname
[MAX_PATH
];
1111 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1113 /* build the driverdir */
1114 len
= sizeof(fullname
) -
1115 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1117 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1118 (LPBYTE
) fullname
, len
, &len
)) {
1119 /* Should never fail */
1120 SetLastError(ERROR_BUFFER_OVERFLOW
);
1124 lstrcatW(fullname
, env
->versionsubdir
);
1125 lstrcatW(fullname
, backslashW
);
1126 lstrcatW(fullname
, dllname
);
1128 hui
= LoadLibraryW(fullname
);
1129 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1134 /******************************************************************
1136 * free the data pointer of an opened printer
1138 static VOID
printer_free(printer_t
* printer
)
1141 printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1143 monitor_unload(printer
->pm
);
1145 heap_free(printer
->printername
);
1146 heap_free(printer
->name
);
1150 /******************************************************************
1151 * printer_alloc_handle
1152 * alloc a printer handle and remember the data pointer in the printer handle table
1155 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1157 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1158 printer_t
*printer
= NULL
;
1159 LPCWSTR printername
;
1164 if (copy_servername_from_name(name
, servername
)) {
1165 FIXME("server %s not supported\n", debugstr_w(servername
));
1166 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1170 printername
= get_basename_from_name(name
);
1171 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1173 /* an empty printername is invalid */
1174 if (printername
&& (!printername
[0])) {
1175 SetLastError(ERROR_INVALID_PARAMETER
);
1179 printer
= heap_alloc_zero(sizeof(printer_t
));
1180 if (!printer
) goto end
;
1182 /* clone the base name. This is NULL for the printserver */
1183 printer
->printername
= strdupW(printername
);
1185 /* clone the full name */
1186 printer
->name
= strdupW(name
);
1187 if (name
&& (!printer
->name
)) {
1188 printer_free(printer
);
1192 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1193 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1194 /* OpenPrinter(",XcvMonitor ", ...) detected */
1195 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1196 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1197 if (printer
->pm
== NULL
) {
1198 printer_free(printer
);
1199 SetLastError(ERROR_UNKNOWN_PORT
);
1206 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1207 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1208 /* OpenPrinter(",XcvPort ", ...) detected */
1209 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1210 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1211 if (printer
->pm
== NULL
) {
1212 printer_free(printer
);
1213 SetLastError(ERROR_UNKNOWN_PORT
);
1221 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1222 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1223 pDefault
? pDefault
->DesiredAccess
: 0,
1226 if (printer
->hXcv
== NULL
) {
1227 printer_free(printer
);
1228 SetLastError(ERROR_INVALID_PARAMETER
);
1235 /* Does the Printer exist? */
1236 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1237 ERR("Can't create Printers key\n");
1238 printer_free(printer
);
1239 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1243 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1244 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1245 RegCloseKey(hkeyPrinters
);
1246 printer_free(printer
);
1247 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1251 RegCloseKey(hkeyPrinter
);
1252 RegCloseKey(hkeyPrinters
);
1257 TRACE("using the local printserver\n");
1262 TRACE("==> %p\n", printer
);
1263 return (HANDLE
)printer
;
1266 static inline WCHAR
*get_file_part( WCHAR
*name
)
1268 WCHAR
*ptr
= strrchrW( name
, '\\' );
1269 if (ptr
) return ptr
+ 1;
1273 /******************************************************************************
1274 * myAddPrinterDriverEx [internal]
1276 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1277 * and a special mode with lazy error checking.
1280 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1282 const printenv_t
*env
;
1285 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1295 /* we need to set all entries in the Registry, independent from the Level of
1296 DRIVER_INFO, that the caller supplied */
1298 ZeroMemory(&di
, sizeof(di
));
1299 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
1300 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1303 /* dump the most used infos */
1304 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1305 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1306 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1307 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1308 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1309 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1310 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1311 /* dump only the first of the additional Files */
1312 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1315 /* check environment */
1316 env
= validate_envW(di
.pEnvironment
);
1317 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1319 /* fill the copy-data / get the driverdir */
1320 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1321 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1322 (LPBYTE
) apd
.src
, len
, &len
)) {
1323 /* Should never fail */
1326 memcpy(apd
.dst
, apd
.src
, len
);
1327 lstrcatW(apd
.src
, backslashW
);
1328 apd
.srclen
= lstrlenW(apd
.src
);
1329 lstrcatW(apd
.dst
, env
->versionsubdir
);
1330 lstrcatW(apd
.dst
, backslashW
);
1331 apd
.dstlen
= lstrlenW(apd
.dst
);
1332 apd
.copyflags
= dwFileCopyFlags
;
1334 CreateDirectoryW(apd
.src
, NULL
);
1335 CreateDirectoryW(apd
.dst
, NULL
);
1337 hroot
= open_driver_reg(env
->envname
);
1339 ERR("Can't create Drivers key\n");
1343 /* Fill the Registry for the Driver */
1344 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1345 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1346 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1348 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1355 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1356 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1359 file
= get_file_part( di
.pDriverPath
);
1360 RegSetValueExW( hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1361 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1363 file
= get_file_part( di
.pDataFile
);
1364 RegSetValueExW( hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1365 apd_copyfile( di
.pDataFile
, file
, &apd
);
1367 file
= get_file_part( di
.pConfigFile
);
1368 RegSetValueExW( hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1369 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1371 /* settings for level 3 */
1374 file
= get_file_part( di
.pHelpFile
);
1375 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1376 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1379 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
) );
1381 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1383 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1384 reg
= reg_ptr
= HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di
.pDependentFiles
) );
1386 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= strlenW( in_ptr
) + 1)
1388 file
= get_file_part( in_ptr
);
1389 len
= strlenW( file
) + 1;
1390 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1392 apd_copyfile( in_ptr
, file
, &apd
);
1396 RegSetValueExW( hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
1397 HeapFree( GetProcessHeap(), 0, reg
);
1400 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1402 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1403 if (di
.pMonitorName
)
1404 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1405 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1407 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1409 if (di
.pDefaultDataType
)
1410 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1411 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1413 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1415 /* settings for level 4 */
1416 if (di
.pszzPreviousNames
)
1417 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1418 multi_sz_lenW(di
.pszzPreviousNames
));
1420 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1422 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1425 hui
= driver_load(env
, di
.pConfigFile
);
1426 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1427 if (hui
&& pDrvDriverEvent
) {
1429 /* Support for DrvDriverEvent is optional */
1430 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1431 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1432 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1433 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1437 TRACE("=> TRUE with %u\n", GetLastError());
1442 /******************************************************************************
1443 * fpAddMonitor [exported through PRINTPROVIDOR]
1445 * Install a Printmonitor
1448 * pName [I] Servername or NULL (local Computer)
1449 * Level [I] Structure-Level (Must be 2)
1450 * pMonitors [I] PTR to MONITOR_INFO_2
1457 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1460 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1462 monitor_t
* pm
= NULL
;
1463 LPMONITOR_INFO_2W mi2w
;
1469 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1470 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1471 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1472 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1473 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1475 if (copy_servername_from_name(pName
, NULL
)) {
1476 FIXME("server %s not supported\n", debugstr_w(pName
));
1477 SetLastError(ERROR_ACCESS_DENIED
);
1481 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1482 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1483 SetLastError(ERROR_INVALID_PARAMETER
);
1486 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
1487 WARN("Environment %s requested (we support only %s)\n",
1488 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
1489 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1493 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1494 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1495 SetLastError(ERROR_INVALID_PARAMETER
);
1499 /* Load and initialize the monitor. SetLastError() is called on failure */
1500 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
1505 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1506 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1510 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1511 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1512 &disposition
) == ERROR_SUCCESS
) {
1514 /* Some installers set options for the port before calling AddMonitor.
1515 We query the "Driver" entry to verify that the monitor is installed,
1516 before we return an error.
1517 When a user installs two print monitors at the same time with the
1518 same name, a race condition is possible but silently ignored. */
1522 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1523 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1524 &namesize
) == ERROR_SUCCESS
)) {
1525 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1526 /* 9x use ERROR_ALREADY_EXISTS */
1527 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1532 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1533 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1534 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1536 RegCloseKey(hentry
);
1543 /******************************************************************************
1544 * fpAddPort [exported through PRINTPROVIDOR]
1546 * Add a Port for a specific Monitor
1549 * pName [I] Servername or NULL (local Computer)
1550 * hWnd [I] Handle to parent Window for the Dialog-Box
1551 * pMonitorName [I] Name of the Monitor that manage the Port
1558 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1565 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1567 lres
= copy_servername_from_name(pName
, NULL
);
1569 FIXME("server %s not supported\n", debugstr_w(pName
));
1570 SetLastError(ERROR_INVALID_PARAMETER
);
1574 /* an empty Monitorname is Invalid */
1575 if (!pMonitorName
[0]) {
1576 SetLastError(ERROR_NOT_SUPPORTED
);
1580 pm
= monitor_load(pMonitorName
, NULL
);
1581 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1582 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1583 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1587 pui
= monitor_loadui(pm
);
1588 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1589 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1590 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1594 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1595 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1596 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1598 SetLastError(ERROR_NOT_SUPPORTED
);
1601 monitor_unload(pui
);
1605 TRACE("returning %d with %u\n", res
, GetLastError());
1609 /******************************************************************************
1610 * fpAddPortEx [exported through PRINTPROVIDOR]
1612 * Add a Port for a specific Monitor, without presenting a user interface
1615 * pName [I] Servername or NULL (local Computer)
1616 * level [I] Structure-Level (1 or 2) for pBuffer
1617 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1618 * pMonitorName [I] Name of the Monitor that manage the Port
1625 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1632 pi2
= (PORT_INFO_2W
*) pBuffer
;
1634 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1635 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1636 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1637 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1639 lres
= copy_servername_from_name(pName
, NULL
);
1641 FIXME("server %s not supported\n", debugstr_w(pName
));
1642 SetLastError(ERROR_INVALID_PARAMETER
);
1646 if ((level
< 1) || (level
> 2)) {
1647 SetLastError(ERROR_INVALID_LEVEL
);
1651 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1652 SetLastError(ERROR_INVALID_PARAMETER
);
1656 /* load the Monitor */
1657 pm
= monitor_load(pMonitorName
, NULL
);
1658 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1659 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1660 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1664 FIXME("not implemented for %s (monitor %p: %s)\n",
1665 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1666 SetLastError(ERROR_INVALID_PARAMETER
);
1673 /******************************************************************************
1674 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1676 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1679 * pName [I] Servername or NULL (local Computer)
1680 * level [I] Level for the supplied DRIVER_INFO_*W struct
1681 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1682 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1689 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1693 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1694 lres
= copy_servername_from_name(pName
, NULL
);
1696 FIXME("server %s not supported\n", debugstr_w(pName
));
1697 SetLastError(ERROR_ACCESS_DENIED
);
1701 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1702 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1705 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1708 /******************************************************************************
1709 * fpClosePrinter [exported through PRINTPROVIDOR]
1711 * Close a printer handle and free associated resources
1714 * hPrinter [I] Printerhandle to close
1721 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1723 printer_t
*printer
= (printer_t
*) hPrinter
;
1725 TRACE("(%p)\n", hPrinter
);
1728 printer_free(printer
);
1734 /******************************************************************************
1735 * fpConfigurePort [exported through PRINTPROVIDOR]
1737 * Display the Configuration-Dialog for a specific Port
1740 * pName [I] Servername or NULL (local Computer)
1741 * hWnd [I] Handle to parent Window for the Dialog-Box
1742 * pPortName [I] Name of the Port, that should be configured
1749 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1756 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1758 lres
= copy_servername_from_name(pName
, NULL
);
1760 FIXME("server %s not supported\n", debugstr_w(pName
));
1761 SetLastError(ERROR_INVALID_NAME
);
1765 /* an empty Portname is Invalid, but can popup a Dialog */
1766 if (!pPortName
[0]) {
1767 SetLastError(ERROR_NOT_SUPPORTED
);
1771 pm
= monitor_load_by_port(pPortName
);
1772 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1773 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1774 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1775 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1776 TRACE("got %d with %u\n", res
, GetLastError());
1780 pui
= monitor_loadui(pm
);
1781 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1782 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1783 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1784 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1785 TRACE("got %d with %u\n", res
, GetLastError());
1789 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1790 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1791 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1793 SetLastError(ERROR_NOT_SUPPORTED
);
1796 monitor_unload(pui
);
1800 TRACE("returning %d with %u\n", res
, GetLastError());
1804 /******************************************************************
1805 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1807 * Delete a specific Printmonitor from a Printing-Environment
1810 * pName [I] Servername or NULL (local Computer)
1811 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1812 * pMonitorName [I] Name of the Monitor, that should be deleted
1819 * pEnvironment is ignored in Windows for the local Computer.
1823 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1828 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1829 debugstr_w(pMonitorName
));
1831 lres
= copy_servername_from_name(pName
, NULL
);
1833 FIXME("server %s not supported\n", debugstr_w(pName
));
1834 SetLastError(ERROR_INVALID_NAME
);
1838 /* pEnvironment is ignored in Windows for the local Computer */
1839 if (!pMonitorName
|| !pMonitorName
[0]) {
1840 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1841 SetLastError(ERROR_INVALID_PARAMETER
);
1845 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1846 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1850 if(SHDeleteKeyW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1851 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1856 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1859 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1860 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1864 /*****************************************************************************
1865 * fpDeletePort [exported through PRINTPROVIDOR]
1867 * Delete a specific Port
1870 * pName [I] Servername or NULL (local Computer)
1871 * hWnd [I] Handle to parent Window for the Dialog-Box
1872 * pPortName [I] Name of the Port, that should be deleted
1879 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1886 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1888 lres
= copy_servername_from_name(pName
, NULL
);
1890 FIXME("server %s not supported\n", debugstr_w(pName
));
1891 SetLastError(ERROR_INVALID_NAME
);
1895 /* an empty Portname is Invalid */
1896 if (!pPortName
[0]) {
1897 SetLastError(ERROR_NOT_SUPPORTED
);
1901 pm
= monitor_load_by_port(pPortName
);
1902 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1903 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1904 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1905 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1906 TRACE("got %d with %u\n", res
, GetLastError());
1910 pui
= monitor_loadui(pm
);
1911 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1912 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1913 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1914 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1915 TRACE("got %d with %u\n", res
, GetLastError());
1919 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1920 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1921 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1923 SetLastError(ERROR_NOT_SUPPORTED
);
1926 monitor_unload(pui
);
1930 TRACE("returning %d with %u\n", res
, GetLastError());
1934 /*****************************************************************************
1935 * fpEnumMonitors [exported through PRINTPROVIDOR]
1937 * Enumerate available Port-Monitors
1940 * pName [I] Servername or NULL (local Computer)
1941 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1942 * pMonitors [O] PTR to Buffer that receives the Result
1943 * cbBuf [I] Size of Buffer at pMonitors
1944 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1945 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1949 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1952 * Windows reads the Registry once and cache the Results.
1955 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1956 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1958 DWORD numentries
= 0;
1963 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1964 cbBuf
, pcbNeeded
, pcReturned
);
1966 lres
= copy_servername_from_name(pName
, NULL
);
1968 FIXME("server %s not supported\n", debugstr_w(pName
));
1969 SetLastError(ERROR_INVALID_NAME
);
1973 if (!Level
|| (Level
> 2)) {
1974 WARN("level (%d) is ignored in win9x\n", Level
);
1975 SetLastError(ERROR_INVALID_LEVEL
);
1979 /* Scan all Monitor-Keys */
1981 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1983 /* we calculated the needed buffersize. now do more error-checks */
1984 if (cbBuf
< needed
) {
1985 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1989 /* fill the Buffer with the Monitor-Keys */
1990 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
1994 if (pcbNeeded
) *pcbNeeded
= needed
;
1995 if (pcReturned
) *pcReturned
= numentries
;
1997 TRACE("returning %d with %d (%d byte for %d entries)\n",
1998 res
, GetLastError(), needed
, numentries
);
2003 /******************************************************************************
2004 * fpEnumPorts [exported through PRINTPROVIDOR]
2006 * Enumerate available Ports
2009 * pName [I] Servername or NULL (local Computer)
2010 * Level [I] Structure-Level (1 or 2)
2011 * pPorts [O] PTR to Buffer that receives the Result
2012 * cbBuf [I] Size of Buffer at pPorts
2013 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2014 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2018 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2021 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2022 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2025 DWORD numentries
= 0;
2029 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2030 cbBuf
, pcbNeeded
, pcReturned
);
2032 lres
= copy_servername_from_name(pName
, NULL
);
2034 FIXME("server %s not supported\n", debugstr_w(pName
));
2035 SetLastError(ERROR_INVALID_NAME
);
2039 if (!Level
|| (Level
> 2)) {
2040 SetLastError(ERROR_INVALID_LEVEL
);
2044 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2045 SetLastError(RPC_X_NULL_REF_POINTER
);
2049 EnterCriticalSection(&monitor_handles_cs
);
2052 /* Scan all local Ports */
2054 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2056 /* we calculated the needed buffersize. now do the error-checks */
2057 if (cbBuf
< needed
) {
2058 monitor_unloadall();
2059 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2060 goto emP_cleanup_cs
;
2062 else if (!pPorts
|| !pcReturned
) {
2063 monitor_unloadall();
2064 SetLastError(RPC_X_NULL_REF_POINTER
);
2065 goto emP_cleanup_cs
;
2068 /* Fill the Buffer */
2069 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2071 monitor_unloadall();
2074 LeaveCriticalSection(&monitor_handles_cs
);
2077 if (pcbNeeded
) *pcbNeeded
= needed
;
2078 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2080 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2081 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2086 /*****************************************************************************
2087 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2089 * Enumerate available Print Processors
2092 * pName [I] Servername or NULL (local Computer)
2093 * pEnvironment [I] Printing-Environment or NULL (Default)
2094 * Level [I] Structure-Level (Only 1 is allowed)
2095 * pPPInfo [O] PTR to Buffer that receives the Result
2096 * cbBuf [I] Size of Buffer at pMonitors
2097 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2098 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2102 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2105 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2106 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2108 const printenv_t
* env
;
2109 LPWSTR regpathW
= NULL
;
2110 DWORD numentries
= 0;
2115 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2116 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2118 lres
= copy_servername_from_name(pName
, NULL
);
2120 FIXME("server %s not supported\n", debugstr_w(pName
));
2121 SetLastError(ERROR_INVALID_NAME
);
2126 SetLastError(ERROR_INVALID_LEVEL
);
2130 env
= validate_envW(pEnvironment
);
2132 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2134 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2135 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2140 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2142 /* Scan all Printprocessor-Keys */
2144 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2146 /* we calculated the needed buffersize. now do more error-checks */
2147 if (cbBuf
< needed
) {
2148 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2152 /* fill the Buffer with the Printprocessor Infos */
2153 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2157 heap_free(regpathW
);
2158 if (pcbNeeded
) *pcbNeeded
= needed
;
2159 if (pcReturned
) *pcReturned
= numentries
;
2161 TRACE("returning %d with %d (%d byte for %d entries)\n",
2162 res
, GetLastError(), needed
, numentries
);
2167 /******************************************************************************
2168 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2170 * Return the PATH for the Print-Processors
2173 * pName [I] Servername or NULL (this computer)
2174 * pEnvironment [I] Printing-Environment or NULL (Default)
2175 * level [I] Structure-Level (must be 1)
2176 * pPPInfo [O] PTR to Buffer that receives the Result
2177 * cbBuf [I] Size of Buffer at pPPInfo
2178 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2182 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2184 * Native Values returned in pPPInfo on Success for this computer:
2185 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2186 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2187 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2189 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2192 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2193 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2195 const printenv_t
* env
;
2199 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2200 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2203 lres
= copy_servername_from_name(pName
, NULL
);
2205 FIXME("server %s not supported\n", debugstr_w(pName
));
2206 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2210 env
= validate_envW(pEnvironment
);
2212 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2214 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2215 needed
= GetSystemDirectoryW(NULL
, 0);
2216 /* add the Size for the Subdirectories */
2217 needed
+= lstrlenW(spoolprtprocsW
);
2218 needed
+= lstrlenW(env
->subdir
);
2219 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2221 *pcbNeeded
= needed
;
2223 if (needed
> cbBuf
) {
2224 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2228 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2229 /* add the Subdirectories */
2230 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2231 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2232 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2236 /******************************************************************************
2237 * fpOpenPrinter [exported through PRINTPROVIDOR]
2239 * Open a Printer / Printserver or a Printer-Object
2242 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2243 * pPrinter [O] The resulting Handle is stored here
2244 * pDefaults [I] PTR to Default Printer Settings or NULL
2251 * lpPrinterName is one of:
2252 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2253 *| Printer: "PrinterName"
2254 *| Printer-Object: "PrinterName,Job xxx"
2255 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2256 *| XcvPort: "Servername,XcvPort PortName"
2260 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2261 LPPRINTER_DEFAULTSW pDefaults
)
2264 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2266 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2268 return (*pPrinter
!= 0);
2271 /******************************************************************************
2272 * fpXcvData [exported through PRINTPROVIDOR]
2274 * Execute commands in the Printmonitor DLL
2277 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2278 * pszDataName [i] Name of the command to execute
2279 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2280 * cbInputData [i] Size in Bytes of Buffer at pInputData
2281 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2282 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2283 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2284 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2291 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2292 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2294 * Minimal List of commands, that a Printmonitor DLL should support:
2296 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2297 *| "AddPort" : Add a Port
2298 *| "DeletePort": Delete a Port
2300 * Many Printmonitors support additional commands. Examples for localspl.dll:
2301 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2302 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2305 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2306 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2307 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2309 printer_t
*printer
= (printer_t
* ) hXcv
;
2311 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2312 pInputData
, cbInputData
, pOutputData
,
2313 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2315 if (!printer
|| (!printer
->hXcv
)) {
2316 SetLastError(ERROR_INVALID_HANDLE
);
2320 if (!pcbOutputNeeded
) {
2321 SetLastError(ERROR_INVALID_PARAMETER
);
2325 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2326 SetLastError(RPC_X_NULL_REF_POINTER
);
2330 *pcbOutputNeeded
= 0;
2332 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2333 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2338 /*****************************************************
2339 * setup_provider [internal]
2341 void setup_provider(void)
2343 static const PRINTPROVIDOR backend
= {
2345 NULL
, /* fpSetJob */
2346 NULL
, /* fpGetJob */
2347 NULL
, /* fpEnumJobs */
2348 NULL
, /* fpAddPrinter */
2349 NULL
, /* fpDeletePrinter */
2350 NULL
, /* fpSetPrinter */
2351 NULL
, /* fpGetPrinter */
2352 NULL
, /* fpEnumPrinters */
2353 NULL
, /* fpAddPrinterDriver */
2354 NULL
, /* fpEnumPrinterDrivers */
2355 NULL
, /* fpGetPrinterDriver */
2356 fpGetPrinterDriverDirectory
,
2357 NULL
, /* fpDeletePrinterDriver */
2358 NULL
, /* fpAddPrintProcessor */
2359 fpEnumPrintProcessors
,
2360 fpGetPrintProcessorDirectory
,
2361 NULL
, /* fpDeletePrintProcessor */
2362 NULL
, /* fpEnumPrintProcessorDatatypes */
2363 NULL
, /* fpStartDocPrinter */
2364 NULL
, /* fpStartPagePrinter */
2365 NULL
, /* fpWritePrinter */
2366 NULL
, /* fpEndPagePrinter */
2367 NULL
, /* fpAbortPrinter */
2368 NULL
, /* fpReadPrinter */
2369 NULL
, /* fpEndDocPrinter */
2370 NULL
, /* fpAddJob */
2371 NULL
, /* fpScheduleJob */
2372 NULL
, /* fpGetPrinterData */
2373 NULL
, /* fpSetPrinterData */
2374 NULL
, /* fpWaitForPrinterChange */
2376 NULL
, /* fpAddForm */
2377 NULL
, /* fpDeleteForm */
2378 NULL
, /* fpGetForm */
2379 NULL
, /* fpSetForm */
2380 NULL
, /* fpEnumForms */
2386 NULL
, /* fpCreatePrinterIC */
2387 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2388 NULL
, /* fpDeletePrinterIC */
2389 NULL
, /* fpAddPrinterConnection */
2390 NULL
, /* fpDeletePrinterConnection */
2391 NULL
, /* fpPrinterMessageBox */
2394 NULL
, /* fpResetPrinter */
2395 NULL
, /* fpGetPrinterDriverEx */
2396 NULL
, /* fpFindFirstPrinterChangeNotification */
2397 NULL
, /* fpFindClosePrinterChangeNotification */
2399 NULL
, /* fpShutDown */
2400 NULL
, /* fpRefreshPrinterChangeNotification */
2401 NULL
, /* fpOpenPrinterEx */
2402 NULL
, /* fpAddPrinterEx */
2403 NULL
, /* fpSetPort */
2404 NULL
, /* fpEnumPrinterData */
2405 NULL
, /* fpDeletePrinterData */
2406 NULL
, /* fpClusterSplOpen */
2407 NULL
, /* fpClusterSplClose */
2408 NULL
, /* fpClusterSplIsAlive */
2409 NULL
, /* fpSetPrinterDataEx */
2410 NULL
, /* fpGetPrinterDataEx */
2411 NULL
, /* fpEnumPrinterDataEx */
2412 NULL
, /* fpEnumPrinterKey */
2413 NULL
, /* fpDeletePrinterDataEx */
2414 NULL
, /* fpDeletePrinterKey */
2415 NULL
, /* fpSeekPrinter */
2416 NULL
, /* fpDeletePrinterDriverEx */
2417 NULL
, /* fpAddPerMachineConnection */
2418 NULL
, /* fpDeletePerMachineConnection */
2419 NULL
, /* fpEnumPerMachineConnections */
2421 fpAddPrinterDriverEx
,
2422 NULL
, /* fpSplReadPrinter */
2423 NULL
, /* fpDriverUnloadComplete */
2424 NULL
, /* fpGetSpoolFileInfo */
2425 NULL
, /* fpCommitSpoolData */
2426 NULL
, /* fpCloseSpoolFileHandle */
2427 NULL
, /* fpFlushPrinter */
2428 NULL
, /* fpSendRecvBidiData */
2429 NULL
/* fpAddDriverCatalog */
2431 pprovider
= &backend
;
2435 /*****************************************************
2436 * InitializePrintProvidor (localspl.@)
2438 * Initialize the Printprovider
2441 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2442 * cbPrintProvidor [I] Size of Buffer in Bytes
2443 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2446 * Success: TRUE and pPrintProvidor filled
2450 * The RegistryPath should be:
2451 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2452 * but this Parameter is ignored in "localspl.dll".
2456 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2457 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2460 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2461 memcpy(pPrintProvidor
, pprovider
,
2462 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));