kernel32: Change all functions to use CDECL.
[wine/wine64.git] / dlls / localspl / localspl_main.c
blob4483ac8890593711b798b3f0bc195f8a433055c7
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 "ddk/winsplp.h"
32 #include "winuser.h"
34 #include "wine/list.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "localspl_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(localspl);
41 /* ############################### */
43 static CRITICAL_SECTION monitor_handles_cs;
44 static CRITICAL_SECTION_DEBUG monitor_handles_cs_debug =
46 0, 0, &monitor_handles_cs,
47 { &monitor_handles_cs_debug.ProcessLocksList, &monitor_handles_cs_debug.ProcessLocksList },
48 0, 0, { (DWORD_PTR)(__FILE__ ": monitor_handles_cs") }
50 static CRITICAL_SECTION monitor_handles_cs = { &monitor_handles_cs_debug, -1, 0, 0, 0, 0 };
52 /* ############################### */
54 typedef struct {
55 WCHAR src[MAX_PATH+MAX_PATH];
56 WCHAR dst[MAX_PATH+MAX_PATH];
57 DWORD srclen;
58 DWORD dstlen;
59 DWORD copyflags;
60 BOOL lazy;
61 } apd_data_t;
63 typedef struct {
64 struct list entry;
65 LPWSTR name;
66 LPWSTR dllname;
67 PMONITORUI monitorUI;
68 LPMONITOR monitor;
69 HMODULE hdll;
70 DWORD refcount;
71 DWORD dwMonitorSize;
72 } monitor_t;
74 typedef struct {
75 LPCWSTR envname;
76 LPCWSTR subdir;
77 DWORD driverversion;
78 LPCWSTR versionregpath;
79 LPCWSTR versionsubdir;
80 } printenv_t;
83 /* ############################### */
85 static struct list monitor_handles = LIST_INIT( monitor_handles );
86 static monitor_t * pm_localport;
88 HINSTANCE LOCALSPL_hInstance = NULL;
90 static const PRINTPROVIDOR * pp = NULL;
92 static const WCHAR backslashW[] = {'\\',0};
93 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
94 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
95 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
96 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
97 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
98 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
99 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
100 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
101 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
102 'c','o','n','t','r','o','l','\\',
103 'P','r','i','n','t','\\',
104 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
105 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
106 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
107 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
108 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
109 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
110 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
111 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
112 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
113 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
114 'C','o','n','t','r','o','l','\\',
115 'P','r','i','n','t','\\',
116 'M','o','n','i','t','o','r','s','\\',0};
117 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
118 static const WCHAR nameW[] = {'N','a','m','e',0};
119 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
120 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
121 static const WCHAR portW[] = {'P','o','r','t',0};
122 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
123 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
124 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
126 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
127 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
128 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
129 static const WCHAR version0_subdirW[] = {'\\','0',0};
131 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
132 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
133 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
134 static const WCHAR version3_subdirW[] = {'\\','3',0};
137 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
138 version3_regpathW, version3_subdirW};
140 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
141 version0_regpathW, version0_subdirW};
143 static const printenv_t * const all_printenv[] = {&env_x86, &env_win40};
146 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
147 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
148 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
149 0, sizeof(DRIVER_INFO_8W)};
152 /******************************************************************
153 * strdupW [internal]
155 * create a copy of a unicode-string
159 static LPWSTR strdupW(LPCWSTR p)
161 LPWSTR ret;
162 DWORD len;
164 if(!p) return NULL;
165 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
166 ret = heap_alloc(len);
167 memcpy(ret, p, len);
168 return ret;
171 /******************************************************************
172 * apd_copyfile [internal]
174 * Copy a file from the driverdirectory to the versioned directory
176 * RETURNS
177 * Success: TRUE
178 * Failure: FALSE
181 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
183 LPWSTR ptr;
184 LPWSTR srcname;
185 DWORD res;
187 apd->src[apd->srclen] = '\0';
188 apd->dst[apd->dstlen] = '\0';
190 if (!filename || !filename[0]) {
191 /* nothing to copy */
192 return TRUE;
195 ptr = strrchrW(filename, '\\');
196 if (ptr) {
197 ptr++;
199 else
201 ptr = filename;
204 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
205 /* we have an absolute Path */
206 srcname = filename;
208 else
210 srcname = apd->src;
211 lstrcatW(srcname, ptr);
213 lstrcatW(apd->dst, ptr);
215 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
217 /* FIXME: handle APD_COPY_NEW_FILES */
218 res = CopyFileW(srcname, apd->dst, FALSE);
219 TRACE("got %u with %u\n", res, GetLastError());
221 return (apd->lazy) ? TRUE : res;
224 /******************************************************************
225 * copy_servername_from_name (internal)
227 * for an external server, the serverpart from the name is copied.
229 * RETURNS
230 * the length (in WCHAR) of the serverpart (0 for the local computer)
231 * (-length), when the name is to long
234 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
236 LPCWSTR server;
237 LPWSTR ptr;
238 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
239 DWORD len;
240 DWORD serverlen;
242 if (target) *target = '\0';
244 if (name == NULL) return 0;
245 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
247 server = &name[2];
248 /* skip over both backslash, find separator '\' */
249 ptr = strchrW(server, '\\');
250 serverlen = (ptr) ? ptr - server : lstrlenW(server);
252 /* servername is empty or to long */
253 if (serverlen == 0) return 0;
255 TRACE("found %s\n", debugstr_wn(server, serverlen));
257 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
259 len = sizeof(buffer) / sizeof(buffer[0]);
260 if (GetComputerNameW(buffer, &len)) {
261 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
262 /* The requested Servername is our computername */
263 if (target) {
264 memcpy(target, server, serverlen * sizeof(WCHAR));
265 target[serverlen] = '\0';
267 return serverlen;
270 return 0;
273 /******************************************************************
274 * monitor_unload [internal]
276 * release a printmonitor and unload it from memory, when needed
279 static void monitor_unload(monitor_t * pm)
281 if (pm == NULL) return;
282 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
284 EnterCriticalSection(&monitor_handles_cs);
286 if (pm->refcount) pm->refcount--;
288 if (pm->refcount == 0) {
289 list_remove(&pm->entry);
290 FreeLibrary(pm->hdll);
291 heap_free(pm->name);
292 heap_free(pm->dllname);
293 heap_free(pm);
295 LeaveCriticalSection(&monitor_handles_cs);
298 /******************************************************************
299 * monitor_load [internal]
301 * load a printmonitor, get the dllname from the registry, when needed
302 * initialize the monitor and dump found function-pointers
304 * On failure, SetLastError() is called and NULL is returned
307 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
309 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
310 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
311 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
312 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
313 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
315 monitor_t * pm = NULL;
316 monitor_t * cursor;
317 LPWSTR regroot = NULL;
318 LPWSTR driver = dllname;
320 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
321 /* Is the Monitor already loaded? */
322 EnterCriticalSection(&monitor_handles_cs);
324 if (name) {
325 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
327 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
328 pm = cursor;
329 break;
334 if (pm == NULL) {
335 pm = heap_alloc_zero(sizeof(monitor_t));
336 if (pm == NULL) goto cleanup;
337 list_add_tail(&monitor_handles, &pm->entry);
339 pm->refcount++;
341 if (pm->name == NULL) {
342 /* Load the monitor */
343 LPMONITOREX pmonitorEx;
344 DWORD len;
346 if (name) {
347 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
348 regroot = heap_alloc(len * sizeof(WCHAR));
351 if (regroot) {
352 lstrcpyW(regroot, monitorsW);
353 lstrcatW(regroot, name);
354 /* Get the Driver from the Registry */
355 if (driver == NULL) {
356 HKEY hroot;
357 DWORD namesize;
358 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
359 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
360 &namesize) == ERROR_SUCCESS) {
361 driver = heap_alloc(namesize);
362 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
364 RegCloseKey(hroot);
369 pm->name = strdupW(name);
370 pm->dllname = strdupW(driver);
372 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
373 monitor_unload(pm);
374 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
375 pm = NULL;
376 goto cleanup;
379 pm->hdll = LoadLibraryW(driver);
380 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
382 if (pm->hdll == NULL) {
383 monitor_unload(pm);
384 SetLastError(ERROR_MOD_NOT_FOUND);
385 pm = NULL;
386 goto cleanup;
389 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
390 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
391 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
392 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
393 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
396 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
397 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
398 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
399 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
400 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
402 if (pInitializePrintMonitorUI != NULL) {
403 pm->monitorUI = pInitializePrintMonitorUI();
404 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
405 if (pm->monitorUI) {
406 TRACE("0x%08x: dwMonitorSize (%d)\n",
407 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
412 if (pInitializePrintMonitor && regroot) {
413 pmonitorEx = pInitializePrintMonitor(regroot);
414 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
415 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
417 if (pmonitorEx) {
418 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
419 pm->monitor = &(pmonitorEx->Monitor);
423 if (pm->monitor) {
424 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
428 if (!pm->monitor && regroot) {
429 if (pInitializePrintMonitor2 != NULL) {
430 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
432 if (pInitializeMonitorEx != NULL) {
433 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
435 if (pInitializeMonitor != NULL) {
436 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
439 if (!pm->monitor && !pm->monitorUI) {
440 monitor_unload(pm);
441 SetLastError(ERROR_PROC_NOT_FOUND);
442 pm = NULL;
445 cleanup:
446 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
447 pm->refcount++;
448 pm_localport = pm;
450 LeaveCriticalSection(&monitor_handles_cs);
451 if (driver != dllname) heap_free(driver);
452 heap_free(regroot);
453 TRACE("=> %p\n", pm);
454 return pm;
457 /******************************************************************
458 * Return the number of bytes for an multi_sz string.
459 * The result includes all \0s
460 * (specifically the extra \0, that is needed as multi_sz terminator).
462 static int multi_sz_lenW(const WCHAR *str)
464 const WCHAR *ptr = str;
465 if (!str) return 0;
468 ptr += lstrlenW(ptr) + 1;
469 } while (*ptr);
471 return (ptr - str + 1) * sizeof(WCHAR);
474 /******************************************************************
475 * validate_envW [internal]
477 * validate the user-supplied printing-environment
479 * PARAMS
480 * env [I] PTR to Environment-String or NULL
482 * RETURNS
483 * Success: PTR to printenv_t
484 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
486 * NOTES
487 * An empty string is handled the same way as NULL.
491 static const printenv_t * validate_envW(LPCWSTR env)
493 const printenv_t *result = NULL;
494 unsigned int i;
496 TRACE("(%s)\n", debugstr_w(env));
497 if (env && env[0])
499 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
501 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
503 result = all_printenv[i];
504 break;
507 if (result == NULL) {
508 FIXME("unsupported Environment: %s\n", debugstr_w(env));
509 SetLastError(ERROR_INVALID_ENVIRONMENT);
511 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
513 else
515 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
518 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
519 return result;
522 /*****************************************************************************
523 * enumerate the local monitors (INTERNAL)
525 * returns the needed size (in bytes) for pMonitors
526 * and *lpreturned is set to number of entries returned in pMonitors
528 * Language-Monitors are also installed in the same Registry-Location but
529 * they are filtered in Windows (not returned by EnumMonitors).
530 * We do no filtering to simplify our Code.
533 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
535 HKEY hroot = NULL;
536 HKEY hentry = NULL;
537 LPWSTR ptr;
538 LPMONITOR_INFO_2W mi;
539 WCHAR buffer[MAX_PATH];
540 WCHAR dllname[MAX_PATH];
541 DWORD dllsize;
542 DWORD len;
543 DWORD index = 0;
544 DWORD needed = 0;
545 DWORD numentries;
546 DWORD entrysize;
548 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
550 numentries = *lpreturned; /* this is 0, when we scan the registry */
551 len = entrysize * numentries;
552 ptr = (LPWSTR) &pMonitors[len];
554 numentries = 0;
555 len = sizeof(buffer)/sizeof(buffer[0]);
556 buffer[0] = '\0';
558 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
559 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
560 /* Scan all Monitor-Registry-Keys */
561 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
562 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
563 dllsize = sizeof(dllname);
564 dllname[0] = '\0';
566 /* The Monitor must have a Driver-DLL */
567 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
568 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
569 /* We found a valid DLL for this Monitor. */
570 TRACE("using Driver: %s\n", debugstr_w(dllname));
572 RegCloseKey(hentry);
575 /* Windows returns only Port-Monitors here, but to simplify our code,
576 we do no filtering for Language-Monitors */
577 if (dllname[0]) {
578 numentries++;
579 needed += entrysize;
580 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
581 if (level > 1) {
582 /* we install and return only monitors for "Windows NT x86" */
583 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
584 needed += dllsize;
587 /* required size is calculated. Now fill the user-buffer */
588 if (pMonitors && (cbBuf >= needed)){
589 mi = (LPMONITOR_INFO_2W) pMonitors;
590 pMonitors += entrysize;
592 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
593 mi->pName = ptr;
594 lstrcpyW(ptr, buffer); /* Name of the Monitor */
595 ptr += (len+1); /* len is lstrlenW(monitorname) */
596 if (level > 1) {
597 mi->pEnvironment = ptr;
598 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
599 ptr += (lstrlenW(x86_envnameW)+1);
601 mi->pDLLName = ptr;
602 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
603 ptr += (dllsize / sizeof(WCHAR));
607 index++;
608 len = sizeof(buffer)/sizeof(buffer[0]);
609 buffer[0] = '\0';
611 RegCloseKey(hroot);
613 *lpreturned = numentries;
614 TRACE("need %d byte for %d entries\n", needed, numentries);
615 return needed;
618 /*****************************************************************************
619 * open_driver_reg [internal]
621 * opens the registry for the printer drivers depending on the given input
622 * variable pEnvironment
624 * RETURNS:
625 * Success: the opened hkey
626 * Failure: NULL
628 static HKEY open_driver_reg(LPCWSTR pEnvironment)
630 HKEY retval = NULL;
631 LPWSTR buffer;
632 const printenv_t * env;
634 TRACE("(%s)\n", debugstr_w(pEnvironment));
636 env = validate_envW(pEnvironment);
637 if (!env) return NULL;
639 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
640 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
642 if (buffer) {
643 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
644 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
645 HeapFree(GetProcessHeap(), 0, buffer);
647 return retval;
650 /*****************************************************************************
651 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
653 * Return the PATH for the Printer-Drivers
655 * PARAMS
656 * pName [I] Servername (NT only) or NULL (local Computer)
657 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
658 * Level [I] Structure-Level (must be 1)
659 * pDriverDirectory [O] PTR to Buffer that receives the Result
660 * cbBuf [I] Size of Buffer at pDriverDirectory
661 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
662 * required for pDriverDirectory
664 * RETURNS
665 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
666 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
667 * if cbBuf is too small
669 * Native Values returned in pDriverDirectory on Success:
670 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
671 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
672 *| win9x(Windows 4.0): "%winsysdir%"
674 * "%winsysdir%" is the Value from GetSystemDirectoryW()
677 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
678 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
680 DWORD needed;
681 const printenv_t * env;
683 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
684 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
686 if (pName != NULL && pName[0]) {
687 FIXME("server %s not supported\n", debugstr_w(pName));
688 SetLastError(ERROR_INVALID_PARAMETER);
689 return FALSE;
692 env = validate_envW(pEnvironment);
693 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
696 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
697 needed = GetSystemDirectoryW(NULL, 0);
698 /* add the Size for the Subdirectories */
699 needed += lstrlenW(spooldriversW);
700 needed += lstrlenW(env->subdir);
701 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
703 *pcbNeeded = needed;
705 if (needed > cbBuf) {
706 SetLastError(ERROR_INSUFFICIENT_BUFFER);
707 return FALSE;
710 if (pDriverDirectory == NULL) {
711 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
712 SetLastError(ERROR_INVALID_USER_BUFFER);
713 return FALSE;
716 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
717 /* add the Subdirectories */
718 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
719 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
721 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
722 return TRUE;
725 /******************************************************************************
726 * myAddPrinterDriverEx [internal]
728 * Install a Printer Driver with the Option to upgrade / downgrade the Files
729 * and a special mode with lazy error checking.
732 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
734 static const WCHAR emptyW[1];
735 const printenv_t *env;
736 apd_data_t apd;
737 DRIVER_INFO_8W di;
738 LPWSTR ptr;
739 HKEY hroot;
740 HKEY hdrv;
741 DWORD disposition;
742 DWORD len;
743 LONG lres;
745 /* we need to set all entries in the Registry, independent from the Level of
746 DRIVER_INFO, that the caller supplied */
748 ZeroMemory(&di, sizeof(di));
749 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
750 memcpy(&di, pDriverInfo, di_sizeof[level]);
753 /* dump the most used infos */
754 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
755 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
756 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
757 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
758 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
759 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
760 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
761 /* dump only the first of the additional Files */
762 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
765 /* check environment */
766 env = validate_envW(di.pEnvironment);
767 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
769 /* fill the copy-data / get the driverdir */
770 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
771 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
772 (LPBYTE) apd.src, len, &len)) {
773 /* Should never Fail */
774 return FALSE;
776 memcpy(apd.dst, apd.src, len);
777 lstrcatW(apd.src, backslashW);
778 apd.srclen = lstrlenW(apd.src);
779 lstrcatW(apd.dst, env->versionsubdir);
780 lstrcatW(apd.dst, backslashW);
781 apd.dstlen = lstrlenW(apd.dst);
782 apd.copyflags = dwFileCopyFlags;
783 apd.lazy = lazy;
784 CreateDirectoryW(apd.src, NULL);
785 CreateDirectoryW(apd.dst, NULL);
787 hroot = open_driver_reg(env->envname);
788 if (!hroot) {
789 ERR("Can't create Drivers key\n");
790 return FALSE;
793 /* Fill the Registry for the Driver */
794 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
795 KEY_WRITE | KEY_QUERY_VALUE, NULL,
796 &hdrv, &disposition)) != ERROR_SUCCESS) {
798 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
799 RegCloseKey(hroot);
800 SetLastError(lres);
801 return FALSE;
803 RegCloseKey(hroot);
805 if (disposition == REG_OPENED_EXISTING_KEY) {
806 TRACE("driver %s already installed\n", debugstr_w(di.pName));
807 RegCloseKey(hdrv);
808 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
809 return FALSE;
812 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
813 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
814 sizeof(DWORD));
816 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
817 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
818 apd_copyfile(di.pDriverPath, &apd);
820 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
821 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
822 apd_copyfile(di.pDataFile, &apd);
824 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
825 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
826 apd_copyfile(di.pConfigFile, &apd);
828 /* settings for level 3 */
829 if (di.pHelpFile)
830 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
831 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
832 else
833 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
834 apd_copyfile(di.pHelpFile, &apd);
837 ptr = di.pDependentFiles;
838 if (ptr)
839 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
840 multi_sz_lenW(di.pDependentFiles));
841 else
842 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
843 while ((ptr != NULL) && (ptr[0])) {
844 if (apd_copyfile(ptr, &apd)) {
845 ptr += lstrlenW(ptr) + 1;
847 else
849 WARN("Failed to copy %s\n", debugstr_w(ptr));
850 ptr = NULL;
853 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
854 if (di.pMonitorName)
855 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
856 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
857 else
858 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
860 if (di.pDefaultDataType)
861 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
862 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
863 else
864 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
866 /* settings for level 4 */
867 if (di.pszzPreviousNames)
868 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
869 multi_sz_lenW(di.pszzPreviousNames));
870 else
871 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
873 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
875 RegCloseKey(hdrv);
876 TRACE("### DrvDriverEvent(...,DRIVEREVENT_INITIALIZE) not implemented yet\n");
878 TRACE("=> TRUE with %u\n", GetLastError());
879 return TRUE;
883 /******************************************************************************
884 * fpAddMonitor [exported through PRINTPROVIDOR]
886 * Install a Printmonitor
888 * PARAMS
889 * pName [I] Servername or NULL (local Computer)
890 * Level [I] Structure-Level (Must be 2)
891 * pMonitors [I] PTR to MONITOR_INFO_2
893 * RETURNS
894 * Success: TRUE
895 * Failure: FALSE
897 * NOTES
898 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
901 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
903 monitor_t * pm = NULL;
904 LPMONITOR_INFO_2W mi2w;
905 HKEY hroot = NULL;
906 HKEY hentry = NULL;
907 DWORD disposition;
908 BOOL res = FALSE;
910 mi2w = (LPMONITOR_INFO_2W) pMonitors;
911 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
912 debugstr_w(mi2w ? mi2w->pName : NULL),
913 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
914 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
916 if (copy_servername_from_name(pName, NULL)) {
917 FIXME("server %s not supported\n", debugstr_w(pName));
918 SetLastError(ERROR_ACCESS_DENIED);
919 return FALSE;
922 if (!mi2w->pName || (! mi2w->pName[0])) {
923 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
924 SetLastError(ERROR_INVALID_PARAMETER);
925 return FALSE;
927 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
928 WARN("Environment %s requested (we support only %s)\n",
929 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
930 SetLastError(ERROR_INVALID_ENVIRONMENT);
931 return FALSE;
934 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
935 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
936 SetLastError(ERROR_INVALID_PARAMETER);
937 return FALSE;
940 /* Load and initialize the monitor. SetLastError() is called on failure */
941 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
942 return FALSE;
944 monitor_unload(pm);
946 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
947 ERR("unable to create key %s\n", debugstr_w(monitorsW));
948 return FALSE;
951 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
952 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
953 &disposition) == ERROR_SUCCESS) {
955 /* Some installers set options for the port before calling AddMonitor.
956 We query the "Driver" entry to verify that the monitor is installed,
957 before we return an error.
958 When a user installs two print monitors at the same time with the
959 same name, a race condition is possible but silently ignored. */
961 DWORD namesize = 0;
963 if ((disposition == REG_OPENED_EXISTING_KEY) &&
964 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
965 &namesize) == ERROR_SUCCESS)) {
966 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
967 /* 9x use ERROR_ALREADY_EXISTS */
968 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
970 else
972 INT len;
973 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
974 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
975 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
977 RegCloseKey(hentry);
980 RegCloseKey(hroot);
981 return (res);
984 /******************************************************************************
985 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
987 * Install a Printer Driver with the Option to upgrade / downgrade the Files
989 * PARAMS
990 * pName [I] Servername or NULL (local Computer)
991 * level [I] Level for the supplied DRIVER_INFO_*W struct
992 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
993 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
995 * RESULTS
996 * Success: TRUE
997 * Failure: FALSE
1000 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1002 LONG lres;
1004 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1005 lres = copy_servername_from_name(pName, NULL);
1006 if (lres) {
1007 FIXME("server %s not supported\n", debugstr_w(pName));
1008 SetLastError(ERROR_ACCESS_DENIED);
1009 return FALSE;
1012 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1013 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1016 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1018 /******************************************************************
1019 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1021 * Delete a specific Printmonitor from a Printing-Environment
1023 * PARAMS
1024 * pName [I] Servername or NULL (local Computer)
1025 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1026 * pMonitorName [I] Name of the Monitor, that should be deleted
1028 * RETURNS
1029 * Success: TRUE
1030 * Failure: FALSE
1032 * NOTES
1033 * pEnvironment is ignored in Windows for the local Computer.
1037 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1039 HKEY hroot = NULL;
1040 LONG lres;
1042 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1043 debugstr_w(pMonitorName));
1045 lres = copy_servername_from_name(pName, NULL);
1046 if (lres) {
1047 FIXME("server %s not supported\n", debugstr_w(pName));
1048 SetLastError(ERROR_INVALID_NAME);
1049 return FALSE;
1052 /* pEnvironment is ignored in Windows for the local Computer */
1053 if (!pMonitorName || !pMonitorName[0]) {
1054 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1055 SetLastError(ERROR_INVALID_PARAMETER);
1056 return FALSE;
1059 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1060 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1061 return FALSE;
1064 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1065 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1066 RegCloseKey(hroot);
1067 return TRUE;
1070 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1071 RegCloseKey(hroot);
1073 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1074 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1075 return FALSE;
1078 /*****************************************************************************
1079 * fpEnumMonitors [exported through PRINTPROVIDOR]
1081 * Enumerate available Port-Monitors
1083 * PARAMS
1084 * pName [I] Servername or NULL (local Computer)
1085 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1086 * pMonitors [O] PTR to Buffer that receives the Result
1087 * cbBuf [I] Size of Buffer at pMonitors
1088 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1089 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1091 * RETURNS
1092 * Success: TRUE
1093 * Failure: FALSE and in pcbNeeded the Bytes required for buffer, if cbBuf is too small
1095 * NOTES
1096 * Windows reads the Registry once and cache the Results.
1099 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1100 LPDWORD pcbNeeded, LPDWORD pcReturned)
1102 DWORD numentries = 0;
1103 DWORD needed = 0;
1104 LONG lres;
1105 BOOL res = FALSE;
1107 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1108 cbBuf, pcbNeeded, pcReturned);
1110 lres = copy_servername_from_name(pName, NULL);
1111 if (lres) {
1112 FIXME("server %s not supported\n", debugstr_w(pName));
1113 SetLastError(ERROR_INVALID_NAME);
1114 goto em_cleanup;
1117 if (!Level || (Level > 2)) {
1118 WARN("level (%d) is ignored in win9x\n", Level);
1119 SetLastError(ERROR_INVALID_LEVEL);
1120 return FALSE;
1123 /* Scan all Monitor-Keys */
1124 numentries = 0;
1125 needed = get_local_monitors(Level, NULL, 0, &numentries);
1127 /* we calculated the needed buffersize. now do more error-checks */
1128 if (cbBuf < needed) {
1129 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1130 goto em_cleanup;
1133 /* fill the Buffer with the Monitor-Keys */
1134 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1135 res = TRUE;
1137 em_cleanup:
1138 if (pcbNeeded) *pcbNeeded = needed;
1139 if (pcReturned) *pcReturned = numentries;
1141 TRACE("returning %d with %d (%d byte for %d entries)\n",
1142 res, GetLastError(), needed, numentries);
1144 return (res);
1147 /*****************************************************
1148 * get_backend [internal]
1150 static const PRINTPROVIDOR * get_backend(void)
1152 static const PRINTPROVIDOR backend = {
1153 NULL, /* fpOpenPrinter */
1154 NULL, /* fpSetJob */
1155 NULL, /* fpGetJob */
1156 NULL, /* fpEnumJobs */
1157 NULL, /* fpAddPrinter */
1158 NULL, /* fpDeletePrinter */
1159 NULL, /* fpSetPrinter */
1160 NULL, /* fpGetPrinter */
1161 NULL, /* fpEnumPrinters */
1162 NULL, /* fpAddPrinterDriver */
1163 NULL, /* fpEnumPrinterDrivers */
1164 NULL, /* fpGetPrinterDriver */
1165 fpGetPrinterDriverDirectory,
1166 NULL, /* fpDeletePrinterDriver */
1167 NULL, /* fpAddPrintProcessor */
1168 NULL, /* fpEnumPrintProcessors */
1169 NULL, /* fpGetPrintProcessorDirectory */
1170 NULL, /* fpDeletePrintProcessor */
1171 NULL, /* fpEnumPrintProcessorDatatypes */
1172 NULL, /* fpStartDocPrinter */
1173 NULL, /* fpStartPagePrinter */
1174 NULL, /* fpWritePrinter */
1175 NULL, /* fpEndPagePrinter */
1176 NULL, /* fpAbortPrinter */
1177 NULL, /* fpReadPrinter */
1178 NULL, /* fpEndDocPrinter */
1179 NULL, /* fpAddJob */
1180 NULL, /* fpScheduleJob */
1181 NULL, /* fpGetPrinterData */
1182 NULL, /* fpSetPrinterData */
1183 NULL, /* fpWaitForPrinterChange */
1184 NULL, /* fpClosePrinter */
1185 NULL, /* fpAddForm */
1186 NULL, /* fpDeleteForm */
1187 NULL, /* fpGetForm */
1188 NULL, /* fpSetForm */
1189 NULL, /* fpEnumForms */
1190 fpEnumMonitors,
1191 NULL, /* fpEnumPorts */
1192 NULL, /* fpAddPort */
1193 NULL, /* fpConfigurePort */
1194 NULL, /* fpDeletePort */
1195 NULL, /* fpCreatePrinterIC */
1196 NULL, /* fpPlayGdiScriptOnPrinterIC */
1197 NULL, /* fpDeletePrinterIC */
1198 NULL, /* fpAddPrinterConnection */
1199 NULL, /* fpDeletePrinterConnection */
1200 NULL, /* fpPrinterMessageBox */
1201 fpAddMonitor,
1202 fpDeleteMonitor,
1203 NULL, /* fpResetPrinter */
1204 NULL, /* fpGetPrinterDriverEx */
1205 NULL, /* fpFindFirstPrinterChangeNotification */
1206 NULL, /* fpFindClosePrinterChangeNotification */
1207 NULL, /* fpAddPortEx */
1208 NULL, /* fpShutDown */
1209 NULL, /* fpRefreshPrinterChangeNotification */
1210 NULL, /* fpOpenPrinterEx */
1211 NULL, /* fpAddPrinterEx */
1212 NULL, /* fpSetPort */
1213 NULL, /* fpEnumPrinterData */
1214 NULL, /* fpDeletePrinterData */
1215 NULL, /* fpClusterSplOpen */
1216 NULL, /* fpClusterSplClose */
1217 NULL, /* fpClusterSplIsAlive */
1218 NULL, /* fpSetPrinterDataEx */
1219 NULL, /* fpGetPrinterDataEx */
1220 NULL, /* fpEnumPrinterDataEx */
1221 NULL, /* fpEnumPrinterKey */
1222 NULL, /* fpDeletePrinterDataEx */
1223 NULL, /* fpDeletePrinterKey */
1224 NULL, /* fpSeekPrinter */
1225 NULL, /* fpDeletePrinterDriverEx */
1226 NULL, /* fpAddPerMachineConnection */
1227 NULL, /* fpDeletePerMachineConnection */
1228 NULL, /* fpEnumPerMachineConnections */
1229 NULL, /* fpXcvData */
1230 fpAddPrinterDriverEx,
1231 NULL, /* fpSplReadPrinter */
1232 NULL, /* fpDriverUnloadComplete */
1233 NULL, /* fpGetSpoolFileInfo */
1234 NULL, /* fpCommitSpoolData */
1235 NULL, /* fpCloseSpoolFileHandle */
1236 NULL, /* fpFlushPrinter */
1237 NULL, /* fpSendRecvBidiData */
1238 NULL /* fpAddDriverCatalog */
1240 TRACE("=> %p\n", &backend);
1241 return &backend;
1245 /*****************************************************
1246 * DllMain
1248 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1250 TRACE("(%p, %d, %p)\n",hinstDLL, fdwReason, lpvReserved);
1252 switch(fdwReason)
1254 case DLL_WINE_PREATTACH:
1255 return FALSE; /* prefer native version */
1257 case DLL_PROCESS_ATTACH:
1258 DisableThreadLibraryCalls( hinstDLL );
1259 LOCALSPL_hInstance = hinstDLL;
1260 pp = get_backend();
1261 break;
1263 return TRUE;
1267 /*****************************************************
1268 * InitializePrintProvidor (localspl.@)
1270 * Initialize the Printprovider
1272 * PARAMS
1273 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
1274 * cbPrintProvidor [I] Size of Buffer in Bytes
1275 * pFullRegistryPath [I] Registry-Path for the Printprovidor
1277 * RETURNS
1278 * Success: TRUE and pPrintProvidor filled
1279 * Failure: FALSE
1281 * NOTES
1282 * The RegistryPath should be:
1283 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
1284 * but this Parameter is ignored in "localspl.dll".
1288 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
1289 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
1292 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
1293 memcpy(pPrintProvidor, pp, (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
1295 return TRUE;