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 dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
87 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
88 static const WCHAR emptyW
[] = {0};
89 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
90 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
91 'c','o','n','t','r','o','l','\\',
92 'P','r','i','n','t','\\',
93 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
94 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
95 static const WCHAR fmt_printprocessorsW
[] = { 'S','y','s','t','e','m','\\',
96 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
97 'C','o','n','t','r','o','l','\\',
98 'P','r','i','n','t','\\',
99 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
100 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
101 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
102 static const WCHAR ia64_envnameW
[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
103 static const WCHAR ia64_subdirW
[] = {'i','a','6','4',0};
104 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
105 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
106 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
107 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
108 'C','o','n','t','r','o','l','\\',
109 'P','r','i','n','t','\\',
110 'M','o','n','i','t','o','r','s','\\',0};
111 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
112 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
113 static const WCHAR printersW
[] = {'S','y','s','t','e','m','\\',
114 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
115 'C','o','n','t','r','o','l','\\',
116 'P','r','i','n','t','\\',
117 'P','r','i','n','t','e','r','s',0};
118 static const WCHAR spoolW
[] = {'\\','s','p','o','o','l',0};
119 static const WCHAR driversW
[] = {'\\','d','r','i','v','e','r','s','\\',0};
120 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
121 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
122 static const WCHAR version0_subdirW
[] = {'\\','0',0};
123 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
124 static const WCHAR version3_subdirW
[] = {'\\','3',0};
125 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
126 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
127 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
128 static const WCHAR winnt_cv_portsW
[] = {'S','o','f','t','w','a','r','e','\\',
129 'M','i','c','r','o','s','o','f','t','\\',
130 'W','i','n','d','o','w','s',' ','N','T','\\',
131 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
132 'P','o','r','t','s',0};
133 static const WCHAR winprintW
[] = {'w','i','n','p','r','i','n','t',0};
134 static const WCHAR x64_envnameW
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
135 static const WCHAR x64_subdirW
[] = {'x','6','4',0};
136 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
137 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
138 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
139 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
142 static const printenv_t env_ia64
= {ia64_envnameW
, ia64_subdirW
, 3,
143 version3_regpathW
, version3_subdirW
};
145 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
146 version3_regpathW
, version3_subdirW
};
148 static const printenv_t env_x64
= {x64_envnameW
, x64_subdirW
, 3,
149 version3_regpathW
, version3_subdirW
};
151 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
152 version0_regpathW
, version0_subdirW
};
154 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_win40
};
157 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
158 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
159 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
160 0, sizeof(DRIVER_INFO_8W
)};
163 /******************************************************************
166 * create a copy of a unicode-string
169 static LPWSTR
strdupW(LPCWSTR p
)
175 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
176 ret
= heap_alloc(len
);
177 if (ret
) memcpy(ret
, p
, len
);
181 /******************************************************************
182 * apd_copyfile [internal]
184 * Copy a file from the driverdirectory to the versioned directory
191 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
196 apd
->src
[apd
->srclen
] = '\0';
197 apd
->dst
[apd
->dstlen
] = '\0';
199 if (!pathname
|| !pathname
[0]) {
200 /* nothing to copy */
204 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
209 strcatW( srcname
, file_part
);
211 strcatW( apd
->dst
, file_part
);
213 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
215 /* FIXME: handle APD_COPY_NEW_FILES */
216 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
217 TRACE("got %d with %u\n", res
, GetLastError());
219 return apd
->lazy
|| res
;
222 /******************************************************************
223 * copy_servername_from_name (internal)
225 * for an external server, the serverpart from the name is copied.
228 * the length (in WCHAR) of the serverpart (0 for the local computer)
229 * (-length), when the name is too long
232 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
236 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
240 if (target
) *target
= '\0';
242 if (name
== NULL
) return 0;
243 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
246 /* skip over both backslash, find separator '\' */
247 ptr
= strchrW(server
, '\\');
248 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
250 /* servername is empty */
251 if (serverlen
== 0) return 0;
253 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
255 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
258 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
259 target
[serverlen
] = '\0';
262 len
= sizeof(buffer
) / sizeof(buffer
[0]);
263 if (GetComputerNameW(buffer
, &len
)) {
264 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
265 /* The requested Servername is our computername */
272 /******************************************************************
273 * get_basename_from_name (internal)
275 * skip over the serverpart from the full name
278 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
280 if (name
== NULL
) return NULL
;
281 if ((name
[0] == '\\') && (name
[1] == '\\')) {
282 /* skip over the servername and search for the following '\' */
283 name
= strchrW(&name
[2], '\\');
284 if ((name
) && (name
[1])) {
285 /* found a separator ('\') followed by a name:
286 skip over the separator and return the rest */
291 /* no basename present (we found only a servername) */
298 /******************************************************************
299 * monitor_unload [internal]
301 * release a printmonitor and unload it from memory, when needed
304 static void monitor_unload(monitor_t
* pm
)
306 if (pm
== NULL
) return;
307 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
309 EnterCriticalSection(&monitor_handles_cs
);
311 if (pm
->refcount
) pm
->refcount
--;
313 if (pm
->refcount
== 0) {
314 list_remove(&pm
->entry
);
315 FreeLibrary(pm
->hdll
);
317 heap_free(pm
->dllname
);
320 LeaveCriticalSection(&monitor_handles_cs
);
323 /******************************************************************
324 * monitor_unloadall [internal]
326 * release all registered printmonitors and unload them from memory, when needed
330 static void monitor_unloadall(void)
335 EnterCriticalSection(&monitor_handles_cs
);
336 /* iterate through the list, with safety against removal */
337 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
339 /* skip monitorui dlls */
340 if (pm
->monitor
) monitor_unload(pm
);
342 LeaveCriticalSection(&monitor_handles_cs
);
345 /******************************************************************
346 * monitor_load [internal]
348 * load a printmonitor, get the dllname from the registry, when needed
349 * initialize the monitor and dump found function-pointers
351 * On failure, SetLastError() is called and NULL is returned
354 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
356 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
357 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
358 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
359 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
360 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
362 monitor_t
* pm
= NULL
;
364 LPWSTR regroot
= NULL
;
365 LPWSTR driver
= dllname
;
367 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
368 /* Is the Monitor already loaded? */
369 EnterCriticalSection(&monitor_handles_cs
);
372 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
374 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
382 pm
= heap_alloc_zero(sizeof(monitor_t
));
383 if (pm
== NULL
) goto cleanup
;
384 list_add_tail(&monitor_handles
, &pm
->entry
);
388 if (pm
->name
== NULL
) {
389 /* Load the monitor */
390 LPMONITOREX pmonitorEx
;
394 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
395 regroot
= heap_alloc(len
* sizeof(WCHAR
));
399 lstrcpyW(regroot
, monitorsW
);
400 lstrcatW(regroot
, name
);
401 /* Get the Driver from the Registry */
402 if (driver
== NULL
) {
405 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
406 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
407 &namesize
) == ERROR_SUCCESS
) {
408 driver
= heap_alloc(namesize
);
409 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
416 pm
->name
= strdupW(name
);
417 pm
->dllname
= strdupW(driver
);
419 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
421 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
426 pm
->hdll
= LoadLibraryW(driver
);
427 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
429 if (pm
->hdll
== NULL
) {
431 SetLastError(ERROR_MOD_NOT_FOUND
);
436 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
437 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
438 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
439 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
440 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
443 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
444 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
445 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
446 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
447 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
449 if (pInitializePrintMonitorUI
!= NULL
) {
450 pm
->monitorUI
= pInitializePrintMonitorUI();
451 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
453 TRACE("0x%08x: dwMonitorSize (%d)\n",
454 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
459 if (pInitializePrintMonitor
&& regroot
) {
460 pmonitorEx
= pInitializePrintMonitor(regroot
);
461 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
462 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
465 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
466 pm
->monitor
= &(pmonitorEx
->Monitor
);
471 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
475 if (!pm
->monitor
&& regroot
) {
476 if (pInitializePrintMonitor2
!= NULL
) {
477 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
479 if (pInitializeMonitorEx
!= NULL
) {
480 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
482 if (pInitializeMonitor
!= NULL
) {
483 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
486 if (!pm
->monitor
&& !pm
->monitorUI
) {
488 SetLastError(ERROR_PROC_NOT_FOUND
);
493 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
497 LeaveCriticalSection(&monitor_handles_cs
);
498 if (driver
!= dllname
) heap_free(driver
);
500 TRACE("=> %p\n", pm
);
504 /******************************************************************
505 * monitor_loadall [internal]
507 * Load all registered monitors
510 static DWORD
monitor_loadall(void)
513 DWORD registered
= 0;
516 WCHAR buffer
[MAX_PATH
];
519 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
520 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
521 NULL
, NULL
, NULL
, NULL
, NULL
);
523 TRACE("%d monitors registered\n", registered
);
525 while (id
< registered
) {
527 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
528 pm
= monitor_load(buffer
, NULL
);
532 RegCloseKey(hmonitors
);
534 TRACE("%d monitors loaded\n", loaded
);
538 /******************************************************************
539 * monitor_loadui [internal]
541 * load the userinterface-dll for a given portmonitor
543 * On failure, NULL is returned
545 static monitor_t
* monitor_loadui(monitor_t
* pm
)
547 monitor_t
* pui
= NULL
;
548 WCHAR buffer
[MAX_PATH
];
553 if (pm
== NULL
) return NULL
;
554 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
556 /* Try the Portmonitor first; works for many monitors */
558 EnterCriticalSection(&monitor_handles_cs
);
560 LeaveCriticalSection(&monitor_handles_cs
);
564 /* query the userinterface-dllname from the Portmonitor */
565 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
566 /* building (",XcvMonitor %s",pm->name) not needed yet */
567 res
= pm
->monitor
->pfnXcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
568 TRACE("got %u with %p\n", res
, hXcv
);
570 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
571 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
572 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
573 pm
->monitor
->pfnXcvClosePort(hXcv
);
579 /******************************************************************
580 * monitor_load_by_port [internal]
582 * load a printmonitor for a given port
584 * On failure, NULL is returned
587 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
592 monitor_t
* pm
= NULL
;
593 DWORD registered
= 0;
597 TRACE("(%s)\n", debugstr_w(portname
));
599 /* Try the Local Monitor first */
600 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
601 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
602 /* found the portname */
604 return monitor_load(localportW
, NULL
);
609 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
610 buffer
= heap_alloc(len
* sizeof(WCHAR
));
611 if (buffer
== NULL
) return NULL
;
613 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
614 EnterCriticalSection(&monitor_handles_cs
);
615 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
617 while ((pm
== NULL
) && (id
< registered
)) {
619 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
620 TRACE("testing %s\n", debugstr_w(buffer
));
621 len
= lstrlenW(buffer
);
622 lstrcatW(buffer
, bs_ports_bsW
);
623 lstrcatW(buffer
, portname
);
624 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
626 buffer
[len
] = '\0'; /* use only the Monitor-Name */
627 pm
= monitor_load(buffer
, NULL
);
631 LeaveCriticalSection(&monitor_handles_cs
);
638 /******************************************************************
639 * Return the number of bytes for an multi_sz string.
640 * The result includes all \0s
641 * (specifically the extra \0, that is needed as multi_sz terminator).
643 static int multi_sz_lenW(const WCHAR
*str
)
645 const WCHAR
*ptr
= str
;
649 ptr
+= lstrlenW(ptr
) + 1;
652 return (ptr
- str
+ 1) * sizeof(WCHAR
);
655 /******************************************************************
656 * validate_envW [internal]
658 * validate the user-supplied printing-environment
661 * env [I] PTR to Environment-String or NULL
664 * Success: PTR to printenv_t
665 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
668 * An empty string is handled the same way as NULL.
672 static const printenv_t
* validate_envW(LPCWSTR env
)
674 const printenv_t
*result
= NULL
;
677 TRACE("(%s)\n", debugstr_w(env
));
680 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
682 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
684 result
= all_printenv
[i
];
688 if (result
== NULL
) {
689 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
690 SetLastError(ERROR_INVALID_ENVIRONMENT
);
692 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
696 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
699 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
703 /*****************************************************************************
704 * enumerate the local monitors (INTERNAL)
706 * returns the needed size (in bytes) for pMonitors
707 * and *lpreturned is set to number of entries returned in pMonitors
709 * Language-Monitors are also installed in the same Registry-Location but
710 * they are filtered in Windows (not returned by EnumMonitors).
711 * We do no filtering to simplify our Code.
714 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
719 LPMONITOR_INFO_2W mi
;
720 WCHAR buffer
[MAX_PATH
];
721 WCHAR dllname
[MAX_PATH
];
729 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
731 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
732 len
= entrysize
* numentries
;
733 ptr
= (LPWSTR
) &pMonitors
[len
];
736 len
= sizeof(buffer
)/sizeof(buffer
[0]);
739 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
740 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
741 /* Scan all Monitor-Registry-Keys */
742 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
743 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
744 dllsize
= sizeof(dllname
);
747 /* The Monitor must have a Driver-DLL */
748 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
749 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
750 /* We found a valid DLL for this Monitor. */
751 TRACE("using Driver: %s\n", debugstr_w(dllname
));
756 /* Windows returns only Port-Monitors here, but to simplify our code,
757 we do no filtering for Language-Monitors */
761 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
763 /* we install and return only monitors for "Windows NT x86" */
764 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
768 /* required size is calculated. Now fill the user-buffer */
769 if (pMonitors
&& (cbBuf
>= needed
)){
770 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
771 pMonitors
+= entrysize
;
773 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
775 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
776 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
778 mi
->pEnvironment
= ptr
;
779 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
780 ptr
+= (lstrlenW(x86_envnameW
)+1);
783 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
784 ptr
+= (dllsize
/ sizeof(WCHAR
));
789 len
= sizeof(buffer
)/sizeof(buffer
[0]);
794 *lpreturned
= numentries
;
795 TRACE("need %d byte for %d entries\n", needed
, numentries
);
799 /*****************************************************************************
800 * enumerate the local print processors (INTERNAL)
802 * returns the needed size (in bytes) for pPPInfo
803 * and *lpreturned is set to number of entries returned in pPPInfo
806 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
811 PPRINTPROCESSOR_INFO_1W ppi
;
812 WCHAR buffer
[MAX_PATH
];
813 WCHAR dllname
[MAX_PATH
];
820 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
821 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
822 ptr
= (LPWSTR
) &pPPInfo
[len
];
825 len
= sizeof(buffer
)/sizeof(buffer
[0]);
828 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
829 /* add "winprint" first */
831 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(winprintW
);
832 if (pPPInfo
&& (cbBuf
>= needed
)){
833 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
834 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
836 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
838 lstrcpyW(ptr
, winprintW
); /* Name of the Print Processor */
839 ptr
+= sizeof(winprintW
) / sizeof(WCHAR
);
842 /* Scan all Printprocessor Keys */
843 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
844 (lstrcmpiW(buffer
, winprintW
) != 0)) {
845 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
846 dllsize
= sizeof(dllname
);
849 /* The Print Processor must have a Driver-DLL */
850 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
851 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
852 /* We found a valid DLL for this Print Processor */
853 TRACE("using Driver: %s\n", debugstr_w(dllname
));
860 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
861 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
863 /* required size is calculated. Now fill the user-buffer */
864 if (pPPInfo
&& (cbBuf
>= needed
)){
865 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
866 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
868 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
870 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
871 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
875 len
= sizeof(buffer
)/sizeof(buffer
[0]);
880 *lpreturned
= numentries
;
881 TRACE("need %d byte for %d entries\n", needed
, numentries
);
885 /******************************************************************
886 * enumerate the local Ports from all loaded monitors (internal)
888 * returns the needed size (in bytes) for pPorts
889 * and *lpreturned is set to number of entries returned in pPorts
892 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
896 LPPORT_INFO_2W cache
;
898 LPBYTE pi_buffer
= NULL
;
899 DWORD pi_allocated
= 0;
910 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
911 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
913 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
914 needed
= entrysize
* numentries
;
915 ptr
= (LPWSTR
) &pPorts
[needed
];
920 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
922 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
925 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
926 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
927 /* Do not use heap_realloc (we do not need the old data in the buffer) */
928 heap_free(pi_buffer
);
929 pi_buffer
= heap_alloc(pi_needed
);
930 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
931 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
933 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
934 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
936 numentries
+= pi_returned
;
939 /* fill the output-buffer (pPorts), if we have one */
940 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
942 while (pi_returned
> pi_index
) {
943 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
944 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
945 out
->pPortName
= ptr
;
946 lstrcpyW(ptr
, cache
->pPortName
);
947 ptr
+= (lstrlenW(ptr
)+1);
949 out
->pMonitorName
= ptr
;
950 lstrcpyW(ptr
, cache
->pMonitorName
);
951 ptr
+= (lstrlenW(ptr
)+1);
953 out
->pDescription
= ptr
;
954 lstrcpyW(ptr
, cache
->pDescription
);
955 ptr
+= (lstrlenW(ptr
)+1);
956 out
->fPortType
= cache
->fPortType
;
957 out
->Reserved
= cache
->Reserved
;
965 /* the temporary portinfo-buffer is no longer needed */
966 heap_free(pi_buffer
);
968 *lpreturned
= numentries
;
969 TRACE("need %d byte for %d entries\n", needed
, numentries
);
974 /*****************************************************************************
975 * open_driver_reg [internal]
977 * opens the registry for the printer drivers depending on the given input
978 * variable pEnvironment
981 * Success: the opened hkey
984 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
988 const printenv_t
* env
;
990 TRACE("(%s)\n", debugstr_w(pEnvironment
));
992 env
= validate_envW(pEnvironment
);
993 if (!env
) return NULL
;
995 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
996 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
999 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1000 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1001 HeapFree(GetProcessHeap(), 0, buffer
);
1006 /*****************************************************************************
1007 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1009 * Return the PATH for the Printer-Drivers
1012 * pName [I] Servername (NT only) or NULL (local Computer)
1013 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1014 * Level [I] Structure-Level (must be 1)
1015 * pDriverDirectory [O] PTR to Buffer that receives the Result
1016 * cbBuf [I] Size of Buffer at pDriverDirectory
1017 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1018 * required for pDriverDirectory
1021 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1022 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1023 * if cbBuf is too small
1025 * Native Values returned in pDriverDirectory on Success:
1026 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1027 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1028 *| win9x(Windows 4.0): "%winsysdir%"
1030 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1033 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1034 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1037 const printenv_t
* env
;
1038 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1040 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1041 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1043 if (pName
!= NULL
&& pName
[0]) {
1044 FIXME("server %s not supported\n", debugstr_w(pName
));
1045 SetLastError(ERROR_INVALID_PARAMETER
);
1049 env
= validate_envW(pEnvironment
);
1050 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1053 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1054 needed
= GetSystemDirectoryW(NULL
, 0);
1055 /* add the Size for the Subdirectories */
1056 needed
+= lstrlenW(spoolW
);
1057 needed
+= lstrlenW(driversW
);
1058 needed
+= lstrlenW(env
->subdir
);
1059 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1061 *pcbNeeded
= needed
;
1063 if (needed
> cbBuf
) {
1064 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1069 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1070 SetLastError(ERROR_INVALID_USER_BUFFER
);
1074 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1075 /* add the Subdirectories */
1076 lstrcatW( dir
, spoolW
);
1077 CreateDirectoryW( dir
, NULL
);
1078 lstrcatW( dir
, driversW
);
1079 CreateDirectoryW( dir
, NULL
);
1080 lstrcatW( dir
, env
->subdir
);
1081 CreateDirectoryW( dir
, NULL
);
1083 TRACE( "=> %s\n", debugstr_w( dir
) );
1087 /******************************************************************
1088 * driver_load [internal]
1090 * load a driver user interface dll
1092 * On failure, NULL is returned
1096 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1098 WCHAR fullname
[MAX_PATH
];
1102 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1104 /* build the driverdir */
1105 len
= sizeof(fullname
) -
1106 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1108 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1109 (LPBYTE
) fullname
, len
, &len
)) {
1110 /* Should never fail */
1111 SetLastError(ERROR_BUFFER_OVERFLOW
);
1115 lstrcatW(fullname
, env
->versionsubdir
);
1116 lstrcatW(fullname
, backslashW
);
1117 lstrcatW(fullname
, dllname
);
1119 hui
= LoadLibraryW(fullname
);
1120 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1125 /******************************************************************
1127 * free the data pointer of an opened printer
1129 static VOID
printer_free(printer_t
* printer
)
1132 printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1134 monitor_unload(printer
->pm
);
1136 heap_free(printer
->printername
);
1137 heap_free(printer
->name
);
1141 /******************************************************************
1142 * printer_alloc_handle
1143 * alloc a printer handle and remember the data pointer in the printer handle table
1146 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1148 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1149 printer_t
*printer
= NULL
;
1150 LPCWSTR printername
;
1155 if (copy_servername_from_name(name
, servername
)) {
1156 FIXME("server %s not supported\n", debugstr_w(servername
));
1157 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1161 printername
= get_basename_from_name(name
);
1162 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1164 /* an empty printername is invalid */
1165 if (printername
&& (!printername
[0])) {
1166 SetLastError(ERROR_INVALID_PARAMETER
);
1170 printer
= heap_alloc_zero(sizeof(printer_t
));
1171 if (!printer
) goto end
;
1173 /* clone the base name. This is NULL for the printserver */
1174 printer
->printername
= strdupW(printername
);
1176 /* clone the full name */
1177 printer
->name
= strdupW(name
);
1178 if (name
&& (!printer
->name
)) {
1179 printer_free(printer
);
1183 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1184 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1185 /* OpenPrinter(",XcvMonitor ", ...) detected */
1186 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1187 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1188 if (printer
->pm
== NULL
) {
1189 printer_free(printer
);
1190 SetLastError(ERROR_UNKNOWN_PORT
);
1197 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1198 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1199 /* OpenPrinter(",XcvPort ", ...) detected */
1200 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1201 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1202 if (printer
->pm
== NULL
) {
1203 printer_free(printer
);
1204 SetLastError(ERROR_UNKNOWN_PORT
);
1212 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1213 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1214 pDefault
? pDefault
->DesiredAccess
: 0,
1217 if (printer
->hXcv
== NULL
) {
1218 printer_free(printer
);
1219 SetLastError(ERROR_INVALID_PARAMETER
);
1226 /* Does the Printer exist? */
1227 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1228 ERR("Can't create Printers key\n");
1229 printer_free(printer
);
1230 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1234 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1235 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1236 RegCloseKey(hkeyPrinters
);
1237 printer_free(printer
);
1238 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1242 RegCloseKey(hkeyPrinter
);
1243 RegCloseKey(hkeyPrinters
);
1248 TRACE("using the local printserver\n");
1253 TRACE("==> %p\n", printer
);
1254 return (HANDLE
)printer
;
1257 static inline WCHAR
*get_file_part( WCHAR
*name
)
1259 WCHAR
*ptr
= strrchrW( name
, '\\' );
1260 if (ptr
) return ptr
+ 1;
1264 /******************************************************************************
1265 * myAddPrinterDriverEx [internal]
1267 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1268 * and a special mode with lazy error checking.
1271 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1273 const printenv_t
*env
;
1276 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1286 /* we need to set all entries in the Registry, independent from the Level of
1287 DRIVER_INFO, that the caller supplied */
1289 ZeroMemory(&di
, sizeof(di
));
1290 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
1291 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1294 /* dump the most used infos */
1295 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1296 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1297 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1298 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1299 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1300 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1301 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1302 /* dump only the first of the additional Files */
1303 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1306 /* check environment */
1307 env
= validate_envW(di
.pEnvironment
);
1308 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1310 /* fill the copy-data / get the driverdir */
1311 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1312 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1313 (LPBYTE
) apd
.src
, len
, &len
)) {
1314 /* Should never fail */
1317 memcpy(apd
.dst
, apd
.src
, len
);
1318 lstrcatW(apd
.src
, backslashW
);
1319 apd
.srclen
= lstrlenW(apd
.src
);
1320 lstrcatW(apd
.dst
, env
->versionsubdir
);
1321 lstrcatW(apd
.dst
, backslashW
);
1322 apd
.dstlen
= lstrlenW(apd
.dst
);
1323 apd
.copyflags
= dwFileCopyFlags
;
1325 CreateDirectoryW(apd
.src
, NULL
);
1326 CreateDirectoryW(apd
.dst
, NULL
);
1328 hroot
= open_driver_reg(env
->envname
);
1330 ERR("Can't create Drivers key\n");
1334 /* Fill the Registry for the Driver */
1335 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1336 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1337 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1339 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1346 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1347 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1350 file
= get_file_part( di
.pDriverPath
);
1351 RegSetValueExW( hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1352 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1354 file
= get_file_part( di
.pDataFile
);
1355 RegSetValueExW( hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1356 apd_copyfile( di
.pDataFile
, file
, &apd
);
1358 file
= get_file_part( di
.pConfigFile
);
1359 RegSetValueExW( hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1360 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1362 /* settings for level 3 */
1365 file
= get_file_part( di
.pHelpFile
);
1366 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1367 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1370 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
) );
1372 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1374 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1375 reg
= reg_ptr
= HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di
.pDependentFiles
) );
1377 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= strlenW( in_ptr
) + 1)
1379 file
= get_file_part( in_ptr
);
1380 len
= strlenW( file
) + 1;
1381 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1383 apd_copyfile( in_ptr
, file
, &apd
);
1387 RegSetValueExW( hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
1388 HeapFree( GetProcessHeap(), 0, reg
);
1391 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1393 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1394 if (di
.pMonitorName
)
1395 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1396 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1398 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1400 if (di
.pDefaultDataType
)
1401 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1402 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1404 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1406 /* settings for level 4 */
1407 if (di
.pszzPreviousNames
)
1408 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1409 multi_sz_lenW(di
.pszzPreviousNames
));
1411 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1413 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1416 hui
= driver_load(env
, di
.pConfigFile
);
1417 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1418 if (hui
&& pDrvDriverEvent
) {
1420 /* Support for DrvDriverEvent is optional */
1421 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1422 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1423 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1424 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1428 TRACE("=> TRUE with %u\n", GetLastError());
1433 /******************************************************************************
1434 * fpAddMonitor [exported through PRINTPROVIDOR]
1436 * Install a Printmonitor
1439 * pName [I] Servername or NULL (local Computer)
1440 * Level [I] Structure-Level (Must be 2)
1441 * pMonitors [I] PTR to MONITOR_INFO_2
1448 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1451 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1453 monitor_t
* pm
= NULL
;
1454 LPMONITOR_INFO_2W mi2w
;
1460 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1461 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1462 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1463 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1464 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1466 if (copy_servername_from_name(pName
, NULL
)) {
1467 FIXME("server %s not supported\n", debugstr_w(pName
));
1468 SetLastError(ERROR_ACCESS_DENIED
);
1472 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1473 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1474 SetLastError(ERROR_INVALID_PARAMETER
);
1477 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
1478 WARN("Environment %s requested (we support only %s)\n",
1479 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
1480 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1484 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1485 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1486 SetLastError(ERROR_INVALID_PARAMETER
);
1490 /* Load and initialize the monitor. SetLastError() is called on failure */
1491 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
1496 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1497 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1501 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1502 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1503 &disposition
) == ERROR_SUCCESS
) {
1505 /* Some installers set options for the port before calling AddMonitor.
1506 We query the "Driver" entry to verify that the monitor is installed,
1507 before we return an error.
1508 When a user installs two print monitors at the same time with the
1509 same name, a race condition is possible but silently ignored. */
1513 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1514 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1515 &namesize
) == ERROR_SUCCESS
)) {
1516 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1517 /* 9x use ERROR_ALREADY_EXISTS */
1518 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1523 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1524 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1525 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1527 RegCloseKey(hentry
);
1534 /******************************************************************************
1535 * fpAddPort [exported through PRINTPROVIDOR]
1537 * Add a Port for a specific Monitor
1540 * pName [I] Servername or NULL (local Computer)
1541 * hWnd [I] Handle to parent Window for the Dialog-Box
1542 * pMonitorName [I] Name of the Monitor that manage the Port
1549 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1556 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1558 lres
= copy_servername_from_name(pName
, NULL
);
1560 FIXME("server %s not supported\n", debugstr_w(pName
));
1561 SetLastError(ERROR_INVALID_PARAMETER
);
1565 /* an empty Monitorname is Invalid */
1566 if (!pMonitorName
[0]) {
1567 SetLastError(ERROR_NOT_SUPPORTED
);
1571 pm
= monitor_load(pMonitorName
, NULL
);
1572 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1573 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1574 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1578 pui
= monitor_loadui(pm
);
1579 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1580 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1581 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1585 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1586 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1587 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1589 SetLastError(ERROR_NOT_SUPPORTED
);
1592 monitor_unload(pui
);
1596 TRACE("returning %d with %u\n", res
, GetLastError());
1600 /******************************************************************************
1601 * fpAddPortEx [exported through PRINTPROVIDOR]
1603 * Add a Port for a specific Monitor, without presenting a user interface
1606 * pName [I] Servername or NULL (local Computer)
1607 * level [I] Structure-Level (1 or 2) for pBuffer
1608 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1609 * pMonitorName [I] Name of the Monitor that manage the Port
1616 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1623 pi2
= (PORT_INFO_2W
*) pBuffer
;
1625 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1626 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1627 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1628 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1630 lres
= copy_servername_from_name(pName
, NULL
);
1632 FIXME("server %s not supported\n", debugstr_w(pName
));
1633 SetLastError(ERROR_INVALID_PARAMETER
);
1637 if ((level
< 1) || (level
> 2)) {
1638 SetLastError(ERROR_INVALID_LEVEL
);
1642 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1643 SetLastError(ERROR_INVALID_PARAMETER
);
1647 /* load the Monitor */
1648 pm
= monitor_load(pMonitorName
, NULL
);
1649 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1650 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1651 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1655 FIXME("not implemented for %s (monitor %p: %s)\n",
1656 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1657 SetLastError(ERROR_INVALID_PARAMETER
);
1664 /******************************************************************************
1665 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1667 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1670 * pName [I] Servername or NULL (local Computer)
1671 * level [I] Level for the supplied DRIVER_INFO_*W struct
1672 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1673 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1680 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1684 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1685 lres
= copy_servername_from_name(pName
, NULL
);
1687 FIXME("server %s not supported\n", debugstr_w(pName
));
1688 SetLastError(ERROR_ACCESS_DENIED
);
1692 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1693 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1696 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1699 /******************************************************************************
1700 * fpClosePrinter [exported through PRINTPROVIDOR]
1702 * Close a printer handle and free associated resources
1705 * hPrinter [I] Printerhandle to close
1712 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1714 printer_t
*printer
= (printer_t
*) hPrinter
;
1716 TRACE("(%p)\n", hPrinter
);
1719 printer_free(printer
);
1725 /******************************************************************************
1726 * fpConfigurePort [exported through PRINTPROVIDOR]
1728 * Display the Configuration-Dialog for a specific Port
1731 * pName [I] Servername or NULL (local Computer)
1732 * hWnd [I] Handle to parent Window for the Dialog-Box
1733 * pPortName [I] Name of the Port, that should be configured
1740 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1747 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1749 lres
= copy_servername_from_name(pName
, NULL
);
1751 FIXME("server %s not supported\n", debugstr_w(pName
));
1752 SetLastError(ERROR_INVALID_NAME
);
1756 /* an empty Portname is Invalid, but can popup a Dialog */
1757 if (!pPortName
[0]) {
1758 SetLastError(ERROR_NOT_SUPPORTED
);
1762 pm
= monitor_load_by_port(pPortName
);
1763 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1764 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1765 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1766 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1767 TRACE("got %d with %u\n", res
, GetLastError());
1771 pui
= monitor_loadui(pm
);
1772 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1773 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1774 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1775 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1776 TRACE("got %d with %u\n", res
, GetLastError());
1780 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1781 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1782 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1784 SetLastError(ERROR_NOT_SUPPORTED
);
1787 monitor_unload(pui
);
1791 TRACE("returning %d with %u\n", res
, GetLastError());
1795 /******************************************************************
1796 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1798 * Delete a specific Printmonitor from a Printing-Environment
1801 * pName [I] Servername or NULL (local Computer)
1802 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1803 * pMonitorName [I] Name of the Monitor, that should be deleted
1810 * pEnvironment is ignored in Windows for the local Computer.
1814 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1819 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1820 debugstr_w(pMonitorName
));
1822 lres
= copy_servername_from_name(pName
, NULL
);
1824 FIXME("server %s not supported\n", debugstr_w(pName
));
1825 SetLastError(ERROR_INVALID_NAME
);
1829 /* pEnvironment is ignored in Windows for the local Computer */
1830 if (!pMonitorName
|| !pMonitorName
[0]) {
1831 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1832 SetLastError(ERROR_INVALID_PARAMETER
);
1836 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1837 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1841 if(SHDeleteKeyW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1842 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1847 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1850 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1851 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1855 /*****************************************************************************
1856 * fpDeletePort [exported through PRINTPROVIDOR]
1858 * Delete a specific Port
1861 * pName [I] Servername or NULL (local Computer)
1862 * hWnd [I] Handle to parent Window for the Dialog-Box
1863 * pPortName [I] Name of the Port, that should be deleted
1870 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1877 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1879 lres
= copy_servername_from_name(pName
, NULL
);
1881 FIXME("server %s not supported\n", debugstr_w(pName
));
1882 SetLastError(ERROR_INVALID_NAME
);
1886 /* an empty Portname is Invalid */
1887 if (!pPortName
[0]) {
1888 SetLastError(ERROR_NOT_SUPPORTED
);
1892 pm
= monitor_load_by_port(pPortName
);
1893 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1894 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1895 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1896 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1897 TRACE("got %d with %u\n", res
, GetLastError());
1901 pui
= monitor_loadui(pm
);
1902 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1903 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1904 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1905 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1906 TRACE("got %d with %u\n", res
, GetLastError());
1910 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1911 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1912 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1914 SetLastError(ERROR_NOT_SUPPORTED
);
1917 monitor_unload(pui
);
1921 TRACE("returning %d with %u\n", res
, GetLastError());
1925 /*****************************************************************************
1926 * fpEnumMonitors [exported through PRINTPROVIDOR]
1928 * Enumerate available Port-Monitors
1931 * pName [I] Servername or NULL (local Computer)
1932 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1933 * pMonitors [O] PTR to Buffer that receives the Result
1934 * cbBuf [I] Size of Buffer at pMonitors
1935 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1936 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1940 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1943 * Windows reads the Registry once and cache the Results.
1946 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1947 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1949 DWORD numentries
= 0;
1954 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1955 cbBuf
, pcbNeeded
, pcReturned
);
1957 lres
= copy_servername_from_name(pName
, NULL
);
1959 FIXME("server %s not supported\n", debugstr_w(pName
));
1960 SetLastError(ERROR_INVALID_NAME
);
1964 if (!Level
|| (Level
> 2)) {
1965 WARN("level (%d) is ignored in win9x\n", Level
);
1966 SetLastError(ERROR_INVALID_LEVEL
);
1970 /* Scan all Monitor-Keys */
1972 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1974 /* we calculated the needed buffersize. now do more error-checks */
1975 if (cbBuf
< needed
) {
1976 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1980 /* fill the Buffer with the Monitor-Keys */
1981 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
1985 if (pcbNeeded
) *pcbNeeded
= needed
;
1986 if (pcReturned
) *pcReturned
= numentries
;
1988 TRACE("returning %d with %d (%d byte for %d entries)\n",
1989 res
, GetLastError(), needed
, numentries
);
1994 /******************************************************************************
1995 * fpEnumPorts [exported through PRINTPROVIDOR]
1997 * Enumerate available Ports
2000 * pName [I] Servername or NULL (local Computer)
2001 * Level [I] Structure-Level (1 or 2)
2002 * pPorts [O] PTR to Buffer that receives the Result
2003 * cbBuf [I] Size of Buffer at pPorts
2004 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2005 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2009 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2012 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2013 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2016 DWORD numentries
= 0;
2020 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2021 cbBuf
, pcbNeeded
, pcReturned
);
2023 lres
= copy_servername_from_name(pName
, NULL
);
2025 FIXME("server %s not supported\n", debugstr_w(pName
));
2026 SetLastError(ERROR_INVALID_NAME
);
2030 if (!Level
|| (Level
> 2)) {
2031 SetLastError(ERROR_INVALID_LEVEL
);
2035 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2036 SetLastError(RPC_X_NULL_REF_POINTER
);
2040 EnterCriticalSection(&monitor_handles_cs
);
2043 /* Scan all local Ports */
2045 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2047 /* we calculated the needed buffersize. now do the error-checks */
2048 if (cbBuf
< needed
) {
2049 monitor_unloadall();
2050 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2051 goto emP_cleanup_cs
;
2053 else if (!pPorts
|| !pcReturned
) {
2054 monitor_unloadall();
2055 SetLastError(RPC_X_NULL_REF_POINTER
);
2056 goto emP_cleanup_cs
;
2059 /* Fill the Buffer */
2060 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2062 monitor_unloadall();
2065 LeaveCriticalSection(&monitor_handles_cs
);
2068 if (pcbNeeded
) *pcbNeeded
= needed
;
2069 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2071 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2072 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2077 /*****************************************************************************
2078 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2080 * Enumerate available Print Processors
2083 * pName [I] Servername or NULL (local Computer)
2084 * pEnvironment [I] Printing-Environment or NULL (Default)
2085 * Level [I] Structure-Level (Only 1 is allowed)
2086 * pPPInfo [O] PTR to Buffer that receives the Result
2087 * cbBuf [I] Size of Buffer at pMonitors
2088 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2089 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2093 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2096 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2097 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2099 const printenv_t
* env
;
2100 LPWSTR regpathW
= NULL
;
2101 DWORD numentries
= 0;
2106 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2107 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2109 lres
= copy_servername_from_name(pName
, NULL
);
2111 FIXME("server %s not supported\n", debugstr_w(pName
));
2112 SetLastError(ERROR_INVALID_NAME
);
2117 SetLastError(ERROR_INVALID_LEVEL
);
2121 env
= validate_envW(pEnvironment
);
2123 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2125 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2126 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2131 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2133 /* Scan all Printprocessor-Keys */
2135 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2137 /* we calculated the needed buffersize. now do more error-checks */
2138 if (cbBuf
< needed
) {
2139 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2143 /* fill the Buffer with the Printprocessor Infos */
2144 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2148 heap_free(regpathW
);
2149 if (pcbNeeded
) *pcbNeeded
= needed
;
2150 if (pcReturned
) *pcReturned
= numentries
;
2152 TRACE("returning %d with %d (%d byte for %d entries)\n",
2153 res
, GetLastError(), needed
, numentries
);
2158 /******************************************************************************
2159 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2161 * Return the PATH for the Print-Processors
2164 * pName [I] Servername or NULL (this computer)
2165 * pEnvironment [I] Printing-Environment or NULL (Default)
2166 * level [I] Structure-Level (must be 1)
2167 * pPPInfo [O] PTR to Buffer that receives the Result
2168 * cbBuf [I] Size of Buffer at pPPInfo
2169 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2173 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2175 * Native Values returned in pPPInfo on Success for this computer:
2176 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2177 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2178 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2180 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2183 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2184 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2186 const printenv_t
* env
;
2190 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2191 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2194 lres
= copy_servername_from_name(pName
, NULL
);
2196 FIXME("server %s not supported\n", debugstr_w(pName
));
2197 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2201 env
= validate_envW(pEnvironment
);
2203 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2205 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2206 needed
= GetSystemDirectoryW(NULL
, 0);
2207 /* add the Size for the Subdirectories */
2208 needed
+= lstrlenW(spoolprtprocsW
);
2209 needed
+= lstrlenW(env
->subdir
);
2210 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2212 *pcbNeeded
= needed
;
2214 if (needed
> cbBuf
) {
2215 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2219 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2220 /* add the Subdirectories */
2221 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2222 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2223 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2227 /******************************************************************************
2228 * fpOpenPrinter [exported through PRINTPROVIDOR]
2230 * Open a Printer / Printserver or a Printer-Object
2233 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2234 * pPrinter [O] The resulting Handle is stored here
2235 * pDefaults [I] PTR to Default Printer Settings or NULL
2242 * lpPrinterName is one of:
2243 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2244 *| Printer: "PrinterName"
2245 *| Printer-Object: "PrinterName,Job xxx"
2246 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2247 *| XcvPort: "Servername,XcvPort PortName"
2251 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2252 LPPRINTER_DEFAULTSW pDefaults
)
2255 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2257 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2259 return (*pPrinter
!= 0);
2262 /******************************************************************************
2263 * fpXcvData [exported through PRINTPROVIDOR]
2265 * Execute commands in the Printmonitor DLL
2268 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2269 * pszDataName [i] Name of the command to execute
2270 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2271 * cbInputData [i] Size in Bytes of Buffer at pInputData
2272 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2273 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2274 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2275 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2282 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2283 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2285 * Minimal List of commands, that a Printmonitor DLL should support:
2287 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2288 *| "AddPort" : Add a Port
2289 *| "DeletePort": Delete a Port
2291 * Many Printmonitors support additional commands. Examples for localspl.dll:
2292 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2293 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2296 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2297 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2298 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2300 printer_t
*printer
= (printer_t
* ) hXcv
;
2302 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2303 pInputData
, cbInputData
, pOutputData
,
2304 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2306 if (!printer
|| (!printer
->hXcv
)) {
2307 SetLastError(ERROR_INVALID_HANDLE
);
2311 if (!pcbOutputNeeded
) {
2312 SetLastError(ERROR_INVALID_PARAMETER
);
2316 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2317 SetLastError(RPC_X_NULL_REF_POINTER
);
2321 *pcbOutputNeeded
= 0;
2323 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2324 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2329 /*****************************************************
2330 * setup_provider [internal]
2332 void setup_provider(void)
2334 static const PRINTPROVIDOR backend
= {
2336 NULL
, /* fpSetJob */
2337 NULL
, /* fpGetJob */
2338 NULL
, /* fpEnumJobs */
2339 NULL
, /* fpAddPrinter */
2340 NULL
, /* fpDeletePrinter */
2341 NULL
, /* fpSetPrinter */
2342 NULL
, /* fpGetPrinter */
2343 NULL
, /* fpEnumPrinters */
2344 NULL
, /* fpAddPrinterDriver */
2345 NULL
, /* fpEnumPrinterDrivers */
2346 NULL
, /* fpGetPrinterDriver */
2347 fpGetPrinterDriverDirectory
,
2348 NULL
, /* fpDeletePrinterDriver */
2349 NULL
, /* fpAddPrintProcessor */
2350 fpEnumPrintProcessors
,
2351 fpGetPrintProcessorDirectory
,
2352 NULL
, /* fpDeletePrintProcessor */
2353 NULL
, /* fpEnumPrintProcessorDatatypes */
2354 NULL
, /* fpStartDocPrinter */
2355 NULL
, /* fpStartPagePrinter */
2356 NULL
, /* fpWritePrinter */
2357 NULL
, /* fpEndPagePrinter */
2358 NULL
, /* fpAbortPrinter */
2359 NULL
, /* fpReadPrinter */
2360 NULL
, /* fpEndDocPrinter */
2361 NULL
, /* fpAddJob */
2362 NULL
, /* fpScheduleJob */
2363 NULL
, /* fpGetPrinterData */
2364 NULL
, /* fpSetPrinterData */
2365 NULL
, /* fpWaitForPrinterChange */
2367 NULL
, /* fpAddForm */
2368 NULL
, /* fpDeleteForm */
2369 NULL
, /* fpGetForm */
2370 NULL
, /* fpSetForm */
2371 NULL
, /* fpEnumForms */
2377 NULL
, /* fpCreatePrinterIC */
2378 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2379 NULL
, /* fpDeletePrinterIC */
2380 NULL
, /* fpAddPrinterConnection */
2381 NULL
, /* fpDeletePrinterConnection */
2382 NULL
, /* fpPrinterMessageBox */
2385 NULL
, /* fpResetPrinter */
2386 NULL
, /* fpGetPrinterDriverEx */
2387 NULL
, /* fpFindFirstPrinterChangeNotification */
2388 NULL
, /* fpFindClosePrinterChangeNotification */
2390 NULL
, /* fpShutDown */
2391 NULL
, /* fpRefreshPrinterChangeNotification */
2392 NULL
, /* fpOpenPrinterEx */
2393 NULL
, /* fpAddPrinterEx */
2394 NULL
, /* fpSetPort */
2395 NULL
, /* fpEnumPrinterData */
2396 NULL
, /* fpDeletePrinterData */
2397 NULL
, /* fpClusterSplOpen */
2398 NULL
, /* fpClusterSplClose */
2399 NULL
, /* fpClusterSplIsAlive */
2400 NULL
, /* fpSetPrinterDataEx */
2401 NULL
, /* fpGetPrinterDataEx */
2402 NULL
, /* fpEnumPrinterDataEx */
2403 NULL
, /* fpEnumPrinterKey */
2404 NULL
, /* fpDeletePrinterDataEx */
2405 NULL
, /* fpDeletePrinterKey */
2406 NULL
, /* fpSeekPrinter */
2407 NULL
, /* fpDeletePrinterDriverEx */
2408 NULL
, /* fpAddPerMachineConnection */
2409 NULL
, /* fpDeletePerMachineConnection */
2410 NULL
, /* fpEnumPerMachineConnections */
2412 fpAddPrinterDriverEx
,
2413 NULL
, /* fpSplReadPrinter */
2414 NULL
, /* fpDriverUnloadComplete */
2415 NULL
, /* fpGetSpoolFileInfo */
2416 NULL
, /* fpCommitSpoolData */
2417 NULL
, /* fpCloseSpoolFileHandle */
2418 NULL
, /* fpFlushPrinter */
2419 NULL
, /* fpSendRecvBidiData */
2420 NULL
/* fpAddDriverCatalog */
2422 pprovider
= &backend
;
2426 /*****************************************************
2427 * InitializePrintProvidor (localspl.@)
2429 * Initialize the Printprovider
2432 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2433 * cbPrintProvidor [I] Size of Buffer in Bytes
2434 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2437 * Success: TRUE and pPrintProvidor filled
2441 * The RegistryPath should be:
2442 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2443 * but this Parameter is ignored in "localspl.dll".
2447 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2448 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2451 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2452 memcpy(pPrintProvidor
, pprovider
,
2453 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));