2 * Implementation of the Local Printmonitor
4 * Copyright 2006-2008 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
31 #include "ddk/winsplp.h"
34 #include "wine/list.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "localspl_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(localspl
);
41 /* ############################### */
43 static CRITICAL_SECTION monitor_handles_cs
;
44 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug
=
46 0, 0, &monitor_handles_cs
,
47 { &monitor_handles_cs_debug
.ProcessLocksList
, &monitor_handles_cs_debug
.ProcessLocksList
},
48 0, 0, { (DWORD_PTR
)(__FILE__
": monitor_handles_cs") }
50 static CRITICAL_SECTION monitor_handles_cs
= { &monitor_handles_cs_debug
, -1, 0, 0, 0, 0 };
52 /* ############################### */
55 WCHAR src
[MAX_PATH
+MAX_PATH
];
56 WCHAR dst
[MAX_PATH
+MAX_PATH
];
78 LPCWSTR versionregpath
;
79 LPCWSTR versionsubdir
;
83 /* ############################### */
85 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
86 static monitor_t
* pm_localport
;
88 HINSTANCE LOCALSPL_hInstance
= NULL
;
90 static const PRINTPROVIDOR
* pp
= NULL
;
92 static const WCHAR backslashW
[] = {'\\',0};
93 static const WCHAR configuration_fileW
[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
94 static const WCHAR datatypeW
[] = {'D','a','t','a','t','y','p','e',0};
95 static const WCHAR data_fileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
96 static const WCHAR default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
97 static const WCHAR dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
98 static const WCHAR descriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
99 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
100 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
101 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
102 'c','o','n','t','r','o','l','\\',
103 'P','r','i','n','t','\\',
104 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
105 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
106 static const WCHAR hardwareidW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
107 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
108 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
109 static const WCHAR locationW
[] = {'L','o','c','a','t','i','o','n',0};
110 static const WCHAR manufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
111 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
112 static const WCHAR monitorsW
[] = {'S','y','s','t','e','m','\\',
113 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
114 'C','o','n','t','r','o','l','\\',
115 'P','r','i','n','t','\\',
116 'M','o','n','i','t','o','r','s','\\',0};
117 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
118 static const WCHAR nameW
[] = {'N','a','m','e',0};
119 static const WCHAR oem_urlW
[] = {'O','E','M',' ','U','r','l',0};
120 static const WCHAR parametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
121 static const WCHAR portW
[] = {'P','o','r','t',0};
122 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
123 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
124 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
126 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
127 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
128 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
129 static const WCHAR version0_subdirW
[] = {'\\','0',0};
131 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
132 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
133 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
134 static const WCHAR version3_subdirW
[] = {'\\','3',0};
137 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
138 version3_regpathW
, version3_subdirW
};
140 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
141 version0_regpathW
, version0_subdirW
};
143 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_win40
};
146 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
147 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
148 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
149 0, sizeof(DRIVER_INFO_8W
)};
152 /******************************************************************
155 * create a copy of a unicode-string
159 static LPWSTR
strdupW(LPCWSTR p
)
165 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
166 ret
= heap_alloc(len
);
171 /******************************************************************
172 * apd_copyfile [internal]
174 * Copy a file from the driverdirectory to the versioned directory
181 static BOOL
apd_copyfile(LPWSTR filename
, apd_data_t
*apd
)
187 apd
->src
[apd
->srclen
] = '\0';
188 apd
->dst
[apd
->dstlen
] = '\0';
190 if (!filename
|| !filename
[0]) {
191 /* nothing to copy */
195 ptr
= strrchrW(filename
, '\\');
204 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
) {
205 /* we have an absolute Path */
211 lstrcatW(srcname
, ptr
);
213 lstrcatW(apd
->dst
, ptr
);
215 TRACE("%s => %s\n", debugstr_w(filename
), debugstr_w(apd
->dst
));
217 /* FIXME: handle APD_COPY_NEW_FILES */
218 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
219 TRACE("got %u with %u\n", res
, GetLastError());
221 return (apd
->lazy
) ? TRUE
: res
;
224 /******************************************************************
225 * copy_servername_from_name (internal)
227 * for an external server, the serverpart from the name is copied.
230 * the length (in WCHAR) of the serverpart (0 for the local computer)
231 * (-length), when the name is to long
234 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
238 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
242 if (target
) *target
= '\0';
244 if (name
== NULL
) return 0;
245 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
248 /* skip over both backslash, find separator '\' */
249 ptr
= strchrW(server
, '\\');
250 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
252 /* servername is empty or to long */
253 if (serverlen
== 0) return 0;
255 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
257 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
259 len
= sizeof(buffer
) / sizeof(buffer
[0]);
260 if (GetComputerNameW(buffer
, &len
)) {
261 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
262 /* The requested Servername is our computername */
264 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
265 target
[serverlen
] = '\0';
273 /******************************************************************
274 * monitor_unload [internal]
276 * release a printmonitor and unload it from memory, when needed
279 static void monitor_unload(monitor_t
* pm
)
281 if (pm
== NULL
) return;
282 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
284 EnterCriticalSection(&monitor_handles_cs
);
286 if (pm
->refcount
) pm
->refcount
--;
288 if (pm
->refcount
== 0) {
289 list_remove(&pm
->entry
);
290 FreeLibrary(pm
->hdll
);
292 heap_free(pm
->dllname
);
295 LeaveCriticalSection(&monitor_handles_cs
);
298 /******************************************************************
299 * monitor_load [internal]
301 * load a printmonitor, get the dllname from the registry, when needed
302 * initialize the monitor and dump found function-pointers
304 * On failure, SetLastError() is called and NULL is returned
307 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
309 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
310 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
311 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
312 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
313 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
315 monitor_t
* pm
= NULL
;
317 LPWSTR regroot
= NULL
;
318 LPWSTR driver
= dllname
;
320 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
321 /* Is the Monitor already loaded? */
322 EnterCriticalSection(&monitor_handles_cs
);
325 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
327 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
335 pm
= heap_alloc_zero(sizeof(monitor_t
));
336 if (pm
== NULL
) goto cleanup
;
337 list_add_tail(&monitor_handles
, &pm
->entry
);
341 if (pm
->name
== NULL
) {
342 /* Load the monitor */
343 LPMONITOREX pmonitorEx
;
347 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
348 regroot
= heap_alloc(len
* sizeof(WCHAR
));
352 lstrcpyW(regroot
, monitorsW
);
353 lstrcatW(regroot
, name
);
354 /* Get the Driver from the Registry */
355 if (driver
== NULL
) {
358 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
359 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
360 &namesize
) == ERROR_SUCCESS
) {
361 driver
= heap_alloc(namesize
);
362 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
369 pm
->name
= strdupW(name
);
370 pm
->dllname
= strdupW(driver
);
372 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
374 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
379 pm
->hdll
= LoadLibraryW(driver
);
380 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
382 if (pm
->hdll
== NULL
) {
384 SetLastError(ERROR_MOD_NOT_FOUND
);
389 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
390 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
391 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
392 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
393 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
396 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
397 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
398 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
399 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
400 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
402 if (pInitializePrintMonitorUI
!= NULL
) {
403 pm
->monitorUI
= pInitializePrintMonitorUI();
404 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
406 TRACE("0x%08x: dwMonitorSize (%d)\n",
407 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
412 if (pInitializePrintMonitor
&& regroot
) {
413 pmonitorEx
= pInitializePrintMonitor(regroot
);
414 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
415 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
418 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
419 pm
->monitor
= &(pmonitorEx
->Monitor
);
424 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
428 if (!pm
->monitor
&& regroot
) {
429 if (pInitializePrintMonitor2
!= NULL
) {
430 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
432 if (pInitializeMonitorEx
!= NULL
) {
433 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
435 if (pInitializeMonitor
!= NULL
) {
436 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
439 if (!pm
->monitor
&& !pm
->monitorUI
) {
441 SetLastError(ERROR_PROC_NOT_FOUND
);
446 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
450 LeaveCriticalSection(&monitor_handles_cs
);
451 if (driver
!= dllname
) heap_free(driver
);
453 TRACE("=> %p\n", pm
);
457 /******************************************************************
458 * Return the number of bytes for an multi_sz string.
459 * The result includes all \0s
460 * (specifically the extra \0, that is needed as multi_sz terminator).
462 static int multi_sz_lenW(const WCHAR
*str
)
464 const WCHAR
*ptr
= str
;
468 ptr
+= lstrlenW(ptr
) + 1;
471 return (ptr
- str
+ 1) * sizeof(WCHAR
);
474 /******************************************************************
475 * validate_envW [internal]
477 * validate the user-supplied printing-environment
480 * env [I] PTR to Environment-String or NULL
483 * Success: PTR to printenv_t
484 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
487 * An empty string is handled the same way as NULL.
491 static const printenv_t
* validate_envW(LPCWSTR env
)
493 const printenv_t
*result
= NULL
;
496 TRACE("(%s)\n", debugstr_w(env
));
499 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
501 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
503 result
= all_printenv
[i
];
507 if (result
== NULL
) {
508 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
509 SetLastError(ERROR_INVALID_ENVIRONMENT
);
511 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
515 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
518 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
522 /*****************************************************************************
523 * enumerate the local monitors (INTERNAL)
525 * returns the needed size (in bytes) for pMonitors
526 * and *lpreturned is set to number of entries returned in pMonitors
528 * Language-Monitors are also installed in the same Registry-Location but
529 * they are filtered in Windows (not returned by EnumMonitors).
530 * We do no filtering to simplify our Code.
533 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
538 LPMONITOR_INFO_2W mi
;
539 WCHAR buffer
[MAX_PATH
];
540 WCHAR dllname
[MAX_PATH
];
548 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
550 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
551 len
= entrysize
* numentries
;
552 ptr
= (LPWSTR
) &pMonitors
[len
];
555 len
= sizeof(buffer
)/sizeof(buffer
[0]);
558 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
559 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
560 /* Scan all Monitor-Registry-Keys */
561 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
562 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
563 dllsize
= sizeof(dllname
);
566 /* The Monitor must have a Driver-DLL */
567 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
568 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
569 /* We found a valid DLL for this Monitor. */
570 TRACE("using Driver: %s\n", debugstr_w(dllname
));
575 /* Windows returns only Port-Monitors here, but to simplify our code,
576 we do no filtering for Language-Monitors */
580 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
582 /* we install and return only monitors for "Windows NT x86" */
583 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
587 /* required size is calculated. Now fill the user-buffer */
588 if (pMonitors
&& (cbBuf
>= needed
)){
589 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
590 pMonitors
+= entrysize
;
592 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
594 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
595 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
597 mi
->pEnvironment
= ptr
;
598 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
599 ptr
+= (lstrlenW(x86_envnameW
)+1);
602 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
603 ptr
+= (dllsize
/ sizeof(WCHAR
));
608 len
= sizeof(buffer
)/sizeof(buffer
[0]);
613 *lpreturned
= numentries
;
614 TRACE("need %d byte for %d entries\n", needed
, numentries
);
618 /*****************************************************************************
619 * open_driver_reg [internal]
621 * opens the registry for the printer drivers depending on the given input
622 * variable pEnvironment
625 * Success: the opened hkey
628 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
632 const printenv_t
* env
;
634 TRACE("(%s)\n", debugstr_w(pEnvironment
));
636 env
= validate_envW(pEnvironment
);
637 if (!env
) return NULL
;
639 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
640 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
643 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
644 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
645 HeapFree(GetProcessHeap(), 0, buffer
);
650 /*****************************************************************************
651 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
653 * Return the PATH for the Printer-Drivers
656 * pName [I] Servername (NT only) or NULL (local Computer)
657 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
658 * Level [I] Structure-Level (must be 1)
659 * pDriverDirectory [O] PTR to Buffer that receives the Result
660 * cbBuf [I] Size of Buffer at pDriverDirectory
661 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
662 * required for pDriverDirectory
665 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
666 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
667 * if cbBuf is too small
669 * Native Values returned in pDriverDirectory on Success:
670 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
671 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
672 *| win9x(Windows 4.0): "%winsysdir%"
674 * "%winsysdir%" is the Value from GetSystemDirectoryW()
677 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
678 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
681 const printenv_t
* env
;
683 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
684 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
686 if (pName
!= NULL
&& pName
[0]) {
687 FIXME("server %s not supported\n", debugstr_w(pName
));
688 SetLastError(ERROR_INVALID_PARAMETER
);
692 env
= validate_envW(pEnvironment
);
693 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
696 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
697 needed
= GetSystemDirectoryW(NULL
, 0);
698 /* add the Size for the Subdirectories */
699 needed
+= lstrlenW(spooldriversW
);
700 needed
+= lstrlenW(env
->subdir
);
701 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
705 if (needed
> cbBuf
) {
706 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
710 if (pDriverDirectory
== NULL
) {
711 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
712 SetLastError(ERROR_INVALID_USER_BUFFER
);
716 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
717 /* add the Subdirectories */
718 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
719 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
721 TRACE("=> %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
725 /******************************************************************************
726 * myAddPrinterDriverEx [internal]
728 * Install a Printer Driver with the Option to upgrade / downgrade the Files
729 * and a special mode with lazy error checking.
732 static BOOL WINAPI
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
734 static const WCHAR emptyW
[1];
735 const printenv_t
*env
;
745 /* we need to set all entries in the Registry, independent from the Level of
746 DRIVER_INFO, that the caller supplied */
748 ZeroMemory(&di
, sizeof(di
));
749 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
750 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
753 /* dump the most used infos */
754 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
755 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
756 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
757 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
758 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
759 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
760 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
761 /* dump only the first of the additional Files */
762 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
765 /* check environment */
766 env
= validate_envW(di
.pEnvironment
);
767 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
769 /* fill the copy-data / get the driverdir */
770 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
771 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
772 (LPBYTE
) apd
.src
, len
, &len
)) {
773 /* Should never Fail */
776 memcpy(apd
.dst
, apd
.src
, len
);
777 lstrcatW(apd
.src
, backslashW
);
778 apd
.srclen
= lstrlenW(apd
.src
);
779 lstrcatW(apd
.dst
, env
->versionsubdir
);
780 lstrcatW(apd
.dst
, backslashW
);
781 apd
.dstlen
= lstrlenW(apd
.dst
);
782 apd
.copyflags
= dwFileCopyFlags
;
784 CreateDirectoryW(apd
.src
, NULL
);
785 CreateDirectoryW(apd
.dst
, NULL
);
787 hroot
= open_driver_reg(env
->envname
);
789 ERR("Can't create Drivers key\n");
793 /* Fill the Registry for the Driver */
794 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
795 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
796 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
798 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
805 if (disposition
== REG_OPENED_EXISTING_KEY
) {
806 TRACE("driver %s already installed\n", debugstr_w(di
.pName
));
808 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
812 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
813 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (LPBYTE
) &env
->driverversion
,
816 RegSetValueExW(hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
) di
.pDriverPath
,
817 (lstrlenW(di
.pDriverPath
)+1)* sizeof(WCHAR
));
818 apd_copyfile(di
.pDriverPath
, &apd
);
820 RegSetValueExW(hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pDataFile
,
821 (lstrlenW(di
.pDataFile
)+1)* sizeof(WCHAR
));
822 apd_copyfile(di
.pDataFile
, &apd
);
824 RegSetValueExW(hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pConfigFile
,
825 (lstrlenW(di
.pConfigFile
)+1)* sizeof(WCHAR
));
826 apd_copyfile(di
.pConfigFile
, &apd
);
828 /* settings for level 3 */
830 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pHelpFile
,
831 (lstrlenW(di
.pHelpFile
)+1)* sizeof(WCHAR
));
833 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
834 apd_copyfile(di
.pHelpFile
, &apd
);
837 ptr
= di
.pDependentFiles
;
839 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pDependentFiles
,
840 multi_sz_lenW(di
.pDependentFiles
));
842 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
843 while ((ptr
!= NULL
) && (ptr
[0])) {
844 if (apd_copyfile(ptr
, &apd
)) {
845 ptr
+= lstrlenW(ptr
) + 1;
849 WARN("Failed to copy %s\n", debugstr_w(ptr
));
853 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
855 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
856 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
858 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
860 if (di
.pDefaultDataType
)
861 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
862 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
864 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
866 /* settings for level 4 */
867 if (di
.pszzPreviousNames
)
868 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
869 multi_sz_lenW(di
.pszzPreviousNames
));
871 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
873 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
876 TRACE("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
878 TRACE("=> TRUE with %u\n", GetLastError());
883 /******************************************************************************
884 * fpAddMonitor [exported through PRINTPROVIDOR]
886 * Install a Printmonitor
889 * pName [I] Servername or NULL (local Computer)
890 * Level [I] Structure-Level (Must be 2)
891 * pMonitors [I] PTR to MONITOR_INFO_2
898 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
901 BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
903 monitor_t
* pm
= NULL
;
904 LPMONITOR_INFO_2W mi2w
;
910 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
911 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
912 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
913 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
914 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
916 if (copy_servername_from_name(pName
, NULL
)) {
917 FIXME("server %s not supported\n", debugstr_w(pName
));
918 SetLastError(ERROR_ACCESS_DENIED
);
922 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
923 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
924 SetLastError(ERROR_INVALID_PARAMETER
);
927 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
928 WARN("Environment %s requested (we support only %s)\n",
929 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
930 SetLastError(ERROR_INVALID_ENVIRONMENT
);
934 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
935 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
936 SetLastError(ERROR_INVALID_PARAMETER
);
940 /* Load and initialize the monitor. SetLastError() is called on failure */
941 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
946 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
947 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
951 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
952 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
953 &disposition
) == ERROR_SUCCESS
) {
955 /* Some installers set options for the port before calling AddMonitor.
956 We query the "Driver" entry to verify that the monitor is installed,
957 before we return an error.
958 When a user installs two print monitors at the same time with the
959 same name, a race condition is possible but silently ignored. */
963 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
964 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
965 &namesize
) == ERROR_SUCCESS
)) {
966 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
967 /* 9x use ERROR_ALREADY_EXISTS */
968 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
973 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
974 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
975 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
984 /******************************************************************************
985 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
987 * Install a Printer Driver with the Option to upgrade / downgrade the Files
990 * pName [I] Servername or NULL (local Computer)
991 * level [I] Level for the supplied DRIVER_INFO_*W struct
992 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
993 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1000 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1004 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1005 lres
= copy_servername_from_name(pName
, NULL
);
1007 FIXME("server %s not supported\n", debugstr_w(pName
));
1008 SetLastError(ERROR_ACCESS_DENIED
);
1012 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1013 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1016 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1018 /******************************************************************
1019 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1021 * Delete a specific Printmonitor from a Printing-Environment
1024 * pName [I] Servername or NULL (local Computer)
1025 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1026 * pMonitorName [I] Name of the Monitor, that should be deleted
1033 * pEnvironment is ignored in Windows for the local Computer.
1037 BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1042 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1043 debugstr_w(pMonitorName
));
1045 lres
= copy_servername_from_name(pName
, NULL
);
1047 FIXME("server %s not supported\n", debugstr_w(pName
));
1048 SetLastError(ERROR_INVALID_NAME
);
1052 /* pEnvironment is ignored in Windows for the local Computer */
1053 if (!pMonitorName
|| !pMonitorName
[0]) {
1054 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1055 SetLastError(ERROR_INVALID_PARAMETER
);
1059 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1060 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1064 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1065 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1070 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1073 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1074 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1078 /*****************************************************************************
1079 * fpEnumMonitors [exported through PRINTPROVIDOR]
1081 * Enumerate available Port-Monitors
1084 * pName [I] Servername or NULL (local Computer)
1085 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1086 * pMonitors [O] PTR to Buffer that receives the Result
1087 * cbBuf [I] Size of Buffer at pMonitors
1088 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1089 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1093 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
1096 * Windows reads the Registry once and cache the Results.
1099 BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1100 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1102 DWORD numentries
= 0;
1107 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1108 cbBuf
, pcbNeeded
, pcReturned
);
1110 lres
= copy_servername_from_name(pName
, NULL
);
1112 FIXME("server %s not supported\n", debugstr_w(pName
));
1113 SetLastError(ERROR_INVALID_NAME
);
1117 if (!Level
|| (Level
> 2)) {
1118 WARN("level (%d) is ignored in win9x\n", Level
);
1119 SetLastError(ERROR_INVALID_LEVEL
);
1123 /* Scan all Monitor-Keys */
1125 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1127 /* we calculated the needed buffersize. now do more error-checks */
1128 if (cbBuf
< needed
) {
1129 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1133 /* fill the Buffer with the Monitor-Keys */
1134 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
1138 if (pcbNeeded
) *pcbNeeded
= needed
;
1139 if (pcReturned
) *pcReturned
= numentries
;
1141 TRACE("returning %d with %d (%d byte for %d entries)\n",
1142 res
, GetLastError(), needed
, numentries
);
1147 /*****************************************************
1148 * get_backend [internal]
1150 static const PRINTPROVIDOR
* get_backend(void)
1152 static const PRINTPROVIDOR backend
= {
1153 NULL
, /* fpOpenPrinter */
1154 NULL
, /* fpSetJob */
1155 NULL
, /* fpGetJob */
1156 NULL
, /* fpEnumJobs */
1157 NULL
, /* fpAddPrinter */
1158 NULL
, /* fpDeletePrinter */
1159 NULL
, /* fpSetPrinter */
1160 NULL
, /* fpGetPrinter */
1161 NULL
, /* fpEnumPrinters */
1162 NULL
, /* fpAddPrinterDriver */
1163 NULL
, /* fpEnumPrinterDrivers */
1164 NULL
, /* fpGetPrinterDriver */
1165 fpGetPrinterDriverDirectory
,
1166 NULL
, /* fpDeletePrinterDriver */
1167 NULL
, /* fpAddPrintProcessor */
1168 NULL
, /* fpEnumPrintProcessors */
1169 NULL
, /* fpGetPrintProcessorDirectory */
1170 NULL
, /* fpDeletePrintProcessor */
1171 NULL
, /* fpEnumPrintProcessorDatatypes */
1172 NULL
, /* fpStartDocPrinter */
1173 NULL
, /* fpStartPagePrinter */
1174 NULL
, /* fpWritePrinter */
1175 NULL
, /* fpEndPagePrinter */
1176 NULL
, /* fpAbortPrinter */
1177 NULL
, /* fpReadPrinter */
1178 NULL
, /* fpEndDocPrinter */
1179 NULL
, /* fpAddJob */
1180 NULL
, /* fpScheduleJob */
1181 NULL
, /* fpGetPrinterData */
1182 NULL
, /* fpSetPrinterData */
1183 NULL
, /* fpWaitForPrinterChange */
1184 NULL
, /* fpClosePrinter */
1185 NULL
, /* fpAddForm */
1186 NULL
, /* fpDeleteForm */
1187 NULL
, /* fpGetForm */
1188 NULL
, /* fpSetForm */
1189 NULL
, /* fpEnumForms */
1191 NULL
, /* fpEnumPorts */
1192 NULL
, /* fpAddPort */
1193 NULL
, /* fpConfigurePort */
1194 NULL
, /* fpDeletePort */
1195 NULL
, /* fpCreatePrinterIC */
1196 NULL
, /* fpPlayGdiScriptOnPrinterIC */
1197 NULL
, /* fpDeletePrinterIC */
1198 NULL
, /* fpAddPrinterConnection */
1199 NULL
, /* fpDeletePrinterConnection */
1200 NULL
, /* fpPrinterMessageBox */
1203 NULL
, /* fpResetPrinter */
1204 NULL
, /* fpGetPrinterDriverEx */
1205 NULL
, /* fpFindFirstPrinterChangeNotification */
1206 NULL
, /* fpFindClosePrinterChangeNotification */
1207 NULL
, /* fpAddPortEx */
1208 NULL
, /* fpShutDown */
1209 NULL
, /* fpRefreshPrinterChangeNotification */
1210 NULL
, /* fpOpenPrinterEx */
1211 NULL
, /* fpAddPrinterEx */
1212 NULL
, /* fpSetPort */
1213 NULL
, /* fpEnumPrinterData */
1214 NULL
, /* fpDeletePrinterData */
1215 NULL
, /* fpClusterSplOpen */
1216 NULL
, /* fpClusterSplClose */
1217 NULL
, /* fpClusterSplIsAlive */
1218 NULL
, /* fpSetPrinterDataEx */
1219 NULL
, /* fpGetPrinterDataEx */
1220 NULL
, /* fpEnumPrinterDataEx */
1221 NULL
, /* fpEnumPrinterKey */
1222 NULL
, /* fpDeletePrinterDataEx */
1223 NULL
, /* fpDeletePrinterKey */
1224 NULL
, /* fpSeekPrinter */
1225 NULL
, /* fpDeletePrinterDriverEx */
1226 NULL
, /* fpAddPerMachineConnection */
1227 NULL
, /* fpDeletePerMachineConnection */
1228 NULL
, /* fpEnumPerMachineConnections */
1229 NULL
, /* fpXcvData */
1230 fpAddPrinterDriverEx
,
1231 NULL
, /* fpSplReadPrinter */
1232 NULL
, /* fpDriverUnloadComplete */
1233 NULL
, /* fpGetSpoolFileInfo */
1234 NULL
, /* fpCommitSpoolData */
1235 NULL
, /* fpCloseSpoolFileHandle */
1236 NULL
, /* fpFlushPrinter */
1237 NULL
, /* fpSendRecvBidiData */
1238 NULL
/* fpAddDriverCatalog */
1240 TRACE("=> %p\n", &backend
);
1245 /*****************************************************
1248 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
1250 TRACE("(%p, %d, %p)\n",hinstDLL
, fdwReason
, lpvReserved
);
1254 case DLL_WINE_PREATTACH
:
1255 return FALSE
; /* prefer native version */
1257 case DLL_PROCESS_ATTACH
:
1258 DisableThreadLibraryCalls( hinstDLL
);
1259 LOCALSPL_hInstance
= hinstDLL
;
1267 /*****************************************************
1268 * InitializePrintProvidor (localspl.@)
1270 * Initialize the Printprovider
1273 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
1274 * cbPrintProvidor [I] Size of Buffer in Bytes
1275 * pFullRegistryPath [I] Registry-Path for the Printprovidor
1278 * Success: TRUE and pPrintProvidor filled
1282 * The RegistryPath should be:
1283 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
1284 * but this Parameter is ignored in "localspl.dll".
1288 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
1289 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
1292 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
1293 memcpy(pPrintProvidor
, pp
, (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));