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/debug.h"
35 #include "wine/unicode.h"
36 #include "localspl_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(localspl
);
40 /* ############################### */
43 WCHAR src
[MAX_PATH
+MAX_PATH
];
44 WCHAR dst
[MAX_PATH
+MAX_PATH
];
55 LPCWSTR versionregpath
;
56 LPCWSTR versionsubdir
;
59 /* ############################### */
61 HINSTANCE LOCALSPL_hInstance
= NULL
;
63 static const PRINTPROVIDOR
* pp
= NULL
;
66 static const WCHAR backslashW
[] = {'\\',0};
67 static const WCHAR configuration_fileW
[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
68 static const WCHAR datatypeW
[] = {'D','a','t','a','t','y','p','e',0};
69 static const WCHAR data_fileW
[] = {'D','a','t','a',' ','F','i','l','e',0};
70 static const WCHAR default_devmodeW
[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
71 static const WCHAR dependent_filesW
[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
72 static const WCHAR descriptionW
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
73 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
74 static const WCHAR fmt_driversW
[] = { 'S','y','s','t','e','m','\\',
75 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
76 'c','o','n','t','r','o','l','\\',
77 'P','r','i','n','t','\\',
78 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
79 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
80 static const WCHAR hardwareidW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
81 static const WCHAR help_fileW
[] = {'H','e','l','p',' ','F','i','l','e',0};
82 static const WCHAR locationW
[] = {'L','o','c','a','t','i','o','n',0};
83 static const WCHAR manufacturerW
[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
84 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
85 static const WCHAR monitorUIW
[] = {'M','o','n','i','t','o','r','U','I',0};
86 static const WCHAR nameW
[] = {'N','a','m','e',0};
87 static const WCHAR oem_urlW
[] = {'O','E','M',' ','U','r','l',0};
88 static const WCHAR parametersW
[] = {'P','a','r','a','m','e','t','e','r','s',0};
89 static const WCHAR portW
[] = {'P','o','r','t',0};
90 static const WCHAR previous_namesW
[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
91 static const WCHAR spooldriversW
[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
92 static const WCHAR versionW
[] = {'V','e','r','s','i','o','n',0};
94 static const WCHAR win40_envnameW
[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
95 static const WCHAR win40_subdirW
[] = {'w','i','n','4','0',0};
96 static const WCHAR version0_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','0',0};
97 static const WCHAR version0_subdirW
[] = {'\\','0',0};
99 static const WCHAR x86_envnameW
[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
100 static const WCHAR x86_subdirW
[] = {'w','3','2','x','8','6',0};
101 static const WCHAR version3_regpathW
[] = {'\\','V','e','r','s','i','o','n','-','3',0};
102 static const WCHAR version3_subdirW
[] = {'\\','3',0};
105 static const printenv_t env_x86
= {x86_envnameW
, x86_subdirW
, 3,
106 version3_regpathW
, version3_subdirW
};
108 static const printenv_t env_win40
= {win40_envnameW
, win40_subdirW
, 0,
109 version0_regpathW
, version0_subdirW
};
111 static const printenv_t
* const all_printenv
[] = {&env_x86
, &env_win40
};
114 static const DWORD di_sizeof
[] = {0, sizeof(DRIVER_INFO_1W
), sizeof(DRIVER_INFO_2W
),
115 sizeof(DRIVER_INFO_3W
), sizeof(DRIVER_INFO_4W
),
116 sizeof(DRIVER_INFO_5W
), sizeof(DRIVER_INFO_6W
),
117 0, sizeof(DRIVER_INFO_8W
)};
119 /******************************************************************
120 * apd_copyfile [internal]
122 * Copy a file from the driverdirectory to the versioned directory
129 static BOOL
apd_copyfile(LPWSTR filename
, apd_data_t
*apd
)
135 apd
->src
[apd
->srclen
] = '\0';
136 apd
->dst
[apd
->dstlen
] = '\0';
138 if (!filename
|| !filename
[0]) {
139 /* nothing to copy */
143 ptr
= strrchrW(filename
, '\\');
152 if (apd
->copyflags
& APD_COPY_FROM_DIRECTORY
) {
153 /* we have an absolute Path */
159 lstrcatW(srcname
, ptr
);
161 lstrcatW(apd
->dst
, ptr
);
163 TRACE("%s => %s\n", debugstr_w(filename
), debugstr_w(apd
->dst
));
165 /* FIXME: handle APD_COPY_NEW_FILES */
166 res
= CopyFileW(srcname
, apd
->dst
, FALSE
);
167 TRACE("got %u with %u\n", res
, GetLastError());
169 return (apd
->lazy
) ? TRUE
: res
;
172 /******************************************************************
173 * copy_servername_from_name (internal)
175 * for an external server, the serverpart from the name is copied.
178 * the length (in WCHAR) of the serverpart (0 for the local computer)
179 * (-length), when the name is to long
182 static LONG
copy_servername_from_name(LPCWSTR name
, LPWSTR target
)
186 WCHAR buffer
[MAX_COMPUTERNAME_LENGTH
+1];
190 if (target
) *target
= '\0';
192 if (name
== NULL
) return 0;
193 if ((name
[0] != '\\') || (name
[1] != '\\')) return 0;
196 /* skip over both backslash, find separator '\' */
197 ptr
= strchrW(server
, '\\');
198 serverlen
= (ptr
) ? ptr
- server
: lstrlenW(server
);
200 /* servername is empty or to long */
201 if (serverlen
== 0) return 0;
203 TRACE("found %s\n", debugstr_wn(server
, serverlen
));
205 if (serverlen
> MAX_COMPUTERNAME_LENGTH
) return -serverlen
;
207 len
= sizeof(buffer
) / sizeof(buffer
[0]);
208 if (GetComputerNameW(buffer
, &len
)) {
209 if ((serverlen
== len
) && (strncmpiW(server
, buffer
, len
) == 0)) {
210 /* The requested Servername is our computername */
212 memcpy(target
, server
, serverlen
* sizeof(WCHAR
));
213 target
[serverlen
] = '\0';
221 /******************************************************************
222 * Return the number of bytes for an multi_sz string.
223 * The result includes all \0s
224 * (specifically the extra \0, that is needed as multi_sz terminator).
226 static int multi_sz_lenW(const WCHAR
*str
)
228 const WCHAR
*ptr
= str
;
232 ptr
+= lstrlenW(ptr
) + 1;
235 return (ptr
- str
+ 1) * sizeof(WCHAR
);
238 /******************************************************************
239 * validate_envW [internal]
241 * validate the user-supplied printing-environment
244 * env [I] PTR to Environment-String or NULL
247 * Success: PTR to printenv_t
248 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
251 * An empty string is handled the same way as NULL.
255 static const printenv_t
* validate_envW(LPCWSTR env
)
257 const printenv_t
*result
= NULL
;
260 TRACE("(%s)\n", debugstr_w(env
));
263 for (i
= 0; i
< sizeof(all_printenv
)/sizeof(all_printenv
[0]); i
++)
265 if (lstrcmpiW(env
, all_printenv
[i
]->envname
) == 0)
267 result
= all_printenv
[i
];
271 if (result
== NULL
) {
272 FIXME("unsupported Environment: %s\n", debugstr_w(env
));
273 SetLastError(ERROR_INVALID_ENVIRONMENT
);
275 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
279 result
= (GetVersion() & 0x80000000) ? &env_win40
: &env_x86
;
282 TRACE("=> using %p: %s\n", result
, debugstr_w(result
? result
->envname
: NULL
));
286 /*****************************************************************************
287 * open_driver_reg [internal]
289 * opens the registry for the printer drivers depending on the given input
290 * variable pEnvironment
293 * Success: the opened hkey
296 static HKEY
open_driver_reg(LPCWSTR pEnvironment
)
300 const printenv_t
* env
;
302 TRACE("(%s)\n", debugstr_w(pEnvironment
));
304 env
= validate_envW(pEnvironment
);
305 if (!env
) return NULL
;
307 buffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW
) +
308 (lstrlenW(env
->envname
) + lstrlenW(env
->versionregpath
)) * sizeof(WCHAR
));
311 wsprintfW(buffer
, fmt_driversW
, env
->envname
, env
->versionregpath
);
312 RegCreateKeyW(HKEY_LOCAL_MACHINE
, buffer
, &retval
);
313 HeapFree(GetProcessHeap(), 0, buffer
);
318 /*****************************************************************************
319 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
321 * Return the PATH for the Printer-Drivers
324 * pName [I] Servername (NT only) or NULL (local Computer)
325 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
326 * Level [I] Structure-Level (must be 1)
327 * pDriverDirectory [O] PTR to Buffer that receives the Result
328 * cbBuf [I] Size of Buffer at pDriverDirectory
329 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
330 * required for pDriverDirectory
333 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
334 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
335 * if cbBuf is too small
337 * Native Values returned in pDriverDirectory on Success:
338 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
339 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
340 *| win9x(Windows 4.0): "%winsysdir%"
342 * "%winsysdir%" is the Value from GetSystemDirectoryW()
345 static BOOL WINAPI
fpGetPrinterDriverDirectory(LPWSTR pName
, LPWSTR pEnvironment
,
346 DWORD Level
, LPBYTE pDriverDirectory
, DWORD cbBuf
, LPDWORD pcbNeeded
)
349 const printenv_t
* env
;
351 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName
),
352 debugstr_w(pEnvironment
), Level
, pDriverDirectory
, cbBuf
, pcbNeeded
);
354 if (pName
!= NULL
&& pName
[0]) {
355 FIXME("server %s not supported\n", debugstr_w(pName
));
356 SetLastError(ERROR_INVALID_PARAMETER
);
360 env
= validate_envW(pEnvironment
);
361 if (!env
) return FALSE
; /* pEnvironment invalid or unsupported */
364 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
365 needed
= GetSystemDirectoryW(NULL
, 0);
366 /* add the Size for the Subdirectories */
367 needed
+= lstrlenW(spooldriversW
);
368 needed
+= lstrlenW(env
->subdir
);
369 needed
*= sizeof(WCHAR
); /* return-value is size in Bytes */
373 if (needed
> cbBuf
) {
374 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
378 if (pDriverDirectory
== NULL
) {
379 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
380 SetLastError(ERROR_INVALID_USER_BUFFER
);
384 GetSystemDirectoryW((LPWSTR
) pDriverDirectory
, cbBuf
/sizeof(WCHAR
));
385 /* add the Subdirectories */
386 lstrcatW((LPWSTR
) pDriverDirectory
, spooldriversW
);
387 lstrcatW((LPWSTR
) pDriverDirectory
, env
->subdir
);
389 TRACE("=> %s\n", debugstr_w((LPWSTR
) pDriverDirectory
));
393 /******************************************************************************
394 * myAddPrinterDriverEx [internal]
396 * Install a Printer Driver with the Option to upgrade / downgrade the Files
397 * and a special mode with lazy error checking.
400 static BOOL WINAPI
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
402 static const WCHAR emptyW
[1];
403 const printenv_t
*env
;
413 /* we need to set all entries in the Registry, independent from the Level of
414 DRIVER_INFO, that the caller supplied */
416 ZeroMemory(&di
, sizeof(di
));
417 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
418 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
421 /* dump the most used infos */
422 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
423 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
424 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
425 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
426 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
427 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
428 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
429 /* dump only the first of the additional Files */
430 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
433 /* check environment */
434 env
= validate_envW(di
.pEnvironment
);
435 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
437 /* fill the copy-data / get the driverdir */
438 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
439 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
440 (LPBYTE
) apd
.src
, len
, &len
)) {
441 /* Should never Fail */
444 memcpy(apd
.dst
, apd
.src
, len
);
445 lstrcatW(apd
.src
, backslashW
);
446 apd
.srclen
= lstrlenW(apd
.src
);
447 lstrcatW(apd
.dst
, env
->versionsubdir
);
448 lstrcatW(apd
.dst
, backslashW
);
449 apd
.dstlen
= lstrlenW(apd
.dst
);
450 apd
.copyflags
= dwFileCopyFlags
;
452 CreateDirectoryW(apd
.src
, NULL
);
453 CreateDirectoryW(apd
.dst
, NULL
);
455 hroot
= open_driver_reg(env
->envname
);
457 ERR("Can't create Drivers key\n");
461 /* Fill the Registry for the Driver */
462 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
463 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
464 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
466 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
473 if (disposition
== REG_OPENED_EXISTING_KEY
) {
474 TRACE("driver %s already installed\n", debugstr_w(di
.pName
));
476 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
480 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
481 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (LPBYTE
) &env
->driverversion
,
484 RegSetValueExW(hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
) di
.pDriverPath
,
485 (lstrlenW(di
.pDriverPath
)+1)* sizeof(WCHAR
));
486 apd_copyfile(di
.pDriverPath
, &apd
);
488 RegSetValueExW(hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pDataFile
,
489 (lstrlenW(di
.pDataFile
)+1)* sizeof(WCHAR
));
490 apd_copyfile(di
.pDataFile
, &apd
);
492 RegSetValueExW(hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pConfigFile
,
493 (lstrlenW(di
.pConfigFile
)+1)* sizeof(WCHAR
));
494 apd_copyfile(di
.pConfigFile
, &apd
);
496 /* settings for level 3 */
498 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pHelpFile
,
499 (lstrlenW(di
.pHelpFile
)+1)* sizeof(WCHAR
));
501 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
502 apd_copyfile(di
.pHelpFile
, &apd
);
505 ptr
= di
.pDependentFiles
;
507 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pDependentFiles
,
508 multi_sz_lenW(di
.pDependentFiles
));
510 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
511 while ((ptr
!= NULL
) && (ptr
[0])) {
512 if (apd_copyfile(ptr
, &apd
)) {
513 ptr
+= lstrlenW(ptr
) + 1;
517 WARN("Failed to copy %s\n", debugstr_w(ptr
));
521 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
523 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
524 (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
));
526 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
528 if (di
.pDefaultDataType
)
529 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
530 (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
));
532 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
534 /* settings for level 4 */
535 if (di
.pszzPreviousNames
)
536 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
537 multi_sz_lenW(di
.pszzPreviousNames
));
539 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
)emptyW
, sizeof(emptyW
));
541 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
544 TRACE("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
546 TRACE("=> TRUE with %u\n", GetLastError());
551 /******************************************************************************
552 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
554 * Install a Printer Driver with the Option to upgrade / downgrade the Files
557 * pName [I] Servername or NULL (local Computer)
558 * level [I] Level for the supplied DRIVER_INFO_*W struct
559 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
560 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
567 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
571 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
572 lres
= copy_servername_from_name(pName
, NULL
);
574 FIXME("server %s not supported\n", debugstr_w(pName
));
575 SetLastError(ERROR_ACCESS_DENIED
);
579 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
580 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
583 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
586 /*****************************************************
587 * get_backend [internal]
589 static const PRINTPROVIDOR
* get_backend(void)
591 static const PRINTPROVIDOR backend
= {
592 NULL
, /* fpOpenPrinter */
595 NULL
, /* fpEnumJobs */
596 NULL
, /* fpAddPrinter */
597 NULL
, /* fpDeletePrinter */
598 NULL
, /* fpSetPrinter */
599 NULL
, /* fpGetPrinter */
600 NULL
, /* fpEnumPrinters */
601 NULL
, /* fpAddPrinterDriver */
602 NULL
, /* fpEnumPrinterDrivers */
603 NULL
, /* fpGetPrinterDriver */
604 fpGetPrinterDriverDirectory
,
605 NULL
, /* fpDeletePrinterDriver */
606 NULL
, /* fpAddPrintProcessor */
607 NULL
, /* fpEnumPrintProcessors */
608 NULL
, /* fpGetPrintProcessorDirectory */
609 NULL
, /* fpDeletePrintProcessor */
610 NULL
, /* fpEnumPrintProcessorDatatypes */
611 NULL
, /* fpStartDocPrinter */
612 NULL
, /* fpStartPagePrinter */
613 NULL
, /* fpWritePrinter */
614 NULL
, /* fpEndPagePrinter */
615 NULL
, /* fpAbortPrinter */
616 NULL
, /* fpReadPrinter */
617 NULL
, /* fpEndDocPrinter */
619 NULL
, /* fpScheduleJob */
620 NULL
, /* fpGetPrinterData */
621 NULL
, /* fpSetPrinterData */
622 NULL
, /* fpWaitForPrinterChange */
623 NULL
, /* fpClosePrinter */
624 NULL
, /* fpAddForm */
625 NULL
, /* fpDeleteForm */
626 NULL
, /* fpGetForm */
627 NULL
, /* fpSetForm */
628 NULL
, /* fpEnumForms */
629 NULL
, /* fpEnumMonitors */
630 NULL
, /* fpEnumPorts */
631 NULL
, /* fpAddPort */
632 NULL
, /* fpConfigurePort */
633 NULL
, /* fpDeletePort */
634 NULL
, /* fpCreatePrinterIC */
635 NULL
, /* fpPlayGdiScriptOnPrinterIC */
636 NULL
, /* fpDeletePrinterIC */
637 NULL
, /* fpAddPrinterConnection */
638 NULL
, /* fpDeletePrinterConnection */
639 NULL
, /* fpPrinterMessageBox */
640 NULL
, /* fpAddMonitor */
641 NULL
, /* fpDeleteMonitor */
642 NULL
, /* fpResetPrinter */
643 NULL
, /* fpGetPrinterDriverEx */
644 NULL
, /* fpFindFirstPrinterChangeNotification */
645 NULL
, /* fpFindClosePrinterChangeNotification */
646 NULL
, /* fpAddPortEx */
647 NULL
, /* fpShutDown */
648 NULL
, /* fpRefreshPrinterChangeNotification */
649 NULL
, /* fpOpenPrinterEx */
650 NULL
, /* fpAddPrinterEx */
651 NULL
, /* fpSetPort */
652 NULL
, /* fpEnumPrinterData */
653 NULL
, /* fpDeletePrinterData */
654 NULL
, /* fpClusterSplOpen */
655 NULL
, /* fpClusterSplClose */
656 NULL
, /* fpClusterSplIsAlive */
657 NULL
, /* fpSetPrinterDataEx */
658 NULL
, /* fpGetPrinterDataEx */
659 NULL
, /* fpEnumPrinterDataEx */
660 NULL
, /* fpEnumPrinterKey */
661 NULL
, /* fpDeletePrinterDataEx */
662 NULL
, /* fpDeletePrinterKey */
663 NULL
, /* fpSeekPrinter */
664 NULL
, /* fpDeletePrinterDriverEx */
665 NULL
, /* fpAddPerMachineConnection */
666 NULL
, /* fpDeletePerMachineConnection */
667 NULL
, /* fpEnumPerMachineConnections */
668 NULL
, /* fpXcvData */
669 fpAddPrinterDriverEx
,
670 NULL
, /* fpSplReadPrinter */
671 NULL
, /* fpDriverUnloadComplete */
672 NULL
, /* fpGetSpoolFileInfo */
673 NULL
, /* fpCommitSpoolData */
674 NULL
, /* fpCloseSpoolFileHandle */
675 NULL
, /* fpFlushPrinter */
676 NULL
, /* fpSendRecvBidiData */
677 NULL
/* fpAddDriverCatalog */
679 TRACE("=> %p\n", &backend
);
684 /*****************************************************
687 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
689 TRACE("(%p, %d, %p)\n",hinstDLL
, fdwReason
, lpvReserved
);
693 case DLL_WINE_PREATTACH
:
694 return FALSE
; /* prefer native version */
696 case DLL_PROCESS_ATTACH
:
697 DisableThreadLibraryCalls( hinstDLL
);
698 LOCALSPL_hInstance
= hinstDLL
;
706 /*****************************************************
707 * InitializePrintProvidor (localspl.@)
709 * Initialize the Printprovider
712 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
713 * cbPrintProvidor [I] Size of Buffer in Bytes
714 * pFullRegistryPath [I] Registry-Path for the Printprovidor
717 * Success: TRUE and pPrintProvidor filled
721 * The RegistryPath should be:
722 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
723 * but this Parameter is ignored in "localspl.dll".
727 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
728 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
731 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
732 memcpy(pPrintProvidor
, pp
, (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));