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 ckecking
400 static BOOL WINAPI
myAddPrinterDriverEx(DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
, BOOL lazy
)
402 const printenv_t
*env
;
412 /* we need to set all entries in the Registry, independent from the Level of
413 DRIVER_INFO, that the caller supplied */
415 ZeroMemory(&di
, sizeof(di
));
416 if (pDriverInfo
&& (level
< (sizeof(di_sizeof
) / sizeof(di_sizeof
[0])))) {
417 memcpy(&di
, pDriverInfo
, di_sizeof
[level
]);
420 /* dump the most used infos */
421 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo
, di
.cVersion
, di
.cVersion
);
422 TRACE("%p: .pName : %s\n", di
.pName
, debugstr_w(di
.pName
));
423 TRACE("%p: .pEnvironment: %s\n", di
.pEnvironment
, debugstr_w(di
.pEnvironment
));
424 TRACE("%p: .pDriverPath : %s\n", di
.pDriverPath
, debugstr_w(di
.pDriverPath
));
425 TRACE("%p: .pDataFile : %s\n", di
.pDataFile
, debugstr_w(di
.pDataFile
));
426 TRACE("%p: .pConfigFile : %s\n", di
.pConfigFile
, debugstr_w(di
.pConfigFile
));
427 TRACE("%p: .pHelpFile : %s\n", di
.pHelpFile
, debugstr_w(di
.pHelpFile
));
428 /* dump only the first of the additional Files */
429 TRACE("%p: .pDependentFiles: %s\n", di
.pDependentFiles
, debugstr_w(di
.pDependentFiles
));
432 /* check environment */
433 env
= validate_envW(di
.pEnvironment
);
434 if (env
== NULL
) return FALSE
; /* ERROR_INVALID_ENVIRONMENT */
436 /* fill the copy-data / get the driverdir */
437 len
= sizeof(apd
.src
) - sizeof(version3_subdirW
) - sizeof(WCHAR
);
438 if (!fpGetPrinterDriverDirectory(NULL
, (LPWSTR
) env
->envname
, 1,
439 (LPBYTE
) apd
.src
, len
, &len
)) {
440 /* Should never Fail */
443 memcpy(apd
.dst
, apd
.src
, len
);
444 lstrcatW(apd
.src
, backslashW
);
445 apd
.srclen
= lstrlenW(apd
.src
);
446 lstrcatW(apd
.dst
, env
->versionsubdir
);
447 lstrcatW(apd
.dst
, backslashW
);
448 apd
.dstlen
= lstrlenW(apd
.dst
);
449 apd
.copyflags
= dwFileCopyFlags
;
451 CreateDirectoryW(apd
.src
, NULL
);
452 CreateDirectoryW(apd
.dst
, NULL
);
454 hroot
= open_driver_reg(env
->envname
);
456 ERR("Can't create Drivers key\n");
460 /* Fill the Registry for the Driver */
461 if ((lres
= RegCreateKeyExW(hroot
, di
.pName
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
462 KEY_WRITE
| KEY_QUERY_VALUE
, NULL
,
463 &hdrv
, &disposition
)) != ERROR_SUCCESS
) {
465 ERR("can't create driver %s: %u\n", debugstr_w(di
.pName
), lres
);
472 if (disposition
== REG_OPENED_EXISTING_KEY
) {
473 TRACE("driver %s already installed\n", debugstr_w(di
.pName
));
475 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
);
479 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
480 RegSetValueExW(hdrv
, versionW
, 0, REG_DWORD
, (LPBYTE
) &env
->driverversion
,
483 RegSetValueExW(hdrv
, driverW
, 0, REG_SZ
, (LPBYTE
) di
.pDriverPath
,
484 (lstrlenW(di
.pDriverPath
)+1)* sizeof(WCHAR
));
485 apd_copyfile(di
.pDriverPath
, &apd
);
487 RegSetValueExW(hdrv
, data_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pDataFile
,
488 (lstrlenW(di
.pDataFile
)+1)* sizeof(WCHAR
));
489 apd_copyfile(di
.pDataFile
, &apd
);
491 RegSetValueExW(hdrv
, configuration_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pConfigFile
,
492 (lstrlenW(di
.pConfigFile
)+1)* sizeof(WCHAR
));
493 apd_copyfile(di
.pConfigFile
, &apd
);
495 /* settings for level 3 */
496 RegSetValueExW(hdrv
, help_fileW
, 0, REG_SZ
, (LPBYTE
) di
.pHelpFile
,
497 di
.pHelpFile
? (lstrlenW(di
.pHelpFile
)+1)* sizeof(WCHAR
) : 0);
498 apd_copyfile(di
.pHelpFile
, &apd
);
501 ptr
= di
.pDependentFiles
;
502 RegSetValueExW(hdrv
, dependent_filesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pDependentFiles
,
503 di
.pDependentFiles
? multi_sz_lenW(di
.pDependentFiles
) : 0);
504 while ((ptr
!= NULL
) && (ptr
[0])) {
505 if (apd_copyfile(ptr
, &apd
)) {
506 ptr
+= lstrlenW(ptr
) + 1;
510 WARN("Failed to copy %s\n", debugstr_w(ptr
));
514 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
515 RegSetValueExW(hdrv
, monitorW
, 0, REG_SZ
, (LPBYTE
) di
.pMonitorName
,
516 di
.pMonitorName
? (lstrlenW(di
.pMonitorName
)+1)* sizeof(WCHAR
) : 0);
518 RegSetValueExW(hdrv
, datatypeW
, 0, REG_SZ
, (LPBYTE
) di
.pDefaultDataType
,
519 di
.pDefaultDataType
? (lstrlenW(di
.pDefaultDataType
)+1)* sizeof(WCHAR
) : 0);
521 /* settings for level 4 */
522 RegSetValueExW(hdrv
, previous_namesW
, 0, REG_MULTI_SZ
, (LPBYTE
) di
.pszzPreviousNames
,
523 di
.pszzPreviousNames
? multi_sz_lenW(di
.pszzPreviousNames
) : 0);
525 if (level
> 5) TRACE("level %u for Driver %s is incomplete\n", level
, debugstr_w(di
.pName
));
528 TRACE("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
530 TRACE("=> TRUE with %u\n", GetLastError());
535 /******************************************************************************
536 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
538 * Install a Printer Driver with the Option to upgrade / downgrade the Files
541 * pName [I] Servername or NULL (local Computer)
542 * level [I] Level for the supplied DRIVER_INFO_*W struct
543 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
544 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
551 static BOOL WINAPI
fpAddPrinterDriverEx(LPWSTR pName
, DWORD level
, LPBYTE pDriverInfo
, DWORD dwFileCopyFlags
)
555 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName
), level
, pDriverInfo
, dwFileCopyFlags
);
556 lres
= copy_servername_from_name(pName
, NULL
);
558 FIXME("server %s not supported\n", debugstr_w(pName
));
559 SetLastError(ERROR_ACCESS_DENIED
);
563 if ((dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
) != APD_COPY_ALL_FILES
) {
564 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags
& ~APD_COPY_FROM_DIRECTORY
);
567 return myAddPrinterDriverEx(level
, pDriverInfo
, dwFileCopyFlags
, TRUE
);
570 /*****************************************************
571 * get_backend [internal]
573 static const PRINTPROVIDOR
* get_backend(void)
575 static const PRINTPROVIDOR backend
= {
576 NULL
, /* fpOpenPrinter */
579 NULL
, /* fpEnumJobs */
580 NULL
, /* fpAddPrinter */
581 NULL
, /* fpDeletePrinter */
582 NULL
, /* fpSetPrinter */
583 NULL
, /* fpGetPrinter */
584 NULL
, /* fpEnumPrinters */
585 NULL
, /* fpAddPrinterDriver */
586 NULL
, /* fpEnumPrinterDrivers */
587 NULL
, /* fpGetPrinterDriver */
588 fpGetPrinterDriverDirectory
,
589 NULL
, /* fpDeletePrinterDriver */
590 NULL
, /* fpAddPrintProcessor */
591 NULL
, /* fpEnumPrintProcessors */
592 NULL
, /* fpGetPrintProcessorDirectory */
593 NULL
, /* fpDeletePrintProcessor */
594 NULL
, /* fpEnumPrintProcessorDatatypes */
595 NULL
, /* fpStartDocPrinter */
596 NULL
, /* fpStartPagePrinter */
597 NULL
, /* fpWritePrinter */
598 NULL
, /* fpEndPagePrinter */
599 NULL
, /* fpAbortPrinter */
600 NULL
, /* fpReadPrinter */
601 NULL
, /* fpEndDocPrinter */
603 NULL
, /* fpScheduleJob */
604 NULL
, /* fpGetPrinterData */
605 NULL
, /* fpSetPrinterData */
606 NULL
, /* fpWaitForPrinterChange */
607 NULL
, /* fpClosePrinter */
608 NULL
, /* fpAddForm */
609 NULL
, /* fpDeleteForm */
610 NULL
, /* fpGetForm */
611 NULL
, /* fpSetForm */
612 NULL
, /* fpEnumForms */
613 NULL
, /* fpEnumMonitors */
614 NULL
, /* fpEnumPorts */
615 NULL
, /* fpAddPort */
616 NULL
, /* fpConfigurePort */
617 NULL
, /* fpDeletePort */
618 NULL
, /* fpCreatePrinterIC */
619 NULL
, /* fpPlayGdiScriptOnPrinterIC */
620 NULL
, /* fpDeletePrinterIC */
621 NULL
, /* fpAddPrinterConnection */
622 NULL
, /* fpDeletePrinterConnection */
623 NULL
, /* fpPrinterMessageBox */
624 NULL
, /* fpAddMonitor */
625 NULL
, /* fpDeleteMonitor */
626 NULL
, /* fpResetPrinter */
627 NULL
, /* fpGetPrinterDriverEx */
628 NULL
, /* fpFindFirstPrinterChangeNotification */
629 NULL
, /* fpFindClosePrinterChangeNotification */
630 NULL
, /* fpAddPortEx */
631 NULL
, /* fpShutDown */
632 NULL
, /* fpRefreshPrinterChangeNotification */
633 NULL
, /* fpOpenPrinterEx */
634 NULL
, /* fpAddPrinterEx */
635 NULL
, /* fpSetPort */
636 NULL
, /* fpEnumPrinterData */
637 NULL
, /* fpDeletePrinterData */
638 NULL
, /* fpClusterSplOpen */
639 NULL
, /* fpClusterSplClose */
640 NULL
, /* fpClusterSplIsAlive */
641 NULL
, /* fpSetPrinterDataEx */
642 NULL
, /* fpGetPrinterDataEx */
643 NULL
, /* fpEnumPrinterDataEx */
644 NULL
, /* fpEnumPrinterKey */
645 NULL
, /* fpDeletePrinterDataEx */
646 NULL
, /* fpDeletePrinterKey */
647 NULL
, /* fpSeekPrinter */
648 NULL
, /* fpDeletePrinterDriverEx */
649 NULL
, /* fpAddPerMachineConnection */
650 NULL
, /* fpDeletePerMachineConnection */
651 NULL
, /* fpEnumPerMachineConnections */
652 NULL
, /* fpXcvData */
653 fpAddPrinterDriverEx
,
654 NULL
, /* fpSplReadPrinter */
655 NULL
, /* fpDriverUnloadComplete */
656 NULL
, /* fpGetSpoolFileInfo */
657 NULL
, /* fpCommitSpoolData */
658 NULL
, /* fpCloseSpoolFileHandle */
659 NULL
, /* fpFlushPrinter */
660 NULL
, /* fpSendRecvBidiData */
661 NULL
/* fpAddDriverCatalog */
663 TRACE("=> %p\n", &backend
);
668 /*****************************************************
671 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
673 TRACE("(%p, %d, %p)\n",hinstDLL
, fdwReason
, lpvReserved
);
677 case DLL_WINE_PREATTACH
:
678 return FALSE
; /* prefer native version */
680 case DLL_PROCESS_ATTACH
:
681 DisableThreadLibraryCalls( hinstDLL
);
682 LOCALSPL_hInstance
= hinstDLL
;
690 /*****************************************************
691 * InitializePrintProvidor (localspl.@)
693 * Initialize the Printprovider
696 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
697 * cbPrintProvidor [I] Size of Buffer in Bytes
698 * pFullRegistryPath [I] Registry-Path for the Printprovidor
701 * Success: TRUE and pPrintProvidor filled
705 * The RegistryPath should be:
706 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
707 * but this Parameter is ignored in "localspl.dll".
711 BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor
,
712 DWORD cbPrintProvidor
, LPWSTR pFullRegistryPath
)
715 TRACE("(%p, %u, %s)\n", pPrintProvidor
, cbPrintProvidor
, debugstr_w(pFullRegistryPath
));
716 memcpy(pPrintProvidor
, pp
, (cbPrintProvidor
< sizeof(PRINTPROVIDOR
)) ? cbPrintProvidor
: sizeof(PRINTPROVIDOR
));