msvcrt/tests: Fix 3 tests that always fail on Vista.
[wine] / dlls / localspl / localspl_main.c
1 /*
2  * Implementation of the Local Printmonitor
3  *
4  * Copyright 2006-2008 Detlef Riekenberg
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winspool.h"
31 #include "ddk/winsplp.h"
32 #include "winuser.h"
33
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "localspl_private.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
39
40 /* ############################### */
41
42 typedef struct {
43     WCHAR   src[MAX_PATH+MAX_PATH];
44     WCHAR   dst[MAX_PATH+MAX_PATH];
45     DWORD   srclen;
46     DWORD   dstlen;
47     DWORD   copyflags;
48     BOOL    lazy;
49 } apd_data_t;
50
51 typedef struct {
52     LPCWSTR  envname;
53     LPCWSTR  subdir;
54     DWORD    driverversion;
55     LPCWSTR  versionregpath;
56     LPCWSTR  versionsubdir;
57 } printenv_t;
58
59 /* ############################### */
60
61 HINSTANCE LOCALSPL_hInstance = NULL;
62
63 static const PRINTPROVIDOR * pp = NULL;
64
65
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};
93
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};
98
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};
103
104
105 static const printenv_t env_x86 =   {x86_envnameW, x86_subdirW, 3,
106                                      version3_regpathW, version3_subdirW};
107
108 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
109                                      version0_regpathW, version0_subdirW};
110
111 static const printenv_t * const all_printenv[] = {&env_x86, &env_win40};
112
113
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)};
118
119 /******************************************************************
120  *  apd_copyfile [internal]
121  *
122  * Copy a file from the driverdirectory to the versioned directory
123  *
124  * RETURNS
125  *  Success: TRUE
126  *  Failure: FALSE
127  *
128  */
129 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
130 {
131     LPWSTR  ptr;
132     LPWSTR  srcname;
133     DWORD   res;
134
135     apd->src[apd->srclen] = '\0';
136     apd->dst[apd->dstlen] = '\0';
137
138     if (!filename || !filename[0]) {
139         /* nothing to copy */
140         return TRUE;
141     }
142
143     ptr = strrchrW(filename, '\\');
144     if (ptr) {
145         ptr++;
146     }
147     else
148     {
149         ptr = filename;
150     }
151
152     if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
153         /* we have an absolute Path */
154         srcname = filename;
155     }
156     else
157     {
158         srcname = apd->src;
159         lstrcatW(srcname, ptr);
160     }
161     lstrcatW(apd->dst, ptr);
162
163     TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
164
165     /* FIXME: handle APD_COPY_NEW_FILES */
166     res = CopyFileW(srcname, apd->dst, FALSE);
167     TRACE("got %u with %u\n", res, GetLastError());
168
169     return (apd->lazy) ? TRUE : res;
170 }
171
172 /******************************************************************
173  * copy_servername_from_name  (internal)
174  *
175  * for an external server, the serverpart from the name is copied.
176  *
177  * RETURNS
178  *  the length (in WCHAR) of the serverpart (0 for the local computer)
179  *  (-length), when the name is to long
180  *
181  */
182 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
183 {
184     LPCWSTR server;
185     LPWSTR  ptr;
186     WCHAR   buffer[MAX_COMPUTERNAME_LENGTH +1];
187     DWORD   len;
188     DWORD   serverlen;
189
190     if (target) *target = '\0';
191
192     if (name == NULL) return 0;
193     if ((name[0] != '\\') || (name[1] != '\\')) return 0;
194
195     server = &name[2];
196     /* skip over both backslash, find separator '\' */
197     ptr = strchrW(server, '\\');
198     serverlen = (ptr) ? ptr - server : lstrlenW(server);
199
200     /* servername is empty or to long */
201     if (serverlen == 0) return 0;
202
203     TRACE("found %s\n", debugstr_wn(server, serverlen));
204
205     if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
206
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 */
211             if (target) {
212                 memcpy(target, server, serverlen * sizeof(WCHAR));
213                 target[serverlen] = '\0';
214             }
215             return serverlen;
216         }
217     }
218     return 0;
219 }
220
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).
225  */
226 static int multi_sz_lenW(const WCHAR *str)
227 {
228     const WCHAR *ptr = str;
229     if (!str) return 0;
230     do
231     {
232         ptr += lstrlenW(ptr) + 1;
233     } while (*ptr);
234
235     return (ptr - str + 1) * sizeof(WCHAR);
236 }
237
238 /******************************************************************
239  * validate_envW [internal]
240  *
241  * validate the user-supplied printing-environment
242  *
243  * PARAMS
244  *  env  [I] PTR to Environment-String or NULL
245  *
246  * RETURNS
247  *  Success:  PTR to printenv_t
248  *  Failure:  NULL and ERROR_INVALID_ENVIRONMENT
249  *
250  * NOTES
251  *  An empty string is handled the same way as NULL.
252  *
253  */
254
255 static const  printenv_t * validate_envW(LPCWSTR env)
256 {
257     const printenv_t *result = NULL;
258     unsigned int i;
259
260     TRACE("(%s)\n", debugstr_w(env));
261     if (env && env[0])
262     {
263         for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
264         {
265             if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
266             {
267                 result = all_printenv[i];
268                 break;
269             }
270         }
271         if (result == NULL) {
272             FIXME("unsupported Environment: %s\n", debugstr_w(env));
273             SetLastError(ERROR_INVALID_ENVIRONMENT);
274         }
275         /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
276     }
277     else
278     {
279         result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
280     }
281
282     TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
283     return result;
284 }
285
286 /*****************************************************************************
287  * open_driver_reg [internal]
288  *
289  * opens the registry for the printer drivers depending on the given input
290  * variable pEnvironment
291  *
292  * RETURNS:
293  *    Success: the opened hkey
294  *    Failure: NULL
295  */
296 static HKEY open_driver_reg(LPCWSTR pEnvironment)
297 {
298     HKEY  retval = NULL;
299     LPWSTR buffer;
300     const printenv_t * env;
301
302     TRACE("(%s)\n", debugstr_w(pEnvironment));
303
304     env = validate_envW(pEnvironment);
305     if (!env) return NULL;
306
307     buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
308                 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
309
310     if (buffer) {
311         wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
312         RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
313         HeapFree(GetProcessHeap(), 0, buffer);
314     }
315     return retval;
316 }
317
318 /*****************************************************************************
319  * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
320  *
321  * Return the PATH for the Printer-Drivers
322  *
323  * PARAMS
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
331  *
332  * RETURNS
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
336  *
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%"
341  *
342  *   "%winsysdir%" is the Value from GetSystemDirectoryW()
343  *
344  */
345 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
346             DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
347 {
348     DWORD needed;
349     const printenv_t * env;
350
351     TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
352           debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
353
354     if (pName != NULL && pName[0]) {
355         FIXME("server %s not supported\n", debugstr_w(pName));
356         SetLastError(ERROR_INVALID_PARAMETER);
357         return FALSE;
358     }
359
360     env = validate_envW(pEnvironment);
361     if (!env) return FALSE;  /* pEnvironment invalid or unsupported */
362
363
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 */
370
371     *pcbNeeded = needed;
372
373     if (needed > cbBuf) {
374         SetLastError(ERROR_INSUFFICIENT_BUFFER);
375         return FALSE;
376     }
377
378     if (pDriverDirectory == NULL) {
379         /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
380         SetLastError(ERROR_INVALID_USER_BUFFER);
381         return FALSE;
382     }
383
384     GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
385     /* add the Subdirectories */
386     lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
387     lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
388
389     TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
390     return TRUE;
391 }
392
393 /******************************************************************************
394  *  myAddPrinterDriverEx [internal]
395  *
396  * Install a Printer Driver with the Option to upgrade / downgrade the Files
397  * and a special mode with lazy error checking.
398  *
399  */
400 static BOOL WINAPI myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
401 {
402     static const WCHAR emptyW[1];
403     const printenv_t *env;
404     apd_data_t apd;
405     DRIVER_INFO_8W di;
406     LPWSTR  ptr;
407     HKEY    hroot;
408     HKEY    hdrv;
409     DWORD   disposition;
410     DWORD   len;
411     LONG    lres;
412
413     /* we need to set all entries in the Registry, independent from the Level of
414        DRIVER_INFO, that the caller supplied */
415
416     ZeroMemory(&di, sizeof(di));
417     if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
418         memcpy(&di, pDriverInfo, di_sizeof[level]);
419     }
420
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));
431
432
433     /* check environment */
434     env = validate_envW(di.pEnvironment);
435     if (env == NULL) return FALSE;        /* ERROR_INVALID_ENVIRONMENT */
436
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 */
442         return FALSE;
443     }
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;
451     apd.lazy = lazy;
452     CreateDirectoryW(apd.src, NULL);
453     CreateDirectoryW(apd.dst, NULL);
454
455     hroot = open_driver_reg(env->envname);
456     if (!hroot) {
457         ERR("Can't create Drivers key\n");
458         return FALSE;
459     }
460
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) {
465
466         ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
467         RegCloseKey(hroot);
468         SetLastError(lres);
469         return FALSE;
470     }
471     RegCloseKey(hroot);
472
473     if (disposition == REG_OPENED_EXISTING_KEY) {
474         TRACE("driver %s already installed\n", debugstr_w(di.pName));
475         RegCloseKey(hdrv);
476         SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
477         return FALSE;
478     }
479
480     /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
481     RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
482                    sizeof(DWORD));
483
484     RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
485                    (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
486     apd_copyfile(di.pDriverPath, &apd);
487
488     RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
489                    (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
490     apd_copyfile(di.pDataFile, &apd);
491
492     RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
493                    (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
494     apd_copyfile(di.pConfigFile, &apd);
495
496     /* settings for level 3 */
497     if (di.pHelpFile)
498         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
499                        (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
500     else
501         RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
502     apd_copyfile(di.pHelpFile, &apd);
503
504
505     ptr = di.pDependentFiles;
506     if (ptr)
507         RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
508                        multi_sz_lenW(di.pDependentFiles));
509     else
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;
514         }
515         else
516         {
517             WARN("Failed to copy %s\n", debugstr_w(ptr));
518             ptr = NULL;
519         }
520     }
521     /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
522     if (di.pMonitorName)
523         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
524                        (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
525     else
526         RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
527
528     if (di.pDefaultDataType)
529         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
530                        (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
531     else
532         RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
533
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));
538     else
539         RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
540
541     if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
542
543     RegCloseKey(hdrv);
544     TRACE("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
545
546     TRACE("=> TRUE with %u\n", GetLastError());
547     return TRUE;
548
549 }
550
551 /******************************************************************************
552  * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
553  *
554  * Install a Printer Driver with the Option to upgrade / downgrade the Files
555  *
556  * PARAMS
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
561  *
562  * RESULTS
563  *  Success: TRUE
564  *  Failure: FALSE
565  *
566  */
567 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
568 {
569     LONG lres;
570
571     TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
572     lres = copy_servername_from_name(pName, NULL);
573     if (lres) {
574         FIXME("server %s not supported\n", debugstr_w(pName));
575         SetLastError(ERROR_ACCESS_DENIED);
576         return FALSE;
577     }
578
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);
581     }
582
583     return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
584 }
585
586 /*****************************************************
587  *  get_backend [internal]
588  */
589 static const PRINTPROVIDOR * get_backend(void)
590 {
591     static const PRINTPROVIDOR backend = {
592         NULL,   /* fpOpenPrinter */
593         NULL,   /* fpSetJob */
594         NULL,   /* fpGetJob */
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 */
618         NULL,   /* fpAddJob */
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 */
678     };
679     TRACE("=> %p\n", &backend);
680     return &backend;
681
682 }
683
684 /*****************************************************
685  *      DllMain
686  */
687 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
688 {
689     TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
690
691     switch(fdwReason)
692     {
693         case DLL_WINE_PREATTACH:
694             return FALSE;           /* prefer native version */
695
696         case DLL_PROCESS_ATTACH:
697             DisableThreadLibraryCalls( hinstDLL );
698             LOCALSPL_hInstance = hinstDLL;
699             pp = get_backend();
700             break;
701     }
702     return TRUE;
703 }
704
705
706 /*****************************************************
707  * InitializePrintProvidor     (localspl.@)
708  *
709  * Initialize the Printprovider
710  *
711  * PARAMS
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
715  *
716  * RETURNS
717  *  Success: TRUE and pPrintProvidor filled
718  *  Failure: FALSE
719  *
720  * NOTES
721  *  The RegistryPath should be:
722  *  "System\CurrentControlSet\Control\Print\Providers\<providername>",
723  *  but this Parameter is ignored in "localspl.dll".
724  *
725  */
726
727 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
728                                     DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
729 {
730
731     TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
732     memcpy(pPrintProvidor, pp, (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
733
734     return TRUE;
735 }