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
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
;
84 /* ############################### */
86 static struct list monitor_handles
= LIST_INIT( monitor_handles
);
87 static monitor_t
* pm_localport
;
89 HINSTANCE LOCALSPL_hInstance
= NULL
;
91 static const PRINTPROVIDOR
* pp
= NULL
;
93 static const WCHAR backslashW
[] = {'\\',0};
94 static const WCHAR configuration_fileW
[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
95 static const WCHAR datatypeW
[] = {'D','a','t','a','t','y','p','e',0};
96 static const WCHAR data_fileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
97 static const WCHAR default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
98 static const WCHAR dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
99 static const WCHAR descriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
100 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
101 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
102 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
103 'c','o','n','t','r','o','l','\\',
104 'P','r','i','n','t','\\',
105 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
106 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
107 static const WCHAR hardwareidW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
108 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
109 static const WCHAR localportW
[] = {'L','o','c','a','l',' ','P','o','r','t',0};
110 static const WCHAR locationW
[] = {'L','o','c','a','t','i','o','n',0};
111 static const WCHAR manufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
112 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
113 static const WCHAR monitorsW
[] = {'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 'M','o','n','i','t','o','r','s','\\',0};
118 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
119 static const WCHAR nameW
[] = {'N','a','m','e',0};
120 static const WCHAR oem_urlW
[] = {'O','E','M',' ','U','r','l',0};
121 static const WCHAR parametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
122 static const WCHAR portW
[] = {'P','o','r','t',0};
123 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
124 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
125 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
127 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
128 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
129 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
130 static const WCHAR version0_subdirW
[] = {'\\','0',0};
132 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
133 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
134 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
135 static const WCHAR version3_subdirW
[] = {'\\','3',0};
138 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
139 version3_regpathW
, version3_subdirW
};
141 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
142 version0_regpathW
, version0_subdirW
};
144 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_win40
};
147 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
148 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
149 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
150 0, sizeof(DRIVER_INFO_8W
)};
153 /******************************************************************
156 * create a copy of a unicode-string
160 static LPWSTR
strdupW(LPCWSTR p
)
166 len
= (lstrlenW(p
) + 1) * sizeof(WCHAR
);
167 ret
= heap_alloc(len
);
172 /******************************************************************
173 * apd_copyfile [internal]
175 * Copy a file from the driverdirectory to the versioned directory
182 static BOOL
apd_copyfile(LPWSTR filename
, apd_data_t
*apd
)
188 apd
->src
[apd
->srclen
] = '\0';
189 apd
->dst
[apd
->dstlen
] = '\0';
191 if (!filename
|| !filename
[0]) {
192 /* nothing to copy */
196 ptr
= strrchrW(filename
, '\\');
205 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
) {
206 /* we have an absolute Path */
212 lstrcatW(srcname
, ptr
);
214 lstrcatW(apd
->dst
, ptr
);
216 TRACE("%s => %s\n", debugstr_w(filename
), debugstr_w(apd
->dst
));
218 /* FIXME: handle APD_COPY_NEW_FILES */
219 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
220 TRACE("got %u with %u\n", res
, GetLastError());
222 return (apd
->lazy
) ? TRUE
: res
;
225 /******************************************************************
226 * copy_servername_from_name (internal)
228 * for an external server, the serverpart from the name is copied.
231 * the length (in WCHAR) of the serverpart (0 for the local computer)
232 * (-length), when the name is to long
235 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
239 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
243 if (target
) *target
= '\0';
245 if (name
== NULL
) return 0;
246 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
249 /* skip over both backslash, find separator '\' */
250 ptr
= strchrW(server
, '\\');
251 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
253 /* servername is empty or to long */
254 if (serverlen
== 0) return 0;
256 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
258 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
260 len
= sizeof(buffer
) / sizeof(buffer
[0]);
261 if (GetComputerNameW(buffer
, &len
)) {
262 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
263 /* The requested Servername is our computername */
265 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
266 target
[serverlen
] = '\0';
274 /******************************************************************
275 * monitor_unload [internal]
277 * release a printmonitor and unload it from memory, when needed
280 static void monitor_unload(monitor_t
* pm
)
282 if (pm
== NULL
) return;
283 TRACE("%p (refcount: %d) %s\n", pm
, pm
->refcount
, debugstr_w(pm
->name
));
285 EnterCriticalSection(&monitor_handles_cs
);
287 if (pm
->refcount
) pm
->refcount
--;
289 if (pm
->refcount
== 0) {
290 list_remove(&pm
->entry
);
291 FreeLibrary(pm
->hdll
);
293 heap_free(pm
->dllname
);
296 LeaveCriticalSection(&monitor_handles_cs
);
299 /******************************************************************
300 * monitor_load [internal]
302 * load a printmonitor, get the dllname from the registry, when needed
303 * initialize the monitor and dump found function-pointers
305 * On failure, SetLastError() is called and NULL is returned
308 static monitor_t
* monitor_load(LPCWSTR name
, LPWSTR dllname
)
310 LPMONITOR2 (WINAPI
*pInitializePrintMonitor2
) (PMONITORINIT
, LPHANDLE
);
311 PMONITORUI (WINAPI
*pInitializePrintMonitorUI
)(VOID
);
312 LPMONITOREX (WINAPI
*pInitializePrintMonitor
) (LPWSTR
);
313 DWORD (WINAPI
*pInitializeMonitorEx
)(LPWSTR
, LPMONITOR
);
314 DWORD (WINAPI
*pInitializeMonitor
) (LPWSTR
);
316 monitor_t
* pm
= NULL
;
318 LPWSTR regroot
= NULL
;
319 LPWSTR driver
= dllname
;
321 TRACE("(%s, %s)\n", debugstr_w(name
), debugstr_w(dllname
));
322 /* Is the Monitor already loaded? */
323 EnterCriticalSection(&monitor_handles_cs
);
326 LIST_FOR_EACH_ENTRY(cursor
, &monitor_handles
, monitor_t
, entry
)
328 if (cursor
->name
&& (lstrcmpW(name
, cursor
->name
) == 0)) {
336 pm
= heap_alloc_zero(sizeof(monitor_t
));
337 if (pm
== NULL
) goto cleanup
;
338 list_add_tail(&monitor_handles
, &pm
->entry
);
342 if (pm
->name
== NULL
) {
343 /* Load the monitor */
344 LPMONITOREX pmonitorEx
;
348 len
= lstrlenW(monitorsW
) + lstrlenW(name
) + 2;
349 regroot
= heap_alloc(len
* sizeof(WCHAR
));
353 lstrcpyW(regroot
, monitorsW
);
354 lstrcatW(regroot
, name
);
355 /* Get the Driver from the Registry */
356 if (driver
== NULL
) {
359 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
, regroot
, &hroot
) == ERROR_SUCCESS
) {
360 if (RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, NULL
,
361 &namesize
) == ERROR_SUCCESS
) {
362 driver
= heap_alloc(namesize
);
363 RegQueryValueExW(hroot
, driverW
, NULL
, NULL
, (LPBYTE
) driver
, &namesize
) ;
370 pm
->name
= strdupW(name
);
371 pm
->dllname
= strdupW(driver
);
373 if ((name
&& (!regroot
|| !pm
->name
)) || !pm
->dllname
) {
375 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
380 pm
->hdll
= LoadLibraryW(driver
);
381 TRACE("%p: LoadLibrary(%s) => %d\n", pm
->hdll
, debugstr_w(driver
), GetLastError());
383 if (pm
->hdll
== NULL
) {
385 SetLastError(ERROR_MOD_NOT_FOUND
);
390 pInitializePrintMonitor2
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor2");
391 pInitializePrintMonitorUI
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitorUI");
392 pInitializePrintMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializePrintMonitor");
393 pInitializeMonitorEx
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitorEx");
394 pInitializeMonitor
= (void *)GetProcAddress(pm
->hdll
, "InitializeMonitor");
397 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2
, debugstr_w(driver
));
398 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI
, debugstr_w(driver
));
399 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor
, debugstr_w(driver
));
400 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx
, debugstr_w(driver
));
401 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor
, debugstr_w(driver
));
403 if (pInitializePrintMonitorUI
!= NULL
) {
404 pm
->monitorUI
= pInitializePrintMonitorUI();
405 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm
->monitorUI
, debugstr_w(driver
));
407 TRACE("0x%08x: dwMonitorSize (%d)\n",
408 pm
->monitorUI
->dwMonitorUISize
, pm
->monitorUI
->dwMonitorUISize
);
413 if (pInitializePrintMonitor
&& regroot
) {
414 pmonitorEx
= pInitializePrintMonitor(regroot
);
415 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
416 pmonitorEx
, debugstr_w(driver
), debugstr_w(regroot
));
419 pm
->dwMonitorSize
= pmonitorEx
->dwMonitorSize
;
420 pm
->monitor
= &(pmonitorEx
->Monitor
);
425 TRACE("0x%08x: dwMonitorSize (%d)\n", pm
->dwMonitorSize
, pm
->dwMonitorSize
);
429 if (!pm
->monitor
&& regroot
) {
430 if (pInitializePrintMonitor2
!= NULL
) {
431 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver
));
433 if (pInitializeMonitorEx
!= NULL
) {
434 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver
));
436 if (pInitializeMonitor
!= NULL
) {
437 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver
));
440 if (!pm
->monitor
&& !pm
->monitorUI
) {
442 SetLastError(ERROR_PROC_NOT_FOUND
);
447 if ((pm_localport
== NULL
) && (pm
!= NULL
) && (lstrcmpW(pm
->name
, localportW
) == 0)) {
451 LeaveCriticalSection(&monitor_handles_cs
);
452 if (driver
!= dllname
) heap_free(driver
);
454 TRACE("=> %p\n", pm
);
458 /******************************************************************
459 * Return the number of bytes for an multi_sz string.
460 * The result includes all \0s
461 * (specifically the extra \0, that is needed as multi_sz terminator).
463 static int multi_sz_lenW(const WCHAR
*str
)
465 const WCHAR
*ptr
= str
;
469 ptr
+= lstrlenW(ptr
) + 1;
472 return (ptr
- str
+ 1) * sizeof(WCHAR
);
475 /******************************************************************
476 * validate_envW [internal]
478 * validate the user-supplied printing-environment
481 * env [I] PTR to Environment-String or NULL
484 * Success: PTR to printenv_t
485 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
488 * An empty string is handled the same way as NULL.
492 static const printenv_t
* validate_envW(LPCWSTR env
)
494 const printenv_t
*result
= NULL
;
497 TRACE("(%s)\n", debugstr_w(env
));
500 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
502 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
504 result
= all_printenv
[i
];
508 if (result
== NULL
) {
509 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
510 SetLastError(ERROR_INVALID_ENVIRONMENT
);
512 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
516 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
519 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
523 /*****************************************************************************
524 * enumerate the local monitors (INTERNAL)
526 * returns the needed size (in bytes) for pMonitors
527 * and *lpreturned is set to number of entries returned in pMonitors
529 * Language-Monitors are also installed in the same Registry-Location but
530 * they are filtered in Windows (not returned by EnumMonitors).
531 * We do no filtering to simplify our Code.
534 static DWORD
get_local_monitors(DWORD level
, LPBYTE pMonitors
, DWORD cbBuf
, LPDWORD lpreturned
)
539 LPMONITOR_INFO_2W mi
;
540 WCHAR buffer
[MAX_PATH
];
541 WCHAR dllname
[MAX_PATH
];
549 entrysize
= (level
== 1) ? sizeof(MONITOR_INFO_1W
) : sizeof(MONITOR_INFO_2W
);
551 numentries
= *lpreturned
; /* this is 0, when we scan the registry */
552 len
= entrysize
* numentries
;
553 ptr
= (LPWSTR
) &pMonitors
[len
];
556 len
= sizeof(buffer
)/sizeof(buffer
[0]);
559 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
560 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) == ERROR_SUCCESS
) {
561 /* Scan all Monitor-Registry-Keys */
562 while (RegEnumKeyExW(hroot
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
) {
563 TRACE("Monitor_%d: %s\n", numentries
, debugstr_w(buffer
));
564 dllsize
= sizeof(dllname
);
567 /* The Monitor must have a Driver-DLL */
568 if (RegOpenKeyExW(hroot
, buffer
, 0, KEY_READ
, &hentry
) == ERROR_SUCCESS
) {
569 if (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, (LPBYTE
) dllname
, &dllsize
) == ERROR_SUCCESS
) {
570 /* We found a valid DLL for this Monitor. */
571 TRACE("using Driver: %s\n", debugstr_w(dllname
));
576 /* Windows returns only Port-Monitors here, but to simplify our code,
577 we do no filtering for Language-Monitors */
581 needed
+= (len
+1) * sizeof(WCHAR
); /* len is lstrlenW(monitorname) */
583 /* we install and return only monitors for "Windows NT x86" */
584 needed
+= (lstrlenW(x86_envnameW
) +1) * sizeof(WCHAR
);
588 /* required size is calculated. Now fill the user-buffer */
589 if (pMonitors
&& (cbBuf
>= needed
)){
590 mi
= (LPMONITOR_INFO_2W
) pMonitors
;
591 pMonitors
+= entrysize
;
593 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi
, level
, numentries
);
595 lstrcpyW(ptr
, buffer
); /* Name of the Monitor */
596 ptr
+= (len
+1); /* len is lstrlenW(monitorname) */
598 mi
->pEnvironment
= ptr
;
599 lstrcpyW(ptr
, x86_envnameW
); /* fixed to "Windows NT x86" */
600 ptr
+= (lstrlenW(x86_envnameW
)+1);
603 lstrcpyW(ptr
, dllname
); /* Name of the Driver-DLL */
604 ptr
+= (dllsize
/ sizeof(WCHAR
));
609 len
= sizeof(buffer
)/sizeof(buffer
[0]);
614 *lpreturned
= numentries
;
615 TRACE("need %d byte for %d entries\n", needed
, numentries
);
619 /*****************************************************************************
620 * open_driver_reg [internal]
622 * opens the registry for the printer drivers depending on the given input
623 * variable pEnvironment
626 * Success: the opened hkey
629 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
633 const printenv_t
* env
;
635 TRACE("(%s)\n", debugstr_w(pEnvironment
));
637 env
= validate_envW(pEnvironment
);
638 if (!env
) return NULL
;
640 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
641 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
644 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
645 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
646 HeapFree(GetProcessHeap(), 0, buffer
);
651 /*****************************************************************************
652 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
654 * Return the PATH for the Printer-Drivers
657 * pName [I] Servername (NT only) or NULL (local Computer)
658 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
659 * Level [I] Structure-Level (must be 1)
660 * pDriverDirectory [O] PTR to Buffer that receives the Result
661 * cbBuf [I] Size of Buffer at pDriverDirectory
662 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
663 * required for pDriverDirectory
666 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
667 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
668 * if cbBuf is too small
670 * Native Values returned in pDriverDirectory on Success:
671 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
672 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
673 *| win9x(Windows 4.0): "%winsysdir%"
675 * "%winsysdir%" is the Value from GetSystemDirectoryW()
678 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
679 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
682 const printenv_t
* env
;
684 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
685 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
687 if (pName
!= NULL
&& pName
[0]) {
688 FIXME("server %s not supported\n", debugstr_w(pName
));
689 SetLastError(ERROR_INVALID_PARAMETER
);
693 env
= validate_envW(pEnvironment
);
694 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
697 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
698 needed
= GetSystemDirectoryW(NULL
, 0);
699 /* add the Size for the Subdirectories */
700 needed
+= lstrlenW(spooldriversW
);
701 needed
+= lstrlenW(env
->subdir
);
702 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
706 if (needed
> cbBuf
) {
707 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
711 if (pDriverDirectory
== NULL
) {
712 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
713 SetLastError(ERROR_INVALID_USER_BUFFER
);
717 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
718 /* add the Subdirectories */
719 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
720 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
722 TRACE("=> %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
726 /******************************************************************
727 * driver_load [internal]
729 * load a driver user interface dll
731 * On failure, NULL is returned
735 static HMODULE
driver_load(const printenv_t
* env
, LPWSTR dllname
)
737 WCHAR fullname
[MAX_PATH
];
741 TRACE("(%p, %s)\n", env
, debugstr_w(dllname
));
743 /* build the driverdir */
744 len
= sizeof(fullname
) -
745 (lstrlenW(env
->versionsubdir
) + 1 + lstrlenW(dllname
) + 1) * sizeof(WCHAR
);
747 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
748 (LPBYTE
) fullname
, len
, &len
)) {
749 /* Should never Fail */
750 SetLastError(ERROR_BUFFER_OVERFLOW
);
754 lstrcatW(fullname
, env
->versionsubdir
);
755 lstrcatW(fullname
, backslashW
);
756 lstrcatW(fullname
, dllname
);
758 hui
= LoadLibraryW(fullname
);
759 TRACE("%p: LoadLibrary(%s) %d\n", hui
, debugstr_w(fullname
), GetLastError());
764 /******************************************************************************
765 * myAddPrinterDriverEx [internal]
767 * Install a Printer Driver with the Option to upgrade / downgrade the Files
768 * and a special mode with lazy error checking.
771 static BOOL
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
773 static const WCHAR emptyW
[1];
774 const printenv_t
*env
;
777 BOOL (WINAPI
*pDrvDriverEvent
)(DWORD
, DWORD
, LPBYTE
, LPARAM
);
787 /* we need to set all entries in the Registry, independent from the Level of
788 DRIVER_INFO, that the caller supplied */
790 ZeroMemory(&di
, sizeof(di
));
791 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
792 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
795 /* dump the most used infos */
796 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
797 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
798 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
799 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
800 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
801 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
802 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
803 /* dump only the first of the additional Files */
804 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
807 /* check environment */
808 env
= validate_envW(di
.pEnvironment
);
809 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
811 /* fill the copy-data / get the driverdir */
812 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
813 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
814 (LPBYTE
) apd
.src
, len
, &len
)) {
815 /* Should never Fail */
818 memcpy(apd
.dst
, apd
.src
, len
);
819 lstrcatW(apd
.src
, backslashW
);
820 apd
.srclen
= lstrlenW(apd
.src
);
821 lstrcatW(apd
.dst
, env
->versionsubdir
);
822 lstrcatW(apd
.dst
, backslashW
);
823 apd
.dstlen
= lstrlenW(apd
.dst
);
824 apd
.copyflags
= dwFileCopyFlags
;
826 CreateDirectoryW(apd
.src
, NULL
);
827 CreateDirectoryW(apd
.dst
, NULL
);
829 hroot
= open_driver_reg(env
->envname
);
831 ERR("Can't create Drivers key\n");
835 /* Fill the Registry for the Driver */
836 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
837 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
838 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
840 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
847 if (disposition
== REG_OPENED_EXISTING_KEY
) {
848 TRACE("driver %s already installed\n", debugstr_w(di
.pName
));
850 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
854 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
855 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (LPBYTE
) &env
->driverversion
,
858 RegSetValueExW(hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
) di
.pDriverPath
,
859 (lstrlenW(di
.pDriverPath
)+1)* sizeof(WCHAR
));
860 apd_copyfile(di
.pDriverPath
, &apd
);
862 RegSetValueExW(hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pDataFile
,
863 (lstrlenW(di
.pDataFile
)+1)* sizeof(WCHAR
));
864 apd_copyfile(di
.pDataFile
, &apd
);
866 RegSetValueExW(hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pConfigFile
,
867 (lstrlenW(di
.pConfigFile
)+1)* sizeof(WCHAR
));
868 apd_copyfile(di
.pConfigFile
, &apd
);
870 /* settings for level 3 */
872 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pHelpFile
,
873 (lstrlenW(di
.pHelpFile
)+1)* sizeof(WCHAR
));
875 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
876 apd_copyfile(di
.pHelpFile
, &apd
);
879 ptr
= di
.pDependentFiles
;
881 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pDependentFiles
,
882 multi_sz_lenW(di
.pDependentFiles
));
884 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
885 while ((ptr
!= NULL
) && (ptr
[0])) {
886 if (apd_copyfile(ptr
, &apd
)) {
887 ptr
+= lstrlenW(ptr
) + 1;
891 WARN("Failed to copy %s\n", debugstr_w(ptr
));
895 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
897 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
898 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
900 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
902 if (di
.pDefaultDataType
)
903 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
904 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
906 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
908 /* settings for level 4 */
909 if (di
.pszzPreviousNames
)
910 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
911 multi_sz_lenW(di
.pszzPreviousNames
));
913 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
915 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
918 hui
= driver_load(env
, di
.pConfigFile
);
919 pDrvDriverEvent
= (void *)GetProcAddress(hui
, "DrvDriverEvent");
920 if (hui
&& pDrvDriverEvent
) {
922 /* Support for DrvDriverEvent is optional */
923 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di
.pName
), debugstr_w(di
.pConfigFile
));
924 /* MSDN: level for DRIVER_INFO is 1 to 3 */
925 res
= pDrvDriverEvent(DRIVER_EVENT_INITIALIZE
, 3, (LPBYTE
) &di
, 0);
926 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res
);
930 TRACE("=> TRUE with %u\n", GetLastError());
935 /******************************************************************************
936 * fpAddMonitor [exported through PRINTPROVIDOR]
938 * Install a Printmonitor
941 * pName [I] Servername or NULL (local Computer)
942 * Level [I] Structure-Level (Must be 2)
943 * pMonitors [I] PTR to MONITOR_INFO_2
950 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
953 static BOOL WINAPI
fpAddMonitor(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
)
955 monitor_t
* pm
= NULL
;
956 LPMONITOR_INFO_2W mi2w
;
962 mi2w
= (LPMONITOR_INFO_2W
) pMonitors
;
963 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName
), Level
, pMonitors
,
964 debugstr_w(mi2w
? mi2w
->pName
: NULL
),
965 debugstr_w(mi2w
? mi2w
->pEnvironment
: NULL
),
966 debugstr_w(mi2w
? mi2w
->pDLLName
: NULL
));
968 if (copy_servername_from_name(pName
, NULL
)) {
969 FIXME("server %s not supported\n", debugstr_w(pName
));
970 SetLastError(ERROR_ACCESS_DENIED
);
974 if (!mi2w
->pName
|| (! mi2w
->pName
[0])) {
975 WARN("pName not valid : %s\n", debugstr_w(mi2w
->pName
));
976 SetLastError(ERROR_INVALID_PARAMETER
);
979 if (!mi2w
->pEnvironment
|| lstrcmpW(mi2w
->pEnvironment
, x86_envnameW
)) {
980 WARN("Environment %s requested (we support only %s)\n",
981 debugstr_w(mi2w
->pEnvironment
), debugstr_w(x86_envnameW
));
982 SetLastError(ERROR_INVALID_ENVIRONMENT
);
986 if (!mi2w
->pDLLName
|| (! mi2w
->pDLLName
[0])) {
987 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w
->pDLLName
));
988 SetLastError(ERROR_INVALID_PARAMETER
);
992 /* Load and initialize the monitor. SetLastError() is called on failure */
993 if ((pm
= monitor_load(mi2w
->pName
, mi2w
->pDLLName
)) == NULL
) {
998 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
999 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1003 if (RegCreateKeyExW(hroot
, mi2w
->pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
1004 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
, &hentry
,
1005 &disposition
) == ERROR_SUCCESS
) {
1007 /* Some installers set options for the port before calling AddMonitor.
1008 We query the "Driver" entry to verify that the monitor is installed,
1009 before we return an error.
1010 When a user installs two print monitors at the same time with the
1011 same name, a race condition is possible but silently ignored. */
1015 if ((disposition
== REG_OPENED_EXISTING_KEY
) &&
1016 (RegQueryValueExW(hentry
, driverW
, NULL
, NULL
, NULL
,
1017 &namesize
) == ERROR_SUCCESS
)) {
1018 TRACE("monitor %s already exists\n", debugstr_w(mi2w
->pName
));
1019 /* 9x use ERROR_ALREADY_EXISTS */
1020 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED
);
1025 len
= (lstrlenW(mi2w
->pDLLName
) +1) * sizeof(WCHAR
);
1026 res
= (RegSetValueExW(hentry
, driverW
, 0, REG_SZ
,
1027 (LPBYTE
) mi2w
->pDLLName
, len
) == ERROR_SUCCESS
);
1029 RegCloseKey(hentry
);
1036 /******************************************************************************
1037 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1039 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1042 * pName [I] Servername or NULL (local Computer)
1043 * level [I] Level for the supplied DRIVER_INFO_*W struct
1044 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1045 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1052 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
1056 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
1057 lres
= copy_servername_from_name(pName
, NULL
);
1059 FIXME("server %s not supported\n", debugstr_w(pName
));
1060 SetLastError(ERROR_ACCESS_DENIED
);
1064 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
1065 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
1068 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
1070 /******************************************************************
1071 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1073 * Delete a specific Printmonitor from a Printing-Environment
1076 * pName [I] Servername or NULL (local Computer)
1077 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1078 * pMonitorName [I] Name of the Monitor, that should be deleted
1085 * pEnvironment is ignored in Windows for the local Computer.
1089 static BOOL WINAPI
fpDeleteMonitor(LPWSTR pName
, LPWSTR pEnvironment
, LPWSTR pMonitorName
)
1094 TRACE("(%s, %s, %s)\n",debugstr_w(pName
),debugstr_w(pEnvironment
),
1095 debugstr_w(pMonitorName
));
1097 lres
= copy_servername_from_name(pName
, NULL
);
1099 FIXME("server %s not supported\n", debugstr_w(pName
));
1100 SetLastError(ERROR_INVALID_NAME
);
1104 /* pEnvironment is ignored in Windows for the local Computer */
1105 if (!pMonitorName
|| !pMonitorName
[0]) {
1106 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName
));
1107 SetLastError(ERROR_INVALID_PARAMETER
);
1111 if(RegCreateKeyW(HKEY_LOCAL_MACHINE
, monitorsW
, &hroot
) != ERROR_SUCCESS
) {
1112 ERR("unable to create key %s\n", debugstr_w(monitorsW
));
1116 if(RegDeleteTreeW(hroot
, pMonitorName
) == ERROR_SUCCESS
) {
1117 TRACE("%s deleted\n", debugstr_w(pMonitorName
));
1122 TRACE("%s does not exist\n", debugstr_w(pMonitorName
));
1125 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1126 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR
);
1130 /*****************************************************************************
1131 * fpEnumMonitors [exported through PRINTPROVIDOR]
1133 * Enumerate available Port-Monitors
1136 * pName [I] Servername or NULL (local Computer)
1137 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1138 * pMonitors [O] PTR to Buffer that receives the Result
1139 * cbBuf [I] Size of Buffer at pMonitors
1140 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1141 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1145 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
1148 * Windows reads the Registry once and cache the Results.
1151 static BOOL WINAPI
fpEnumMonitors(LPWSTR pName
, DWORD Level
, LPBYTE pMonitors
, DWORD cbBuf
,
1152 LPDWORD pcbNeeded
, LPDWORD pcReturned
)
1154 DWORD numentries
= 0;
1159 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName
), Level
, pMonitors
,
1160 cbBuf
, pcbNeeded
, pcReturned
);
1162 lres
= copy_servername_from_name(pName
, NULL
);
1164 FIXME("server %s not supported\n", debugstr_w(pName
));
1165 SetLastError(ERROR_INVALID_NAME
);
1169 if (!Level
|| (Level
> 2)) {
1170 WARN("level (%d) is ignored in win9x\n", Level
);
1171 SetLastError(ERROR_INVALID_LEVEL
);
1175 /* Scan all Monitor-Keys */
1177 needed
= get_local_monitors(Level
, NULL
, 0, &numentries
);
1179 /* we calculated the needed buffersize. now do more error-checks */
1180 if (cbBuf
< needed
) {
1181 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1185 /* fill the Buffer with the Monitor-Keys */
1186 needed
= get_local_monitors(Level
, pMonitors
, cbBuf
, &numentries
);
1190 if (pcbNeeded
) *pcbNeeded
= needed
;
1191 if (pcReturned
) *pcReturned
= numentries
;
1193 TRACE("returning %d with %d (%d byte for %d entries)\n",
1194 res
, GetLastError(), needed
, numentries
);
1199 /*****************************************************
1200 * get_backend [internal]
1202 static const PRINTPROVIDOR
* get_backend(void)
1204 static const PRINTPROVIDOR backend
= {
1205 NULL
, /* fpOpenPrinter */
1206 NULL
, /* fpSetJob */
1207 NULL
, /* fpGetJob */
1208 NULL
, /* fpEnumJobs */
1209 NULL
, /* fpAddPrinter */
1210 NULL
, /* fpDeletePrinter */
1211 NULL
, /* fpSetPrinter */
1212 NULL
, /* fpGetPrinter */
1213 NULL
, /* fpEnumPrinters */
1214 NULL
, /* fpAddPrinterDriver */
1215 NULL
, /* fpEnumPrinterDrivers */
1216 NULL
, /* fpGetPrinterDriver */
1217 fpGetPrinterDriverDirectory
,
1218 NULL
, /* fpDeletePrinterDriver */
1219 NULL
, /* fpAddPrintProcessor */
1220 NULL
, /* fpEnumPrintProcessors */
1221 NULL
, /* fpGetPrintProcessorDirectory */
1222 NULL
, /* fpDeletePrintProcessor */
1223 NULL
, /* fpEnumPrintProcessorDatatypes */
1224 NULL
, /* fpStartDocPrinter */
1225 NULL
, /* fpStartPagePrinter */
1226 NULL
, /* fpWritePrinter */
1227 NULL
, /* fpEndPagePrinter */
1228 NULL
, /* fpAbortPrinter */
1229 NULL
, /* fpReadPrinter */
1230 NULL
, /* fpEndDocPrinter */
1231 NULL
, /* fpAddJob */
1232 NULL
, /* fpScheduleJob */
1233 NULL
, /* fpGetPrinterData */
1234 NULL
, /* fpSetPrinterData */
1235 NULL
, /* fpWaitForPrinterChange */
1236 NULL
, /* fpClosePrinter */
1237 NULL
, /* fpAddForm */
1238 NULL
, /* fpDeleteForm */
1239 NULL
, /* fpGetForm */
1240 NULL
, /* fpSetForm */
1241 NULL
, /* fpEnumForms */
1243 NULL
, /* fpEnumPorts */
1244 NULL
, /* fpAddPort */
1245 NULL
, /* fpConfigurePort */
1246 NULL
, /* fpDeletePort */
1247 NULL
, /* fpCreatePrinterIC */
1248 NULL
, /* fpPlayGdiScriptOnPrinterIC */
1249 NULL
, /* fpDeletePrinterIC */
1250 NULL
, /* fpAddPrinterConnection */
1251 NULL
, /* fpDeletePrinterConnection */
1252 NULL
, /* fpPrinterMessageBox */
1255 NULL
, /* fpResetPrinter */
1256 NULL
, /* fpGetPrinterDriverEx */
1257 NULL
, /* fpFindFirstPrinterChangeNotification */
1258 NULL
, /* fpFindClosePrinterChangeNotification */
1259 NULL
, /* fpAddPortEx */
1260 NULL
, /* fpShutDown */
1261 NULL
, /* fpRefreshPrinterChangeNotification */
1262 NULL
, /* fpOpenPrinterEx */
1263 NULL
, /* fpAddPrinterEx */
1264 NULL
, /* fpSetPort */
1265 NULL
, /* fpEnumPrinterData */
1266 NULL
, /* fpDeletePrinterData */
1267 NULL
, /* fpClusterSplOpen */
1268 NULL
, /* fpClusterSplClose */
1269 NULL
, /* fpClusterSplIsAlive */
1270 NULL
, /* fpSetPrinterDataEx */
1271 NULL
, /* fpGetPrinterDataEx */
1272 NULL
, /* fpEnumPrinterDataEx */
1273 NULL
, /* fpEnumPrinterKey */
1274 NULL
, /* fpDeletePrinterDataEx */
1275 NULL
, /* fpDeletePrinterKey */
1276 NULL
, /* fpSeekPrinter */
1277 NULL
, /* fpDeletePrinterDriverEx */
1278 NULL
, /* fpAddPerMachineConnection */
1279 NULL
, /* fpDeletePerMachineConnection */
1280 NULL
, /* fpEnumPerMachineConnections */
1281 NULL
, /* fpXcvData */
1282 fpAddPrinterDriverEx
,
1283 NULL
, /* fpSplReadPrinter */
1284 NULL
, /* fpDriverUnloadComplete */
1285 NULL
, /* fpGetSpoolFileInfo */
1286 NULL
, /* fpCommitSpoolData */
1287 NULL
, /* fpCloseSpoolFileHandle */
1288 NULL
, /* fpFlushPrinter */
1289 NULL
, /* fpSendRecvBidiData */
1290 NULL
/* fpAddDriverCatalog */
1292 TRACE("=> %p\n", &backend
);
1297 /*****************************************************
1300 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
1302 TRACE("(%p, %d, %p)\n",hinstDLL
, fdwReason
, lpvReserved
);
1306 case DLL_WINE_PREATTACH
:
1307 return FALSE
; /* prefer native version */
1309 case DLL_PROCESS_ATTACH
:
1310 DisableThreadLibraryCalls( hinstDLL
);
1311 LOCALSPL_hInstance
= hinstDLL
;
1319 /*****************************************************
1320 * InitializePrintProvidor (localspl.@)
1322 * Initialize the Printprovider
1325 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
1326 * cbPrintProvidor [I] Size of Buffer in Bytes
1327 * pFullRegistryPath [I] Registry-Path for the Printprovidor
1330 * Success: TRUE and pPrintProvidor filled
1334 * The RegistryPath should be:
1335 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
1336 * but this Parameter is ignored in "localspl.dll".
1340 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
1341 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
1344 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
1345 memcpy(pPrintProvidor
, pp
, (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));