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
24 #define NONAMELESSUNION
32 #include "ddk/winddiui.h"
33 #include "ddk/winsplp.h"
35 #include "wine/list.h"
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38 #include "localspl_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(localspl
);
42 /* ############################### */
44 static CRITICAL_SECTION monitor_handles_cs
;
45 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
47 0, 0, &monitor_handles_cs
,
48 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
49 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
51 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
53 /* ############################### */
56 WCHAR src
[MAX_PATH
+MAX_PATH
];
57 WCHAR dst
[MAX_PATH
+MAX_PATH
];
79 LPCWSTR versionregpath
;
80 LPCWSTR versionsubdir
;
90 /* ############################### */
92 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
93 static monitor_t
* pm_localport
;
95 static const PRINTPROVIDOR
* pprovider
= NULL
;
97 static const WCHAR backslashW
[] = {'\\',0};
98 static const WCHAR bs_ports_bsW
[] = {'\\','P','o','r','t','s','\\',0};
99 static const WCHAR configuration_fileW
[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
100 static const WCHAR datatypeW
[] = {'D','a','t','a','t','y','p','e',0};
101 static const WCHAR data_fileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
102 static const WCHAR default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
103 static const WCHAR dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
104 static const WCHAR descriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
105 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
106 static const WCHAR emptyW
[] = {0};
107 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
108 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
109 'c','o','n','t','r','o','l','\\',
110 'P','r','i','n','t','\\',
111 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
112 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
113 static const WCHAR hardwareidW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
114 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
115 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
116 static const WCHAR locationW
[] = {'L','o','c','a','t','i','o','n',0};
117 static const WCHAR manufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
118 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
119 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
120 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
121 'C','o','n','t','r','o','l','\\',
122 'P','r','i','n','t','\\',
123 'M','o','n','i','t','o','r','s','\\',0};
124 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
125 static const WCHAR nameW
[] = {'N','a','m','e',0};
126 static const WCHAR oem_urlW
[] = {'O','E','M',' ','U','r','l',0};
127 static const WCHAR parametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
128 static const WCHAR portW
[] = {'P','o','r','t',0};
129 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
130 static const WCHAR printersW
[] = {'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'C','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'P','r','i','n','t','e','r','s',0};
135 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
136 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
137 static const WCHAR version0_subdirW
[] = {'\\','0',0};
138 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
139 static const WCHAR version3_subdirW
[] = {'\\','3',0};
140 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
141 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
142 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
143 static const WCHAR winnt_cv_portsW
[] = {'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'P','o','r','t','s',0};
148 static const WCHAR x64_envnameW
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
149 static const WCHAR x64_subdirW
[] = {'x','6','4',0};
150 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
151 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
152 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
153 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
156 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
157 version3_regpathW
, version3_subdirW
};
159 static const printenv_t env_x64
= {x64_envnameW
, x64_subdirW
, 3,
160 version3_regpathW
, version3_subdirW
};
162 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
163 version0_regpathW
, version0_subdirW
};
165 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_win40
};
168 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
169 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
170 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
171 0, sizeof(DRIVER_INFO_8W
)};
174 /******************************************************************
177 * create a copy of a unicode-string
180 static LPWSTR
strdupW(LPCWSTR p
)
186 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
187 ret
= heap_alloc(len
);
192 /******************************************************************
193 * apd_copyfile [internal]
195 * Copy a file from the driverdirectory to the versioned directory
202 static BOOL
apd_copyfile(LPWSTR filename
, apd_data_t
*apd
)
208 apd
->src
[apd
->srclen
] = '\0';
209 apd
->dst
[apd
->dstlen
] = '\0';
211 if (!filename
|| !filename
[0]) {
212 /* nothing to copy */
216 ptr
= strrchrW(filename
, '\\');
225 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
) {
226 /* we have an absolute Path */
232 lstrcatW(srcname
, ptr
);
234 lstrcatW(apd
->dst
, ptr
);
236 TRACE("%s => %s\n", debugstr_w(filename
), debugstr_w(apd
->dst
));
238 /* FIXME: handle APD_COPY_NEW_FILES */
239 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
240 TRACE("got %u with %u\n", res
, GetLastError());
242 return (apd
->lazy
) ? TRUE
: 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 to 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
= strchrW(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
= sizeof(buffer
) / sizeof(buffer
[0]);
286 if (GetComputerNameW(buffer
, &len
)) {
287 if ((serverlen
== len
) && (strncmpiW(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
= strchrW(&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
);
338 FreeLibrary(pm
->hdll
);
340 heap_free(pm
->dllname
);
343 LeaveCriticalSection(&monitor_handles_cs
);
346 /******************************************************************
347 * monitor_unloadall [internal]
349 * release all registered printmonitors and unload them from memory, when needed
353 static void monitor_unloadall(void)
358 EnterCriticalSection(&monitor_handles_cs
);
359 /* iterate through the list, with safety against removal */
360 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
362 /* skip monitorui dlls */
363 if (pm
->monitor
) monitor_unload(pm
);
365 LeaveCriticalSection(&monitor_handles_cs
);
368 /******************************************************************
369 * monitor_load [internal]
371 * load a printmonitor, get the dllname from the registry, when needed
372 * initialize the monitor and dump found function-pointers
374 * On failure, SetLastError() is called and NULL is returned
377 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
379 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
380 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
381 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
382 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
383 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
385 monitor_t
* pm
= NULL
;
387 LPWSTR regroot
= NULL
;
388 LPWSTR driver
= dllname
;
390 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
391 /* Is the Monitor already loaded? */
392 EnterCriticalSection(&monitor_handles_cs
);
395 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
397 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
405 pm
= heap_alloc_zero(sizeof(monitor_t
));
406 if (pm
== NULL
) goto cleanup
;
407 list_add_tail(&monitor_handles
, &pm
->entry
);
411 if (pm
->name
== NULL
) {
412 /* Load the monitor */
413 LPMONITOREX pmonitorEx
;
417 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
418 regroot
= heap_alloc(len
* sizeof(WCHAR
));
422 lstrcpyW(regroot
, monitorsW
);
423 lstrcatW(regroot
, name
);
424 /* Get the Driver from the Registry */
425 if (driver
== NULL
) {
428 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
429 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
430 &namesize
) == ERROR_SUCCESS
) {
431 driver
= heap_alloc(namesize
);
432 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
439 pm
->name
= strdupW(name
);
440 pm
->dllname
= strdupW(driver
);
442 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
444 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
449 pm
->hdll
= LoadLibraryW(driver
);
450 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
452 if (pm
->hdll
== NULL
) {
454 SetLastError(ERROR_MOD_NOT_FOUND
);
459 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
460 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
461 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
462 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
463 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
466 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
467 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
468 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
469 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
470 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
472 if (pInitializePrintMonitorUI
!= NULL
) {
473 pm
->monitorUI
= pInitializePrintMonitorUI();
474 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
476 TRACE("0x%08x: dwMonitorSize (%d)\n",
477 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
482 if (pInitializePrintMonitor
&& regroot
) {
483 pmonitorEx
= pInitializePrintMonitor(regroot
);
484 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
485 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
488 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
489 pm
->monitor
= &(pmonitorEx
->Monitor
);
494 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
498 if (!pm
->monitor
&& regroot
) {
499 if (pInitializePrintMonitor2
!= NULL
) {
500 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
502 if (pInitializeMonitorEx
!= NULL
) {
503 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
505 if (pInitializeMonitor
!= NULL
) {
506 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
509 if (!pm
->monitor
&& !pm
->monitorUI
) {
511 SetLastError(ERROR_PROC_NOT_FOUND
);
516 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
520 LeaveCriticalSection(&monitor_handles_cs
);
521 if (driver
!= dllname
) heap_free(driver
);
523 TRACE("=> %p\n", pm
);
527 /******************************************************************
528 * monitor_loadall [internal]
530 * Load all registered monitors
533 static DWORD
monitor_loadall(void)
536 DWORD registered
= 0;
539 WCHAR buffer
[MAX_PATH
];
542 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
543 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
544 NULL
, NULL
, NULL
, NULL
, NULL
);
546 TRACE("%d monitors registered\n", registered
);
548 while (id
< registered
) {
550 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
551 pm
= monitor_load(buffer
, NULL
);
555 RegCloseKey(hmonitors
);
557 TRACE("%d monitors loaded\n", loaded
);
561 /******************************************************************
562 * monitor_loadui [internal]
564 * load the userinterface-dll for a given portmonitor
566 * On failure, NULL is returned
568 static monitor_t
* monitor_loadui(monitor_t
* pm
)
570 monitor_t
* pui
= NULL
;
571 WCHAR buffer
[MAX_PATH
];
576 if (pm
== NULL
) return NULL
;
577 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
579 /* Try the Portmonitor first; works for many monitors */
581 EnterCriticalSection(&monitor_handles_cs
);
583 LeaveCriticalSection(&monitor_handles_cs
);
587 /* query the userinterface-dllname from the Portmonitor */
588 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
589 /* building (",XcvMonitor %s",pm->name) not needed yet */
590 res
= pm
->monitor
->pfnXcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
591 TRACE("got %u with %p\n", res
, hXcv
);
593 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
594 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
595 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
596 pm
->monitor
->pfnXcvClosePort(hXcv
);
602 /******************************************************************
603 * monitor_load_by_port [internal]
605 * load a printmonitor for a given port
607 * On failure, NULL is returned
610 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
615 monitor_t
* pm
= NULL
;
616 DWORD registered
= 0;
620 TRACE("(%s)\n", debugstr_w(portname
));
622 /* Try the Local Monitor first */
623 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
624 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
625 /* found the portname */
627 return monitor_load(localportW
, NULL
);
632 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
633 buffer
= heap_alloc(len
* sizeof(WCHAR
));
634 if (buffer
== NULL
) return NULL
;
636 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
637 EnterCriticalSection(&monitor_handles_cs
);
638 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
640 while ((pm
== NULL
) && (id
< registered
)) {
642 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
643 TRACE("testing %s\n", debugstr_w(buffer
));
644 len
= lstrlenW(buffer
);
645 lstrcatW(buffer
, bs_ports_bsW
);
646 lstrcatW(buffer
, portname
);
647 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
649 buffer
[len
] = '\0'; /* use only the Monitor-Name */
650 pm
= monitor_load(buffer
, NULL
);
654 LeaveCriticalSection(&monitor_handles_cs
);
661 /******************************************************************
662 * Return the number of bytes for an multi_sz string.
663 * The result includes all \0s
664 * (specifically the extra \0, that is needed as multi_sz terminator).
666 static int multi_sz_lenW(const WCHAR
*str
)
668 const WCHAR
*ptr
= str
;
672 ptr
+= lstrlenW(ptr
) + 1;
675 return (ptr
- str
+ 1) * sizeof(WCHAR
);
678 /******************************************************************
679 * validate_envW [internal]
681 * validate the user-supplied printing-environment
684 * env [I] PTR to Environment-String or NULL
687 * Success: PTR to printenv_t
688 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
691 * An empty string is handled the same way as NULL.
695 static const printenv_t
* validate_envW(LPCWSTR env
)
697 const printenv_t
*result
= NULL
;
700 TRACE("(%s)\n", debugstr_w(env
));
703 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
705 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
707 result
= all_printenv
[i
];
711 if (result
== NULL
) {
712 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
713 SetLastError(ERROR_INVALID_ENVIRONMENT
);
715 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
719 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
722 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
726 /*****************************************************************************
727 * enumerate the local monitors (INTERNAL)
729 * returns the needed size (in bytes) for pMonitors
730 * and *lpreturned is set to number of entries returned in pMonitors
732 * Language-Monitors are also installed in the same Registry-Location but
733 * they are filtered in Windows (not returned by EnumMonitors).
734 * We do no filtering to simplify our Code.
737 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
742 LPMONITOR_INFO_2W mi
;
743 WCHAR buffer
[MAX_PATH
];
744 WCHAR dllname
[MAX_PATH
];
752 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
754 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
755 len
= entrysize
* numentries
;
756 ptr
= (LPWSTR
) &pMonitors
[len
];
759 len
= sizeof(buffer
)/sizeof(buffer
[0]);
762 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
763 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
764 /* Scan all Monitor-Registry-Keys */
765 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
766 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
767 dllsize
= sizeof(dllname
);
770 /* The Monitor must have a Driver-DLL */
771 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
772 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
773 /* We found a valid DLL for this Monitor. */
774 TRACE("using Driver: %s\n", debugstr_w(dllname
));
779 /* Windows returns only Port-Monitors here, but to simplify our code,
780 we do no filtering for Language-Monitors */
784 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
786 /* we install and return only monitors for "Windows NT x86" */
787 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
791 /* required size is calculated. Now fill the user-buffer */
792 if (pMonitors
&& (cbBuf
>= needed
)){
793 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
794 pMonitors
+= entrysize
;
796 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
798 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
799 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
801 mi
->pEnvironment
= ptr
;
802 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
803 ptr
+= (lstrlenW(x86_envnameW
)+1);
806 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
807 ptr
+= (dllsize
/ sizeof(WCHAR
));
812 len
= sizeof(buffer
)/sizeof(buffer
[0]);
817 *lpreturned
= numentries
;
818 TRACE("need %d byte for %d entries\n", needed
, numentries
);
822 /******************************************************************
823 * enumerate the local Ports from all loaded monitors (internal)
825 * returns the needed size (in bytes) for pPorts
826 * and *lpreturned is set to number of entries returned in pPorts
829 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
833 LPPORT_INFO_2W cache
;
835 LPBYTE pi_buffer
= NULL
;
836 DWORD pi_allocated
= 0;
847 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
848 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
850 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
851 needed
= entrysize
* numentries
;
852 ptr
= (LPWSTR
) &pPorts
[needed
];
857 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
859 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
862 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
863 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
864 /* Do not use heap_realloc (we do not need the old data in the buffer) */
865 heap_free(pi_buffer
);
866 pi_buffer
= heap_alloc(pi_needed
);
867 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
868 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
870 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
871 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
873 numentries
+= pi_returned
;
876 /* fill the output-buffer (pPorts), if we have one */
877 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
879 while (pi_returned
> pi_index
) {
880 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
881 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
882 out
->pPortName
= ptr
;
883 lstrcpyW(ptr
, cache
->pPortName
);
884 ptr
+= (lstrlenW(ptr
)+1);
886 out
->pMonitorName
= ptr
;
887 lstrcpyW(ptr
, cache
->pMonitorName
);
888 ptr
+= (lstrlenW(ptr
)+1);
890 out
->pDescription
= ptr
;
891 lstrcpyW(ptr
, cache
->pDescription
);
892 ptr
+= (lstrlenW(ptr
)+1);
893 out
->fPortType
= cache
->fPortType
;
894 out
->Reserved
= cache
->Reserved
;
902 /* the temporary portinfo-buffer is no longer needed */
903 heap_free(pi_buffer
);
905 *lpreturned
= numentries
;
906 TRACE("need %d byte for %d entries\n", needed
, numentries
);
911 /*****************************************************************************
912 * open_driver_reg [internal]
914 * opens the registry for the printer drivers depending on the given input
915 * variable pEnvironment
918 * Success: the opened hkey
921 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
925 const printenv_t
* env
;
927 TRACE("(%s)\n", debugstr_w(pEnvironment
));
929 env
= validate_envW(pEnvironment
);
930 if (!env
) return NULL
;
932 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
933 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
936 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
937 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
938 HeapFree(GetProcessHeap(), 0, buffer
);
943 /*****************************************************************************
944 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
946 * Return the PATH for the Printer-Drivers
949 * pName [I] Servername (NT only) or NULL (local Computer)
950 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
951 * Level [I] Structure-Level (must be 1)
952 * pDriverDirectory [O] PTR to Buffer that receives the Result
953 * cbBuf [I] Size of Buffer at pDriverDirectory
954 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
955 * required for pDriverDirectory
958 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
959 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
960 * if cbBuf is too small
962 * Native Values returned in pDriverDirectory on Success:
963 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
964 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
965 *| win9x(Windows 4.0): "%winsysdir%"
967 * "%winsysdir%" is the Value from GetSystemDirectoryW()
970 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
971 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
974 const printenv_t
* env
;
976 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
977 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
979 if (pName
!= NULL
&& pName
[0]) {
980 FIXME("server %s not supported\n", debugstr_w(pName
));
981 SetLastError(ERROR_INVALID_PARAMETER
);
985 env
= validate_envW(pEnvironment
);
986 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
989 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
990 needed
= GetSystemDirectoryW(NULL
, 0);
991 /* add the Size for the Subdirectories */
992 needed
+= lstrlenW(spooldriversW
);
993 needed
+= lstrlenW(env
->subdir
);
994 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
998 if (needed
> cbBuf
) {
999 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1003 if (pDriverDirectory
== NULL
) {
1004 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1005 SetLastError(ERROR_INVALID_USER_BUFFER
);
1009 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
1010 /* add the Subdirectories */
1011 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
1012 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
1014 TRACE("=> %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
1018 /******************************************************************
1019 * driver_load [internal]
1021 * load a driver user interface dll
1023 * On failure, NULL is returned
1027 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1029 WCHAR fullname
[MAX_PATH
];
1033 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1035 /* build the driverdir */
1036 len
= sizeof(fullname
) -
1037 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1039 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1040 (LPBYTE
) fullname
, len
, &len
)) {
1041 /* Should never Fail */
1042 SetLastError(ERROR_BUFFER_OVERFLOW
);
1046 lstrcatW(fullname
, env
->versionsubdir
);
1047 lstrcatW(fullname
, backslashW
);
1048 lstrcatW(fullname
, dllname
);
1050 hui
= LoadLibraryW(fullname
);
1051 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1056 /******************************************************************
1058 * free the data pointer of an opened printer
1060 static VOID
printer_free(printer_t
* printer
)
1063 printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1065 monitor_unload(printer
->pm
);
1067 heap_free(printer
->printername
);
1068 heap_free(printer
->name
);
1072 /******************************************************************
1073 * printer_alloc_handle
1074 * alloc a printer handle and remember the data pointer in the printer handle table
1077 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1079 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1080 printer_t
*printer
= NULL
;
1081 LPCWSTR printername
;
1086 if (copy_servername_from_name(name
, servername
)) {
1087 FIXME("server %s not supported\n", debugstr_w(servername
));
1088 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1092 printername
= get_basename_from_name(name
);
1093 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1095 /* an empty printername is invalid */
1096 if (printername
&& (!printername
[0])) {
1097 SetLastError(ERROR_INVALID_PARAMETER
);
1101 printer
= heap_alloc_zero(sizeof(printer_t
));
1102 if (!printer
) goto end
;
1104 /* clone the base name. This is NULL for the printserver */
1105 printer
->printername
= strdupW(printername
);
1107 /* clone the full name */
1108 printer
->name
= strdupW(name
);
1109 if (name
&& (!printer
->name
)) {
1110 printer_free(printer
);
1114 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1115 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1116 /* OpenPrinter(",XcvMonitor ", ...) detected */
1117 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1118 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1119 if (printer
->pm
== NULL
) {
1120 printer_free(printer
);
1121 SetLastError(ERROR_UNKNOWN_PORT
);
1128 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1129 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1130 /* OpenPrinter(",XcvPort ", ...) detected */
1131 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1132 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1133 if (printer
->pm
== NULL
) {
1134 printer_free(printer
);
1135 SetLastError(ERROR_UNKNOWN_PORT
);
1143 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1144 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1145 pDefault
? pDefault
->DesiredAccess
: 0,
1148 if (printer
->hXcv
== NULL
) {
1149 printer_free(printer
);
1150 SetLastError(ERROR_INVALID_PARAMETER
);
1157 /* Does the Printer exist? */
1158 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1159 ERR("Can't create Printers key\n");
1160 printer_free(printer
);
1161 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1165 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1166 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1167 RegCloseKey(hkeyPrinters
);
1168 printer_free(printer
);
1169 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1173 RegCloseKey(hkeyPrinter
);
1174 RegCloseKey(hkeyPrinters
);
1179 TRACE("using the local printserver\n");
1184 TRACE("==> %p\n", printer
);
1185 return (HANDLE
)printer
;
1189 /******************************************************************************
1190 * myAddPrinterDriverEx [internal]
1192 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1193 * and a special mode with lazy error checking.
1196 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1198 const printenv_t
*env
;
1201 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1211 /* we need to set all entries in the Registry, independent from the Level of
1212 DRIVER_INFO, that the caller supplied */
1214 ZeroMemory(&di
, sizeof(di
));
1215 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
1216 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1219 /* dump the most used infos */
1220 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1221 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1222 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1223 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1224 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1225 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1226 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1227 /* dump only the first of the additional Files */
1228 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1231 /* check environment */
1232 env
= validate_envW(di
.pEnvironment
);
1233 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1235 /* fill the copy-data / get the driverdir */
1236 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1237 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1238 (LPBYTE
) apd
.src
, len
, &len
)) {
1239 /* Should never Fail */
1242 memcpy(apd
.dst
, apd
.src
, len
);
1243 lstrcatW(apd
.src
, backslashW
);
1244 apd
.srclen
= lstrlenW(apd
.src
);
1245 lstrcatW(apd
.dst
, env
->versionsubdir
);
1246 lstrcatW(apd
.dst
, backslashW
);
1247 apd
.dstlen
= lstrlenW(apd
.dst
);
1248 apd
.copyflags
= dwFileCopyFlags
;
1250 CreateDirectoryW(apd
.src
, NULL
);
1251 CreateDirectoryW(apd
.dst
, NULL
);
1253 hroot
= open_driver_reg(env
->envname
);
1255 ERR("Can't create Drivers key\n");
1259 /* Fill the Registry for the Driver */
1260 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1261 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1262 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1264 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1271 if (disposition
== REG_OPENED_EXISTING_KEY
) {
1272 TRACE("driver %s already installed\n", debugstr_w(di
.pName
));
1274 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
1278 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1279 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (LPBYTE
) &env
->driverversion
,
1282 RegSetValueExW(hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
) di
.pDriverPath
,
1283 (lstrlenW(di
.pDriverPath
)+1)* sizeof(WCHAR
));
1284 apd_copyfile(di
.pDriverPath
, &apd
);
1286 RegSetValueExW(hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pDataFile
,
1287 (lstrlenW(di
.pDataFile
)+1)* sizeof(WCHAR
));
1288 apd_copyfile(di
.pDataFile
, &apd
);
1290 RegSetValueExW(hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pConfigFile
,
1291 (lstrlenW(di
.pConfigFile
)+1)* sizeof(WCHAR
));
1292 apd_copyfile(di
.pConfigFile
, &apd
);
1294 /* settings for level 3 */
1296 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pHelpFile
,
1297 (lstrlenW(di
.pHelpFile
)+1)* sizeof(WCHAR
));
1299 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
1300 apd_copyfile(di
.pHelpFile
, &apd
);
1303 ptr
= di
.pDependentFiles
;
1305 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pDependentFiles
,
1306 multi_sz_lenW(di
.pDependentFiles
));
1308 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
1309 while ((ptr
!= NULL
) && (ptr
[0])) {
1310 if (apd_copyfile(ptr
, &apd
)) {
1311 ptr
+= lstrlenW(ptr
) + 1;
1315 WARN("Failed to copy %s\n", debugstr_w(ptr
));
1319 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1320 if (di
.pMonitorName
)
1321 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1322 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1324 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
1326 if (di
.pDefaultDataType
)
1327 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1328 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1330 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
1332 /* settings for level 4 */
1333 if (di
.pszzPreviousNames
)
1334 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1335 multi_sz_lenW(di
.pszzPreviousNames
));
1337 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
1339 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1342 hui
= driver_load(env
, di
.pConfigFile
);
1343 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1344 if (hui
&& pDrvDriverEvent
) {
1346 /* Support for DrvDriverEvent is optional */
1347 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1348 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1349 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1350 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1354 TRACE("=> TRUE with %u\n", GetLastError());
1359 /******************************************************************************
1360 * fpAddMonitor [exported through PRINTPROVIDOR]
1362 * Install a Printmonitor
1365 * pName [I] Servername or NULL (local Computer)
1366 * Level [I] Structure-Level (Must be 2)
1367 * pMonitors [I] PTR to MONITOR_INFO_2
1374 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1377 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1379 monitor_t
* pm
= NULL
;
1380 LPMONITOR_INFO_2W mi2w
;
1386 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1387 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1388 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1389 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1390 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1392 if (copy_servername_from_name(pName
, NULL
)) {
1393 FIXME("server %s not supported\n", debugstr_w(pName
));
1394 SetLastError(ERROR_ACCESS_DENIED
);
1398 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1399 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1400 SetLastError(ERROR_INVALID_PARAMETER
);
1403 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
1404 WARN("Environment %s requested (we support only %s)\n",
1405 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
1406 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1410 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1411 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1412 SetLastError(ERROR_INVALID_PARAMETER
);
1416 /* Load and initialize the monitor. SetLastError() is called on failure */
1417 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
1422 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1423 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1427 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1428 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1429 &disposition
) == ERROR_SUCCESS
) {
1431 /* Some installers set options for the port before calling AddMonitor.
1432 We query the "Driver" entry to verify that the monitor is installed,
1433 before we return an error.
1434 When a user installs two print monitors at the same time with the
1435 same name, a race condition is possible but silently ignored. */
1439 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1440 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1441 &namesize
) == ERROR_SUCCESS
)) {
1442 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1443 /* 9x use ERROR_ALREADY_EXISTS */
1444 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1449 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1450 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1451 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1453 RegCloseKey(hentry
);
1460 /******************************************************************************
1461 * fpAddPort [exported through PRINTPROVIDOR]
1463 * Add a Port for a specific Monitor
1466 * pName [I] Servername or NULL (local Computer)
1467 * hWnd [I] Handle to parent Window for the Dialog-Box
1468 * pMonitorName [I] Name of the Monitor that manage the Port
1475 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1482 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1484 lres
= copy_servername_from_name(pName
, NULL
);
1486 FIXME("server %s not supported\n", debugstr_w(pName
));
1487 SetLastError(ERROR_INVALID_PARAMETER
);
1491 /* an empty Monitorname is Invalid */
1492 if (!pMonitorName
[0]) {
1493 SetLastError(ERROR_NOT_SUPPORTED
);
1497 pm
= monitor_load(pMonitorName
, NULL
);
1498 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1499 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1500 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1504 pui
= monitor_loadui(pm
);
1505 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1506 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1507 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1511 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1512 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1513 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1515 SetLastError(ERROR_NOT_SUPPORTED
);
1518 monitor_unload(pui
);
1522 TRACE("returning %d with %u\n", res
, GetLastError());
1526 /******************************************************************************
1527 * fpAddPortEx [exported through PRINTPROVIDOR]
1529 * Add a Port for a specific Monitor, without presenting a user interface
1532 * pName [I] Servername or NULL (local Computer)
1533 * level [I] Structure-Level (1 or 2) for pBuffer
1534 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1535 * pMonitorName [I] Name of the Monitor that manage the Port
1542 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1549 pi2
= (PORT_INFO_2W
*) pBuffer
;
1551 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1552 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1553 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1554 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1556 lres
= copy_servername_from_name(pName
, NULL
);
1558 FIXME("server %s not supported\n", debugstr_w(pName
));
1559 SetLastError(ERROR_INVALID_PARAMETER
);
1563 if ((level
< 1) || (level
> 2)) {
1564 SetLastError(ERROR_INVALID_LEVEL
);
1568 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1569 SetLastError(ERROR_INVALID_PARAMETER
);
1573 /* load the Monitor */
1574 pm
= monitor_load(pMonitorName
, NULL
);
1575 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1576 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1577 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1581 FIXME("not implemented for %s (monitor %p: %s)\n",
1582 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : NULL
);
1583 SetLastError(ERROR_INVALID_PARAMETER
);
1590 /******************************************************************************
1591 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1593 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1596 * pName [I] Servername or NULL (local Computer)
1597 * level [I] Level for the supplied DRIVER_INFO_*W struct
1598 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1599 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1606 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1610 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1611 lres
= copy_servername_from_name(pName
, NULL
);
1613 FIXME("server %s not supported\n", debugstr_w(pName
));
1614 SetLastError(ERROR_ACCESS_DENIED
);
1618 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1619 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1622 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1625 /******************************************************************************
1626 * fpClosePrinter [exported through PRINTPROVIDOR]
1628 * Close a printer handle and free associated resources
1631 * hPrinter [I] Printerhandle to close
1638 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1640 printer_t
*printer
= (printer_t
*) hPrinter
;
1642 TRACE("(%p)\n", hPrinter
);
1645 printer_free(printer
);
1651 /******************************************************************************
1652 * fpConfigurePort [exported through PRINTPROVIDOR]
1654 * Display the Configuration-Dialog for a specific Port
1657 * pName [I] Servername or NULL (local Computer)
1658 * hWnd [I] Handle to parent Window for the Dialog-Box
1659 * pPortName [I] Name of the Port, that should be configured
1666 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1673 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1675 lres
= copy_servername_from_name(pName
, NULL
);
1677 FIXME("server %s not supported\n", debugstr_w(pName
));
1678 SetLastError(ERROR_INVALID_NAME
);
1682 /* an empty Portname is Invalid, but can popup a Dialog */
1683 if (!pPortName
[0]) {
1684 SetLastError(ERROR_NOT_SUPPORTED
);
1688 pm
= monitor_load_by_port(pPortName
);
1689 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1690 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1691 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1692 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1693 TRACE("got %d with %u\n", res
, GetLastError());
1697 pui
= monitor_loadui(pm
);
1698 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1699 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1700 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1701 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1702 TRACE("got %d with %u\n", res
, GetLastError());
1706 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1707 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1708 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1710 SetLastError(ERROR_NOT_SUPPORTED
);
1713 monitor_unload(pui
);
1717 TRACE("returning %d with %u\n", res
, GetLastError());
1721 /******************************************************************
1722 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1724 * Delete a specific Printmonitor from a Printing-Environment
1727 * pName [I] Servername or NULL (local Computer)
1728 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1729 * pMonitorName [I] Name of the Monitor, that should be deleted
1736 * pEnvironment is ignored in Windows for the local Computer.
1740 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1745 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1746 debugstr_w(pMonitorName
));
1748 lres
= copy_servername_from_name(pName
, NULL
);
1750 FIXME("server %s not supported\n", debugstr_w(pName
));
1751 SetLastError(ERROR_INVALID_NAME
);
1755 /* pEnvironment is ignored in Windows for the local Computer */
1756 if (!pMonitorName
|| !pMonitorName
[0]) {
1757 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1758 SetLastError(ERROR_INVALID_PARAMETER
);
1762 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1763 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1767 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1768 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1773 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1776 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1777 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1781 /*****************************************************************************
1782 * fpDeletePort [exported through PRINTPROVIDOR]
1784 * Delete a specific Port
1787 * pName [I] Servername or NULL (local Computer)
1788 * hWnd [I] Handle to parent Window for the Dialog-Box
1789 * pPortName [I] Name of the Port, that should be deleted
1796 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1803 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1805 lres
= copy_servername_from_name(pName
, NULL
);
1807 FIXME("server %s not supported\n", debugstr_w(pName
));
1808 SetLastError(ERROR_INVALID_NAME
);
1812 /* an empty Portname is Invalid */
1813 if (!pPortName
[0]) {
1814 SetLastError(ERROR_NOT_SUPPORTED
);
1818 pm
= monitor_load_by_port(pPortName
);
1819 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1820 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1821 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1822 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1823 TRACE("got %d with %u\n", res
, GetLastError());
1827 pui
= monitor_loadui(pm
);
1828 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1829 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1830 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1831 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1832 TRACE("got %d with %u\n", res
, GetLastError());
1836 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1837 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1838 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1840 SetLastError(ERROR_NOT_SUPPORTED
);
1843 monitor_unload(pui
);
1847 TRACE("returning %d with %u\n", res
, GetLastError());
1851 /*****************************************************************************
1852 * fpEnumMonitors [exported through PRINTPROVIDOR]
1854 * Enumerate available Port-Monitors
1857 * pName [I] Servername or NULL (local Computer)
1858 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1859 * pMonitors [O] PTR to Buffer that receives the Result
1860 * cbBuf [I] Size of Buffer at pMonitors
1861 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1862 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1866 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1869 * Windows reads the Registry once and cache the Results.
1872 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1873 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1875 DWORD numentries
= 0;
1880 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1881 cbBuf
, pcbNeeded
, pcReturned
);
1883 lres
= copy_servername_from_name(pName
, NULL
);
1885 FIXME("server %s not supported\n", debugstr_w(pName
));
1886 SetLastError(ERROR_INVALID_NAME
);
1890 if (!Level
|| (Level
> 2)) {
1891 WARN("level (%d) is ignored in win9x\n", Level
);
1892 SetLastError(ERROR_INVALID_LEVEL
);
1896 /* Scan all Monitor-Keys */
1898 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1900 /* we calculated the needed buffersize. now do more error-checks */
1901 if (cbBuf
< needed
) {
1902 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1906 /* fill the Buffer with the Monitor-Keys */
1907 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
1911 if (pcbNeeded
) *pcbNeeded
= needed
;
1912 if (pcReturned
) *pcReturned
= numentries
;
1914 TRACE("returning %d with %d (%d byte for %d entries)\n",
1915 res
, GetLastError(), needed
, numentries
);
1920 /******************************************************************************
1921 * fpEnumPorts [exported through PRINTPROVIDOR]
1923 * Enumerate available Ports
1926 * pName [I] Servername or NULL (local Computer)
1927 * Level [I] Structure-Level (1 or 2)
1928 * pPorts [O] PTR to Buffer that receives the Result
1929 * cbBuf [I] Size of Buffer at pPorts
1930 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1931 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1935 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1938 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
1939 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1942 DWORD numentries
= 0;
1946 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
1947 cbBuf
, pcbNeeded
, pcReturned
);
1949 lres
= copy_servername_from_name(pName
, NULL
);
1951 FIXME("server %s not supported\n", debugstr_w(pName
));
1952 SetLastError(ERROR_INVALID_NAME
);
1956 if (!Level
|| (Level
> 2)) {
1957 SetLastError(ERROR_INVALID_LEVEL
);
1961 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
1962 SetLastError(RPC_X_NULL_REF_POINTER
);
1966 EnterCriticalSection(&monitor_handles_cs
);
1969 /* Scan all local Ports */
1971 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
1973 /* we calculated the needed buffersize. now do the error-checks */
1974 if (cbBuf
< needed
) {
1975 monitor_unloadall();
1976 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1977 goto emP_cleanup_cs
;
1979 else if (!pPorts
|| !pcReturned
) {
1980 monitor_unloadall();
1981 SetLastError(RPC_X_NULL_REF_POINTER
);
1982 goto emP_cleanup_cs
;
1985 /* Fill the Buffer */
1986 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
1988 monitor_unloadall();
1991 LeaveCriticalSection(&monitor_handles_cs
);
1994 if (pcbNeeded
) *pcbNeeded
= needed
;
1995 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
1997 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1998 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2003 /******************************************************************************
2004 * fpOpenPrinter [exported through PRINTPROVIDOR]
2006 * Open a Printer / Printserver or a Printer-Object
2009 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2010 * pPrinter [O] The resulting Handle is stored here
2011 * pDefaults [I] PTR to Default Printer Settings or NULL
2018 * lpPrinterName is one of:
2019 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2020 *| Printer: "PrinterName"
2021 *| Printer-Object: "PrinterName,Job xxx"
2022 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2023 *| XcvPort: "Servername,XcvPort PortName"
2027 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2028 LPPRINTER_DEFAULTSW pDefaults
)
2031 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2033 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2035 return (*pPrinter
!= 0);
2038 /******************************************************************************
2039 * fpXcvData [exported through PRINTPROVIDOR]
2041 * Execute commands in the Printmonitor DLL
2044 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2045 * pszDataName [i] Name of the command to execute
2046 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2047 * cbInputData [i] Size in Bytes of Buffer at pInputData
2048 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2049 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2050 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2051 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2058 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2059 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2061 * Minimal List of commands, that a Printmonitor DLL should support:
2063 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2064 *| "AddPort" : Add a Port
2065 *| "DeletePort": Delete a Port
2067 * Many Printmonitors support additional commands. Examples for localspl.dll:
2068 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2069 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2072 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2073 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2074 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2076 printer_t
*printer
= (printer_t
* ) hXcv
;
2078 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2079 pInputData
, cbInputData
, pOutputData
,
2080 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2082 if (!printer
|| (!printer
->hXcv
)) {
2083 SetLastError(ERROR_INVALID_HANDLE
);
2087 if (!pcbOutputNeeded
) {
2088 SetLastError(ERROR_INVALID_PARAMETER
);
2092 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2093 SetLastError(RPC_X_NULL_REF_POINTER
);
2097 *pcbOutputNeeded
= 0;
2099 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2100 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2105 /*****************************************************
2106 * setup_provider [internal]
2108 void setup_provider(void)
2110 static const PRINTPROVIDOR backend
= {
2112 NULL
, /* fpSetJob */
2113 NULL
, /* fpGetJob */
2114 NULL
, /* fpEnumJobs */
2115 NULL
, /* fpAddPrinter */
2116 NULL
, /* fpDeletePrinter */
2117 NULL
, /* fpSetPrinter */
2118 NULL
, /* fpGetPrinter */
2119 NULL
, /* fpEnumPrinters */
2120 NULL
, /* fpAddPrinterDriver */
2121 NULL
, /* fpEnumPrinterDrivers */
2122 NULL
, /* fpGetPrinterDriver */
2123 fpGetPrinterDriverDirectory
,
2124 NULL
, /* fpDeletePrinterDriver */
2125 NULL
, /* fpAddPrintProcessor */
2126 NULL
, /* fpEnumPrintProcessors */
2127 NULL
, /* fpGetPrintProcessorDirectory */
2128 NULL
, /* fpDeletePrintProcessor */
2129 NULL
, /* fpEnumPrintProcessorDatatypes */
2130 NULL
, /* fpStartDocPrinter */
2131 NULL
, /* fpStartPagePrinter */
2132 NULL
, /* fpWritePrinter */
2133 NULL
, /* fpEndPagePrinter */
2134 NULL
, /* fpAbortPrinter */
2135 NULL
, /* fpReadPrinter */
2136 NULL
, /* fpEndDocPrinter */
2137 NULL
, /* fpAddJob */
2138 NULL
, /* fpScheduleJob */
2139 NULL
, /* fpGetPrinterData */
2140 NULL
, /* fpSetPrinterData */
2141 NULL
, /* fpWaitForPrinterChange */
2143 NULL
, /* fpAddForm */
2144 NULL
, /* fpDeleteForm */
2145 NULL
, /* fpGetForm */
2146 NULL
, /* fpSetForm */
2147 NULL
, /* fpEnumForms */
2153 NULL
, /* fpCreatePrinterIC */
2154 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2155 NULL
, /* fpDeletePrinterIC */
2156 NULL
, /* fpAddPrinterConnection */
2157 NULL
, /* fpDeletePrinterConnection */
2158 NULL
, /* fpPrinterMessageBox */
2161 NULL
, /* fpResetPrinter */
2162 NULL
, /* fpGetPrinterDriverEx */
2163 NULL
, /* fpFindFirstPrinterChangeNotification */
2164 NULL
, /* fpFindClosePrinterChangeNotification */
2166 NULL
, /* fpShutDown */
2167 NULL
, /* fpRefreshPrinterChangeNotification */
2168 NULL
, /* fpOpenPrinterEx */
2169 NULL
, /* fpAddPrinterEx */
2170 NULL
, /* fpSetPort */
2171 NULL
, /* fpEnumPrinterData */
2172 NULL
, /* fpDeletePrinterData */
2173 NULL
, /* fpClusterSplOpen */
2174 NULL
, /* fpClusterSplClose */
2175 NULL
, /* fpClusterSplIsAlive */
2176 NULL
, /* fpSetPrinterDataEx */
2177 NULL
, /* fpGetPrinterDataEx */
2178 NULL
, /* fpEnumPrinterDataEx */
2179 NULL
, /* fpEnumPrinterKey */
2180 NULL
, /* fpDeletePrinterDataEx */
2181 NULL
, /* fpDeletePrinterKey */
2182 NULL
, /* fpSeekPrinter */
2183 NULL
, /* fpDeletePrinterDriverEx */
2184 NULL
, /* fpAddPerMachineConnection */
2185 NULL
, /* fpDeletePerMachineConnection */
2186 NULL
, /* fpEnumPerMachineConnections */
2188 fpAddPrinterDriverEx
,
2189 NULL
, /* fpSplReadPrinter */
2190 NULL
, /* fpDriverUnloadComplete */
2191 NULL
, /* fpGetSpoolFileInfo */
2192 NULL
, /* fpCommitSpoolData */
2193 NULL
, /* fpCloseSpoolFileHandle */
2194 NULL
, /* fpFlushPrinter */
2195 NULL
, /* fpSendRecvBidiData */
2196 NULL
/* fpAddDriverCatalog */
2198 pprovider
= &backend
;
2202 /*****************************************************
2203 * InitializePrintProvidor (localspl.@)
2205 * Initialize the Printprovider
2208 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2209 * cbPrintProvidor [I] Size of Buffer in Bytes
2210 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2213 * Success: TRUE and pPrintProvidor filled
2217 * The RegistryPath should be:
2218 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2219 * but this Parameter is ignored in "localspl.dll".
2223 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2224 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2227 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2228 memcpy(pPrintProvidor
, pprovider
,
2229 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));