msvcrt/tests: Remove a space before a '\n'.
[wine/gsoc-2012-control.git] / dlls / localspl / localspl_main.c
blob7137d9721f821f41a757c71a9aa1b55a596478aa
1 /*
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
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winspool.h"
31 #include "winuser.h"
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 /* ############################### */
55 typedef struct {
56 WCHAR src[MAX_PATH+MAX_PATH];
57 WCHAR dst[MAX_PATH+MAX_PATH];
58 DWORD srclen;
59 DWORD dstlen;
60 DWORD copyflags;
61 BOOL lazy;
62 } apd_data_t;
64 typedef struct {
65 struct list entry;
66 LPWSTR name;
67 LPWSTR dllname;
68 PMONITORUI monitorUI;
69 LPMONITOR monitor;
70 HMODULE hdll;
71 DWORD refcount;
72 DWORD dwMonitorSize;
73 } monitor_t;
75 typedef struct {
76 LPCWSTR envname;
77 LPCWSTR subdir;
78 DWORD driverversion;
79 LPCWSTR versionregpath;
80 LPCWSTR versionsubdir;
81 } printenv_t;
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 /******************************************************************
154 * strdupW [internal]
156 * create a copy of a unicode-string
160 static LPWSTR strdupW(LPCWSTR p)
162 LPWSTR ret;
163 DWORD len;
165 if(!p) return NULL;
166 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
167 ret = heap_alloc(len);
168 memcpy(ret, p, len);
169 return ret;
172 /******************************************************************
173 * apd_copyfile [internal]
175 * Copy a file from the driverdirectory to the versioned directory
177 * RETURNS
178 * Success: TRUE
179 * Failure: FALSE
182 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
184 LPWSTR ptr;
185 LPWSTR srcname;
186 DWORD res;
188 apd->src[apd->srclen] = '\0';
189 apd->dst[apd->dstlen] = '\0';
191 if (!filename || !filename[0]) {
192 /* nothing to copy */
193 return TRUE;
196 ptr = strrchrW(filename, '\\');
197 if (ptr) {
198 ptr++;
200 else
202 ptr = filename;
205 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
206 /* we have an absolute Path */
207 srcname = filename;
209 else
211 srcname = apd->src;
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.
230 * RETURNS
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)
237 LPCWSTR server;
238 LPWSTR ptr;
239 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
240 DWORD len;
241 DWORD serverlen;
243 if (target) *target = '\0';
245 if (name == NULL) return 0;
246 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
248 server = &name[2];
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 */
264 if (target) {
265 memcpy(target, server, serverlen * sizeof(WCHAR));
266 target[serverlen] = '\0';
268 return serverlen;
271 return 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);
292 heap_free(pm->name);
293 heap_free(pm->dllname);
294 heap_free(pm);
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;
317 monitor_t * cursor;
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);
325 if (name) {
326 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
328 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
329 pm = cursor;
330 break;
335 if (pm == NULL) {
336 pm = heap_alloc_zero(sizeof(monitor_t));
337 if (pm == NULL) goto cleanup;
338 list_add_tail(&monitor_handles, &pm->entry);
340 pm->refcount++;
342 if (pm->name == NULL) {
343 /* Load the monitor */
344 LPMONITOREX pmonitorEx;
345 DWORD len;
347 if (name) {
348 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
349 regroot = heap_alloc(len * sizeof(WCHAR));
352 if (regroot) {
353 lstrcpyW(regroot, monitorsW);
354 lstrcatW(regroot, name);
355 /* Get the Driver from the Registry */
356 if (driver == NULL) {
357 HKEY hroot;
358 DWORD namesize;
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) ;
365 RegCloseKey(hroot);
370 pm->name = strdupW(name);
371 pm->dllname = strdupW(driver);
373 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
374 monitor_unload(pm);
375 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
376 pm = NULL;
377 goto cleanup;
380 pm->hdll = LoadLibraryW(driver);
381 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
383 if (pm->hdll == NULL) {
384 monitor_unload(pm);
385 SetLastError(ERROR_MOD_NOT_FOUND);
386 pm = NULL;
387 goto cleanup;
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));
406 if (pm->monitorUI) {
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));
418 if (pmonitorEx) {
419 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
420 pm->monitor = &(pmonitorEx->Monitor);
424 if (pm->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) {
441 monitor_unload(pm);
442 SetLastError(ERROR_PROC_NOT_FOUND);
443 pm = NULL;
446 cleanup:
447 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
448 pm->refcount++;
449 pm_localport = pm;
451 LeaveCriticalSection(&monitor_handles_cs);
452 if (driver != dllname) heap_free(driver);
453 heap_free(regroot);
454 TRACE("=> %p\n", pm);
455 return 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;
466 if (!str) return 0;
469 ptr += lstrlenW(ptr) + 1;
470 } while (*ptr);
472 return (ptr - str + 1) * sizeof(WCHAR);
475 /******************************************************************
476 * validate_envW [internal]
478 * validate the user-supplied printing-environment
480 * PARAMS
481 * env [I] PTR to Environment-String or NULL
483 * RETURNS
484 * Success: PTR to printenv_t
485 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
487 * NOTES
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;
495 unsigned int i;
497 TRACE("(%s)\n", debugstr_w(env));
498 if (env && env[0])
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];
505 break;
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 */
514 else
516 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
519 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
520 return result;
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)
536 HKEY hroot = NULL;
537 HKEY hentry = NULL;
538 LPWSTR ptr;
539 LPMONITOR_INFO_2W mi;
540 WCHAR buffer[MAX_PATH];
541 WCHAR dllname[MAX_PATH];
542 DWORD dllsize;
543 DWORD len;
544 DWORD index = 0;
545 DWORD needed = 0;
546 DWORD numentries;
547 DWORD entrysize;
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];
555 numentries = 0;
556 len = sizeof(buffer)/sizeof(buffer[0]);
557 buffer[0] = '\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);
565 dllname[0] = '\0';
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));
573 RegCloseKey(hentry);
576 /* Windows returns only Port-Monitors here, but to simplify our code,
577 we do no filtering for Language-Monitors */
578 if (dllname[0]) {
579 numentries++;
580 needed += entrysize;
581 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
582 if (level > 1) {
583 /* we install and return only monitors for "Windows NT x86" */
584 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
585 needed += dllsize;
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);
594 mi->pName = ptr;
595 lstrcpyW(ptr, buffer); /* Name of the Monitor */
596 ptr += (len+1); /* len is lstrlenW(monitorname) */
597 if (level > 1) {
598 mi->pEnvironment = ptr;
599 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
600 ptr += (lstrlenW(x86_envnameW)+1);
602 mi->pDLLName = ptr;
603 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
604 ptr += (dllsize / sizeof(WCHAR));
608 index++;
609 len = sizeof(buffer)/sizeof(buffer[0]);
610 buffer[0] = '\0';
612 RegCloseKey(hroot);
614 *lpreturned = numentries;
615 TRACE("need %d byte for %d entries\n", needed, numentries);
616 return needed;
619 /*****************************************************************************
620 * open_driver_reg [internal]
622 * opens the registry for the printer drivers depending on the given input
623 * variable pEnvironment
625 * RETURNS:
626 * Success: the opened hkey
627 * Failure: NULL
629 static HKEY open_driver_reg(LPCWSTR pEnvironment)
631 HKEY retval = NULL;
632 LPWSTR buffer;
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));
643 if (buffer) {
644 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
645 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
646 HeapFree(GetProcessHeap(), 0, buffer);
648 return retval;
651 /*****************************************************************************
652 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
654 * Return the PATH for the Printer-Drivers
656 * PARAMS
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
665 * RETURNS
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)
681 DWORD needed;
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);
690 return FALSE;
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 */
704 *pcbNeeded = needed;
706 if (needed > cbBuf) {
707 SetLastError(ERROR_INSUFFICIENT_BUFFER);
708 return FALSE;
711 if (pDriverDirectory == NULL) {
712 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
713 SetLastError(ERROR_INVALID_USER_BUFFER);
714 return FALSE;
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));
723 return TRUE;
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];
738 HMODULE hui;
739 DWORD len;
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);
751 return NULL;
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());
761 return hui;
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;
775 apd_data_t apd;
776 DRIVER_INFO_8W di;
777 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
778 HMODULE hui;
779 LPWSTR ptr;
780 HKEY hroot;
781 HKEY hdrv;
782 DWORD disposition;
783 DWORD len;
784 LONG lres;
785 BOOL res;
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 */
816 return FALSE;
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;
825 apd.lazy = lazy;
826 CreateDirectoryW(apd.src, NULL);
827 CreateDirectoryW(apd.dst, NULL);
829 hroot = open_driver_reg(env->envname);
830 if (!hroot) {
831 ERR("Can't create Drivers key\n");
832 return FALSE;
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);
841 RegCloseKey(hroot);
842 SetLastError(lres);
843 return FALSE;
845 RegCloseKey(hroot);
847 if (disposition == REG_OPENED_EXISTING_KEY) {
848 TRACE("driver %s already installed\n", debugstr_w(di.pName));
849 RegCloseKey(hdrv);
850 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
851 return FALSE;
854 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
855 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
856 sizeof(DWORD));
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 */
871 if (di.pHelpFile)
872 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
873 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
874 else
875 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
876 apd_copyfile(di.pHelpFile, &apd);
879 ptr = di.pDependentFiles;
880 if (ptr)
881 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
882 multi_sz_lenW(di.pDependentFiles));
883 else
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;
889 else
891 WARN("Failed to copy %s\n", debugstr_w(ptr));
892 ptr = NULL;
895 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
896 if (di.pMonitorName)
897 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
898 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
899 else
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));
905 else
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));
912 else
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));
917 RegCloseKey(hdrv);
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);
928 FreeLibrary(hui);
930 TRACE("=> TRUE with %u\n", GetLastError());
931 return TRUE;
935 /******************************************************************************
936 * fpAddMonitor [exported through PRINTPROVIDOR]
938 * Install a Printmonitor
940 * PARAMS
941 * pName [I] Servername or NULL (local Computer)
942 * Level [I] Structure-Level (Must be 2)
943 * pMonitors [I] PTR to MONITOR_INFO_2
945 * RETURNS
946 * Success: TRUE
947 * Failure: FALSE
949 * NOTES
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;
957 HKEY hroot = NULL;
958 HKEY hentry = NULL;
959 DWORD disposition;
960 BOOL res = FALSE;
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);
971 return FALSE;
974 if (!mi2w->pName || (! mi2w->pName[0])) {
975 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
976 SetLastError(ERROR_INVALID_PARAMETER);
977 return FALSE;
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);
983 return FALSE;
986 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
987 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
988 SetLastError(ERROR_INVALID_PARAMETER);
989 return FALSE;
992 /* Load and initialize the monitor. SetLastError() is called on failure */
993 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
994 return FALSE;
996 monitor_unload(pm);
998 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
999 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1000 return FALSE;
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. */
1013 DWORD namesize = 0;
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);
1022 else
1024 INT len;
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);
1032 RegCloseKey(hroot);
1033 return (res);
1036 /******************************************************************************
1037 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1039 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1041 * PARAMS
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
1047 * RESULTS
1048 * Success: TRUE
1049 * Failure: FALSE
1052 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1054 LONG lres;
1056 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1057 lres = copy_servername_from_name(pName, NULL);
1058 if (lres) {
1059 FIXME("server %s not supported\n", debugstr_w(pName));
1060 SetLastError(ERROR_ACCESS_DENIED);
1061 return FALSE;
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
1075 * PARAMS
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
1080 * RETURNS
1081 * Success: TRUE
1082 * Failure: FALSE
1084 * NOTES
1085 * pEnvironment is ignored in Windows for the local Computer.
1089 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1091 HKEY hroot = NULL;
1092 LONG lres;
1094 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1095 debugstr_w(pMonitorName));
1097 lres = copy_servername_from_name(pName, NULL);
1098 if (lres) {
1099 FIXME("server %s not supported\n", debugstr_w(pName));
1100 SetLastError(ERROR_INVALID_NAME);
1101 return FALSE;
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);
1108 return FALSE;
1111 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1112 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1113 return FALSE;
1116 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1117 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1118 RegCloseKey(hroot);
1119 return TRUE;
1122 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1123 RegCloseKey(hroot);
1125 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1126 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1127 return FALSE;
1130 /*****************************************************************************
1131 * fpEnumMonitors [exported through PRINTPROVIDOR]
1133 * Enumerate available Port-Monitors
1135 * PARAMS
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
1143 * RETURNS
1144 * Success: TRUE
1145 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
1147 * NOTES
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;
1155 DWORD needed = 0;
1156 LONG lres;
1157 BOOL res = FALSE;
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);
1163 if (lres) {
1164 FIXME("server %s not supported\n", debugstr_w(pName));
1165 SetLastError(ERROR_INVALID_NAME);
1166 goto em_cleanup;
1169 if (!Level || (Level > 2)) {
1170 WARN("level (%d) is ignored in win9x\n", Level);
1171 SetLastError(ERROR_INVALID_LEVEL);
1172 return FALSE;
1175 /* Scan all Monitor-Keys */
1176 numentries = 0;
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);
1182 goto em_cleanup;
1185 /* fill the Buffer with the Monitor-Keys */
1186 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1187 res = TRUE;
1189 em_cleanup:
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);
1196 return (res);
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 */
1242 fpEnumMonitors,
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 */
1253 fpAddMonitor,
1254 fpDeleteMonitor,
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);
1293 return &backend;
1297 /*****************************************************
1298 * DllMain
1300 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1302 TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
1304 switch(fdwReason)
1306 case DLL_WINE_PREATTACH:
1307 return FALSE; /* prefer native version */
1309 case DLL_PROCESS_ATTACH:
1310 DisableThreadLibraryCalls( hinstDLL );
1311 LOCALSPL_hInstance = hinstDLL;
1312 pp = get_backend();
1313 break;
1315 return TRUE;
1319 /*****************************************************
1320 * InitializePrintProvidor (localspl.@)
1322 * Initialize the Printprovider
1324 * PARAMS
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
1329 * RETURNS
1330 * Success: TRUE and pPrintProvidor filled
1331 * Failure: FALSE
1333 * NOTES
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));
1347 return TRUE;