2 * Implementation of the Local Printprovider
4 * Copyright 2006-2009 Detlef Riekenberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "ddk/winddiui.h"
32 #include "ddk/winsplp.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/list.h"
37 #include "localspl_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(localspl
);
41 /* ############################### */
43 static CRITICAL_SECTION monitor_handles_cs
;
44 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
46 0, 0, &monitor_handles_cs
,
47 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
48 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
50 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
52 /* ############################### */
55 WCHAR src
[MAX_PATH
+MAX_PATH
];
56 WCHAR dst
[MAX_PATH
+MAX_PATH
];
69 BOOL (WINAPI
*old_EnumPorts
)(LPWSTR
,DWORD
,LPBYTE
,DWORD
,LPDWORD
,LPDWORD
);
70 BOOL (WINAPI
*old_OpenPort
)(LPWSTR
,PHANDLE
);
71 BOOL (WINAPI
*old_OpenPortEx
)(LPWSTR
,LPWSTR
,PHANDLE
,struct _MONITOR
*);
72 BOOL (WINAPI
*old_AddPort
)(LPWSTR
,HWND
,LPWSTR
);
73 BOOL (WINAPI
*old_AddPortEx
)(LPWSTR
,DWORD
,LPBYTE
,LPWSTR
);
74 BOOL (WINAPI
*old_ConfigurePort
)(LPWSTR
,HWND
,LPWSTR
);
75 BOOL (WINAPI
*old_DeletePort
)(LPWSTR
,HWND
,LPWSTR
);
76 BOOL (WINAPI
*old_XcvOpenPort
)(LPCWSTR
,ACCESS_MASK
,PHANDLE
);
86 LPCWSTR versionregpath
;
87 LPCWSTR versionsubdir
;
97 /* ############################### */
99 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
100 static monitor_t
* pm_localport
;
102 static const WCHAR fmt_driversW
[] =
103 L
"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers%s";
104 static const WCHAR fmt_printprocessorsW
[] =
105 L
"System\\CurrentControlSet\\Control\\Print\\Environments\\%s\\Print Processors";
106 static const WCHAR monitorsW
[] = L
"System\\CurrentControlSet\\Control\\Print\\Monitors\\";
107 static const WCHAR printersW
[] = L
"System\\CurrentControlSet\\Control\\Print\\Printers";
108 static const WCHAR winnt_cv_portsW
[] = L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports";
109 static const WCHAR x86_envnameW
[] = L
"Windows NT x86";
112 static const printenv_t env_ia64
= {L
"Windows IA64", L
"ia64", 3,
113 L
"\\Version-3", L
"\\3"};
115 static const printenv_t env_x86
= {x86_envnameW
, L
"w32x86", 3,
116 L
"\\Version-3", L
"\\3"};
118 static const printenv_t env_x64
= {L
"Windows x64", L
"x64", 3,
119 L
"\\Version-3", L
"\\3"};
121 static const printenv_t env_win40
= {L
"Windows 4.0", L
"win40", 0,
122 L
"\\Version-0", L
"\\0"};
124 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_win40
};
127 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
128 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
129 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
130 0, sizeof(DRIVER_INFO_8W
)};
133 /******************************************************************
136 * create a copy of a unicode-string
139 static LPWSTR
strdupW(LPCWSTR p
)
145 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
146 ret
= heap_alloc(len
);
147 if (ret
) memcpy(ret
, p
, len
);
151 /******************************************************************
152 * apd_copyfile [internal]
154 * Copy a file from the driverdirectory to the versioned directory
161 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
166 apd
->src
[apd
->srclen
] = '\0';
167 apd
->dst
[apd
->dstlen
] = '\0';
169 if (!pathname
|| !pathname
[0]) {
170 /* nothing to copy */
174 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
179 lstrcatW( srcname
, file_part
);
181 lstrcatW( apd
->dst
, file_part
);
183 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
185 /* FIXME: handle APD_COPY_NEW_FILES */
186 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
187 TRACE("got %d with %u\n", res
, GetLastError());
189 return apd
->lazy
|| res
;
192 /******************************************************************
193 * copy_servername_from_name (internal)
195 * for an external server, the serverpart from the name is copied.
198 * the length (in WCHAR) of the serverpart (0 for the local computer)
199 * (-length), when the name is too long
202 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
206 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
210 if (target
) *target
= '\0';
212 if (name
== NULL
) return 0;
213 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
216 /* skip over both backslash, find separator '\' */
217 ptr
= wcschr(server
, '\\');
218 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
220 /* servername is empty */
221 if (serverlen
== 0) return 0;
223 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
225 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
228 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
229 target
[serverlen
] = '\0';
232 len
= ARRAY_SIZE(buffer
);
233 if (GetComputerNameW(buffer
, &len
)) {
234 if ((serverlen
== len
) && (wcsnicmp(server
, buffer
, len
) == 0)) {
235 /* The requested Servername is our computername */
242 /******************************************************************
243 * get_basename_from_name (internal)
245 * skip over the serverpart from the full name
248 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
250 if (name
== NULL
) return NULL
;
251 if ((name
[0] == '\\') && (name
[1] == '\\')) {
252 /* skip over the servername and search for the following '\' */
253 name
= wcschr(&name
[2], '\\');
254 if ((name
) && (name
[1])) {
255 /* found a separator ('\') followed by a name:
256 skip over the separator and return the rest */
261 /* no basename present (we found only a servername) */
268 /******************************************************************
269 * monitor_unload [internal]
271 * release a printmonitor and unload it from memory, when needed
274 static void monitor_unload(monitor_t
* pm
)
276 if (pm
== NULL
) return;
277 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
279 EnterCriticalSection(&monitor_handles_cs
);
281 if (pm
->refcount
) pm
->refcount
--;
283 if (pm
->refcount
== 0) {
284 list_remove(&pm
->entry
);
286 if (pm
->monitor
.pfnShutdown
)
287 pm
->monitor
.pfnShutdown(pm
->hmon
);
289 FreeLibrary(pm
->hdll
);
291 heap_free(pm
->dllname
);
294 LeaveCriticalSection(&monitor_handles_cs
);
297 /******************************************************************
298 * monitor_unloadall [internal]
300 * release all registered printmonitors and unload them from memory, when needed
304 static void monitor_unloadall(void)
309 EnterCriticalSection(&monitor_handles_cs
);
310 /* iterate through the list, with safety against removal */
311 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
313 /* skip monitorui dlls */
314 if (pm
->monitor
.cbSize
) monitor_unload(pm
);
316 LeaveCriticalSection(&monitor_handles_cs
);
319 static LONG WINAPI
CreateKey(HANDLE hcKey
, LPCWSTR pszSubKey
, DWORD dwOptions
,
320 REGSAM samDesired
, PSECURITY_ATTRIBUTES pSecurityAttributes
,
321 PHANDLE phckResult
, PDWORD pdwDisposition
, HANDLE hSpooler
)
324 return ERROR_CALL_NOT_IMPLEMENTED
;
327 static LONG WINAPI
OpenKey(HANDLE hcKey
, LPCWSTR pszSubKey
, REGSAM samDesired
,
328 PHANDLE phkResult
, HANDLE hSpooler
)
331 return ERROR_CALL_NOT_IMPLEMENTED
;
334 static LONG WINAPI
CloseKey(HANDLE hcKey
, HANDLE hSpooler
)
337 return ERROR_CALL_NOT_IMPLEMENTED
;
340 static LONG WINAPI
DeleteKey(HANDLE hcKey
, LPCWSTR pszSubKey
, HANDLE hSpooler
)
343 return ERROR_CALL_NOT_IMPLEMENTED
;
346 static LONG WINAPI
EnumKey(HANDLE hcKey
, DWORD dwIndex
, LPWSTR pszName
,
347 PDWORD pcchName
, PFILETIME pftLastWriteTime
, HANDLE hSpooler
)
350 return ERROR_CALL_NOT_IMPLEMENTED
;
353 static LONG WINAPI
QueryInfoKey(HANDLE hcKey
, PDWORD pcSubKeys
, PDWORD pcbKey
,
354 PDWORD pcValues
, PDWORD pcbValue
, PDWORD pcbData
,
355 PDWORD pcbSecurityDescriptor
, PFILETIME pftLastWriteTime
,
359 return ERROR_CALL_NOT_IMPLEMENTED
;
362 static LONG WINAPI
SetValue(HANDLE hcKey
, LPCWSTR pszValue
, DWORD dwType
,
363 const BYTE
* pData
, DWORD cbData
, HANDLE hSpooler
)
366 return ERROR_CALL_NOT_IMPLEMENTED
;
369 static LONG WINAPI
DeleteValue(HANDLE hcKey
, LPCWSTR pszValue
, HANDLE hSpooler
)
372 return ERROR_CALL_NOT_IMPLEMENTED
;
375 static LONG WINAPI
EnumValue(HANDLE hcKey
, DWORD dwIndex
, LPWSTR pszValue
,
376 PDWORD pcbValue
, PDWORD pType
, PBYTE pData
, PDWORD pcbData
,
380 return ERROR_CALL_NOT_IMPLEMENTED
;
383 static LONG WINAPI
QueryValue(HANDLE hcKey
, LPCWSTR pszValue
, PDWORD pType
,
384 PBYTE pData
, PDWORD pcbData
, HANDLE hSpooler
)
387 return ERROR_CALL_NOT_IMPLEMENTED
;
390 static MONITORREG monreg
=
405 /******************************************************************
406 * monitor_load [internal]
408 * load a printmonitor, get the dllname from the registry, when needed
409 * initialize the monitor and dump found function-pointers
411 * On failure, SetLastError() is called and NULL is returned
414 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
416 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
417 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
418 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
419 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
420 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
422 monitor_t
* pm
= NULL
;
424 LPWSTR regroot
= NULL
;
425 LPWSTR driver
= dllname
;
428 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
429 /* Is the Monitor already loaded? */
430 EnterCriticalSection(&monitor_handles_cs
);
433 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
435 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
443 pm
= heap_alloc_zero(sizeof(monitor_t
));
444 if (pm
== NULL
) goto cleanup
;
445 list_add_tail(&monitor_handles
, &pm
->entry
);
449 if (pm
->name
== NULL
) {
450 /* Load the monitor */
454 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
455 regroot
= heap_alloc(len
* sizeof(WCHAR
));
459 lstrcpyW(regroot
, monitorsW
);
460 lstrcatW(regroot
, name
);
461 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
462 /* Get the Driver from the Registry */
463 if (driver
== NULL
) {
465 if (RegQueryValueExW(hroot
, L
"Driver", NULL
, NULL
, NULL
,
466 &namesize
) == ERROR_SUCCESS
) {
467 driver
= heap_alloc(namesize
);
468 RegQueryValueExW(hroot
, L
"Driver", NULL
, NULL
, (BYTE
*)driver
, &namesize
);
473 WARN("%s not found\n", debugstr_w(regroot
));
476 pm
->name
= strdupW(name
);
477 pm
->dllname
= strdupW(driver
);
479 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
481 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
486 pm
->hdll
= LoadLibraryW(driver
);
487 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
489 if (pm
->hdll
== NULL
) {
491 SetLastError(ERROR_MOD_NOT_FOUND
);
496 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
497 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
498 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
499 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
500 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
503 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
504 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
505 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
506 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
507 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
509 if (pInitializePrintMonitorUI
!= NULL
) {
510 pm
->monitorUI
= pInitializePrintMonitorUI();
511 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
513 TRACE("0x%08x: dwMonitorSize (%d)\n",
514 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
519 if (pInitializePrintMonitor2
&& hroot
) {
524 memset(&init
, 0, sizeof(init
));
525 init
.cbSize
= sizeof(init
);
526 init
.hckRegistryRoot
= hroot
;
527 init
.pMonitorReg
= &monreg
;
530 monitor2
= pInitializePrintMonitor2(&init
, &hmon
);
531 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
532 monitor2
, debugstr_w(driver
), debugstr_w(regroot
));
535 memcpy(&pm
->monitor
, monitor2
, min(monitor2
->cbSize
, sizeof(pm
->monitor
)));
539 else if (pInitializePrintMonitor
&& regroot
) {
540 MONITOREX
*pmonitorEx
;
542 pmonitorEx
= pInitializePrintMonitor(regroot
);
543 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
544 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
547 /* Layout of MONITOREX and MONITOR2 mostly matches */
548 memcpy(&pm
->monitor
, pmonitorEx
, min(pmonitorEx
->dwMonitorSize
+ sizeof(void *), sizeof(pm
->monitor
)));
549 /* MONITOREX.dwMonitorSize doesn't include the size field, while MONITOR2.cbSize does */
550 pm
->monitor
.cbSize
+= sizeof(void *);
552 pm
->old_EnumPorts
= pmonitorEx
->Monitor
.pfnEnumPorts
;
553 pm
->old_OpenPort
= pmonitorEx
->Monitor
.pfnOpenPort
;
554 pm
->old_OpenPortEx
= pmonitorEx
->Monitor
.pfnOpenPortEx
;
555 pm
->old_AddPort
= pmonitorEx
->Monitor
.pfnAddPort
;
556 pm
->old_AddPortEx
= pmonitorEx
->Monitor
.pfnAddPortEx
;
557 pm
->old_ConfigurePort
= pmonitorEx
->Monitor
.pfnConfigurePort
;
558 pm
->old_DeletePort
= pmonitorEx
->Monitor
.pfnDeletePort
;
559 pm
->old_XcvOpenPort
= pmonitorEx
->Monitor
.pfnXcvOpenPort
;
561 pm
->monitor
.pfnEnumPorts
= NULL
;
562 pm
->monitor
.pfnOpenPort
= NULL
;
563 pm
->monitor
.pfnOpenPortEx
= NULL
;
564 pm
->monitor
.pfnAddPort
= NULL
;
565 pm
->monitor
.pfnAddPortEx
= NULL
;
566 pm
->monitor
.pfnConfigurePort
= NULL
;
567 pm
->monitor
.pfnDeletePort
= NULL
;
568 pm
->monitor
.pfnXcvOpenPort
= NULL
;
572 if (!pm
->monitor
.cbSize
&& regroot
) {
573 if (pInitializeMonitorEx
!= NULL
) {
574 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
576 if (pInitializeMonitor
!= NULL
) {
577 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
580 if (!pm
->monitor
.cbSize
&& !pm
->monitorUI
) {
582 SetLastError(ERROR_PROC_NOT_FOUND
);
587 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, L
"Local Port") == 0)) {
591 LeaveCriticalSection(&monitor_handles_cs
);
592 if (driver
!= dllname
) heap_free(driver
);
593 if (hroot
) RegCloseKey(hroot
);
595 TRACE("=> %p\n", pm
);
599 /******************************************************************
600 * monitor_loadall [internal]
602 * Load all registered monitors
605 static DWORD
monitor_loadall(void)
608 DWORD registered
= 0;
611 WCHAR buffer
[MAX_PATH
];
614 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
615 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
616 NULL
, NULL
, NULL
, NULL
, NULL
);
618 TRACE("%d monitors registered\n", registered
);
620 while (id
< registered
) {
622 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
623 pm
= monitor_load(buffer
, NULL
);
627 RegCloseKey(hmonitors
);
629 TRACE("%d monitors loaded\n", loaded
);
633 /******************************************************************
634 * monitor_loadui [internal]
636 * load the userinterface-dll for a given portmonitor
638 * On failure, NULL is returned
640 static monitor_t
* monitor_loadui(monitor_t
* pm
)
642 monitor_t
* pui
= NULL
;
643 WCHAR buffer
[MAX_PATH
];
648 if (pm
== NULL
) return NULL
;
649 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
651 /* Try the Portmonitor first; works for many monitors */
653 EnterCriticalSection(&monitor_handles_cs
);
655 LeaveCriticalSection(&monitor_handles_cs
);
659 /* query the userinterface-dllname from the Portmonitor */
660 /* building (",XcvMonitor %s",pm->name) not needed yet */
661 if (pm
->monitor
.pfnXcvOpenPort
)
662 res
= pm
->monitor
.pfnXcvOpenPort(pm
->hmon
, L
"", SERVER_ACCESS_ADMINISTER
, &hXcv
);
663 else if (pm
->old_XcvOpenPort
)
664 res
= pm
->old_XcvOpenPort(L
"", SERVER_ACCESS_ADMINISTER
, &hXcv
);
665 TRACE("got %u with %p\n", res
, hXcv
);
667 res
= pm
->monitor
.pfnXcvDataPort(hXcv
, L
"MonitorUI", NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
668 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
669 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
670 pm
->monitor
.pfnXcvClosePort(hXcv
);
675 /******************************************************************
676 * monitor_load_by_port [internal]
678 * load a printmonitor for a given port
680 * On failure, NULL is returned
683 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
688 monitor_t
* pm
= NULL
;
689 DWORD registered
= 0;
693 TRACE("(%s)\n", debugstr_w(portname
));
695 /* Try the Local Monitor first */
696 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
697 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
698 /* found the portname */
700 return monitor_load(L
"Local Port", NULL
);
705 len
= MAX_PATH
+ lstrlenW(L
"\\Ports\\") + lstrlenW(portname
) + 1;
706 buffer
= heap_alloc(len
* sizeof(WCHAR
));
707 if (buffer
== NULL
) return NULL
;
709 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
710 EnterCriticalSection(&monitor_handles_cs
);
711 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
713 while ((pm
== NULL
) && (id
< registered
)) {
715 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
716 TRACE("testing %s\n", debugstr_w(buffer
));
717 len
= lstrlenW(buffer
);
718 lstrcatW(buffer
, L
"\\Ports\\");
719 lstrcatW(buffer
, portname
);
720 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
722 buffer
[len
] = '\0'; /* use only the Monitor-Name */
723 pm
= monitor_load(buffer
, NULL
);
727 LeaveCriticalSection(&monitor_handles_cs
);
734 /******************************************************************
735 * Return the number of bytes for an multi_sz string.
736 * The result includes all \0s
737 * (specifically the extra \0, that is needed as multi_sz terminator).
739 static int multi_sz_lenW(const WCHAR
*str
)
741 const WCHAR
*ptr
= str
;
745 ptr
+= lstrlenW(ptr
) + 1;
748 return (ptr
- str
+ 1) * sizeof(WCHAR
);
751 /******************************************************************
752 * validate_envW [internal]
754 * validate the user-supplied printing-environment
757 * env [I] PTR to Environment-String or NULL
760 * Success: PTR to printenv_t
761 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
764 * An empty string is handled the same way as NULL.
768 static const printenv_t
* validate_envW(LPCWSTR env
)
770 const printenv_t
*result
= NULL
;
773 TRACE("(%s)\n", debugstr_w(env
));
776 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
778 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
780 result
= all_printenv
[i
];
784 if (result
== NULL
) {
785 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
786 SetLastError(ERROR_INVALID_ENVIRONMENT
);
788 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
792 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
795 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
799 /*****************************************************************************
800 * enumerate the local monitors (INTERNAL)
802 * returns the needed size (in bytes) for pMonitors
803 * and *lpreturned is set to number of entries returned in pMonitors
805 * Language-Monitors are also installed in the same Registry-Location but
806 * they are filtered in Windows (not returned by EnumMonitors).
807 * We do no filtering to simplify our Code.
810 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
815 LPMONITOR_INFO_2W mi
;
816 WCHAR buffer
[MAX_PATH
];
817 WCHAR dllname
[MAX_PATH
];
825 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
827 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
828 len
= entrysize
* numentries
;
829 ptr
= (LPWSTR
) &pMonitors
[len
];
832 len
= ARRAY_SIZE(buffer
);
835 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
836 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
837 /* Scan all Monitor-Registry-Keys */
838 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
839 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
840 dllsize
= sizeof(dllname
);
843 /* The Monitor must have a Driver-DLL */
844 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
845 if (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, (BYTE
*)dllname
, &dllsize
) == ERROR_SUCCESS
) {
846 /* We found a valid DLL for this Monitor. */
847 TRACE("using Driver: %s\n", debugstr_w(dllname
));
852 /* Windows returns only Port-Monitors here, but to simplify our code,
853 we do no filtering for Language-Monitors */
857 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
859 /* we install and return only monitors for "Windows NT x86" */
860 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
864 /* required size is calculated. Now fill the user-buffer */
865 if (pMonitors
&& (cbBuf
>= needed
)){
866 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
867 pMonitors
+= entrysize
;
869 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
871 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
872 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
874 mi
->pEnvironment
= ptr
;
875 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
876 ptr
+= (lstrlenW(x86_envnameW
)+1);
879 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
880 ptr
+= (dllsize
/ sizeof(WCHAR
));
885 len
= ARRAY_SIZE(buffer
);
890 *lpreturned
= numentries
;
891 TRACE("need %d byte for %d entries\n", needed
, numentries
);
895 /*****************************************************************************
896 * enumerate the local print processors (INTERNAL)
898 * returns the needed size (in bytes) for pPPInfo
899 * and *lpreturned is set to number of entries returned in pPPInfo
902 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
907 PPRINTPROCESSOR_INFO_1W ppi
;
908 WCHAR buffer
[MAX_PATH
];
909 WCHAR dllname
[MAX_PATH
];
916 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
917 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
918 ptr
= (LPWSTR
) &pPPInfo
[len
];
921 len
= ARRAY_SIZE(buffer
);
924 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
925 /* add "winprint" first */
927 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(L
"winprint");
928 if (pPPInfo
&& (cbBuf
>= needed
)){
929 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
930 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
932 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
934 lstrcpyW(ptr
, L
"winprint"); /* Name of the Print Processor */
935 ptr
+= ARRAY_SIZE(L
"winprint");
938 /* Scan all Printprocessor Keys */
939 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
940 (lstrcmpiW(buffer
, L
"winprint") != 0)) {
941 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
942 dllsize
= sizeof(dllname
);
945 /* The Print Processor must have a Driver-DLL */
946 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
947 if (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, (BYTE
*)dllname
, &dllsize
) == ERROR_SUCCESS
) {
948 /* We found a valid DLL for this Print Processor */
949 TRACE("using Driver: %s\n", debugstr_w(dllname
));
956 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
957 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
959 /* required size is calculated. Now fill the user-buffer */
960 if (pPPInfo
&& (cbBuf
>= needed
)){
961 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
962 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
964 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
966 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
967 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
971 len
= ARRAY_SIZE(buffer
);
976 *lpreturned
= numentries
;
977 TRACE("need %d byte for %d entries\n", needed
, numentries
);
981 static BOOL
wrap_EnumPorts(monitor_t
*pm
, LPWSTR name
, DWORD level
, LPBYTE buffer
,
982 DWORD size
, LPDWORD needed
, LPDWORD returned
)
984 if (pm
->monitor
.pfnEnumPorts
)
985 return pm
->monitor
.pfnEnumPorts(pm
->hmon
, name
, level
, buffer
, size
, needed
, returned
);
987 if (pm
->old_EnumPorts
)
988 return pm
->old_EnumPorts(name
, level
, buffer
, size
, needed
, returned
);
990 WARN("EnumPorts is not implemented by monitor\n");
994 /******************************************************************
995 * enumerate the local Ports from all loaded monitors (internal)
997 * returns the needed size (in bytes) for pPorts
998 * and *lpreturned is set to number of entries returned in pPorts
1001 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1005 LPPORT_INFO_2W cache
;
1007 LPBYTE pi_buffer
= NULL
;
1008 DWORD pi_allocated
= 0;
1018 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1019 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1021 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1022 needed
= entrysize
* numentries
;
1023 ptr
= (LPWSTR
) &pPorts
[needed
];
1028 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1030 if (pm
->monitor
.pfnEnumPorts
|| pm
->old_EnumPorts
) {
1033 res
= wrap_EnumPorts(pm
, NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1034 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1035 /* Do not use heap_realloc (we do not need the old data in the buffer) */
1036 heap_free(pi_buffer
);
1037 pi_buffer
= heap_alloc(pi_needed
);
1038 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1039 res
= wrap_EnumPorts(pm
, NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1041 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
1042 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1044 numentries
+= pi_returned
;
1045 needed
+= pi_needed
;
1047 /* fill the output-buffer (pPorts), if we have one */
1048 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1050 while (pi_returned
> pi_index
) {
1051 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1052 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1053 out
->pPortName
= ptr
;
1054 lstrcpyW(ptr
, cache
->pPortName
);
1055 ptr
+= (lstrlenW(ptr
)+1);
1057 out
->pMonitorName
= ptr
;
1058 lstrcpyW(ptr
, cache
->pMonitorName
);
1059 ptr
+= (lstrlenW(ptr
)+1);
1061 out
->pDescription
= ptr
;
1062 lstrcpyW(ptr
, cache
->pDescription
);
1063 ptr
+= (lstrlenW(ptr
)+1);
1064 out
->fPortType
= cache
->fPortType
;
1065 out
->Reserved
= cache
->Reserved
;
1073 /* the temporary portinfo-buffer is no longer needed */
1074 heap_free(pi_buffer
);
1076 *lpreturned
= numentries
;
1077 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1082 /*****************************************************************************
1083 * open_driver_reg [internal]
1085 * opens the registry for the printer drivers depending on the given input
1086 * variable pEnvironment
1089 * Success: the opened hkey
1092 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1096 const printenv_t
* env
;
1098 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1100 env
= validate_envW(pEnvironment
);
1101 if (!env
) return NULL
;
1103 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
1104 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
1107 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1108 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1109 HeapFree(GetProcessHeap(), 0, buffer
);
1114 /*****************************************************************************
1115 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1117 * Return the PATH for the Printer-Drivers
1120 * pName [I] Servername (NT only) or NULL (local Computer)
1121 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1122 * Level [I] Structure-Level (must be 1)
1123 * pDriverDirectory [O] PTR to Buffer that receives the Result
1124 * cbBuf [I] Size of Buffer at pDriverDirectory
1125 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1126 * required for pDriverDirectory
1129 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1130 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1131 * if cbBuf is too small
1133 * Native Values returned in pDriverDirectory on Success:
1134 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1135 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1136 *| win9x(Windows 4.0): "%winsysdir%"
1138 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1141 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1142 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1145 const printenv_t
* env
;
1146 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1148 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1149 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1151 if (pName
!= NULL
&& pName
[0]) {
1152 FIXME("server %s not supported\n", debugstr_w(pName
));
1153 SetLastError(ERROR_INVALID_PARAMETER
);
1157 env
= validate_envW(pEnvironment
);
1158 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1161 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1162 needed
= GetSystemDirectoryW(NULL
, 0);
1163 /* add the Size for the Subdirectories */
1164 needed
+= lstrlenW(L
"\\spool");
1165 needed
+= lstrlenW(L
"\\drivers\\");
1166 needed
+= lstrlenW(env
->subdir
);
1167 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1169 *pcbNeeded
= needed
;
1171 if (needed
> cbBuf
) {
1172 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1177 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1178 SetLastError(ERROR_INVALID_USER_BUFFER
);
1182 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1183 /* add the Subdirectories */
1184 lstrcatW( dir
, L
"\\spool" );
1185 CreateDirectoryW( dir
, NULL
);
1186 lstrcatW( dir
, L
"\\drivers\\" );
1187 CreateDirectoryW( dir
, NULL
);
1188 lstrcatW( dir
, env
->subdir
);
1189 CreateDirectoryW( dir
, NULL
);
1191 TRACE( "=> %s\n", debugstr_w( dir
) );
1195 /******************************************************************
1196 * driver_load [internal]
1198 * load a driver user interface dll
1200 * On failure, NULL is returned
1204 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1206 WCHAR fullname
[MAX_PATH
];
1210 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1212 /* build the driverdir */
1213 len
= sizeof(fullname
) -
1214 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1216 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1217 (LPBYTE
) fullname
, len
, &len
)) {
1218 /* Should never fail */
1219 SetLastError(ERROR_BUFFER_OVERFLOW
);
1223 lstrcatW(fullname
, env
->versionsubdir
);
1224 lstrcatW(fullname
, L
"\\");
1225 lstrcatW(fullname
, dllname
);
1227 hui
= LoadLibraryW(fullname
);
1228 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1233 /******************************************************************
1235 * free the data pointer of an opened printer
1237 static VOID
printer_free(printer_t
* printer
)
1241 if (printer
->pm
->monitor
.pfnXcvClosePort
)
1242 printer
->pm
->monitor
.pfnXcvClosePort(printer
->hXcv
);
1245 monitor_unload(printer
->pm
);
1247 heap_free(printer
->printername
);
1248 heap_free(printer
->name
);
1252 /******************************************************************
1253 * printer_alloc_handle
1254 * alloc a printer handle and remember the data pointer in the printer handle table
1257 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1259 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1260 printer_t
*printer
= NULL
;
1261 LPCWSTR printername
;
1266 if (copy_servername_from_name(name
, servername
)) {
1267 FIXME("server %s not supported\n", debugstr_w(servername
));
1268 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1272 printername
= get_basename_from_name(name
);
1273 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1275 /* an empty printername is invalid */
1276 if (printername
&& (!printername
[0])) {
1277 SetLastError(ERROR_INVALID_PARAMETER
);
1281 printer
= heap_alloc_zero(sizeof(printer_t
));
1282 if (!printer
) goto end
;
1284 /* clone the base name. This is NULL for the printserver */
1285 printer
->printername
= strdupW(printername
);
1287 /* clone the full name */
1288 printer
->name
= strdupW(name
);
1289 if (name
&& (!printer
->name
)) {
1290 printer_free(printer
);
1294 len
= ARRAY_SIZE(L
",XcvMonitor ") - 1;
1295 if (wcsncmp(printername
, L
",XcvMonitor ", len
) == 0) {
1296 /* OpenPrinter(",XcvMonitor ", ...) detected */
1297 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1298 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1299 if (printer
->pm
== NULL
) {
1300 printer_free(printer
);
1301 SetLastError(ERROR_UNKNOWN_PORT
);
1308 len
= ARRAY_SIZE(L
",XcvPort ") - 1;
1309 if (wcsncmp( printername
, L
",XcvPort ", len
) == 0) {
1310 /* OpenPrinter(",XcvPort ", ...) detected */
1311 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1312 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1313 if (printer
->pm
== NULL
) {
1314 printer_free(printer
);
1315 SetLastError(ERROR_UNKNOWN_PORT
);
1323 if (printer
->pm
->monitor
.pfnXcvOpenPort
)
1324 printer
->pm
->monitor
.pfnXcvOpenPort(printer
->pm
->hmon
, &printername
[len
],
1325 pDefault
? pDefault
->DesiredAccess
: 0,
1327 else if (printer
->pm
->old_XcvOpenPort
)
1328 printer
->pm
->old_XcvOpenPort(&printername
[len
],
1329 pDefault
? pDefault
->DesiredAccess
: 0,
1331 if (printer
->hXcv
== NULL
) {
1332 printer_free(printer
);
1333 SetLastError(ERROR_INVALID_PARAMETER
);
1340 /* Does the Printer exist? */
1341 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1342 ERR("Can't create Printers key\n");
1343 printer_free(printer
);
1344 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1348 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1349 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1350 RegCloseKey(hkeyPrinters
);
1351 printer_free(printer
);
1352 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1356 RegCloseKey(hkeyPrinter
);
1357 RegCloseKey(hkeyPrinters
);
1362 TRACE("using the local printserver\n");
1367 TRACE("==> %p\n", printer
);
1368 return (HANDLE
)printer
;
1371 static inline WCHAR
*get_file_part( WCHAR
*name
)
1373 WCHAR
*ptr
= wcsrchr( name
, '\\' );
1374 if (ptr
) return ptr
+ 1;
1378 /******************************************************************************
1379 * myAddPrinterDriverEx [internal]
1381 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1382 * and a special mode with lazy error checking.
1385 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1387 const printenv_t
*env
;
1390 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1400 /* we need to set all entries in the Registry, independent from the Level of
1401 DRIVER_INFO, that the caller supplied */
1403 ZeroMemory(&di
, sizeof(di
));
1404 if (pDriverInfo
&& (level
< ARRAY_SIZE(di_sizeof
))) {
1405 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1408 /* dump the most used infos */
1409 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1410 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1411 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1412 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1413 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1414 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1415 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1416 /* dump only the first of the additional Files */
1417 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1420 /* check environment */
1421 env
= validate_envW(di
.pEnvironment
);
1422 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1424 /* fill the copy-data / get the driverdir */
1425 len
= sizeof(apd
.src
) - sizeof(L
"\\3") - sizeof(WCHAR
);
1426 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1427 (LPBYTE
) apd
.src
, len
, &len
)) {
1428 /* Should never fail */
1431 memcpy(apd
.dst
, apd
.src
, len
);
1432 lstrcatW(apd
.src
, L
"\\");
1433 apd
.srclen
= lstrlenW(apd
.src
);
1434 lstrcatW(apd
.dst
, env
->versionsubdir
);
1435 lstrcatW(apd
.dst
, L
"\\");
1436 apd
.dstlen
= lstrlenW(apd
.dst
);
1437 apd
.copyflags
= dwFileCopyFlags
;
1439 CreateDirectoryW(apd
.src
, NULL
);
1440 CreateDirectoryW(apd
.dst
, NULL
);
1442 hroot
= open_driver_reg(env
->envname
);
1444 ERR("Can't create Drivers key\n");
1448 /* Fill the Registry for the Driver */
1449 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1450 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1451 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1453 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1460 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1461 RegSetValueExW(hdrv
, L
"Version", 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1464 file
= get_file_part( di
.pDriverPath
);
1465 RegSetValueExW( hdrv
, L
"Driver", 0, REG_SZ
, (BYTE
*)file
, (lstrlenW( file
) + 1) * sizeof(WCHAR
) );
1466 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1468 file
= get_file_part( di
.pDataFile
);
1469 RegSetValueExW( hdrv
, L
"Data File", 0, REG_SZ
, (BYTE
*)file
, (lstrlenW( file
) + 1) * sizeof(WCHAR
) );
1470 apd_copyfile( di
.pDataFile
, file
, &apd
);
1472 file
= get_file_part( di
.pConfigFile
);
1473 RegSetValueExW( hdrv
, L
"Configuration File", 0, REG_SZ
, (BYTE
*)file
, (lstrlenW( file
) + 1) * sizeof(WCHAR
) );
1474 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1476 /* settings for level 3 */
1479 file
= get_file_part( di
.pHelpFile
);
1480 RegSetValueExW( hdrv
, L
"Help File", 0, REG_SZ
, (BYTE
*)file
, (lstrlenW( file
) + 1) * sizeof(WCHAR
) );
1481 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1484 RegSetValueExW( hdrv
, L
"Help File", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
"") );
1486 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1488 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1489 reg
= reg_ptr
= HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di
.pDependentFiles
) );
1491 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= lstrlenW( in_ptr
) + 1)
1493 file
= get_file_part( in_ptr
);
1494 len
= lstrlenW( file
) + 1;
1495 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1497 apd_copyfile( in_ptr
, file
, &apd
);
1501 RegSetValueExW( hdrv
, L
"Dependent Files", 0, REG_MULTI_SZ
, (BYTE
*)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
1502 HeapFree( GetProcessHeap(), 0, reg
);
1505 RegSetValueExW(hdrv
, L
"Dependent Files", 0, REG_MULTI_SZ
, (const BYTE
*)L
"", sizeof(L
""));
1507 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1508 if (di
.pMonitorName
)
1509 RegSetValueExW(hdrv
, L
"Monitor", 0, REG_SZ
, (BYTE
*)di
.pMonitorName
,
1510 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1512 RegSetValueExW(hdrv
, L
"Monitor", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
""));
1514 if (di
.pDefaultDataType
)
1515 RegSetValueExW(hdrv
, L
"Datatype", 0, REG_SZ
, (BYTE
*)di
.pDefaultDataType
,
1516 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1518 RegSetValueExW(hdrv
, L
"Datatype", 0, REG_SZ
, (const BYTE
*)L
"", sizeof(L
""));
1520 /* settings for level 4 */
1521 if (di
.pszzPreviousNames
)
1522 RegSetValueExW(hdrv
, L
"Previous Names", 0, REG_MULTI_SZ
, (BYTE
*)di
.pszzPreviousNames
,
1523 multi_sz_lenW(di
.pszzPreviousNames
));
1525 RegSetValueExW(hdrv
, L
"Previous Names", 0, REG_MULTI_SZ
, (const BYTE
*)L
"", sizeof(L
""));
1527 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1530 hui
= driver_load(env
, di
.pConfigFile
);
1531 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1532 if (hui
&& pDrvDriverEvent
) {
1534 /* Support for DrvDriverEvent is optional */
1535 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1536 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1537 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1538 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1542 TRACE("=> TRUE with %u\n", GetLastError());
1547 /******************************************************************************
1548 * fpAddMonitor [exported through PRINTPROVIDOR]
1550 * Install a Printmonitor
1553 * pName [I] Servername or NULL (local Computer)
1554 * Level [I] Structure-Level (Must be 2)
1555 * pMonitors [I] PTR to MONITOR_INFO_2
1562 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1565 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1567 const printenv_t
* env
;
1568 monitor_t
* pm
= NULL
;
1569 LPMONITOR_INFO_2W mi2w
;
1575 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1576 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1577 debugstr_w(mi2w
->pName
), debugstr_w(mi2w
->pEnvironment
), debugstr_w(mi2w
->pDLLName
));
1579 if (copy_servername_from_name(pName
, NULL
)) {
1580 FIXME("server %s not supported\n", debugstr_w(pName
));
1581 SetLastError(ERROR_ACCESS_DENIED
);
1585 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1586 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1587 SetLastError(ERROR_INVALID_PARAMETER
);
1591 env
= validate_envW(mi2w
->pEnvironment
);
1593 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1595 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1596 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1597 SetLastError(ERROR_INVALID_PARAMETER
);
1601 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1602 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1606 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1607 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1608 &disposition
) == ERROR_SUCCESS
) {
1610 /* Some installers set options for the port before calling AddMonitor.
1611 We query the "Driver" entry to verify that the monitor is installed,
1612 before we return an error.
1613 When a user installs two print monitors at the same time with the
1614 same name, a race condition is possible but silently ignored. */
1618 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1619 (RegQueryValueExW(hentry
, L
"Driver", NULL
, NULL
, NULL
,
1620 &namesize
) == ERROR_SUCCESS
)) {
1621 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1622 /* 9x use ERROR_ALREADY_EXISTS */
1623 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1628 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1629 res
= (RegSetValueExW(hentry
, L
"Driver", 0, REG_SZ
,
1630 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1632 /* Load and initialize the monitor. SetLastError() is called on failure */
1633 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
)
1635 RegDeleteKeyW(hroot
, mi2w
->pName
);
1639 SetLastError(ERROR_SUCCESS
); /* Monitor installer depends on this */
1642 RegCloseKey(hentry
);
1649 static BOOL
wrap_AddPort(monitor_t
*pm
, LPWSTR name
, HWND hwnd
, LPWSTR monitor_name
)
1651 if (pm
->monitor
.pfnAddPort
)
1652 return pm
->monitor
.pfnAddPort(pm
->hmon
, name
, hwnd
, monitor_name
);
1654 if (pm
->old_AddPort
)
1655 return pm
->old_AddPort(name
, hwnd
, monitor_name
);
1657 WARN("AddPort is not implemented by monitor\n");
1661 /******************************************************************************
1662 * fpAddPort [exported through PRINTPROVIDOR]
1664 * Add a Port for a specific Monitor
1667 * pName [I] Servername or NULL (local Computer)
1668 * hWnd [I] Handle to parent Window for the Dialog-Box
1669 * pMonitorName [I] Name of the Monitor that manage the Port
1676 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1683 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1685 lres
= copy_servername_from_name(pName
, NULL
);
1687 FIXME("server %s not supported\n", debugstr_w(pName
));
1688 SetLastError(ERROR_INVALID_PARAMETER
);
1692 /* an empty Monitorname is Invalid */
1693 if (!pMonitorName
[0]) {
1694 SetLastError(ERROR_NOT_SUPPORTED
);
1698 pm
= monitor_load(pMonitorName
, NULL
);
1699 if (pm
&& (pm
->monitor
.pfnAddPort
|| pm
->old_AddPort
)) {
1700 res
= wrap_AddPort(pm
, pName
, hWnd
, pMonitorName
);
1701 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1705 pui
= monitor_loadui(pm
);
1706 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1707 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1708 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1712 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1713 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1714 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1716 SetLastError(ERROR_NOT_SUPPORTED
);
1719 monitor_unload(pui
);
1723 TRACE("returning %d with %u\n", res
, GetLastError());
1727 static BOOL
wrap_AddPortEx(monitor_t
*pm
, LPWSTR name
, DWORD level
, LPBYTE buffer
, LPWSTR monitor_name
)
1729 if (pm
->monitor
.pfnAddPortEx
)
1730 return pm
->monitor
.pfnAddPortEx(pm
->hmon
, name
, level
, buffer
, monitor_name
);
1732 if (pm
->old_AddPortEx
)
1733 return pm
->old_AddPortEx(name
, level
, buffer
, monitor_name
);
1735 WARN("AddPortEx is not implemented by monitor\n");
1739 /******************************************************************************
1740 * fpAddPortEx [exported through PRINTPROVIDOR]
1742 * Add a Port for a specific Monitor, without presenting a user interface
1745 * pName [I] Servername or NULL (local Computer)
1746 * level [I] Structure-Level (1 or 2) for pBuffer
1747 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1748 * pMonitorName [I] Name of the Monitor that manage the Port
1755 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1762 pi2
= (PORT_INFO_2W
*) pBuffer
;
1764 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1765 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1766 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1767 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1769 lres
= copy_servername_from_name(pName
, NULL
);
1771 FIXME("server %s not supported\n", debugstr_w(pName
));
1772 SetLastError(ERROR_INVALID_PARAMETER
);
1776 if ((level
< 1) || (level
> 2)) {
1777 SetLastError(ERROR_INVALID_LEVEL
);
1781 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1782 SetLastError(ERROR_INVALID_PARAMETER
);
1786 /* load the Monitor */
1787 pm
= monitor_load(pMonitorName
, NULL
);
1788 if (pm
&& (pm
->monitor
.pfnAddPortEx
|| pm
->old_AddPortEx
))
1790 res
= wrap_AddPortEx(pm
, pName
, level
, pBuffer
, pMonitorName
);
1791 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1795 FIXME("not implemented for %s (monitor %p: %s)\n",
1796 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1797 SetLastError(ERROR_INVALID_PARAMETER
);
1804 /******************************************************************************
1805 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1807 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1810 * pName [I] Servername or NULL (local Computer)
1811 * level [I] Level for the supplied DRIVER_INFO_*W struct
1812 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1813 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1820 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1824 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1825 lres
= copy_servername_from_name(pName
, NULL
);
1827 FIXME("server %s not supported\n", debugstr_w(pName
));
1828 SetLastError(ERROR_ACCESS_DENIED
);
1832 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1833 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1836 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1839 /******************************************************************************
1840 * fpClosePrinter [exported through PRINTPROVIDOR]
1842 * Close a printer handle and free associated resources
1845 * hPrinter [I] Printerhandle to close
1852 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1854 printer_t
*printer
= (printer_t
*) hPrinter
;
1856 TRACE("(%p)\n", hPrinter
);
1859 printer_free(printer
);
1865 static BOOL
wrap_ConfigurePort(monitor_t
*pm
, LPWSTR name
, HWND hwnd
, LPWSTR port_name
)
1867 if (pm
->monitor
.pfnConfigurePort
)
1868 return pm
->monitor
.pfnConfigurePort(pm
->hmon
, name
, hwnd
, port_name
);
1870 if (pm
->old_ConfigurePort
)
1871 return pm
->old_ConfigurePort(name
, hwnd
, port_name
);
1873 WARN("ConfigurePort is not implemented by monitor\n");
1877 /******************************************************************************
1878 * fpConfigurePort [exported through PRINTPROVIDOR]
1880 * Display the Configuration-Dialog for a specific Port
1883 * pName [I] Servername or NULL (local Computer)
1884 * hWnd [I] Handle to parent Window for the Dialog-Box
1885 * pPortName [I] Name of the Port, that should be configured
1892 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1899 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1901 lres
= copy_servername_from_name(pName
, NULL
);
1903 FIXME("server %s not supported\n", debugstr_w(pName
));
1904 SetLastError(ERROR_INVALID_NAME
);
1908 /* an empty Portname is Invalid, but can popup a Dialog */
1909 if (!pPortName
[0]) {
1910 SetLastError(ERROR_NOT_SUPPORTED
);
1914 pm
= monitor_load_by_port(pPortName
);
1915 if (pm
&& (pm
->monitor
.pfnConfigurePort
|| pm
->old_ConfigurePort
))
1917 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1918 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1919 res
= wrap_ConfigurePort(pm
, pName
, hWnd
, pPortName
);
1920 TRACE("got %d with %u\n", res
, GetLastError());
1924 pui
= monitor_loadui(pm
);
1925 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1926 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1927 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1928 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1929 TRACE("got %d with %u\n", res
, GetLastError());
1933 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1934 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1935 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1937 SetLastError(ERROR_NOT_SUPPORTED
);
1940 monitor_unload(pui
);
1944 TRACE("returning %d with %u\n", res
, GetLastError());
1948 /******************************************************************
1949 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1951 * Delete a specific Printmonitor from a Printing-Environment
1954 * pName [I] Servername or NULL (local Computer)
1955 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1956 * pMonitorName [I] Name of the Monitor, that should be deleted
1963 * pEnvironment is ignored in Windows for the local Computer.
1967 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1973 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1974 debugstr_w(pMonitorName
));
1976 lres
= copy_servername_from_name(pName
, NULL
);
1978 FIXME("server %s not supported\n", debugstr_w(pName
));
1979 SetLastError(ERROR_INVALID_NAME
);
1983 /* pEnvironment is ignored in Windows for the local Computer */
1984 if (!pMonitorName
|| !pMonitorName
[0]) {
1985 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1986 SetLastError(ERROR_INVALID_PARAMETER
);
1990 /* Unload the monitor if it's loaded */
1991 EnterCriticalSection(&monitor_handles_cs
);
1992 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1994 if (pm
->name
&& !lstrcmpW(pMonitorName
, pm
->name
))
2000 LeaveCriticalSection(&monitor_handles_cs
);
2002 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
2003 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
2007 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2008 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
2013 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
2016 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2017 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2021 static BOOL
wrap_DeletePort(monitor_t
*pm
, LPWSTR name
, HWND hwnd
, LPWSTR port_name
)
2023 if (pm
->monitor
.pfnDeletePort
)
2024 return pm
->monitor
.pfnDeletePort(pm
->hmon
, name
, hwnd
, port_name
);
2026 if (pm
->old_ConfigurePort
)
2027 return pm
->old_DeletePort(name
, hwnd
, port_name
);
2029 WARN("DeletePort is not implemented by monitor\n");
2033 /*****************************************************************************
2034 * fpDeletePort [exported through PRINTPROVIDOR]
2036 * Delete a specific Port
2039 * pName [I] Servername or NULL (local Computer)
2040 * hWnd [I] Handle to parent Window for the Dialog-Box
2041 * pPortName [I] Name of the Port, that should be deleted
2048 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2055 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2057 lres
= copy_servername_from_name(pName
, NULL
);
2059 FIXME("server %s not supported\n", debugstr_w(pName
));
2060 SetLastError(ERROR_INVALID_NAME
);
2064 /* an empty Portname is Invalid */
2065 if (!pPortName
[0]) {
2066 SetLastError(ERROR_NOT_SUPPORTED
);
2070 pm
= monitor_load_by_port(pPortName
);
2071 if (pm
&& (pm
->monitor
.pfnDeletePort
|| pm
->old_DeletePort
))
2073 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
2074 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2075 res
= wrap_DeletePort(pm
, pName
, hWnd
, pPortName
);
2076 TRACE("got %d with %u\n", res
, GetLastError());
2080 pui
= monitor_loadui(pm
);
2081 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2082 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
2083 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2084 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2085 TRACE("got %d with %u\n", res
, GetLastError());
2089 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2090 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
2091 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2093 SetLastError(ERROR_NOT_SUPPORTED
);
2096 monitor_unload(pui
);
2100 TRACE("returning %d with %u\n", res
, GetLastError());
2104 /*****************************************************************************
2105 * fpEnumMonitors [exported through PRINTPROVIDOR]
2107 * Enumerate available Port-Monitors
2110 * pName [I] Servername or NULL (local Computer)
2111 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2112 * pMonitors [O] PTR to Buffer that receives the Result
2113 * cbBuf [I] Size of Buffer at pMonitors
2114 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2115 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2119 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2122 * Windows reads the Registry once and cache the Results.
2125 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
2126 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2128 DWORD numentries
= 0;
2133 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
2134 cbBuf
, pcbNeeded
, pcReturned
);
2136 lres
= copy_servername_from_name(pName
, NULL
);
2138 FIXME("server %s not supported\n", debugstr_w(pName
));
2139 SetLastError(ERROR_INVALID_NAME
);
2143 if (!Level
|| (Level
> 2)) {
2144 WARN("level (%d) is ignored in win9x\n", Level
);
2145 SetLastError(ERROR_INVALID_LEVEL
);
2149 /* Scan all Monitor-Keys */
2151 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
2153 /* we calculated the needed buffersize. now do more error-checks */
2154 if (cbBuf
< needed
) {
2155 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2159 /* fill the Buffer with the Monitor-Keys */
2160 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2164 if (pcbNeeded
) *pcbNeeded
= needed
;
2165 if (pcReturned
) *pcReturned
= numentries
;
2167 TRACE("returning %d with %d (%d byte for %d entries)\n",
2168 res
, GetLastError(), needed
, numentries
);
2173 /******************************************************************************
2174 * fpEnumPorts [exported through PRINTPROVIDOR]
2176 * Enumerate available Ports
2179 * pName [I] Servername or NULL (local Computer)
2180 * Level [I] Structure-Level (1 or 2)
2181 * pPorts [O] PTR to Buffer that receives the Result
2182 * cbBuf [I] Size of Buffer at pPorts
2183 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2184 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2188 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2191 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2192 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2195 DWORD numentries
= 0;
2199 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2200 cbBuf
, pcbNeeded
, pcReturned
);
2202 lres
= copy_servername_from_name(pName
, NULL
);
2204 FIXME("server %s not supported\n", debugstr_w(pName
));
2205 SetLastError(ERROR_INVALID_NAME
);
2209 if (!Level
|| (Level
> 2)) {
2210 SetLastError(ERROR_INVALID_LEVEL
);
2214 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2215 SetLastError(RPC_X_NULL_REF_POINTER
);
2219 EnterCriticalSection(&monitor_handles_cs
);
2222 /* Scan all local Ports */
2224 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2226 /* we calculated the needed buffersize. now do the error-checks */
2227 if (cbBuf
< needed
) {
2228 monitor_unloadall();
2229 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2230 goto emP_cleanup_cs
;
2232 else if (!pPorts
|| !pcReturned
) {
2233 monitor_unloadall();
2234 SetLastError(RPC_X_NULL_REF_POINTER
);
2235 goto emP_cleanup_cs
;
2238 /* Fill the Buffer */
2239 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2241 monitor_unloadall();
2244 LeaveCriticalSection(&monitor_handles_cs
);
2247 if (pcbNeeded
) *pcbNeeded
= needed
;
2248 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2250 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2251 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2256 /*****************************************************************************
2257 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2259 * Enumerate available Print Processors
2262 * pName [I] Servername or NULL (local Computer)
2263 * pEnvironment [I] Printing-Environment or NULL (Default)
2264 * Level [I] Structure-Level (Only 1 is allowed)
2265 * pPPInfo [O] PTR to Buffer that receives the Result
2266 * cbBuf [I] Size of Buffer at pMonitors
2267 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2268 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2272 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2275 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2276 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2278 const printenv_t
* env
;
2279 LPWSTR regpathW
= NULL
;
2280 DWORD numentries
= 0;
2285 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2286 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2288 lres
= copy_servername_from_name(pName
, NULL
);
2290 FIXME("server %s not supported\n", debugstr_w(pName
));
2291 SetLastError(ERROR_INVALID_NAME
);
2296 SetLastError(ERROR_INVALID_LEVEL
);
2300 env
= validate_envW(pEnvironment
);
2302 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2304 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2305 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2310 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2312 /* Scan all Printprocessor-Keys */
2314 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2316 /* we calculated the needed buffersize. now do more error-checks */
2317 if (cbBuf
< needed
) {
2318 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2322 /* fill the Buffer with the Printprocessor Infos */
2323 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2327 heap_free(regpathW
);
2328 if (pcbNeeded
) *pcbNeeded
= needed
;
2329 if (pcReturned
) *pcReturned
= numentries
;
2331 TRACE("returning %d with %d (%d byte for %d entries)\n",
2332 res
, GetLastError(), needed
, numentries
);
2337 /******************************************************************************
2338 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2340 * Return the PATH for the Print-Processors
2343 * pName [I] Servername or NULL (this computer)
2344 * pEnvironment [I] Printing-Environment or NULL (Default)
2345 * level [I] Structure-Level (must be 1)
2346 * pPPInfo [O] PTR to Buffer that receives the Result
2347 * cbBuf [I] Size of Buffer at pPPInfo
2348 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2352 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2354 * Native Values returned in pPPInfo on Success for this computer:
2355 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2356 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2357 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2359 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2362 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2363 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2365 const printenv_t
* env
;
2369 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2370 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2373 lres
= copy_servername_from_name(pName
, NULL
);
2375 FIXME("server %s not supported\n", debugstr_w(pName
));
2376 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2380 env
= validate_envW(pEnvironment
);
2382 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2384 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2385 needed
= GetSystemDirectoryW(NULL
, 0);
2386 /* add the Size for the Subdirectories */
2387 needed
+= lstrlenW(L
"\\spool\\prtprocs\\");
2388 needed
+= lstrlenW(env
->subdir
);
2389 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2391 *pcbNeeded
= needed
;
2393 if (needed
> cbBuf
) {
2394 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2398 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2399 /* add the Subdirectories */
2400 lstrcatW((LPWSTR
) pPPInfo
, L
"\\spool\\prtprocs\\");
2401 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2402 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2406 /******************************************************************************
2407 * fpOpenPrinter [exported through PRINTPROVIDOR]
2409 * Open a Printer / Printserver or a Printer-Object
2412 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2413 * pPrinter [O] The resulting Handle is stored here
2414 * pDefaults [I] PTR to Default Printer Settings or NULL
2421 * lpPrinterName is one of:
2422 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2423 *| Printer: "PrinterName"
2424 *| Printer-Object: "PrinterName,Job xxx"
2425 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2426 *| XcvPort: "Servername,XcvPort PortName"
2430 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2431 LPPRINTER_DEFAULTSW pDefaults
)
2434 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2436 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2438 return (*pPrinter
!= 0);
2441 /******************************************************************************
2442 * fpXcvData [exported through PRINTPROVIDOR]
2444 * Execute commands in the Printmonitor DLL
2447 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2448 * pszDataName [i] Name of the command to execute
2449 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2450 * cbInputData [i] Size in Bytes of Buffer at pInputData
2451 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2452 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2453 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2454 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2461 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2462 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2464 * Minimal List of commands, that a Printmonitor DLL should support:
2466 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2467 *| "AddPort" : Add a Port
2468 *| "DeletePort": Delete a Port
2470 * Many Printmonitors support additional commands. Examples for localspl.dll:
2471 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2472 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2475 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2476 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2477 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2479 printer_t
*printer
= (printer_t
* ) hXcv
;
2481 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2482 pInputData
, cbInputData
, pOutputData
,
2483 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2485 if (!printer
|| (!printer
->hXcv
)) {
2486 SetLastError(ERROR_INVALID_HANDLE
);
2490 if (!pcbOutputNeeded
) {
2491 SetLastError(ERROR_INVALID_PARAMETER
);
2495 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2496 SetLastError(RPC_X_NULL_REF_POINTER
);
2500 *pcbOutputNeeded
= 0;
2502 if (printer
->pm
->monitor
.pfnXcvDataPort
)
2503 *pdwStatus
= printer
->pm
->monitor
.pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2504 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2509 static const PRINTPROVIDOR backend
= {
2511 NULL
, /* fpSetJob */
2512 NULL
, /* fpGetJob */
2513 NULL
, /* fpEnumJobs */
2514 NULL
, /* fpAddPrinter */
2515 NULL
, /* fpDeletePrinter */
2516 NULL
, /* fpSetPrinter */
2517 NULL
, /* fpGetPrinter */
2518 NULL
, /* fpEnumPrinters */
2519 NULL
, /* fpAddPrinterDriver */
2520 NULL
, /* fpEnumPrinterDrivers */
2521 NULL
, /* fpGetPrinterDriver */
2522 fpGetPrinterDriverDirectory
,
2523 NULL
, /* fpDeletePrinterDriver */
2524 NULL
, /* fpAddPrintProcessor */
2525 fpEnumPrintProcessors
,
2526 fpGetPrintProcessorDirectory
,
2527 NULL
, /* fpDeletePrintProcessor */
2528 NULL
, /* fpEnumPrintProcessorDatatypes */
2529 NULL
, /* fpStartDocPrinter */
2530 NULL
, /* fpStartPagePrinter */
2531 NULL
, /* fpWritePrinter */
2532 NULL
, /* fpEndPagePrinter */
2533 NULL
, /* fpAbortPrinter */
2534 NULL
, /* fpReadPrinter */
2535 NULL
, /* fpEndDocPrinter */
2536 NULL
, /* fpAddJob */
2537 NULL
, /* fpScheduleJob */
2538 NULL
, /* fpGetPrinterData */
2539 NULL
, /* fpSetPrinterData */
2540 NULL
, /* fpWaitForPrinterChange */
2542 NULL
, /* fpAddForm */
2543 NULL
, /* fpDeleteForm */
2544 NULL
, /* fpGetForm */
2545 NULL
, /* fpSetForm */
2546 NULL
, /* fpEnumForms */
2552 NULL
, /* fpCreatePrinterIC */
2553 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2554 NULL
, /* fpDeletePrinterIC */
2555 NULL
, /* fpAddPrinterConnection */
2556 NULL
, /* fpDeletePrinterConnection */
2557 NULL
, /* fpPrinterMessageBox */
2560 NULL
, /* fpResetPrinter */
2561 NULL
, /* fpGetPrinterDriverEx */
2562 NULL
, /* fpFindFirstPrinterChangeNotification */
2563 NULL
, /* fpFindClosePrinterChangeNotification */
2565 NULL
, /* fpShutDown */
2566 NULL
, /* fpRefreshPrinterChangeNotification */
2567 NULL
, /* fpOpenPrinterEx */
2568 NULL
, /* fpAddPrinterEx */
2569 NULL
, /* fpSetPort */
2570 NULL
, /* fpEnumPrinterData */
2571 NULL
, /* fpDeletePrinterData */
2572 NULL
, /* fpClusterSplOpen */
2573 NULL
, /* fpClusterSplClose */
2574 NULL
, /* fpClusterSplIsAlive */
2575 NULL
, /* fpSetPrinterDataEx */
2576 NULL
, /* fpGetPrinterDataEx */
2577 NULL
, /* fpEnumPrinterDataEx */
2578 NULL
, /* fpEnumPrinterKey */
2579 NULL
, /* fpDeletePrinterDataEx */
2580 NULL
, /* fpDeletePrinterKey */
2581 NULL
, /* fpSeekPrinter */
2582 NULL
, /* fpDeletePrinterDriverEx */
2583 NULL
, /* fpAddPerMachineConnection */
2584 NULL
, /* fpDeletePerMachineConnection */
2585 NULL
, /* fpEnumPerMachineConnections */
2587 fpAddPrinterDriverEx
,
2588 NULL
, /* fpSplReadPrinter */
2589 NULL
, /* fpDriverUnloadComplete */
2590 NULL
, /* fpGetSpoolFileInfo */
2591 NULL
, /* fpCommitSpoolData */
2592 NULL
, /* fpCloseSpoolFileHandle */
2593 NULL
, /* fpFlushPrinter */
2594 NULL
, /* fpSendRecvBidiData */
2595 NULL
/* fpAddDriverCatalog */
2598 /*****************************************************
2599 * InitializePrintProvidor (localspl.@)
2601 * Initialize the Printprovider
2604 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2605 * cbPrintProvidor [I] Size of Buffer in Bytes
2606 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2609 * Success: TRUE and pPrintProvidor filled
2613 * The RegistryPath should be:
2614 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2615 * but this Parameter is ignored in "localspl.dll".
2619 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2620 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2623 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2624 memcpy(pPrintProvidor
, &backend
,
2625 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));