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 fmt_printprocessorsW
[] = { 'S','y','s','t','e','m','\\',
114 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
115 'C','o','n','t','r','o','l','\\',
116 'P','r','i','n','t','\\',
117 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
118 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
119 static const WCHAR hardwareidW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
120 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
121 static const WCHAR ia64_envnameW
[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
122 static const WCHAR ia64_subdirW
[] = {'i','a','6','4',0};
123 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
124 static const WCHAR locationW
[] = {'L','o','c','a','t','i','o','n',0};
125 static const WCHAR manufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
126 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
127 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
128 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129 'C','o','n','t','r','o','l','\\',
130 'P','r','i','n','t','\\',
131 'M','o','n','i','t','o','r','s','\\',0};
132 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
133 static const WCHAR nameW
[] = {'N','a','m','e',0};
134 static const WCHAR oem_urlW
[] = {'O','E','M',' ','U','r','l',0};
135 static const WCHAR parametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
136 static const WCHAR portW
[] = {'P','o','r','t',0};
137 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
138 static const WCHAR printersW
[] = {'S','y','s','t','e','m','\\',
139 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
140 'C','o','n','t','r','o','l','\\',
141 'P','r','i','n','t','\\',
142 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR spoolW
[] = {'\\','s','p','o','o','l',0};
144 static const WCHAR driversW
[] = {'\\','d','r','i','v','e','r','s','\\',0};
145 static const WCHAR spoolprtprocsW
[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
146 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
147 static const WCHAR version0_subdirW
[] = {'\\','0',0};
148 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
149 static const WCHAR version3_subdirW
[] = {'\\','3',0};
150 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
151 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
152 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
153 static const WCHAR winnt_cv_portsW
[] = {'S','o','f','t','w','a','r','e','\\',
154 'M','i','c','r','o','s','o','f','t','\\',
155 'W','i','n','d','o','w','s',' ','N','T','\\',
156 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
157 'P','o','r','t','s',0};
158 static const WCHAR winprintW
[] = {'w','i','n','p','r','i','n','t',0};
159 static const WCHAR x64_envnameW
[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
160 static const WCHAR x64_subdirW
[] = {'x','6','4',0};
161 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
162 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
163 static const WCHAR XcvMonitorW
[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
164 static const WCHAR XcvPortW
[] = {',','X','c','v','P','o','r','t',' ',0};
167 static const printenv_t env_ia64
= {ia64_envnameW
, ia64_subdirW
, 3,
168 version3_regpathW
, version3_subdirW
};
170 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
171 version3_regpathW
, version3_subdirW
};
173 static const printenv_t env_x64
= {x64_envnameW
, x64_subdirW
, 3,
174 version3_regpathW
, version3_subdirW
};
176 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
177 version0_regpathW
, version0_subdirW
};
179 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_x64
, &env_ia64
, &env_win40
};
182 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
183 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
184 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
185 0, sizeof(DRIVER_INFO_8W
)};
188 /******************************************************************
191 * create a copy of a unicode-string
194 static LPWSTR
strdupW(LPCWSTR p
)
200 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
201 ret
= heap_alloc(len
);
202 if (ret
) memcpy(ret
, p
, len
);
206 /******************************************************************
207 * apd_copyfile [internal]
209 * Copy a file from the driverdirectory to the versioned directory
216 static BOOL
apd_copyfile( WCHAR
*pathname
, WCHAR
*file_part
, apd_data_t
*apd
)
221 apd
->src
[apd
->srclen
] = '\0';
222 apd
->dst
[apd
->dstlen
] = '\0';
224 if (!pathname
|| !pathname
[0]) {
225 /* nothing to copy */
229 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
)
234 strcatW( srcname
, file_part
);
236 strcatW( apd
->dst
, file_part
);
238 TRACE("%s => %s\n", debugstr_w(srcname
), debugstr_w(apd
->dst
));
240 /* FIXME: handle APD_COPY_NEW_FILES */
241 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
242 TRACE("got %u with %u\n", res
, GetLastError());
244 return (apd
->lazy
) ? TRUE
: res
;
247 /******************************************************************
248 * copy_servername_from_name (internal)
250 * for an external server, the serverpart from the name is copied.
253 * the length (in WCHAR) of the serverpart (0 for the local computer)
254 * (-length), when the name is to long
257 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
261 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
265 if (target
) *target
= '\0';
267 if (name
== NULL
) return 0;
268 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
271 /* skip over both backslash, find separator '\' */
272 ptr
= strchrW(server
, '\\');
273 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
275 /* servername is empty */
276 if (serverlen
== 0) return 0;
278 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
280 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
283 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
284 target
[serverlen
] = '\0';
287 len
= sizeof(buffer
) / sizeof(buffer
[0]);
288 if (GetComputerNameW(buffer
, &len
)) {
289 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
290 /* The requested Servername is our computername */
297 /******************************************************************
298 * get_basename_from_name (internal)
300 * skip over the serverpart from the full name
303 static LPCWSTR
get_basename_from_name(LPCWSTR name
)
305 if (name
== NULL
) return NULL
;
306 if ((name
[0] == '\\') && (name
[1] == '\\')) {
307 /* skip over the servername and search for the following '\' */
308 name
= strchrW(&name
[2], '\\');
309 if ((name
) && (name
[1])) {
310 /* found a separator ('\') followed by a name:
311 skip over the separator and return the rest */
316 /* no basename present (we found only a servername) */
323 /******************************************************************
324 * monitor_unload [internal]
326 * release a printmonitor and unload it from memory, when needed
329 static void monitor_unload(monitor_t
* pm
)
331 if (pm
== NULL
) return;
332 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
334 EnterCriticalSection(&monitor_handles_cs
);
336 if (pm
->refcount
) pm
->refcount
--;
338 if (pm
->refcount
== 0) {
339 list_remove(&pm
->entry
);
340 FreeLibrary(pm
->hdll
);
342 heap_free(pm
->dllname
);
345 LeaveCriticalSection(&monitor_handles_cs
);
348 /******************************************************************
349 * monitor_unloadall [internal]
351 * release all registered printmonitors and unload them from memory, when needed
355 static void monitor_unloadall(void)
360 EnterCriticalSection(&monitor_handles_cs
);
361 /* iterate through the list, with safety against removal */
362 LIST_FOR_EACH_ENTRY_SAFE(pm
, next
, &monitor_handles
, monitor_t
, entry
)
364 /* skip monitorui dlls */
365 if (pm
->monitor
) monitor_unload(pm
);
367 LeaveCriticalSection(&monitor_handles_cs
);
370 /******************************************************************
371 * monitor_load [internal]
373 * load a printmonitor, get the dllname from the registry, when needed
374 * initialize the monitor and dump found function-pointers
376 * On failure, SetLastError() is called and NULL is returned
379 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
381 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
382 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
383 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
384 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
385 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
387 monitor_t
* pm
= NULL
;
389 LPWSTR regroot
= NULL
;
390 LPWSTR driver
= dllname
;
392 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
393 /* Is the Monitor already loaded? */
394 EnterCriticalSection(&monitor_handles_cs
);
397 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
399 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
407 pm
= heap_alloc_zero(sizeof(monitor_t
));
408 if (pm
== NULL
) goto cleanup
;
409 list_add_tail(&monitor_handles
, &pm
->entry
);
413 if (pm
->name
== NULL
) {
414 /* Load the monitor */
415 LPMONITOREX pmonitorEx
;
419 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
420 regroot
= heap_alloc(len
* sizeof(WCHAR
));
424 lstrcpyW(regroot
, monitorsW
);
425 lstrcatW(regroot
, name
);
426 /* Get the Driver from the Registry */
427 if (driver
== NULL
) {
430 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
431 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
432 &namesize
) == ERROR_SUCCESS
) {
433 driver
= heap_alloc(namesize
);
434 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
441 pm
->name
= strdupW(name
);
442 pm
->dllname
= strdupW(driver
);
444 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
446 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
451 pm
->hdll
= LoadLibraryW(driver
);
452 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
454 if (pm
->hdll
== NULL
) {
456 SetLastError(ERROR_MOD_NOT_FOUND
);
461 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
462 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
463 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
464 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
465 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
468 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
469 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
470 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
471 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
472 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
474 if (pInitializePrintMonitorUI
!= NULL
) {
475 pm
->monitorUI
= pInitializePrintMonitorUI();
476 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
478 TRACE("0x%08x: dwMonitorSize (%d)\n",
479 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
484 if (pInitializePrintMonitor
&& regroot
) {
485 pmonitorEx
= pInitializePrintMonitor(regroot
);
486 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
487 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
490 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
491 pm
->monitor
= &(pmonitorEx
->Monitor
);
496 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
500 if (!pm
->monitor
&& regroot
) {
501 if (pInitializePrintMonitor2
!= NULL
) {
502 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
504 if (pInitializeMonitorEx
!= NULL
) {
505 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
507 if (pInitializeMonitor
!= NULL
) {
508 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
511 if (!pm
->monitor
&& !pm
->monitorUI
) {
513 SetLastError(ERROR_PROC_NOT_FOUND
);
518 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
522 LeaveCriticalSection(&monitor_handles_cs
);
523 if (driver
!= dllname
) heap_free(driver
);
525 TRACE("=> %p\n", pm
);
529 /******************************************************************
530 * monitor_loadall [internal]
532 * Load all registered monitors
535 static DWORD
monitor_loadall(void)
538 DWORD registered
= 0;
541 WCHAR buffer
[MAX_PATH
];
544 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hmonitors
) == ERROR_SUCCESS
) {
545 RegQueryInfoKeyW(hmonitors
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
,
546 NULL
, NULL
, NULL
, NULL
, NULL
);
548 TRACE("%d monitors registered\n", registered
);
550 while (id
< registered
) {
552 RegEnumKeyW(hmonitors
, id
, buffer
, MAX_PATH
);
553 pm
= monitor_load(buffer
, NULL
);
557 RegCloseKey(hmonitors
);
559 TRACE("%d monitors loaded\n", loaded
);
563 /******************************************************************
564 * monitor_loadui [internal]
566 * load the userinterface-dll for a given portmonitor
568 * On failure, NULL is returned
570 static monitor_t
* monitor_loadui(monitor_t
* pm
)
572 monitor_t
* pui
= NULL
;
573 WCHAR buffer
[MAX_PATH
];
578 if (pm
== NULL
) return NULL
;
579 TRACE("(%p) => dllname: %s\n", pm
, debugstr_w(pm
->dllname
));
581 /* Try the Portmonitor first; works for many monitors */
583 EnterCriticalSection(&monitor_handles_cs
);
585 LeaveCriticalSection(&monitor_handles_cs
);
589 /* query the userinterface-dllname from the Portmonitor */
590 if ((pm
->monitor
) && (pm
->monitor
->pfnXcvDataPort
)) {
591 /* building (",XcvMonitor %s",pm->name) not needed yet */
592 res
= pm
->monitor
->pfnXcvOpenPort(emptyW
, SERVER_ACCESS_ADMINISTER
, &hXcv
);
593 TRACE("got %u with %p\n", res
, hXcv
);
595 res
= pm
->monitor
->pfnXcvDataPort(hXcv
, monitorUIW
, NULL
, 0, (BYTE
*) buffer
, sizeof(buffer
), &len
);
596 TRACE("got %u with %s\n", res
, debugstr_w(buffer
));
597 if (res
== ERROR_SUCCESS
) pui
= monitor_load(NULL
, buffer
);
598 pm
->monitor
->pfnXcvClosePort(hXcv
);
604 /******************************************************************
605 * monitor_load_by_port [internal]
607 * load a printmonitor for a given port
609 * On failure, NULL is returned
612 static monitor_t
* monitor_load_by_port(LPCWSTR portname
)
617 monitor_t
* pm
= NULL
;
618 DWORD registered
= 0;
622 TRACE("(%s)\n", debugstr_w(portname
));
624 /* Try the Local Monitor first */
625 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, winnt_cv_portsW
, &hroot
) == ERROR_SUCCESS
) {
626 if (RegQueryValueExW(hroot
, portname
, NULL
, NULL
, NULL
, &len
) == ERROR_SUCCESS
) {
627 /* found the portname */
629 return monitor_load(localportW
, NULL
);
634 len
= MAX_PATH
+ lstrlenW(bs_ports_bsW
) + lstrlenW(portname
) + 1;
635 buffer
= heap_alloc(len
* sizeof(WCHAR
));
636 if (buffer
== NULL
) return NULL
;
638 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
639 EnterCriticalSection(&monitor_handles_cs
);
640 RegQueryInfoKeyW(hroot
, NULL
, NULL
, NULL
, ®istered
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
642 while ((pm
== NULL
) && (id
< registered
)) {
644 RegEnumKeyW(hroot
, id
, buffer
, MAX_PATH
);
645 TRACE("testing %s\n", debugstr_w(buffer
));
646 len
= lstrlenW(buffer
);
647 lstrcatW(buffer
, bs_ports_bsW
);
648 lstrcatW(buffer
, portname
);
649 if (RegOpenKeyW(hroot
, buffer
, &hport
) == ERROR_SUCCESS
) {
651 buffer
[len
] = '\0'; /* use only the Monitor-Name */
652 pm
= monitor_load(buffer
, NULL
);
656 LeaveCriticalSection(&monitor_handles_cs
);
663 /******************************************************************
664 * Return the number of bytes for an multi_sz string.
665 * The result includes all \0s
666 * (specifically the extra \0, that is needed as multi_sz terminator).
668 static int multi_sz_lenW(const WCHAR
*str
)
670 const WCHAR
*ptr
= str
;
674 ptr
+= lstrlenW(ptr
) + 1;
677 return (ptr
- str
+ 1) * sizeof(WCHAR
);
680 /******************************************************************
681 * validate_envW [internal]
683 * validate the user-supplied printing-environment
686 * env [I] PTR to Environment-String or NULL
689 * Success: PTR to printenv_t
690 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
693 * An empty string is handled the same way as NULL.
697 static const printenv_t
* validate_envW(LPCWSTR env
)
699 const printenv_t
*result
= NULL
;
702 TRACE("(%s)\n", debugstr_w(env
));
705 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
707 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
709 result
= all_printenv
[i
];
713 if (result
== NULL
) {
714 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
715 SetLastError(ERROR_INVALID_ENVIRONMENT
);
717 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
721 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
724 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
728 /*****************************************************************************
729 * enumerate the local monitors (INTERNAL)
731 * returns the needed size (in bytes) for pMonitors
732 * and *lpreturned is set to number of entries returned in pMonitors
734 * Language-Monitors are also installed in the same Registry-Location but
735 * they are filtered in Windows (not returned by EnumMonitors).
736 * We do no filtering to simplify our Code.
739 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
744 LPMONITOR_INFO_2W mi
;
745 WCHAR buffer
[MAX_PATH
];
746 WCHAR dllname
[MAX_PATH
];
754 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
756 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
757 len
= entrysize
* numentries
;
758 ptr
= (LPWSTR
) &pMonitors
[len
];
761 len
= sizeof(buffer
)/sizeof(buffer
[0]);
764 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
765 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
766 /* Scan all Monitor-Registry-Keys */
767 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
768 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
769 dllsize
= sizeof(dllname
);
772 /* The Monitor must have a Driver-DLL */
773 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
774 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
775 /* We found a valid DLL for this Monitor. */
776 TRACE("using Driver: %s\n", debugstr_w(dllname
));
781 /* Windows returns only Port-Monitors here, but to simplify our code,
782 we do no filtering for Language-Monitors */
786 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
788 /* we install and return only monitors for "Windows NT x86" */
789 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
793 /* required size is calculated. Now fill the user-buffer */
794 if (pMonitors
&& (cbBuf
>= needed
)){
795 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
796 pMonitors
+= entrysize
;
798 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
800 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
801 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
803 mi
->pEnvironment
= ptr
;
804 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
805 ptr
+= (lstrlenW(x86_envnameW
)+1);
808 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
809 ptr
+= (dllsize
/ sizeof(WCHAR
));
814 len
= sizeof(buffer
)/sizeof(buffer
[0]);
819 *lpreturned
= numentries
;
820 TRACE("need %d byte for %d entries\n", needed
, numentries
);
824 /*****************************************************************************
825 * enumerate the local print processors (INTERNAL)
827 * returns the needed size (in bytes) for pPPInfo
828 * and *lpreturned is set to number of entries returned in pPPInfo
831 static DWORD
get_local_printprocessors(LPWSTR regpathW
, LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD lpreturned
)
836 PPRINTPROCESSOR_INFO_1W ppi
;
837 WCHAR buffer
[MAX_PATH
];
838 WCHAR dllname
[MAX_PATH
];
845 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
846 len
= numentries
* sizeof(PRINTPROCESSOR_INFO_1W
);
847 ptr
= (LPWSTR
) &pPPInfo
[len
];
850 len
= sizeof(buffer
)/sizeof(buffer
[0]);
853 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, regpathW
, &hroot
) == ERROR_SUCCESS
) {
854 /* add "winprint" first */
856 needed
= sizeof(PRINTPROCESSOR_INFO_1W
) + sizeof(winprintW
);
857 if (pPPInfo
&& (cbBuf
>= needed
)){
858 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
859 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
861 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
863 lstrcpyW(ptr
, winprintW
); /* Name of the Print Processor */
864 ptr
+= sizeof(winprintW
) / sizeof(WCHAR
);
867 /* Scan all Printprocessor Keys */
868 while ((RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) &&
869 (lstrcmpiW(buffer
, winprintW
) != 0)) {
870 TRACE("PrintProcessor_%d: %s\n", numentries
, debugstr_w(buffer
));
871 dllsize
= sizeof(dllname
);
874 /* The Print Processor must have a Driver-DLL */
875 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
876 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
877 /* We found a valid DLL for this Print Processor */
878 TRACE("using Driver: %s\n", debugstr_w(dllname
));
885 needed
+= sizeof(PRINTPROCESSOR_INFO_1W
);
886 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(printprocessor name) */
888 /* required size is calculated. Now fill the user-buffer */
889 if (pPPInfo
&& (cbBuf
>= needed
)){
890 ppi
= (PPRINTPROCESSOR_INFO_1W
) pPPInfo
;
891 pPPInfo
+= sizeof(PRINTPROCESSOR_INFO_1W
);
893 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi
, numentries
);
895 lstrcpyW(ptr
, buffer
); /* Name of the Print Processor */
896 ptr
+= (len
+1); /* len is lstrlenW(printprosessor name) */
900 len
= sizeof(buffer
)/sizeof(buffer
[0]);
905 *lpreturned
= numentries
;
906 TRACE("need %d byte for %d entries\n", needed
, numentries
);
910 /******************************************************************
911 * enumerate the local Ports from all loaded monitors (internal)
913 * returns the needed size (in bytes) for pPorts
914 * and *lpreturned is set to number of entries returned in pPorts
917 static DWORD
get_ports_from_all_monitors(DWORD level
, LPBYTE pPorts
, DWORD cbBuf
, LPDWORD lpreturned
)
921 LPPORT_INFO_2W cache
;
923 LPBYTE pi_buffer
= NULL
;
924 DWORD pi_allocated
= 0;
935 TRACE("(%d, %p, %d, %p)\n", level
, pPorts
, cbBuf
, lpreturned
);
936 entrysize
= (level
== 1) ? sizeof(PORT_INFO_1W
) : sizeof(PORT_INFO_2W
);
938 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
939 needed
= entrysize
* numentries
;
940 ptr
= (LPWSTR
) &pPorts
[needed
];
945 LIST_FOR_EACH_ENTRY(pm
, &monitor_handles
, monitor_t
, entry
)
947 if ((pm
->monitor
) && (pm
->monitor
->pfnEnumPorts
)) {
950 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
951 if (!res
&& (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)) {
952 /* Do not use heap_realloc (we do not need the old data in the buffer) */
953 heap_free(pi_buffer
);
954 pi_buffer
= heap_alloc(pi_needed
);
955 pi_allocated
= (pi_buffer
) ? pi_needed
: 0;
956 res
= pm
->monitor
->pfnEnumPorts(NULL
, level
, pi_buffer
, pi_allocated
, &pi_needed
, &pi_returned
);
958 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
959 debugstr_w(pm
->name
), res
, GetLastError(), pi_needed
, pi_returned
);
961 numentries
+= pi_returned
;
964 /* fill the output-buffer (pPorts), if we have one */
965 if (pPorts
&& (cbBuf
>= needed
) && pi_buffer
) {
967 while (pi_returned
> pi_index
) {
968 cache
= (LPPORT_INFO_2W
) &pi_buffer
[pi_index
* entrysize
];
969 out
= (LPPORT_INFO_2W
) &pPorts
[outindex
* entrysize
];
970 out
->pPortName
= ptr
;
971 lstrcpyW(ptr
, cache
->pPortName
);
972 ptr
+= (lstrlenW(ptr
)+1);
974 out
->pMonitorName
= ptr
;
975 lstrcpyW(ptr
, cache
->pMonitorName
);
976 ptr
+= (lstrlenW(ptr
)+1);
978 out
->pDescription
= ptr
;
979 lstrcpyW(ptr
, cache
->pDescription
);
980 ptr
+= (lstrlenW(ptr
)+1);
981 out
->fPortType
= cache
->fPortType
;
982 out
->Reserved
= cache
->Reserved
;
990 /* the temporary portinfo-buffer is no longer needed */
991 heap_free(pi_buffer
);
993 *lpreturned
= numentries
;
994 TRACE("need %d byte for %d entries\n", needed
, numentries
);
999 /*****************************************************************************
1000 * open_driver_reg [internal]
1002 * opens the registry for the printer drivers depending on the given input
1003 * variable pEnvironment
1006 * Success: the opened hkey
1009 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
1013 const printenv_t
* env
;
1015 TRACE("(%s)\n", debugstr_w(pEnvironment
));
1017 env
= validate_envW(pEnvironment
);
1018 if (!env
) return NULL
;
1020 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
1021 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
1024 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
1025 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
1026 HeapFree(GetProcessHeap(), 0, buffer
);
1031 /*****************************************************************************
1032 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1034 * Return the PATH for the Printer-Drivers
1037 * pName [I] Servername (NT only) or NULL (local Computer)
1038 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1039 * Level [I] Structure-Level (must be 1)
1040 * pDriverDirectory [O] PTR to Buffer that receives the Result
1041 * cbBuf [I] Size of Buffer at pDriverDirectory
1042 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1043 * required for pDriverDirectory
1046 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1047 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1048 * if cbBuf is too small
1050 * Native Values returned in pDriverDirectory on Success:
1051 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1052 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1053 *| win9x(Windows 4.0): "%winsysdir%"
1055 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1058 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
1059 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
1062 const printenv_t
* env
;
1063 WCHAR
* const dir
= (WCHAR
*)pDriverDirectory
;
1065 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
1066 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
1068 if (pName
!= NULL
&& pName
[0]) {
1069 FIXME("server %s not supported\n", debugstr_w(pName
));
1070 SetLastError(ERROR_INVALID_PARAMETER
);
1074 env
= validate_envW(pEnvironment
);
1075 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
1078 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1079 needed
= GetSystemDirectoryW(NULL
, 0);
1080 /* add the Size for the Subdirectories */
1081 needed
+= lstrlenW(spoolW
);
1082 needed
+= lstrlenW(driversW
);
1083 needed
+= lstrlenW(env
->subdir
);
1084 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
1086 *pcbNeeded
= needed
;
1088 if (needed
> cbBuf
) {
1089 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1094 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1095 SetLastError(ERROR_INVALID_USER_BUFFER
);
1099 GetSystemDirectoryW( dir
, cbBuf
/ sizeof(WCHAR
) );
1100 /* add the Subdirectories */
1101 lstrcatW( dir
, spoolW
);
1102 CreateDirectoryW( dir
, NULL
);
1103 lstrcatW( dir
, driversW
);
1104 CreateDirectoryW( dir
, NULL
);
1105 lstrcatW( dir
, env
->subdir
);
1106 CreateDirectoryW( dir
, NULL
);
1108 TRACE( "=> %s\n", debugstr_w( dir
) );
1112 /******************************************************************
1113 * driver_load [internal]
1115 * load a driver user interface dll
1117 * On failure, NULL is returned
1121 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
1123 WCHAR fullname
[MAX_PATH
];
1127 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
1129 /* build the driverdir */
1130 len
= sizeof(fullname
) -
1131 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
1133 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1134 (LPBYTE
) fullname
, len
, &len
)) {
1135 /* Should never Fail */
1136 SetLastError(ERROR_BUFFER_OVERFLOW
);
1140 lstrcatW(fullname
, env
->versionsubdir
);
1141 lstrcatW(fullname
, backslashW
);
1142 lstrcatW(fullname
, dllname
);
1144 hui
= LoadLibraryW(fullname
);
1145 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
1150 /******************************************************************
1152 * free the data pointer of an opened printer
1154 static VOID
printer_free(printer_t
* printer
)
1157 printer
->pm
->monitor
->pfnXcvClosePort(printer
->hXcv
);
1159 monitor_unload(printer
->pm
);
1161 heap_free(printer
->printername
);
1162 heap_free(printer
->name
);
1166 /******************************************************************
1167 * printer_alloc_handle
1168 * alloc a printer handle and remember the data pointer in the printer handle table
1171 static HANDLE
printer_alloc_handle(LPCWSTR name
, LPPRINTER_DEFAULTSW pDefault
)
1173 WCHAR servername
[MAX_COMPUTERNAME_LENGTH
+ 1];
1174 printer_t
*printer
= NULL
;
1175 LPCWSTR printername
;
1180 if (copy_servername_from_name(name
, servername
)) {
1181 FIXME("server %s not supported\n", debugstr_w(servername
));
1182 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1186 printername
= get_basename_from_name(name
);
1187 if (name
!= printername
) TRACE("converted %s to %s\n", debugstr_w(name
), debugstr_w(printername
));
1189 /* an empty printername is invalid */
1190 if (printername
&& (!printername
[0])) {
1191 SetLastError(ERROR_INVALID_PARAMETER
);
1195 printer
= heap_alloc_zero(sizeof(printer_t
));
1196 if (!printer
) goto end
;
1198 /* clone the base name. This is NULL for the printserver */
1199 printer
->printername
= strdupW(printername
);
1201 /* clone the full name */
1202 printer
->name
= strdupW(name
);
1203 if (name
&& (!printer
->name
)) {
1204 printer_free(printer
);
1208 len
= sizeof(XcvMonitorW
)/sizeof(WCHAR
) - 1;
1209 if (strncmpW(printername
, XcvMonitorW
, len
) == 0) {
1210 /* OpenPrinter(",XcvMonitor ", ...) detected */
1211 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername
[len
]));
1212 printer
->pm
= monitor_load(&printername
[len
], NULL
);
1213 if (printer
->pm
== NULL
) {
1214 printer_free(printer
);
1215 SetLastError(ERROR_UNKNOWN_PORT
);
1222 len
= sizeof(XcvPortW
)/sizeof(WCHAR
) - 1;
1223 if (strncmpW( printername
, XcvPortW
, len
) == 0) {
1224 /* OpenPrinter(",XcvPort ", ...) detected */
1225 TRACE(",XcvPort: %s\n", debugstr_w(&printername
[len
]));
1226 printer
->pm
= monitor_load_by_port(&printername
[len
]);
1227 if (printer
->pm
== NULL
) {
1228 printer_free(printer
);
1229 SetLastError(ERROR_UNKNOWN_PORT
);
1237 if ((printer
->pm
->monitor
) && (printer
->pm
->monitor
->pfnXcvOpenPort
)) {
1238 printer
->pm
->monitor
->pfnXcvOpenPort(&printername
[len
],
1239 pDefault
? pDefault
->DesiredAccess
: 0,
1242 if (printer
->hXcv
== NULL
) {
1243 printer_free(printer
);
1244 SetLastError(ERROR_INVALID_PARAMETER
);
1251 /* Does the Printer exist? */
1252 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, printersW
, &hkeyPrinters
) != ERROR_SUCCESS
) {
1253 ERR("Can't create Printers key\n");
1254 printer_free(printer
);
1255 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1259 if (RegOpenKeyW(hkeyPrinters
, printername
, &hkeyPrinter
) != ERROR_SUCCESS
) {
1260 WARN("Printer not found in Registry: %s\n", debugstr_w(printername
));
1261 RegCloseKey(hkeyPrinters
);
1262 printer_free(printer
);
1263 SetLastError(ERROR_INVALID_PRINTER_NAME
);
1267 RegCloseKey(hkeyPrinter
);
1268 RegCloseKey(hkeyPrinters
);
1273 TRACE("using the local printserver\n");
1278 TRACE("==> %p\n", printer
);
1279 return (HANDLE
)printer
;
1282 static inline WCHAR
*get_file_part( WCHAR
*name
)
1284 WCHAR
*ptr
= strrchrW( name
, '\\' );
1285 if (ptr
) return ptr
+ 1;
1289 /******************************************************************************
1290 * myAddPrinterDriverEx [internal]
1292 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1293 * and a special mode with lazy error checking.
1296 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
1298 const printenv_t
*env
;
1301 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
1311 /* we need to set all entries in the Registry, independent from the Level of
1312 DRIVER_INFO, that the caller supplied */
1314 ZeroMemory(&di
, sizeof(di
));
1315 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
1316 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
1319 /* dump the most used infos */
1320 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
1321 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
1322 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
1323 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
1324 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
1325 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
1326 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
1327 /* dump only the first of the additional Files */
1328 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
1331 /* check environment */
1332 env
= validate_envW(di
.pEnvironment
);
1333 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
1335 /* fill the copy-data / get the driverdir */
1336 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
1337 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
1338 (LPBYTE
) apd
.src
, len
, &len
)) {
1339 /* Should never Fail */
1342 memcpy(apd
.dst
, apd
.src
, len
);
1343 lstrcatW(apd
.src
, backslashW
);
1344 apd
.srclen
= lstrlenW(apd
.src
);
1345 lstrcatW(apd
.dst
, env
->versionsubdir
);
1346 lstrcatW(apd
.dst
, backslashW
);
1347 apd
.dstlen
= lstrlenW(apd
.dst
);
1348 apd
.copyflags
= dwFileCopyFlags
;
1350 CreateDirectoryW(apd
.src
, NULL
);
1351 CreateDirectoryW(apd
.dst
, NULL
);
1353 hroot
= open_driver_reg(env
->envname
);
1355 ERR("Can't create Drivers key\n");
1359 /* Fill the Registry for the Driver */
1360 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1361 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
1362 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
1364 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
1371 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1372 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (const BYTE
*) &env
->driverversion
,
1375 file
= get_file_part( di
.pDriverPath
);
1376 RegSetValueExW( hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1377 apd_copyfile( di
.pDriverPath
, file
, &apd
);
1379 file
= get_file_part( di
.pDataFile
);
1380 RegSetValueExW( hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1381 apd_copyfile( di
.pDataFile
, file
, &apd
);
1383 file
= get_file_part( di
.pConfigFile
);
1384 RegSetValueExW( hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1385 apd_copyfile( di
.pConfigFile
, file
, &apd
);
1387 /* settings for level 3 */
1390 file
= get_file_part( di
.pHelpFile
);
1391 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)file
, (strlenW( file
) + 1) * sizeof(WCHAR
) );
1392 apd_copyfile( di
.pHelpFile
, file
, &apd
);
1395 RegSetValueExW( hdrv
, help_fileW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
) );
1397 if (di
.pDependentFiles
&& *di
.pDependentFiles
)
1399 WCHAR
*reg
, *reg_ptr
, *in_ptr
;
1400 reg
= reg_ptr
= HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di
.pDependentFiles
) );
1402 for (in_ptr
= di
.pDependentFiles
; *in_ptr
; in_ptr
+= strlenW( in_ptr
) + 1)
1404 file
= get_file_part( in_ptr
);
1405 len
= strlenW( file
) + 1;
1406 memcpy( reg_ptr
, file
, len
* sizeof(WCHAR
) );
1408 apd_copyfile( in_ptr
, file
, &apd
);
1412 RegSetValueExW( hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)reg
, (reg_ptr
- reg
+ 1) * sizeof(WCHAR
) );
1413 HeapFree( GetProcessHeap(), 0, reg
);
1416 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1418 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1419 if (di
.pMonitorName
)
1420 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
1421 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
1423 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1425 if (di
.pDefaultDataType
)
1426 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
1427 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
1429 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1431 /* settings for level 4 */
1432 if (di
.pszzPreviousNames
)
1433 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
1434 multi_sz_lenW(di
.pszzPreviousNames
));
1436 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (const BYTE
*)emptyW
, sizeof(emptyW
));
1438 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
1441 hui
= driver_load(env
, di
.pConfigFile
);
1442 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
1443 if (hui
&& pDrvDriverEvent
) {
1445 /* Support for DrvDriverEvent is optional */
1446 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
1447 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1448 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
1449 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
1453 TRACE("=> TRUE with %u\n", GetLastError());
1458 /******************************************************************************
1459 * fpAddMonitor [exported through PRINTPROVIDOR]
1461 * Install a Printmonitor
1464 * pName [I] Servername or NULL (local Computer)
1465 * Level [I] Structure-Level (Must be 2)
1466 * pMonitors [I] PTR to MONITOR_INFO_2
1473 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1476 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
1478 monitor_t
* pm
= NULL
;
1479 LPMONITOR_INFO_2W mi2w
;
1485 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
1486 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
1487 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
1488 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
1489 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
1491 if (copy_servername_from_name(pName
, NULL
)) {
1492 FIXME("server %s not supported\n", debugstr_w(pName
));
1493 SetLastError(ERROR_ACCESS_DENIED
);
1497 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
1498 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
1499 SetLastError(ERROR_INVALID_PARAMETER
);
1502 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
1503 WARN("Environment %s requested (we support only %s)\n",
1504 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
1505 SetLastError(ERROR_INVALID_ENVIRONMENT
);
1509 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
1510 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
1511 SetLastError(ERROR_INVALID_PARAMETER
);
1515 /* Load and initialize the monitor. SetLastError() is called on failure */
1516 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
1521 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1522 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1526 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1527 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1528 &disposition
) == ERROR_SUCCESS
) {
1530 /* Some installers set options for the port before calling AddMonitor.
1531 We query the "Driver" entry to verify that the monitor is installed,
1532 before we return an error.
1533 When a user installs two print monitors at the same time with the
1534 same name, a race condition is possible but silently ignored. */
1538 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1539 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1540 &namesize
) == ERROR_SUCCESS
)) {
1541 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1542 /* 9x use ERROR_ALREADY_EXISTS */
1543 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1548 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1549 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1550 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1552 RegCloseKey(hentry
);
1559 /******************************************************************************
1560 * fpAddPort [exported through PRINTPROVIDOR]
1562 * Add a Port for a specific Monitor
1565 * pName [I] Servername or NULL (local Computer)
1566 * hWnd [I] Handle to parent Window for the Dialog-Box
1567 * pMonitorName [I] Name of the Monitor that manage the Port
1574 static BOOL WINAPI
fpAddPort(LPWSTR pName
, HWND hWnd
, LPWSTR pMonitorName
)
1581 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pMonitorName
));
1583 lres
= copy_servername_from_name(pName
, NULL
);
1585 FIXME("server %s not supported\n", debugstr_w(pName
));
1586 SetLastError(ERROR_INVALID_PARAMETER
);
1590 /* an empty Monitorname is Invalid */
1591 if (!pMonitorName
[0]) {
1592 SetLastError(ERROR_NOT_SUPPORTED
);
1596 pm
= monitor_load(pMonitorName
, NULL
);
1597 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPort
) {
1598 res
= pm
->monitor
->pfnAddPort(pName
, hWnd
, pMonitorName
);
1599 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1603 pui
= monitor_loadui(pm
);
1604 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnAddPortUI
) {
1605 res
= pui
->monitorUI
->pfnAddPortUI(pName
, hWnd
, pMonitorName
, NULL
);
1606 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pui
->dllname
));
1610 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1611 debugstr_w(pMonitorName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1612 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1614 SetLastError(ERROR_NOT_SUPPORTED
);
1617 monitor_unload(pui
);
1621 TRACE("returning %d with %u\n", res
, GetLastError());
1625 /******************************************************************************
1626 * fpAddPortEx [exported through PRINTPROVIDOR]
1628 * Add a Port for a specific Monitor, without presenting a user interface
1631 * pName [I] Servername or NULL (local Computer)
1632 * level [I] Structure-Level (1 or 2) for pBuffer
1633 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1634 * pMonitorName [I] Name of the Monitor that manage the Port
1641 static BOOL WINAPI
fpAddPortEx(LPWSTR pName
, DWORD level
, LPBYTE pBuffer
, LPWSTR pMonitorName
)
1648 pi2
= (PORT_INFO_2W
*) pBuffer
;
1650 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName
), level
, pBuffer
,
1651 debugstr_w(pMonitorName
), debugstr_w(pi2
? pi2
->pPortName
: NULL
),
1652 debugstr_w(((level
> 1) && pi2
) ? pi2
->pMonitorName
: NULL
),
1653 debugstr_w(((level
> 1) && pi2
) ? pi2
->pDescription
: NULL
));
1655 lres
= copy_servername_from_name(pName
, NULL
);
1657 FIXME("server %s not supported\n", debugstr_w(pName
));
1658 SetLastError(ERROR_INVALID_PARAMETER
);
1662 if ((level
< 1) || (level
> 2)) {
1663 SetLastError(ERROR_INVALID_LEVEL
);
1667 if ((!pi2
) || (!pMonitorName
) || (!pMonitorName
[0])) {
1668 SetLastError(ERROR_INVALID_PARAMETER
);
1672 /* load the Monitor */
1673 pm
= monitor_load(pMonitorName
, NULL
);
1674 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnAddPortEx
) {
1675 res
= pm
->monitor
->pfnAddPortEx(pName
, level
, pBuffer
, pMonitorName
);
1676 TRACE("got %d with %u (%s)\n", res
, GetLastError(), debugstr_w(pm
->dllname
));
1680 FIXME("not implemented for %s (monitor %p: %s)\n",
1681 debugstr_w(pMonitorName
), pm
, pm
? debugstr_w(pm
->dllname
) : "(null)");
1682 SetLastError(ERROR_INVALID_PARAMETER
);
1689 /******************************************************************************
1690 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1692 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1695 * pName [I] Servername or NULL (local Computer)
1696 * level [I] Level for the supplied DRIVER_INFO_*W struct
1697 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1698 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1705 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1709 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1710 lres
= copy_servername_from_name(pName
, NULL
);
1712 FIXME("server %s not supported\n", debugstr_w(pName
));
1713 SetLastError(ERROR_ACCESS_DENIED
);
1717 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1718 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1721 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1724 /******************************************************************************
1725 * fpClosePrinter [exported through PRINTPROVIDOR]
1727 * Close a printer handle and free associated resources
1730 * hPrinter [I] Printerhandle to close
1737 static BOOL WINAPI
fpClosePrinter(HANDLE hPrinter
)
1739 printer_t
*printer
= (printer_t
*) hPrinter
;
1741 TRACE("(%p)\n", hPrinter
);
1744 printer_free(printer
);
1750 /******************************************************************************
1751 * fpConfigurePort [exported through PRINTPROVIDOR]
1753 * Display the Configuration-Dialog for a specific Port
1756 * pName [I] Servername or NULL (local Computer)
1757 * hWnd [I] Handle to parent Window for the Dialog-Box
1758 * pPortName [I] Name of the Port, that should be configured
1765 static BOOL WINAPI
fpConfigurePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1772 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1774 lres
= copy_servername_from_name(pName
, NULL
);
1776 FIXME("server %s not supported\n", debugstr_w(pName
));
1777 SetLastError(ERROR_INVALID_NAME
);
1781 /* an empty Portname is Invalid, but can popup a Dialog */
1782 if (!pPortName
[0]) {
1783 SetLastError(ERROR_NOT_SUPPORTED
);
1787 pm
= monitor_load_by_port(pPortName
);
1788 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnConfigurePort
) {
1789 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1790 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1791 res
= pm
->monitor
->pfnConfigurePort(pName
, hWnd
, pPortName
);
1792 TRACE("got %d with %u\n", res
, GetLastError());
1796 pui
= monitor_loadui(pm
);
1797 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnConfigurePortUI
) {
1798 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1799 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1800 res
= pui
->monitorUI
->pfnConfigurePortUI(pName
, hWnd
, pPortName
);
1801 TRACE("got %d with %u\n", res
, GetLastError());
1805 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1806 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1807 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1809 SetLastError(ERROR_NOT_SUPPORTED
);
1812 monitor_unload(pui
);
1816 TRACE("returning %d with %u\n", res
, GetLastError());
1820 /******************************************************************
1821 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1823 * Delete a specific Printmonitor from a Printing-Environment
1826 * pName [I] Servername or NULL (local Computer)
1827 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1828 * pMonitorName [I] Name of the Monitor, that should be deleted
1835 * pEnvironment is ignored in Windows for the local Computer.
1839 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1844 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1845 debugstr_w(pMonitorName
));
1847 lres
= copy_servername_from_name(pName
, NULL
);
1849 FIXME("server %s not supported\n", debugstr_w(pName
));
1850 SetLastError(ERROR_INVALID_NAME
);
1854 /* pEnvironment is ignored in Windows for the local Computer */
1855 if (!pMonitorName
|| !pMonitorName
[0]) {
1856 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1857 SetLastError(ERROR_INVALID_PARAMETER
);
1861 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1862 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1866 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1867 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1872 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1875 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1876 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1880 /*****************************************************************************
1881 * fpDeletePort [exported through PRINTPROVIDOR]
1883 * Delete a specific Port
1886 * pName [I] Servername or NULL (local Computer)
1887 * hWnd [I] Handle to parent Window for the Dialog-Box
1888 * pPortName [I] Name of the Port, that should be deleted
1895 static BOOL WINAPI
fpDeletePort(LPWSTR pName
, HWND hWnd
, LPWSTR pPortName
)
1902 TRACE("(%s, %p, %s)\n", debugstr_w(pName
), hWnd
, debugstr_w(pPortName
));
1904 lres
= copy_servername_from_name(pName
, NULL
);
1906 FIXME("server %s not supported\n", debugstr_w(pName
));
1907 SetLastError(ERROR_INVALID_NAME
);
1911 /* an empty Portname is Invalid */
1912 if (!pPortName
[0]) {
1913 SetLastError(ERROR_NOT_SUPPORTED
);
1917 pm
= monitor_load_by_port(pPortName
);
1918 if (pm
&& pm
->monitor
&& pm
->monitor
->pfnDeletePort
) {
1919 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm
->name
),
1920 debugstr_w(pPortName
), pm
, debugstr_w(pm
->dllname
));
1921 res
= pm
->monitor
->pfnDeletePort(pName
, hWnd
, pPortName
);
1922 TRACE("got %d with %u\n", res
, GetLastError());
1926 pui
= monitor_loadui(pm
);
1927 if (pui
&& pui
->monitorUI
&& pui
->monitorUI
->pfnDeletePortUI
) {
1928 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui
->name
),
1929 debugstr_w(pPortName
), pui
, debugstr_w(pui
->dllname
));
1930 res
= pui
->monitorUI
->pfnDeletePortUI(pName
, hWnd
, pPortName
);
1931 TRACE("got %d with %u\n", res
, GetLastError());
1935 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1936 debugstr_w(pPortName
), pm
, debugstr_w(pm
? pm
->dllname
: NULL
),
1937 pui
, debugstr_w(pui
? pui
->dllname
: NULL
));
1939 SetLastError(ERROR_NOT_SUPPORTED
);
1942 monitor_unload(pui
);
1946 TRACE("returning %d with %u\n", res
, GetLastError());
1950 /*****************************************************************************
1951 * fpEnumMonitors [exported through PRINTPROVIDOR]
1953 * Enumerate available Port-Monitors
1956 * pName [I] Servername or NULL (local Computer)
1957 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1958 * pMonitors [O] PTR to Buffer that receives the Result
1959 * cbBuf [I] Size of Buffer at pMonitors
1960 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1961 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1965 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1968 * Windows reads the Registry once and cache the Results.
1971 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1972 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1974 DWORD numentries
= 0;
1979 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1980 cbBuf
, pcbNeeded
, pcReturned
);
1982 lres
= copy_servername_from_name(pName
, NULL
);
1984 FIXME("server %s not supported\n", debugstr_w(pName
));
1985 SetLastError(ERROR_INVALID_NAME
);
1989 if (!Level
|| (Level
> 2)) {
1990 WARN("level (%d) is ignored in win9x\n", Level
);
1991 SetLastError(ERROR_INVALID_LEVEL
);
1995 /* Scan all Monitor-Keys */
1997 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1999 /* we calculated the needed buffersize. now do more error-checks */
2000 if (cbBuf
< needed
) {
2001 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2005 /* fill the Buffer with the Monitor-Keys */
2006 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
2010 if (pcbNeeded
) *pcbNeeded
= needed
;
2011 if (pcReturned
) *pcReturned
= numentries
;
2013 TRACE("returning %d with %d (%d byte for %d entries)\n",
2014 res
, GetLastError(), needed
, numentries
);
2019 /******************************************************************************
2020 * fpEnumPorts [exported through PRINTPROVIDOR]
2022 * Enumerate available Ports
2025 * pName [I] Servername or NULL (local Computer)
2026 * Level [I] Structure-Level (1 or 2)
2027 * pPorts [O] PTR to Buffer that receives the Result
2028 * cbBuf [I] Size of Buffer at pPorts
2029 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2030 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2034 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2037 static BOOL WINAPI
fpEnumPorts(LPWSTR pName
, DWORD Level
, LPBYTE pPorts
, DWORD cbBuf
,
2038 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2041 DWORD numentries
= 0;
2045 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pPorts
,
2046 cbBuf
, pcbNeeded
, pcReturned
);
2048 lres
= copy_servername_from_name(pName
, NULL
);
2050 FIXME("server %s not supported\n", debugstr_w(pName
));
2051 SetLastError(ERROR_INVALID_NAME
);
2055 if (!Level
|| (Level
> 2)) {
2056 SetLastError(ERROR_INVALID_LEVEL
);
2060 if (!pcbNeeded
|| (!pPorts
&& (cbBuf
> 0))) {
2061 SetLastError(RPC_X_NULL_REF_POINTER
);
2065 EnterCriticalSection(&monitor_handles_cs
);
2068 /* Scan all local Ports */
2070 needed
= get_ports_from_all_monitors(Level
, NULL
, 0, &numentries
);
2072 /* we calculated the needed buffersize. now do the error-checks */
2073 if (cbBuf
< needed
) {
2074 monitor_unloadall();
2075 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2076 goto emP_cleanup_cs
;
2078 else if (!pPorts
|| !pcReturned
) {
2079 monitor_unloadall();
2080 SetLastError(RPC_X_NULL_REF_POINTER
);
2081 goto emP_cleanup_cs
;
2084 /* Fill the Buffer */
2085 needed
= get_ports_from_all_monitors(Level
, pPorts
, cbBuf
, &numentries
);
2087 monitor_unloadall();
2090 LeaveCriticalSection(&monitor_handles_cs
);
2093 if (pcbNeeded
) *pcbNeeded
= needed
;
2094 if (pcReturned
) *pcReturned
= (res
) ? numentries
: 0;
2096 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2097 (res
), GetLastError(), needed
, (res
) ? numentries
: 0, numentries
);
2102 /*****************************************************************************
2103 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2105 * Enumerate available Print Processors
2108 * pName [I] Servername or NULL (local Computer)
2109 * pEnvironment [I] Printing-Environment or NULL (Default)
2110 * Level [I] Structure-Level (Only 1 is allowed)
2111 * pPPInfo [O] PTR to Buffer that receives the Result
2112 * cbBuf [I] Size of Buffer at pMonitors
2113 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2114 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2118 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2121 static BOOL WINAPI
fpEnumPrintProcessors(LPWSTR pName
, LPWSTR pEnvironment
, DWORD Level
,
2122 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
, LPDWORD pcReturned
)
2124 const printenv_t
* env
;
2125 LPWSTR regpathW
= NULL
;
2126 DWORD numentries
= 0;
2131 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2132 Level
, pPPInfo
, cbBuf
, pcbNeeded
, pcReturned
);
2134 lres
= copy_servername_from_name(pName
, NULL
);
2136 FIXME("server %s not supported\n", debugstr_w(pName
));
2137 SetLastError(ERROR_INVALID_NAME
);
2142 SetLastError(ERROR_INVALID_LEVEL
);
2146 env
= validate_envW(pEnvironment
);
2148 goto epp_cleanup
; /* ERROR_INVALID_ENVIRONMENT */
2150 regpathW
= heap_alloc(sizeof(fmt_printprocessorsW
) +
2151 (lstrlenW(env
->envname
) * sizeof(WCHAR
)));
2156 wsprintfW(regpathW
, fmt_printprocessorsW
, env
->envname
);
2158 /* Scan all Printprocessor-Keys */
2160 needed
= get_local_printprocessors(regpathW
, NULL
, 0, &numentries
);
2162 /* we calculated the needed buffersize. now do more error-checks */
2163 if (cbBuf
< needed
) {
2164 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2168 /* fill the Buffer with the Printprocessor Infos */
2169 needed
= get_local_printprocessors(regpathW
, pPPInfo
, cbBuf
, &numentries
);
2173 heap_free(regpathW
);
2174 if (pcbNeeded
) *pcbNeeded
= needed
;
2175 if (pcReturned
) *pcReturned
= numentries
;
2177 TRACE("returning %d with %d (%d byte for %d entries)\n",
2178 res
, GetLastError(), needed
, numentries
);
2183 /******************************************************************************
2184 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2186 * Return the PATH for the Print-Processors
2189 * pName [I] Servername or NULL (this computer)
2190 * pEnvironment [I] Printing-Environment or NULL (Default)
2191 * level [I] Structure-Level (must be 1)
2192 * pPPInfo [O] PTR to Buffer that receives the Result
2193 * cbBuf [I] Size of Buffer at pPPInfo
2194 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2198 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2200 * Native Values returned in pPPInfo on Success for this computer:
2201 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2202 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2203 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2205 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2208 static BOOL WINAPI
fpGetPrintProcessorDirectory(LPWSTR pName
, LPWSTR pEnvironment
, DWORD level
,
2209 LPBYTE pPPInfo
, DWORD cbBuf
, LPDWORD pcbNeeded
)
2211 const printenv_t
* env
;
2215 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
), debugstr_w(pEnvironment
),
2216 level
, pPPInfo
, cbBuf
, pcbNeeded
);
2219 lres
= copy_servername_from_name(pName
, NULL
);
2221 FIXME("server %s not supported\n", debugstr_w(pName
));
2222 SetLastError(RPC_S_SERVER_UNAVAILABLE
);
2226 env
= validate_envW(pEnvironment
);
2228 return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
2230 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2231 needed
= GetSystemDirectoryW(NULL
, 0);
2232 /* add the Size for the Subdirectories */
2233 needed
+= lstrlenW(spoolprtprocsW
);
2234 needed
+= lstrlenW(env
->subdir
);
2235 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
2237 *pcbNeeded
= needed
;
2239 if (needed
> cbBuf
) {
2240 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2244 GetSystemDirectoryW((LPWSTR
) pPPInfo
, cbBuf
/sizeof(WCHAR
));
2245 /* add the Subdirectories */
2246 lstrcatW((LPWSTR
) pPPInfo
, spoolprtprocsW
);
2247 lstrcatW((LPWSTR
) pPPInfo
, env
->subdir
);
2248 TRACE("==> %s\n", debugstr_w((LPWSTR
) pPPInfo
));
2252 /******************************************************************************
2253 * fpOpenPrinter [exported through PRINTPROVIDOR]
2255 * Open a Printer / Printserver or a Printer-Object
2258 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2259 * pPrinter [O] The resulting Handle is stored here
2260 * pDefaults [I] PTR to Default Printer Settings or NULL
2267 * lpPrinterName is one of:
2268 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2269 *| Printer: "PrinterName"
2270 *| Printer-Object: "PrinterName,Job xxx"
2271 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2272 *| XcvPort: "Servername,XcvPort PortName"
2276 static BOOL WINAPI
fpOpenPrinter(LPWSTR lpPrinterName
, HANDLE
*pPrinter
,
2277 LPPRINTER_DEFAULTSW pDefaults
)
2280 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName
), pPrinter
, pDefaults
);
2282 *pPrinter
= printer_alloc_handle(lpPrinterName
, pDefaults
);
2284 return (*pPrinter
!= 0);
2287 /******************************************************************************
2288 * fpXcvData [exported through PRINTPROVIDOR]
2290 * Execute commands in the Printmonitor DLL
2293 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2294 * pszDataName [i] Name of the command to execute
2295 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2296 * cbInputData [i] Size in Bytes of Buffer at pInputData
2297 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2298 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2299 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2300 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2307 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2308 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2310 * Minimal List of commands, that a Printmonitor DLL should support:
2312 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2313 *| "AddPort" : Add a Port
2314 *| "DeletePort": Delete a Port
2316 * Many Printmonitors support additional commands. Examples for localspl.dll:
2317 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2318 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2321 static BOOL WINAPI
fpXcvData(HANDLE hXcv
, LPCWSTR pszDataName
, PBYTE pInputData
,
2322 DWORD cbInputData
, PBYTE pOutputData
, DWORD cbOutputData
,
2323 PDWORD pcbOutputNeeded
, PDWORD pdwStatus
)
2325 printer_t
*printer
= (printer_t
* ) hXcv
;
2327 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv
, debugstr_w(pszDataName
),
2328 pInputData
, cbInputData
, pOutputData
,
2329 cbOutputData
, pcbOutputNeeded
, pdwStatus
);
2331 if (!printer
|| (!printer
->hXcv
)) {
2332 SetLastError(ERROR_INVALID_HANDLE
);
2336 if (!pcbOutputNeeded
) {
2337 SetLastError(ERROR_INVALID_PARAMETER
);
2341 if (!pszDataName
|| !pdwStatus
|| (!pOutputData
&& (cbOutputData
> 0))) {
2342 SetLastError(RPC_X_NULL_REF_POINTER
);
2346 *pcbOutputNeeded
= 0;
2348 *pdwStatus
= printer
->pm
->monitor
->pfnXcvDataPort(printer
->hXcv
, pszDataName
,
2349 pInputData
, cbInputData
, pOutputData
, cbOutputData
, pcbOutputNeeded
);
2354 /*****************************************************
2355 * setup_provider [internal]
2357 void setup_provider(void)
2359 static const PRINTPROVIDOR backend
= {
2361 NULL
, /* fpSetJob */
2362 NULL
, /* fpGetJob */
2363 NULL
, /* fpEnumJobs */
2364 NULL
, /* fpAddPrinter */
2365 NULL
, /* fpDeletePrinter */
2366 NULL
, /* fpSetPrinter */
2367 NULL
, /* fpGetPrinter */
2368 NULL
, /* fpEnumPrinters */
2369 NULL
, /* fpAddPrinterDriver */
2370 NULL
, /* fpEnumPrinterDrivers */
2371 NULL
, /* fpGetPrinterDriver */
2372 fpGetPrinterDriverDirectory
,
2373 NULL
, /* fpDeletePrinterDriver */
2374 NULL
, /* fpAddPrintProcessor */
2375 fpEnumPrintProcessors
,
2376 fpGetPrintProcessorDirectory
,
2377 NULL
, /* fpDeletePrintProcessor */
2378 NULL
, /* fpEnumPrintProcessorDatatypes */
2379 NULL
, /* fpStartDocPrinter */
2380 NULL
, /* fpStartPagePrinter */
2381 NULL
, /* fpWritePrinter */
2382 NULL
, /* fpEndPagePrinter */
2383 NULL
, /* fpAbortPrinter */
2384 NULL
, /* fpReadPrinter */
2385 NULL
, /* fpEndDocPrinter */
2386 NULL
, /* fpAddJob */
2387 NULL
, /* fpScheduleJob */
2388 NULL
, /* fpGetPrinterData */
2389 NULL
, /* fpSetPrinterData */
2390 NULL
, /* fpWaitForPrinterChange */
2392 NULL
, /* fpAddForm */
2393 NULL
, /* fpDeleteForm */
2394 NULL
, /* fpGetForm */
2395 NULL
, /* fpSetForm */
2396 NULL
, /* fpEnumForms */
2402 NULL
, /* fpCreatePrinterIC */
2403 NULL
, /* fpPlayGdiScriptOnPrinterIC */
2404 NULL
, /* fpDeletePrinterIC */
2405 NULL
, /* fpAddPrinterConnection */
2406 NULL
, /* fpDeletePrinterConnection */
2407 NULL
, /* fpPrinterMessageBox */
2410 NULL
, /* fpResetPrinter */
2411 NULL
, /* fpGetPrinterDriverEx */
2412 NULL
, /* fpFindFirstPrinterChangeNotification */
2413 NULL
, /* fpFindClosePrinterChangeNotification */
2415 NULL
, /* fpShutDown */
2416 NULL
, /* fpRefreshPrinterChangeNotification */
2417 NULL
, /* fpOpenPrinterEx */
2418 NULL
, /* fpAddPrinterEx */
2419 NULL
, /* fpSetPort */
2420 NULL
, /* fpEnumPrinterData */
2421 NULL
, /* fpDeletePrinterData */
2422 NULL
, /* fpClusterSplOpen */
2423 NULL
, /* fpClusterSplClose */
2424 NULL
, /* fpClusterSplIsAlive */
2425 NULL
, /* fpSetPrinterDataEx */
2426 NULL
, /* fpGetPrinterDataEx */
2427 NULL
, /* fpEnumPrinterDataEx */
2428 NULL
, /* fpEnumPrinterKey */
2429 NULL
, /* fpDeletePrinterDataEx */
2430 NULL
, /* fpDeletePrinterKey */
2431 NULL
, /* fpSeekPrinter */
2432 NULL
, /* fpDeletePrinterDriverEx */
2433 NULL
, /* fpAddPerMachineConnection */
2434 NULL
, /* fpDeletePerMachineConnection */
2435 NULL
, /* fpEnumPerMachineConnections */
2437 fpAddPrinterDriverEx
,
2438 NULL
, /* fpSplReadPrinter */
2439 NULL
, /* fpDriverUnloadComplete */
2440 NULL
, /* fpGetSpoolFileInfo */
2441 NULL
, /* fpCommitSpoolData */
2442 NULL
, /* fpCloseSpoolFileHandle */
2443 NULL
, /* fpFlushPrinter */
2444 NULL
, /* fpSendRecvBidiData */
2445 NULL
/* fpAddDriverCatalog */
2447 pprovider
= &backend
;
2451 /*****************************************************
2452 * InitializePrintProvidor (localspl.@)
2454 * Initialize the Printprovider
2457 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2458 * cbPrintProvidor [I] Size of Buffer in Bytes
2459 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2462 * Success: TRUE and pPrintProvidor filled
2466 * The RegistryPath should be:
2467 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2468 * but this Parameter is ignored in "localspl.dll".
2472 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
2473 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
2476 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
2477 memcpy(pPrintProvidor
, pprovider
,
2478 (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));