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 PRINTPROVIDOR
* pprovider
= NULL
;
104 static const WCHAR backslashW
[] = {'\\',0};
105 static const WCHAR bs_ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
106 static const WCHAR configuration_fileW
[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
107 static const WCHAR datatypeW
[] = {'D','a','t','a','t','y','p','e',0};
108 static const WCHAR data_fileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
109 static const WCHAR dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
110 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
111 static const WCHAR emptyW
[] = {0};
112 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
113 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
114 'c','o','n','t','r','o','l','\\',
115 'P','r','i','n','t','\\',
116 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
117 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
118 static const WCHAR fmt_printprocessorsW
[] = { 'S','y','s','t','e','m','\\',
119 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
120 'C','o','n','t','r','o','l','\\',
121 'P','r','i','n','t','\\',
122 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
123 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
124 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
125 static const WCHAR ia64_envnameW
[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
126 static const WCHAR ia64_subdirW
[] = {'i','a','6','4',0};
127 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
128 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
129 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
130 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'C','o','n','t','r','o','l','\\',
132 'P','r','i','n','t','\\',
133 'M','o','n','i','t','o','r','s','\\',0};
134 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
135 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
136 static const WCHAR printersW
[] = {'S','y','s','t','e','m','\\',
137 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
138 'C','o','n','t','r','o','l','\\',
139 'P','r','i','n','t','\\',
140 'P','r','i','n','t','e','r','s',0};
141 static const WCHAR spoolW
[] = {'\\','s','p','o','o','l',0};
142 static const WCHAR driversW
[] = {'\\','d','r','i','v','e','r','s','\\',0};
143 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
144 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
145 static const WCHAR version0_subdirW
[] = {'\\','0',0};
146 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
147 static const WCHAR version3_subdirW
[] = {'\\','3',0};
148 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
149 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
150 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
151 static const WCHAR winnt_cv_portsW
[] = {'S','o','f','t','w','a','r','e','\\',
152 'M','i','c','r','o','s','o','f','t','\\',
153 'W','i','n','d','o','w','s',' ','N','T','\\',
154 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
155 'P','o','r','t','s',0};
156 static const WCHAR winprintW
[] = {'w','i','n','p','r','i','n','t',0};
157 static const WCHAR x64_envnameW
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
158 static const WCHAR x64_subdirW
[] = {'x','6','4',0};
159 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
160 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
161 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
162 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
165 static const printenv_t env_ia64
= {ia64_envnameW
, ia64_subdirW
, 3,
166 version3_regpathW
, version3_subdirW
};
168 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
169 version3_regpathW
, version3_subdirW
};
171 static const printenv_t env_x64
= {x64_envnameW
, x64_subdirW
, 3,
172 version3_regpathW
, version3_subdirW
};
174 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
175 version0_regpathW
, version0_subdirW
};
177 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_win40
};
180 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
181 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
182 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
183 0, sizeof(DRIVER_INFO_8W
)};
186 /******************************************************************
189 * create a copy of a unicode-string
192 static LPWSTR
strdupW(LPCWSTR p
)
198 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
199 ret
= heap_alloc(len
);
200 if (ret
) memcpy(ret
, p
, len
);
204 /******************************************************************
205 * apd_copyfile [internal]
207 * Copy a file from the driverdirectory to the versioned directory
214 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
219 apd
->src
[apd
->srclen
] = '\0';
220 apd
->dst
[apd
->dstlen
] = '\0';
222 if (!pathname
|| !pathname
[0]) {
223 /* nothing to copy */
227 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
232 lstrcatW( srcname
, file_part
);
234 lstrcatW( apd
->dst
, file_part
);
236 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
238 /* FIXME: handle APD_COPY_NEW_FILES */
239 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
240 TRACE("got %d with %u\n", res
, GetLastError());
242 return apd
->lazy
|| res
;
245 /******************************************************************
246 * copy_servername_from_name (internal)
248 * for an external server, the serverpart from the name is copied.
251 * the length (in WCHAR) of the serverpart (0 for the local computer)
252 * (-length), when the name is too long
255 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
259 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
263 if (target
) *target
= '\0';
265 if (name
== NULL
) return 0;
266 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
269 /* skip over both backslash, find separator '\' */
270 ptr
= wcschr(server
, '\\');
271 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
273 /* servername is empty */
274 if (serverlen
== 0) return 0;
276 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
278 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
281 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
282 target
[serverlen
] = '\0';
285 len
= ARRAY_SIZE(buffer
);
286 if (GetComputerNameW(buffer
, &len
)) {
287 if ((serverlen
== len
) && (wcsnicmp(server
, buffer
, len
) == 0)) {
288 /* The requested Servername is our computername */
295 /******************************************************************
296 * get_basename_from_name (internal)
298 * skip over the serverpart from the full name
301 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
303 if (name
== NULL
) return NULL
;
304 if ((name
[0] == '\\') && (name
[1] == '\\')) {
305 /* skip over the servername and search for the following '\' */
306 name
= wcschr(&name
[2], '\\');
307 if ((name
) && (name
[1])) {
308 /* found a separator ('\') followed by a name:
309 skip over the separator and return the rest */
314 /* no basename present (we found only a servername) */
321 /******************************************************************
322 * monitor_unload [internal]
324 * release a printmonitor and unload it from memory, when needed
327 static void monitor_unload(monitor_t
* pm
)
329 if (pm
== NULL
) return;
330 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
332 EnterCriticalSection(&monitor_handles_cs
);
334 if (pm
->refcount
) pm
->refcount
--;
336 if (pm
->refcount
== 0) {
337 list_remove(&pm
->entry
);
339 if (pm
->monitor
.pfnShutdown
)
340 pm
->monitor
.pfnShutdown(pm
->hmon
);
342 FreeLibrary(pm
->hdll
);
344 heap_free(pm
->dllname
);
347 LeaveCriticalSection(&monitor_handles_cs
);
350 /******************************************************************
351 * monitor_unloadall [internal]
353 * release all registered printmonitors and unload them from memory, when needed
357 static void monitor_unloadall(void)
362 EnterCriticalSection(&monitor_handles_cs
);
363 /* iterate through the list, with safety against removal */
364 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
366 /* skip monitorui dlls */
367 if (pm
->monitor
.cbSize
) monitor_unload(pm
);
369 LeaveCriticalSection(&monitor_handles_cs
);
372 static LONG WINAPI
CreateKey(HANDLE hcKey
, LPCWSTR pszSubKey
, DWORD dwOptions
,
373 REGSAM samDesired
, PSECURITY_ATTRIBUTES pSecurityAttributes
,
374 PHANDLE phckResult
, PDWORD pdwDisposition
, HANDLE hSpooler
)
377 return ERROR_CALL_NOT_IMPLEMENTED
;
380 static LONG WINAPI
OpenKey(HANDLE hcKey
, LPCWSTR pszSubKey
, REGSAM samDesired
,
381 PHANDLE phkResult
, HANDLE hSpooler
)
384 return ERROR_CALL_NOT_IMPLEMENTED
;
387 static LONG WINAPI
CloseKey(HANDLE hcKey
, HANDLE hSpooler
)
390 return ERROR_CALL_NOT_IMPLEMENTED
;
393 static LONG WINAPI
DeleteKey(HANDLE hcKey
, LPCWSTR pszSubKey
, HANDLE hSpooler
)
396 return ERROR_CALL_NOT_IMPLEMENTED
;
399 static LONG WINAPI
EnumKey(HANDLE hcKey
, DWORD dwIndex
, LPWSTR pszName
,
400 PDWORD pcchName
, PFILETIME pftLastWriteTime
, HANDLE hSpooler
)
403 return ERROR_CALL_NOT_IMPLEMENTED
;
406 static LONG WINAPI
QueryInfoKey(HANDLE hcKey
, PDWORD pcSubKeys
, PDWORD pcbKey
,
407 PDWORD pcValues
, PDWORD pcbValue
, PDWORD pcbData
,
408 PDWORD pcbSecurityDescriptor
, PFILETIME pftLastWriteTime
,
412 return ERROR_CALL_NOT_IMPLEMENTED
;
415 static LONG WINAPI
SetValue(HANDLE hcKey
, LPCWSTR pszValue
, DWORD dwType
,
416 const BYTE
* pData
, DWORD cbData
, HANDLE hSpooler
)
419 return ERROR_CALL_NOT_IMPLEMENTED
;
422 static LONG WINAPI
DeleteValue(HANDLE hcKey
, LPCWSTR pszValue
, HANDLE hSpooler
)
425 return ERROR_CALL_NOT_IMPLEMENTED
;
428 static LONG WINAPI
EnumValue(HANDLE hcKey
, DWORD dwIndex
, LPWSTR pszValue
,
429 PDWORD pcbValue
, PDWORD pType
, PBYTE pData
, PDWORD pcbData
,
433 return ERROR_CALL_NOT_IMPLEMENTED
;
436 static LONG WINAPI
QueryValue(HANDLE hcKey
, LPCWSTR pszValue
, PDWORD pType
,
437 PBYTE pData
, PDWORD pcbData
, HANDLE hSpooler
)
440 return ERROR_CALL_NOT_IMPLEMENTED
;
443 static MONITORREG monreg
=
458 /******************************************************************
459 * monitor_load [internal]
461 * load a printmonitor, get the dllname from the registry, when needed
462 * initialize the monitor and dump found function-pointers
464 * On failure, SetLastError() is called and NULL is returned
467 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
469 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
470 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
471 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
472 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
473 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
475 monitor_t
* pm
= NULL
;
477 LPWSTR regroot
= NULL
;
478 LPWSTR driver
= dllname
;
481 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
482 /* Is the Monitor already loaded? */
483 EnterCriticalSection(&monitor_handles_cs
);
486 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
488 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
496 pm
= heap_alloc_zero(sizeof(monitor_t
));
497 if (pm
== NULL
) goto cleanup
;
498 list_add_tail(&monitor_handles
, &pm
->entry
);
502 if (pm
->name
== NULL
) {
503 /* Load the monitor */
507 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
508 regroot
= heap_alloc(len
* sizeof(WCHAR
));
512 lstrcpyW(regroot
, monitorsW
);
513 lstrcatW(regroot
, name
);
514 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
515 /* Get the Driver from the Registry */
516 if (driver
== NULL
) {
518 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
519 &namesize
) == ERROR_SUCCESS
) {
520 driver
= heap_alloc(namesize
);
521 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
526 WARN("%s not found\n", debugstr_w(regroot
));
529 pm
->name
= strdupW(name
);
530 pm
->dllname
= strdupW(driver
);
532 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
534 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
539 pm
->hdll
= LoadLibraryW(driver
);
540 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
542 if (pm
->hdll
== NULL
) {
544 SetLastError(ERROR_MOD_NOT_FOUND
);
549 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
550 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
551 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
552 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
553 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
556 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
557 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
558 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
559 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
560 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
562 if (pInitializePrintMonitorUI
!= NULL
) {
563 pm
->monitorUI
= pInitializePrintMonitorUI();
564 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
566 TRACE("0x%08x: dwMonitorSize (%d)\n",
567 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
572 if (pInitializePrintMonitor2
&& hroot
) {
577 memset(&init
, 0, sizeof(init
));
578 init
.cbSize
= sizeof(init
);
579 init
.hckRegistryRoot
= hroot
;
580 init
.pMonitorReg
= &monreg
;
583 monitor2
= pInitializePrintMonitor2(&init
, &hmon
);
584 TRACE("%p: MONITOR2 from %s,InitializePrintMonitor2(%s)\n",
585 monitor2
, debugstr_w(driver
), debugstr_w(regroot
));
588 memcpy(&pm
->monitor
, monitor2
, min(monitor2
->cbSize
, sizeof(pm
->monitor
)));
592 else if (pInitializePrintMonitor
&& regroot
) {
593 MONITOREX
*pmonitorEx
;
595 pmonitorEx
= pInitializePrintMonitor(regroot
);
596 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
597 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
600 /* Layout of MONITOREX and MONITOR2 mostly matches */
601 memcpy(&pm
->monitor
, pmonitorEx
, min(pmonitorEx
->dwMonitorSize
+ sizeof(void *), sizeof(pm
->monitor
)));
602 /* MONITOREX.dwMonitorSize doesn't include the size field, while MONITOR2.cbSize does */
603 pm
->monitor
.cbSize
+= sizeof(void *);
605 pm
->old_EnumPorts
= pmonitorEx
->Monitor
.pfnEnumPorts
;
606 pm
->old_OpenPort
= pmonitorEx
->Monitor
.pfnOpenPort
;
607 pm
->old_OpenPortEx
= pmonitorEx
->Monitor
.pfnOpenPortEx
;
608 pm
->old_AddPort
= pmonitorEx
->Monitor
.pfnAddPort
;
609 pm
->old_AddPortEx
= pmonitorEx
->Monitor
.pfnAddPortEx
;
610 pm
->old_ConfigurePort
= pmonitorEx
->Monitor
.pfnConfigurePort
;
611 pm
->old_DeletePort
= pmonitorEx
->Monitor
.pfnDeletePort
;
612 pm
->old_XcvOpenPort
= pmonitorEx
->Monitor
.pfnXcvOpenPort
;
614 pm
->monitor
.pfnEnumPorts
= NULL
;
615 pm
->monitor
.pfnOpenPort
= NULL
;
616 pm
->monitor
.pfnOpenPortEx
= NULL
;
617 pm
->monitor
.pfnAddPort
= NULL
;
618 pm
->monitor
.pfnAddPortEx
= NULL
;
619 pm
->monitor
.pfnConfigurePort
= NULL
;
620 pm
->monitor
.pfnDeletePort
= NULL
;
621 pm
->monitor
.pfnXcvOpenPort
= NULL
;
625 if (!pm
->monitor
.cbSize
&& regroot
) {
626 if (pInitializeMonitorEx
!= NULL
) {
627 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
629 if (pInitializeMonitor
!= NULL
) {
630 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
633 if (!pm
->monitor
.cbSize
&& !pm
->monitorUI
) {
635 SetLastError(ERROR_PROC_NOT_FOUND
);
640 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
644 LeaveCriticalSection(&monitor_handles_cs
);
645 if (driver
!= dllname
) heap_free(driver
);
646 if (hroot
) RegCloseKey(hroot
);
648 TRACE("=> %p\n", pm
);
652 /******************************************************************
653 * monitor_loadall [internal]
655 * Load all registered monitors
658 static DWORD
monitor_loadall(void)
661 DWORD registered
= 0;
664 WCHAR buffer
[MAX_PATH
];
667 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
668 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
669 NULL
, NULL
, NULL
, NULL
, NULL
);
671 TRACE("%d monitors registered\n", registered
);
673 while (id
< registered
) {
675 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
676 pm
= monitor_load(buffer
, NULL
);
680 RegCloseKey(hmonitors
);
682 TRACE("%d monitors loaded\n", loaded
);
686 /******************************************************************
687 * monitor_loadui [internal]
689 * load the userinterface-dll for a given portmonitor
691 * On failure, NULL is returned
693 static monitor_t
* monitor_loadui(monitor_t
* pm
)
695 monitor_t
* pui
= NULL
;
696 WCHAR buffer
[MAX_PATH
];
701 if (pm
== NULL
) return NULL
;
702 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
704 /* Try the Portmonitor first; works for many monitors */
706 EnterCriticalSection(&monitor_handles_cs
);
708 LeaveCriticalSection(&monitor_handles_cs
);
712 /* query the userinterface-dllname from the Portmonitor */
713 /* building (",XcvMonitor %s",pm->name) not needed yet */
714 if (pm
->monitor
.pfnXcvOpenPort
)
715 res
= pm
->monitor
.pfnXcvOpenPort(pm
->hmon
, emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
716 else if (pm
->old_XcvOpenPort
)
717 res
= pm
->old_XcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
718 TRACE("got %u with %p\n", res
, hXcv
);
720 res
= pm
->monitor
.pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
721 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
722 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
723 pm
->monitor
.pfnXcvClosePort(hXcv
);
728 /******************************************************************
729 * monitor_load_by_port [internal]
731 * load a printmonitor for a given port
733 * On failure, NULL is returned
736 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
741 monitor_t
* pm
= NULL
;
742 DWORD registered
= 0;
746 TRACE("(%s)\n", debugstr_w(portname
));
748 /* Try the Local Monitor first */
749 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
750 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
751 /* found the portname */
753 return monitor_load(localportW
, NULL
);
758 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
759 buffer
= heap_alloc(len
* sizeof(WCHAR
));
760 if (buffer
== NULL
) return NULL
;
762 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
763 EnterCriticalSection(&monitor_handles_cs
);
764 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
766 while ((pm
== NULL
) && (id
< registered
)) {
768 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
769 TRACE("testing %s\n", debugstr_w(buffer
));
770 len
= lstrlenW(buffer
);
771 lstrcatW(buffer
, bs_ports_bsW
);
772 lstrcatW(buffer
, portname
);
773 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
775 buffer
[len
] = '\0'; /* use only the Monitor-Name */
776 pm
= monitor_load(buffer
, NULL
);
780 LeaveCriticalSection(&monitor_handles_cs
);
787 /******************************************************************
788 * Return the number of bytes for an multi_sz string.
789 * The result includes all \0s
790 * (specifically the extra \0, that is needed as multi_sz terminator).
792 static int multi_sz_lenW(const WCHAR
*str
)
794 const WCHAR
*ptr
= str
;
798 ptr
+= lstrlenW(ptr
) + 1;
801 return (ptr
- str
+ 1) * sizeof(WCHAR
);
804 /******************************************************************
805 * validate_envW [internal]
807 * validate the user-supplied printing-environment
810 * env [I] PTR to Environment-String or NULL
813 * Success: PTR to printenv_t
814 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
817 * An empty string is handled the same way as NULL.
821 static const printenv_t
* validate_envW(LPCWSTR env
)
823 const printenv_t
*result
= NULL
;
826 TRACE("(%s)\n", debugstr_w(env
));
829 for (i
= 0; i
< ARRAY_SIZE(all_printenv
); i
++)
831 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
833 result
= all_printenv
[i
];
837 if (result
== NULL
) {
838 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
839 SetLastError(ERROR_INVALID_ENVIRONMENT
);
841 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
845 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
848 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
852 /*****************************************************************************
853 * enumerate the local monitors (INTERNAL)
855 * returns the needed size (in bytes) for pMonitors
856 * and *lpreturned is set to number of entries returned in pMonitors
858 * Language-Monitors are also installed in the same Registry-Location but
859 * they are filtered in Windows (not returned by EnumMonitors).
860 * We do no filtering to simplify our Code.
863 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
868 LPMONITOR_INFO_2W mi
;
869 WCHAR buffer
[MAX_PATH
];
870 WCHAR dllname
[MAX_PATH
];
878 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
880 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
881 len
= entrysize
* numentries
;
882 ptr
= (LPWSTR
) &pMonitors
[len
];
885 len
= ARRAY_SIZE(buffer
);
888 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
889 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
890 /* Scan all Monitor-Registry-Keys */
891 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
892 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
893 dllsize
= sizeof(dllname
);
896 /* The Monitor must have a Driver-DLL */
897 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
898 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
899 /* We found a valid DLL for this Monitor. */
900 TRACE("using Driver: %s\n", debugstr_w(dllname
));
905 /* Windows returns only Port-Monitors here, but to simplify our code,
906 we do no filtering for Language-Monitors */
910 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
912 /* we install and return only monitors for "Windows NT x86" */
913 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
917 /* required size is calculated. Now fill the user-buffer */
918 if (pMonitors
&& (cbBuf
>= needed
)){
919 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
920 pMonitors
+= entrysize
;
922 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
924 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
925 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
927 mi
->pEnvironment
= ptr
;
928 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
929 ptr
+= (lstrlenW(x86_envnameW
)+1);
932 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
933 ptr
+= (dllsize
/ sizeof(WCHAR
));
938 len
= ARRAY_SIZE(buffer
);
943 *lpreturned
= numentries
;
944 TRACE("need %d byte for %d entries\n", needed
, numentries
);
948 /*****************************************************************************
949 * enumerate the local print processors (INTERNAL)
951 * returns the needed size (in bytes) for pPPInfo
952 * and *lpreturned is set to number of entries returned in pPPInfo
955 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
960 PPRINTPROCESSOR_INFO_1W ppi
;
961 WCHAR buffer
[MAX_PATH
];
962 WCHAR dllname
[MAX_PATH
];
969 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
970 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
971 ptr
= (LPWSTR
) &pPPInfo
[len
];
974 len
= ARRAY_SIZE(buffer
);
977 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
978 /* add "winprint" first */
980 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(winprintW
);
981 if (pPPInfo
&& (cbBuf
>= needed
)){
982 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
983 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
985 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
987 lstrcpyW(ptr
, winprintW
); /* Name of the Print Processor */
988 ptr
+= ARRAY_SIZE(winprintW
);
991 /* Scan all Printprocessor Keys */
992 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
993 (lstrcmpiW(buffer
, winprintW
) != 0)) {
994 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
995 dllsize
= sizeof(dllname
);
998 /* The Print Processor must have a Driver-DLL */
999 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
1000 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
1001 /* We found a valid DLL for this Print Processor */
1002 TRACE("using Driver: %s\n", debugstr_w(dllname
));
1004 RegCloseKey(hentry
);
1009 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
1010 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
1012 /* required size is calculated. Now fill the user-buffer */
1013 if (pPPInfo
&& (cbBuf
>= needed
)){
1014 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
1015 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
1017 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
1019 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
1020 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
1024 len
= ARRAY_SIZE(buffer
);
1029 *lpreturned
= numentries
;
1030 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1034 static BOOL
wrap_EnumPorts(monitor_t
*pm
, LPWSTR name
, DWORD level
, LPBYTE buffer
,
1035 DWORD size
, LPDWORD needed
, LPDWORD returned
)
1037 if (pm
->monitor
.pfnEnumPorts
)
1038 return pm
->monitor
.pfnEnumPorts(pm
->hmon
, name
, level
, buffer
, size
, needed
, returned
);
1040 if (pm
->old_EnumPorts
)
1041 return pm
->old_EnumPorts(name
, level
, buffer
, size
, needed
, returned
);
1043 WARN("EnumPorts is not implemented by monitor\n");
1047 /******************************************************************
1048 * enumerate the local Ports from all loaded monitors (internal)
1050 * returns the needed size (in bytes) for pPorts
1051 * and *lpreturned is set to number of entries returned in pPorts
1054 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
1058 LPPORT_INFO_2W cache
;
1060 LPBYTE pi_buffer
= NULL
;
1061 DWORD pi_allocated
= 0;
1071 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
1072 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
1074 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
1075 needed
= entrysize
* numentries
;
1076 ptr
= (LPWSTR
) &pPorts
[needed
];
1081 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
1083 if (pm
->monitor
.pfnEnumPorts
|| pm
->old_EnumPorts
) {
1086 res
= wrap_EnumPorts(pm
, NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1087 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
1088 /* Do not use heap_realloc (we do not need the old data in the buffer) */
1089 heap_free(pi_buffer
);
1090 pi_buffer
= heap_alloc(pi_needed
);
1091 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
1092 res
= wrap_EnumPorts(pm
, NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
1094 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
1095 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
1097 numentries
+= pi_returned
;
1098 needed
+= pi_needed
;
1100 /* fill the output-buffer (pPorts), if we have one */
1101 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
1103 while (pi_returned
> pi_index
) {
1104 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
1105 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
1106 out
->pPortName
= ptr
;
1107 lstrcpyW(ptr
, cache
->pPortName
);
1108 ptr
+= (lstrlenW(ptr
)+1);
1110 out
->pMonitorName
= ptr
;
1111 lstrcpyW(ptr
, cache
->pMonitorName
);
1112 ptr
+= (lstrlenW(ptr
)+1);
1114 out
->pDescription
= ptr
;
1115 lstrcpyW(ptr
, cache
->pDescription
);
1116 ptr
+= (lstrlenW(ptr
)+1);
1117 out
->fPortType
= cache
->fPortType
;
1118 out
->Reserved
= cache
->Reserved
;
1126 /* the temporary portinfo-buffer is no longer needed */
1127 heap_free(pi_buffer
);
1129 *lpreturned
= numentries
;
1130 TRACE("need %d byte for %d entries\n", needed
, numentries
);
1135 /*****************************************************************************
1136 * open_driver_reg [internal]
1138 * opens the registry for the printer drivers depending on the given input
1139 * variable pEnvironment
1142 * Success: the opened hkey
1145 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1149 const printenv_t
* env
;
1151 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1153 env
= validate_envW(pEnvironment
);
1154 if (!env
) return NULL
;
1156 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
1157 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
1160 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1161 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1162 HeapFree(GetProcessHeap(), 0, buffer
);
1167 /*****************************************************************************
1168 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1170 * Return the PATH for the Printer-Drivers
1173 * pName [I] Servername (NT only) or NULL (local Computer)
1174 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1175 * Level [I] Structure-Level (must be 1)
1176 * pDriverDirectory [O] PTR to Buffer that receives the Result
1177 * cbBuf [I] Size of Buffer at pDriverDirectory
1178 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1179 * required for pDriverDirectory
1182 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1183 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1184 * if cbBuf is too small
1186 * Native Values returned in pDriverDirectory on Success:
1187 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1188 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1189 *| win9x(Windows 4.0): "%winsysdir%"
1191 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1194 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1195 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1198 const printenv_t
* env
;
1199 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1201 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1202 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1204 if (pName
!= NULL
&& pName
[0]) {
1205 FIXME("server %s not supported\n", debugstr_w(pName
));
1206 SetLastError(ERROR_INVALID_PARAMETER
);
1210 env
= validate_envW(pEnvironment
);
1211 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1214 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1215 needed
= GetSystemDirectoryW(NULL
, 0);
1216 /* add the Size for the Subdirectories */
1217 needed
+= lstrlenW(spoolW
);
1218 needed
+= lstrlenW(driversW
);
1219 needed
+= lstrlenW(env
->subdir
);
1220 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1222 *pcbNeeded
= needed
;
1224 if (needed
> cbBuf
) {
1225 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1230 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1231 SetLastError(ERROR_INVALID_USER_BUFFER
);
1235 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1236 /* add the Subdirectories */
1237 lstrcatW( dir
, spoolW
);
1238 CreateDirectoryW( dir
, NULL
);
1239 lstrcatW( dir
, driversW
);
1240 CreateDirectoryW( dir
, NULL
);
1241 lstrcatW( dir
, env
->subdir
);
1242 CreateDirectoryW( dir
, NULL
);
1244 TRACE( "=> %s\n", debugstr_w( dir
) );
1248 /******************************************************************
1249 * driver_load [internal]
1251 * load a driver user interface dll
1253 * On failure, NULL is returned
1257 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1259 WCHAR fullname
[MAX_PATH
];
1263 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1265 /* build the driverdir */
1266 len
= sizeof(fullname
) -
1267 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1269 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1270 (LPBYTE
) fullname
, len
, &len
)) {
1271 /* Should never fail */
1272 SetLastError(ERROR_BUFFER_OVERFLOW
);
1276 lstrcatW(fullname
, env
->versionsubdir
);
1277 lstrcatW(fullname
, backslashW
);
1278 lstrcatW(fullname
, dllname
);
1280 hui
= LoadLibraryW(fullname
);
1281 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1286 /******************************************************************
1288 * free the data pointer of an opened printer
1290 static VOID
printer_free(printer_t
* printer
)
1294 if (printer
->pm
->monitor
.pfnXcvClosePort
)
1295 printer
->pm
->monitor
.pfnXcvClosePort(printer
->hXcv
);
1298 monitor_unload(printer
->pm
);
1300 heap_free(printer
->printername
);
1301 heap_free(printer
->name
);
1305 /******************************************************************
1306 * printer_alloc_handle
1307 * alloc a printer handle and remember the data pointer in the printer handle table
1310 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1312 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1313 printer_t
*printer
= NULL
;
1314 LPCWSTR printername
;
1319 if (copy_servername_from_name(name
, servername
)) {
1320 FIXME("server %s not supported\n", debugstr_w(servername
));
1321 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1325 printername
= get_basename_from_name(name
);
1326 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1328 /* an empty printername is invalid */
1329 if (printername
&& (!printername
[0])) {
1330 SetLastError(ERROR_INVALID_PARAMETER
);
1334 printer
= heap_alloc_zero(sizeof(printer_t
));
1335 if (!printer
) goto end
;
1337 /* clone the base name. This is NULL for the printserver */
1338 printer
->printername
= strdupW(printername
);
1340 /* clone the full name */
1341 printer
->name
= strdupW(name
);
1342 if (name
&& (!printer
->name
)) {
1343 printer_free(printer
);
1347 len
= ARRAY_SIZE(XcvMonitorW
) - 1;
1348 if (wcsncmp(printername
, XcvMonitorW
, len
) == 0) {
1349 /* OpenPrinter(",XcvMonitor ", ...) detected */
1350 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1351 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1352 if (printer
->pm
== NULL
) {
1353 printer_free(printer
);
1354 SetLastError(ERROR_UNKNOWN_PORT
);
1361 len
= ARRAY_SIZE(XcvPortW
) - 1;
1362 if (wcsncmp( printername
, XcvPortW
, len
) == 0) {
1363 /* OpenPrinter(",XcvPort ", ...) detected */
1364 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1365 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1366 if (printer
->pm
== NULL
) {
1367 printer_free(printer
);
1368 SetLastError(ERROR_UNKNOWN_PORT
);
1376 if (printer
->pm
->monitor
.pfnXcvOpenPort
)
1377 printer
->pm
->monitor
.pfnXcvOpenPort(printer
->pm
->hmon
, &printername
[len
],
1378 pDefault
? pDefault
->DesiredAccess
: 0,
1380 else if (printer
->pm
->old_XcvOpenPort
)
1381 printer
->pm
->old_XcvOpenPort(&printername
[len
],
1382 pDefault
? pDefault
->DesiredAccess
: 0,
1384 if (printer
->hXcv
== NULL
) {
1385 printer_free(printer
);
1386 SetLastError(ERROR_INVALID_PARAMETER
);
1393 /* Does the Printer exist? */
1394 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1395 ERR("Can't create Printers key\n");
1396 printer_free(printer
);
1397 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1401 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1402 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1403 RegCloseKey(hkeyPrinters
);
1404 printer_free(printer
);
1405 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1409 RegCloseKey(hkeyPrinter
);
1410 RegCloseKey(hkeyPrinters
);
1415 TRACE("using the local printserver\n");
1420 TRACE("==> %p\n", printer
);
1421 return (HANDLE
)printer
;
1424 static inline WCHAR
*get_file_part( WCHAR
*name
)
1426 WCHAR
*ptr
= wcsrchr( name
, '\\' );
1427 if (ptr
) return ptr
+ 1;
1431 /******************************************************************************
1432 * myAddPrinterDriverEx [internal]
1434 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1435 * and a special mode with lazy error checking.
1438 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1440 const printenv_t
*env
;
1443 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1453 /* we need to set all entries in the Registry, independent from the Level of
1454 DRIVER_INFO, that the caller supplied */
1456 ZeroMemory(&di
, sizeof(di
));
1457 if (pDriverInfo
&& (level
< ARRAY_SIZE(di_sizeof
))) {
1458 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1461 /* dump the most used infos */
1462 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1463 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1464 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1465 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1466 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1467 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1468 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1469 /* dump only the first of the additional Files */
1470 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1473 /* check environment */
1474 env
= validate_envW(di
.pEnvironment
);
1475 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1477 /* fill the copy-data / get the driverdir */
1478 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1479 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1480 (LPBYTE
) apd
.src
, len
, &len
)) {
1481 /* Should never fail */
1484 memcpy(apd
.dst
, apd
.src
, len
);
1485 lstrcatW(apd
.src
, backslashW
);
1486 apd
.srclen
= lstrlenW(apd
.src
);
1487 lstrcatW(apd
.dst
, env
->versionsubdir
);
1488 lstrcatW(apd
.dst
, backslashW
);
1489 apd
.dstlen
= lstrlenW(apd
.dst
);
1490 apd
.copyflags
= dwFileCopyFlags
;
1492 CreateDirectoryW(apd
.src
, NULL
);
1493 CreateDirectoryW(apd
.dst
, NULL
);
1495 hroot
= open_driver_reg(env
->envname
);
1497 ERR("Can't create Drivers key\n");
1501 /* Fill the Registry for the Driver */
1502 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1503 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1504 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1506 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1513 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1514 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1517 file
= get_file_part( di
.pDriverPath
);
1518 RegSetValueExW( hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
)file
, (lstrlenW( file
) + 1) * sizeof(WCHAR
) );
1519 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1521 file
= get_file_part( di
.pDataFile
);
1522 RegSetValueExW( hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (lstrlenW( file
) + 1) * sizeof(WCHAR
) );
1523 apd_copyfile( di
.pDataFile
, file
, &apd
);
1525 file
= get_file_part( di
.pConfigFile
);
1526 RegSetValueExW( hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (lstrlenW( file
) + 1) * sizeof(WCHAR
) );
1527 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1529 /* settings for level 3 */
1532 file
= get_file_part( di
.pHelpFile
);
1533 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (lstrlenW( file
) + 1) * sizeof(WCHAR
) );
1534 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1537 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
) );
1539 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1541 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1542 reg
= reg_ptr
= HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di
.pDependentFiles
) );
1544 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= lstrlenW( in_ptr
) + 1)
1546 file
= get_file_part( in_ptr
);
1547 len
= lstrlenW( file
) + 1;
1548 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1550 apd_copyfile( in_ptr
, file
, &apd
);
1554 RegSetValueExW( hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
1555 HeapFree( GetProcessHeap(), 0, reg
);
1558 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1560 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1561 if (di
.pMonitorName
)
1562 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1563 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1565 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1567 if (di
.pDefaultDataType
)
1568 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1569 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1571 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1573 /* settings for level 4 */
1574 if (di
.pszzPreviousNames
)
1575 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1576 multi_sz_lenW(di
.pszzPreviousNames
));
1578 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1580 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1583 hui
= driver_load(env
, di
.pConfigFile
);
1584 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1585 if (hui
&& pDrvDriverEvent
) {
1587 /* Support for DrvDriverEvent is optional */
1588 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1589 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1590 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1591 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1595 TRACE("=> TRUE with %u\n", GetLastError());
1600 /******************************************************************************
1601 * fpAddMonitor [exported through PRINTPROVIDOR]
1603 * Install a Printmonitor
1606 * pName [I] Servername or NULL (local Computer)
1607 * Level [I] Structure-Level (Must be 2)
1608 * pMonitors [I] PTR to MONITOR_INFO_2
1615 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1618 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1620 const printenv_t
* env
;
1621 monitor_t
* pm
= NULL
;
1622 LPMONITOR_INFO_2W mi2w
;
1628 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1629 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1630 debugstr_w(mi2w
->pName
), debugstr_w(mi2w
->pEnvironment
), debugstr_w(mi2w
->pDLLName
));
1632 if (copy_servername_from_name(pName
, NULL
)) {
1633 FIXME("server %s not supported\n", debugstr_w(pName
));
1634 SetLastError(ERROR_ACCESS_DENIED
);
1638 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1639 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1640 SetLastError(ERROR_INVALID_PARAMETER
);
1644 env
= validate_envW(mi2w
->pEnvironment
);
1646 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1648 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1649 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1650 SetLastError(ERROR_INVALID_PARAMETER
);
1654 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1655 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1659 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1660 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1661 &disposition
) == ERROR_SUCCESS
) {
1663 /* Some installers set options for the port before calling AddMonitor.
1664 We query the "Driver" entry to verify that the monitor is installed,
1665 before we return an error.
1666 When a user installs two print monitors at the same time with the
1667 same name, a race condition is possible but silently ignored. */
1671 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1672 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1673 &namesize
) == ERROR_SUCCESS
)) {
1674 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1675 /* 9x use ERROR_ALREADY_EXISTS */
1676 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1681 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1682 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1683 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1685 /* Load and initialize the monitor. SetLastError() is called on failure */
1686 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
)
1688 RegDeleteKeyW(hroot
, mi2w
->pName
);
1692 SetLastError(ERROR_SUCCESS
); /* Monitor installer depends on this */
1695 RegCloseKey(hentry
);
1702 static BOOL
wrap_AddPort(monitor_t
*pm
, LPWSTR name
, HWND hwnd
, LPWSTR monitor_name
)
1704 if (pm
->monitor
.pfnAddPort
)
1705 return pm
->monitor
.pfnAddPort(pm
->hmon
, name
, hwnd
, monitor_name
);
1707 if (pm
->old_AddPort
)
1708 return pm
->old_AddPort(name
, hwnd
, monitor_name
);
1710 WARN("AddPort is not implemented by monitor\n");
1714 /******************************************************************************
1715 * fpAddPort [exported through PRINTPROVIDOR]
1717 * Add a Port for a specific Monitor
1720 * pName [I] Servername or NULL (local Computer)
1721 * hWnd [I] Handle to parent Window for the Dialog-Box
1722 * pMonitorName [I] Name of the Monitor that manage the Port
1729 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1736 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1738 lres
= copy_servername_from_name(pName
, NULL
);
1740 FIXME("server %s not supported\n", debugstr_w(pName
));
1741 SetLastError(ERROR_INVALID_PARAMETER
);
1745 /* an empty Monitorname is Invalid */
1746 if (!pMonitorName
[0]) {
1747 SetLastError(ERROR_NOT_SUPPORTED
);
1751 pm
= monitor_load(pMonitorName
, NULL
);
1752 if (pm
&& (pm
->monitor
.pfnAddPort
|| pm
->old_AddPort
)) {
1753 res
= wrap_AddPort(pm
, pName
, hWnd
, pMonitorName
);
1754 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1758 pui
= monitor_loadui(pm
);
1759 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1760 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1761 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1765 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1766 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1767 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1769 SetLastError(ERROR_NOT_SUPPORTED
);
1772 monitor_unload(pui
);
1776 TRACE("returning %d with %u\n", res
, GetLastError());
1780 static BOOL
wrap_AddPortEx(monitor_t
*pm
, LPWSTR name
, DWORD level
, LPBYTE buffer
, LPWSTR monitor_name
)
1782 if (pm
->monitor
.pfnAddPortEx
)
1783 return pm
->monitor
.pfnAddPortEx(pm
->hmon
, name
, level
, buffer
, monitor_name
);
1785 if (pm
->old_AddPortEx
)
1786 return pm
->old_AddPortEx(name
, level
, buffer
, monitor_name
);
1788 WARN("AddPortEx is not implemented by monitor\n");
1792 /******************************************************************************
1793 * fpAddPortEx [exported through PRINTPROVIDOR]
1795 * Add a Port for a specific Monitor, without presenting a user interface
1798 * pName [I] Servername or NULL (local Computer)
1799 * level [I] Structure-Level (1 or 2) for pBuffer
1800 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1801 * pMonitorName [I] Name of the Monitor that manage the Port
1808 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1815 pi2
= (PORT_INFO_2W
*) pBuffer
;
1817 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1818 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1819 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1820 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1822 lres
= copy_servername_from_name(pName
, NULL
);
1824 FIXME("server %s not supported\n", debugstr_w(pName
));
1825 SetLastError(ERROR_INVALID_PARAMETER
);
1829 if ((level
< 1) || (level
> 2)) {
1830 SetLastError(ERROR_INVALID_LEVEL
);
1834 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1835 SetLastError(ERROR_INVALID_PARAMETER
);
1839 /* load the Monitor */
1840 pm
= monitor_load(pMonitorName
, NULL
);
1841 if (pm
&& (pm
->monitor
.pfnAddPortEx
|| pm
->old_AddPortEx
))
1843 res
= wrap_AddPortEx(pm
, pName
, level
, pBuffer
, pMonitorName
);
1844 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1848 FIXME("not implemented for %s (monitor %p: %s)\n",
1849 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1850 SetLastError(ERROR_INVALID_PARAMETER
);
1857 /******************************************************************************
1858 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1860 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1863 * pName [I] Servername or NULL (local Computer)
1864 * level [I] Level for the supplied DRIVER_INFO_*W struct
1865 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1866 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1873 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1877 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1878 lres
= copy_servername_from_name(pName
, NULL
);
1880 FIXME("server %s not supported\n", debugstr_w(pName
));
1881 SetLastError(ERROR_ACCESS_DENIED
);
1885 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1886 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1889 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1892 /******************************************************************************
1893 * fpClosePrinter [exported through PRINTPROVIDOR]
1895 * Close a printer handle and free associated resources
1898 * hPrinter [I] Printerhandle to close
1905 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1907 printer_t
*printer
= (printer_t
*) hPrinter
;
1909 TRACE("(%p)\n", hPrinter
);
1912 printer_free(printer
);
1918 static BOOL
wrap_ConfigurePort(monitor_t
*pm
, LPWSTR name
, HWND hwnd
, LPWSTR port_name
)
1920 if (pm
->monitor
.pfnConfigurePort
)
1921 return pm
->monitor
.pfnConfigurePort(pm
->hmon
, name
, hwnd
, port_name
);
1923 if (pm
->old_ConfigurePort
)
1924 return pm
->old_ConfigurePort(name
, hwnd
, port_name
);
1926 WARN("ConfigurePort is not implemented by monitor\n");
1930 /******************************************************************************
1931 * fpConfigurePort [exported through PRINTPROVIDOR]
1933 * Display the Configuration-Dialog for a specific Port
1936 * pName [I] Servername or NULL (local Computer)
1937 * hWnd [I] Handle to parent Window for the Dialog-Box
1938 * pPortName [I] Name of the Port, that should be configured
1945 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1952 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1954 lres
= copy_servername_from_name(pName
, NULL
);
1956 FIXME("server %s not supported\n", debugstr_w(pName
));
1957 SetLastError(ERROR_INVALID_NAME
);
1961 /* an empty Portname is Invalid, but can popup a Dialog */
1962 if (!pPortName
[0]) {
1963 SetLastError(ERROR_NOT_SUPPORTED
);
1967 pm
= monitor_load_by_port(pPortName
);
1968 if (pm
&& (pm
->monitor
.pfnConfigurePort
|| pm
->old_ConfigurePort
))
1970 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1971 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1972 res
= wrap_ConfigurePort(pm
, pName
, hWnd
, pPortName
);
1973 TRACE("got %d with %u\n", res
, GetLastError());
1977 pui
= monitor_loadui(pm
);
1978 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1979 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1980 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1981 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1982 TRACE("got %d with %u\n", res
, GetLastError());
1986 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1987 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1988 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1990 SetLastError(ERROR_NOT_SUPPORTED
);
1993 monitor_unload(pui
);
1997 TRACE("returning %d with %u\n", res
, GetLastError());
2001 /******************************************************************
2002 * fpDeleteMonitor [exported through PRINTPROVIDOR]
2004 * Delete a specific Printmonitor from a Printing-Environment
2007 * pName [I] Servername or NULL (local Computer)
2008 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
2009 * pMonitorName [I] Name of the Monitor, that should be deleted
2016 * pEnvironment is ignored in Windows for the local Computer.
2020 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
2026 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
2027 debugstr_w(pMonitorName
));
2029 lres
= copy_servername_from_name(pName
, NULL
);
2031 FIXME("server %s not supported\n", debugstr_w(pName
));
2032 SetLastError(ERROR_INVALID_NAME
);
2036 /* pEnvironment is ignored in Windows for the local Computer */
2037 if (!pMonitorName
|| !pMonitorName
[0]) {
2038 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
2039 SetLastError(ERROR_INVALID_PARAMETER
);
2043 /* Unload the monitor if it's loaded */
2044 EnterCriticalSection(&monitor_handles_cs
);
2045 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
2047 if (pm
->name
&& !lstrcmpW(pMonitorName
, pm
->name
))
2053 LeaveCriticalSection(&monitor_handles_cs
);
2055 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
2056 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
2060 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
2061 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
2066 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
2069 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
2070 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
2074 static BOOL
wrap_DeletePort(monitor_t
*pm
, LPWSTR name
, HWND hwnd
, LPWSTR port_name
)
2076 if (pm
->monitor
.pfnDeletePort
)
2077 return pm
->monitor
.pfnDeletePort(pm
->hmon
, name
, hwnd
, port_name
);
2079 if (pm
->old_ConfigurePort
)
2080 return pm
->old_DeletePort(name
, hwnd
, port_name
);
2082 WARN("DeletePort is not implemented by monitor\n");
2086 /*****************************************************************************
2087 * fpDeletePort [exported through PRINTPROVIDOR]
2089 * Delete a specific Port
2092 * pName [I] Servername or NULL (local Computer)
2093 * hWnd [I] Handle to parent Window for the Dialog-Box
2094 * pPortName [I] Name of the Port, that should be deleted
2101 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
2108 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
2110 lres
= copy_servername_from_name(pName
, NULL
);
2112 FIXME("server %s not supported\n", debugstr_w(pName
));
2113 SetLastError(ERROR_INVALID_NAME
);
2117 /* an empty Portname is Invalid */
2118 if (!pPortName
[0]) {
2119 SetLastError(ERROR_NOT_SUPPORTED
);
2123 pm
= monitor_load_by_port(pPortName
);
2124 if (pm
&& (pm
->monitor
.pfnDeletePort
|| pm
->old_DeletePort
))
2126 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
2127 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
2128 res
= wrap_DeletePort(pm
, pName
, hWnd
, pPortName
);
2129 TRACE("got %d with %u\n", res
, GetLastError());
2133 pui
= monitor_loadui(pm
);
2134 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
2135 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
2136 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
2137 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
2138 TRACE("got %d with %u\n", res
, GetLastError());
2142 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
2143 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
2144 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
2146 SetLastError(ERROR_NOT_SUPPORTED
);
2149 monitor_unload(pui
);
2153 TRACE("returning %d with %u\n", res
, GetLastError());
2157 /*****************************************************************************
2158 * fpEnumMonitors [exported through PRINTPROVIDOR]
2160 * Enumerate available Port-Monitors
2163 * pName [I] Servername or NULL (local Computer)
2164 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
2165 * pMonitors [O] PTR to Buffer that receives the Result
2166 * cbBuf [I] Size of Buffer at pMonitors
2167 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
2168 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
2172 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
2175 * Windows reads the Registry once and cache the Results.
2178 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
2179 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2181 DWORD numentries
= 0;
2186 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
2187 cbBuf
, pcbNeeded
, pcReturned
);
2189 lres
= copy_servername_from_name(pName
, NULL
);
2191 FIXME("server %s not supported\n", debugstr_w(pName
));
2192 SetLastError(ERROR_INVALID_NAME
);
2196 if (!Level
|| (Level
> 2)) {
2197 WARN("level (%d) is ignored in win9x\n", Level
);
2198 SetLastError(ERROR_INVALID_LEVEL
);
2202 /* Scan all Monitor-Keys */
2204 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
2206 /* we calculated the needed buffersize. now do more error-checks */
2207 if (cbBuf
< needed
) {
2208 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2212 /* fill the Buffer with the Monitor-Keys */
2213 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2217 if (pcbNeeded
) *pcbNeeded
= needed
;
2218 if (pcReturned
) *pcReturned
= numentries
;
2220 TRACE("returning %d with %d (%d byte for %d entries)\n",
2221 res
, GetLastError(), needed
, numentries
);
2226 /******************************************************************************
2227 * fpEnumPorts [exported through PRINTPROVIDOR]
2229 * Enumerate available Ports
2232 * pName [I] Servername or NULL (local Computer)
2233 * Level [I] Structure-Level (1 or 2)
2234 * pPorts [O] PTR to Buffer that receives the Result
2235 * cbBuf [I] Size of Buffer at pPorts
2236 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2237 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2241 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2244 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2245 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2248 DWORD numentries
= 0;
2252 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2253 cbBuf
, pcbNeeded
, pcReturned
);
2255 lres
= copy_servername_from_name(pName
, NULL
);
2257 FIXME("server %s not supported\n", debugstr_w(pName
));
2258 SetLastError(ERROR_INVALID_NAME
);
2262 if (!Level
|| (Level
> 2)) {
2263 SetLastError(ERROR_INVALID_LEVEL
);
2267 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2268 SetLastError(RPC_X_NULL_REF_POINTER
);
2272 EnterCriticalSection(&monitor_handles_cs
);
2275 /* Scan all local Ports */
2277 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2279 /* we calculated the needed buffersize. now do the error-checks */
2280 if (cbBuf
< needed
) {
2281 monitor_unloadall();
2282 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2283 goto emP_cleanup_cs
;
2285 else if (!pPorts
|| !pcReturned
) {
2286 monitor_unloadall();
2287 SetLastError(RPC_X_NULL_REF_POINTER
);
2288 goto emP_cleanup_cs
;
2291 /* Fill the Buffer */
2292 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2294 monitor_unloadall();
2297 LeaveCriticalSection(&monitor_handles_cs
);
2300 if (pcbNeeded
) *pcbNeeded
= needed
;
2301 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2303 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2304 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2309 /*****************************************************************************
2310 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2312 * Enumerate available Print Processors
2315 * pName [I] Servername or NULL (local Computer)
2316 * pEnvironment [I] Printing-Environment or NULL (Default)
2317 * Level [I] Structure-Level (Only 1 is allowed)
2318 * pPPInfo [O] PTR to Buffer that receives the Result
2319 * cbBuf [I] Size of Buffer at pMonitors
2320 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2321 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2325 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2328 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2329 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2331 const printenv_t
* env
;
2332 LPWSTR regpathW
= NULL
;
2333 DWORD numentries
= 0;
2338 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2339 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2341 lres
= copy_servername_from_name(pName
, NULL
);
2343 FIXME("server %s not supported\n", debugstr_w(pName
));
2344 SetLastError(ERROR_INVALID_NAME
);
2349 SetLastError(ERROR_INVALID_LEVEL
);
2353 env
= validate_envW(pEnvironment
);
2355 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2357 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2358 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2363 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2365 /* Scan all Printprocessor-Keys */
2367 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2369 /* we calculated the needed buffersize. now do more error-checks */
2370 if (cbBuf
< needed
) {
2371 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2375 /* fill the Buffer with the Printprocessor Infos */
2376 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2380 heap_free(regpathW
);
2381 if (pcbNeeded
) *pcbNeeded
= needed
;
2382 if (pcReturned
) *pcReturned
= numentries
;
2384 TRACE("returning %d with %d (%d byte for %d entries)\n",
2385 res
, GetLastError(), needed
, numentries
);
2390 /******************************************************************************
2391 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2393 * Return the PATH for the Print-Processors
2396 * pName [I] Servername or NULL (this computer)
2397 * pEnvironment [I] Printing-Environment or NULL (Default)
2398 * level [I] Structure-Level (must be 1)
2399 * pPPInfo [O] PTR to Buffer that receives the Result
2400 * cbBuf [I] Size of Buffer at pPPInfo
2401 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2405 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2407 * Native Values returned in pPPInfo on Success for this computer:
2408 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2409 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2410 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2412 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2415 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2416 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2418 const printenv_t
* env
;
2422 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2423 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2426 lres
= copy_servername_from_name(pName
, NULL
);
2428 FIXME("server %s not supported\n", debugstr_w(pName
));
2429 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2433 env
= validate_envW(pEnvironment
);
2435 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2437 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2438 needed
= GetSystemDirectoryW(NULL
, 0);
2439 /* add the Size for the Subdirectories */
2440 needed
+= lstrlenW(spoolprtprocsW
);
2441 needed
+= lstrlenW(env
->subdir
);
2442 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2444 *pcbNeeded
= needed
;
2446 if (needed
> cbBuf
) {
2447 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2451 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2452 /* add the Subdirectories */
2453 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2454 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2455 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2459 /******************************************************************************
2460 * fpOpenPrinter [exported through PRINTPROVIDOR]
2462 * Open a Printer / Printserver or a Printer-Object
2465 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2466 * pPrinter [O] The resulting Handle is stored here
2467 * pDefaults [I] PTR to Default Printer Settings or NULL
2474 * lpPrinterName is one of:
2475 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2476 *| Printer: "PrinterName"
2477 *| Printer-Object: "PrinterName,Job xxx"
2478 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2479 *| XcvPort: "Servername,XcvPort PortName"
2483 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2484 LPPRINTER_DEFAULTSW pDefaults
)
2487 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2489 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2491 return (*pPrinter
!= 0);
2494 /******************************************************************************
2495 * fpXcvData [exported through PRINTPROVIDOR]
2497 * Execute commands in the Printmonitor DLL
2500 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2501 * pszDataName [i] Name of the command to execute
2502 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2503 * cbInputData [i] Size in Bytes of Buffer at pInputData
2504 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2505 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2506 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2507 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2514 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2515 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2517 * Minimal List of commands, that a Printmonitor DLL should support:
2519 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2520 *| "AddPort" : Add a Port
2521 *| "DeletePort": Delete a Port
2523 * Many Printmonitors support additional commands. Examples for localspl.dll:
2524 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2525 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2528 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2529 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2530 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2532 printer_t
*printer
= (printer_t
* ) hXcv
;
2534 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2535 pInputData
, cbInputData
, pOutputData
,
2536 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2538 if (!printer
|| (!printer
->hXcv
)) {
2539 SetLastError(ERROR_INVALID_HANDLE
);
2543 if (!pcbOutputNeeded
) {
2544 SetLastError(ERROR_INVALID_PARAMETER
);
2548 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2549 SetLastError(RPC_X_NULL_REF_POINTER
);
2553 *pcbOutputNeeded
= 0;
2555 if (printer
->pm
->monitor
.pfnXcvDataPort
)
2556 *pdwStatus
= printer
->pm
->monitor
.pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2557 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2562 /*****************************************************
2563 * setup_provider [internal]
2565 void setup_provider(void)
2567 static const PRINTPROVIDOR backend
= {
2569 NULL
, /* fpSetJob */
2570 NULL
, /* fpGetJob */
2571 NULL
, /* fpEnumJobs */
2572 NULL
, /* fpAddPrinter */
2573 NULL
, /* fpDeletePrinter */
2574 NULL
, /* fpSetPrinter */
2575 NULL
, /* fpGetPrinter */
2576 NULL
, /* fpEnumPrinters */
2577 NULL
, /* fpAddPrinterDriver */
2578 NULL
, /* fpEnumPrinterDrivers */
2579 NULL
, /* fpGetPrinterDriver */
2580 fpGetPrinterDriverDirectory
,
2581 NULL
, /* fpDeletePrinterDriver */
2582 NULL
, /* fpAddPrintProcessor */
2583 fpEnumPrintProcessors
,
2584 fpGetPrintProcessorDirectory
,
2585 NULL
, /* fpDeletePrintProcessor */
2586 NULL
, /* fpEnumPrintProcessorDatatypes */
2587 NULL
, /* fpStartDocPrinter */
2588 NULL
, /* fpStartPagePrinter */
2589 NULL
, /* fpWritePrinter */
2590 NULL
, /* fpEndPagePrinter */
2591 NULL
, /* fpAbortPrinter */
2592 NULL
, /* fpReadPrinter */
2593 NULL
, /* fpEndDocPrinter */
2594 NULL
, /* fpAddJob */
2595 NULL
, /* fpScheduleJob */
2596 NULL
, /* fpGetPrinterData */
2597 NULL
, /* fpSetPrinterData */
2598 NULL
, /* fpWaitForPrinterChange */
2600 NULL
, /* fpAddForm */
2601 NULL
, /* fpDeleteForm */
2602 NULL
, /* fpGetForm */
2603 NULL
, /* fpSetForm */
2604 NULL
, /* fpEnumForms */
2610 NULL
, /* fpCreatePrinterIC */
2611 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2612 NULL
, /* fpDeletePrinterIC */
2613 NULL
, /* fpAddPrinterConnection */
2614 NULL
, /* fpDeletePrinterConnection */
2615 NULL
, /* fpPrinterMessageBox */
2618 NULL
, /* fpResetPrinter */
2619 NULL
, /* fpGetPrinterDriverEx */
2620 NULL
, /* fpFindFirstPrinterChangeNotification */
2621 NULL
, /* fpFindClosePrinterChangeNotification */
2623 NULL
, /* fpShutDown */
2624 NULL
, /* fpRefreshPrinterChangeNotification */
2625 NULL
, /* fpOpenPrinterEx */
2626 NULL
, /* fpAddPrinterEx */
2627 NULL
, /* fpSetPort */
2628 NULL
, /* fpEnumPrinterData */
2629 NULL
, /* fpDeletePrinterData */
2630 NULL
, /* fpClusterSplOpen */
2631 NULL
, /* fpClusterSplClose */
2632 NULL
, /* fpClusterSplIsAlive */
2633 NULL
, /* fpSetPrinterDataEx */
2634 NULL
, /* fpGetPrinterDataEx */
2635 NULL
, /* fpEnumPrinterDataEx */
2636 NULL
, /* fpEnumPrinterKey */
2637 NULL
, /* fpDeletePrinterDataEx */
2638 NULL
, /* fpDeletePrinterKey */
2639 NULL
, /* fpSeekPrinter */
2640 NULL
, /* fpDeletePrinterDriverEx */
2641 NULL
, /* fpAddPerMachineConnection */
2642 NULL
, /* fpDeletePerMachineConnection */
2643 NULL
, /* fpEnumPerMachineConnections */
2645 fpAddPrinterDriverEx
,
2646 NULL
, /* fpSplReadPrinter */
2647 NULL
, /* fpDriverUnloadComplete */
2648 NULL
, /* fpGetSpoolFileInfo */
2649 NULL
, /* fpCommitSpoolData */
2650 NULL
, /* fpCloseSpoolFileHandle */
2651 NULL
, /* fpFlushPrinter */
2652 NULL
, /* fpSendRecvBidiData */
2653 NULL
/* fpAddDriverCatalog */
2655 pprovider
= &backend
;
2659 /*****************************************************
2660 * InitializePrintProvidor (localspl.@)
2662 * Initialize the Printprovider
2665 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2666 * cbPrintProvidor [I] Size of Buffer in Bytes
2667 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2670 * Success: TRUE and pPrintProvidor filled
2674 * The RegistryPath should be:
2675 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2676 * but this Parameter is ignored in "localspl.dll".
2680 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2681 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2684 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2685 memcpy(pPrintProvidor
, pprovider
,
2686 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));