dplayx: Code to forward player creation
[wine/gsoc_dplay.git] / dlls / localspl / provider.c
blob79541db993711fde5a033f87402a9eed21d34bd2
1 /*
2 * Implementation of the Local Printprovider
4 * Copyright 2006-2009 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;
83 typedef struct {
84 LPWSTR name;
85 LPWSTR printername;
86 monitor_t * pm;
87 HANDLE hXcv;
88 } printer_t;
90 /* ############################### */
92 static struct list monitor_handles = LIST_INIT( monitor_handles );
93 static monitor_t * pm_localport;
95 static const PRINTPROVIDOR * pprovider = NULL;
97 static const WCHAR backslashW[] = {'\\',0};
98 static const WCHAR bs_ports_bsW[] = {'\\','P','o','r','t','s','\\',0};
99 static const WCHAR configuration_fileW[] = {'C','o','n','f','i','g','u','r','a','t','i','o','n',' ','F','i','l','e',0};
100 static const WCHAR datatypeW[] = {'D','a','t','a','t','y','p','e',0};
101 static const WCHAR data_fileW[] = {'D','a','t','a',' ','F','i','l','e',0};
102 static const WCHAR default_devmodeW[] = {'D','e','f','a','u','l','t',' ','D','e','v','M','o','d','e',0};
103 static const WCHAR dependent_filesW[] = {'D','e','p','e','n','d','e','n','t',' ','F','i','l','e','s',0};
104 static const WCHAR descriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
105 static const WCHAR driverW[] = {'D','r','i','v','e','r',0};
106 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
107 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
108 'c','o','n','t','r','o','l','\\',
109 'P','r','i','n','t','\\',
110 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
111 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
112 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
113 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
114 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
115 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
116 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
117 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
118 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
119 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
120 'C','o','n','t','r','o','l','\\',
121 'P','r','i','n','t','\\',
122 'M','o','n','i','t','o','r','s','\\',0};
123 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
124 static const WCHAR nameW[] = {'N','a','m','e',0};
125 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
126 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
127 static const WCHAR portW[] = {'P','o','r','t',0};
128 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
129 static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
130 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
131 'C','o','n','t','r','o','l','\\',
132 'P','r','i','n','t','\\',
133 'P','r','i','n','t','e','r','s',0};
134 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
135 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
136 static const WCHAR version0_subdirW[] = {'\\','0',0};
137 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
138 static const WCHAR version3_subdirW[] = {'\\','3',0};
139 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
140 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
141 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
142 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
143 'M','i','c','r','o','s','o','f','t','\\',
144 'W','i','n','d','o','w','s',' ','N','T','\\',
145 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
146 'P','o','r','t','s',0};
147 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
148 static const WCHAR x64_subdirW[] = {'x','6','4',0};
149 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
150 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
151 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
152 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
155 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
156 version3_regpathW, version3_subdirW};
158 static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
159 version3_regpathW, version3_subdirW};
161 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
162 version0_regpathW, version0_subdirW};
164 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
167 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
168 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
169 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
170 0, sizeof(DRIVER_INFO_8W)};
173 /******************************************************************
174 * strdupW [internal]
176 * create a copy of a unicode-string
179 static LPWSTR strdupW(LPCWSTR p)
181 LPWSTR ret;
182 DWORD len;
184 if(!p) return NULL;
185 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
186 ret = heap_alloc(len);
187 memcpy(ret, p, len);
188 return ret;
191 /******************************************************************
192 * apd_copyfile [internal]
194 * Copy a file from the driverdirectory to the versioned directory
196 * RETURNS
197 * Success: TRUE
198 * Failure: FALSE
201 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
203 LPWSTR ptr;
204 LPWSTR srcname;
205 DWORD res;
207 apd->src[apd->srclen] = '\0';
208 apd->dst[apd->dstlen] = '\0';
210 if (!filename || !filename[0]) {
211 /* nothing to copy */
212 return TRUE;
215 ptr = strrchrW(filename, '\\');
216 if (ptr) {
217 ptr++;
219 else
221 ptr = filename;
224 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
225 /* we have an absolute Path */
226 srcname = filename;
228 else
230 srcname = apd->src;
231 lstrcatW(srcname, ptr);
233 lstrcatW(apd->dst, ptr);
235 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
237 /* FIXME: handle APD_COPY_NEW_FILES */
238 res = CopyFileW(srcname, apd->dst, FALSE);
239 TRACE("got %u with %u\n", res, GetLastError());
241 return (apd->lazy) ? TRUE : res;
244 /******************************************************************
245 * copy_servername_from_name (internal)
247 * for an external server, the serverpart from the name is copied.
249 * RETURNS
250 * the length (in WCHAR) of the serverpart (0 for the local computer)
251 * (-length), when the name is to long
254 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
256 LPCWSTR server;
257 LPWSTR ptr;
258 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
259 DWORD len;
260 DWORD serverlen;
262 if (target) *target = '\0';
264 if (name == NULL) return 0;
265 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
267 server = &name[2];
268 /* skip over both backslash, find separator '\' */
269 ptr = strchrW(server, '\\');
270 serverlen = (ptr) ? ptr - server : lstrlenW(server);
272 /* servername is empty */
273 if (serverlen == 0) return 0;
275 TRACE("found %s\n", debugstr_wn(server, serverlen));
277 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
279 if (target) {
280 memcpy(target, server, serverlen * sizeof(WCHAR));
281 target[serverlen] = '\0';
284 len = sizeof(buffer) / sizeof(buffer[0]);
285 if (GetComputerNameW(buffer, &len)) {
286 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
287 /* The requested Servername is our computername */
288 return 0;
291 return serverlen;
294 /******************************************************************
295 * get_basename_from_name (internal)
297 * skip over the serverpart from the full name
300 static LPCWSTR get_basename_from_name(LPCWSTR name)
302 if (name == NULL) return NULL;
303 if ((name[0] == '\\') && (name[1] == '\\')) {
304 /* skip over the servername and search for the following '\' */
305 name = strchrW(&name[2], '\\');
306 if ((name) && (name[1])) {
307 /* found a separator ('\') followed by a name:
308 skip over the separator and return the rest */
309 name++;
311 else
313 /* no basename present (we found only a servername) */
314 return NULL;
317 return name;
320 /******************************************************************
321 * monitor_unload [internal]
323 * release a printmonitor and unload it from memory, when needed
326 static void monitor_unload(monitor_t * pm)
328 if (pm == NULL) return;
329 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
331 EnterCriticalSection(&monitor_handles_cs);
333 if (pm->refcount) pm->refcount--;
335 if (pm->refcount == 0) {
336 list_remove(&pm->entry);
337 FreeLibrary(pm->hdll);
338 heap_free(pm->name);
339 heap_free(pm->dllname);
340 heap_free(pm);
342 LeaveCriticalSection(&monitor_handles_cs);
345 /******************************************************************
346 * monitor_unloadall [internal]
348 * release all printmonitors and unload them from memory, when needed
352 static void monitor_unloadall(void)
354 monitor_t * pm;
355 monitor_t * next;
357 EnterCriticalSection(&monitor_handles_cs);
358 /* iterate through the list, with safety against removal */
359 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
361 monitor_unload(pm);
363 LeaveCriticalSection(&monitor_handles_cs);
366 /******************************************************************
367 * monitor_load [internal]
369 * load a printmonitor, get the dllname from the registry, when needed
370 * initialize the monitor and dump found function-pointers
372 * On failure, SetLastError() is called and NULL is returned
375 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
377 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
378 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
379 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
380 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
381 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
383 monitor_t * pm = NULL;
384 monitor_t * cursor;
385 LPWSTR regroot = NULL;
386 LPWSTR driver = dllname;
388 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
389 /* Is the Monitor already loaded? */
390 EnterCriticalSection(&monitor_handles_cs);
392 if (name) {
393 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
395 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
396 pm = cursor;
397 break;
402 if (pm == NULL) {
403 pm = heap_alloc_zero(sizeof(monitor_t));
404 if (pm == NULL) goto cleanup;
405 list_add_tail(&monitor_handles, &pm->entry);
407 pm->refcount++;
409 if (pm->name == NULL) {
410 /* Load the monitor */
411 LPMONITOREX pmonitorEx;
412 DWORD len;
414 if (name) {
415 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
416 regroot = heap_alloc(len * sizeof(WCHAR));
419 if (regroot) {
420 lstrcpyW(regroot, monitorsW);
421 lstrcatW(regroot, name);
422 /* Get the Driver from the Registry */
423 if (driver == NULL) {
424 HKEY hroot;
425 DWORD namesize;
426 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
427 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
428 &namesize) == ERROR_SUCCESS) {
429 driver = heap_alloc(namesize);
430 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
432 RegCloseKey(hroot);
437 pm->name = strdupW(name);
438 pm->dllname = strdupW(driver);
440 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
441 monitor_unload(pm);
442 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
443 pm = NULL;
444 goto cleanup;
447 pm->hdll = LoadLibraryW(driver);
448 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
450 if (pm->hdll == NULL) {
451 monitor_unload(pm);
452 SetLastError(ERROR_MOD_NOT_FOUND);
453 pm = NULL;
454 goto cleanup;
457 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
458 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
459 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
460 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
461 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
464 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
465 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
466 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
467 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
468 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
470 if (pInitializePrintMonitorUI != NULL) {
471 pm->monitorUI = pInitializePrintMonitorUI();
472 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
473 if (pm->monitorUI) {
474 TRACE("0x%08x: dwMonitorSize (%d)\n",
475 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
480 if (pInitializePrintMonitor && regroot) {
481 pmonitorEx = pInitializePrintMonitor(regroot);
482 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
483 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
485 if (pmonitorEx) {
486 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
487 pm->monitor = &(pmonitorEx->Monitor);
491 if (pm->monitor) {
492 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
496 if (!pm->monitor && regroot) {
497 if (pInitializePrintMonitor2 != NULL) {
498 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
500 if (pInitializeMonitorEx != NULL) {
501 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
503 if (pInitializeMonitor != NULL) {
504 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
507 if (!pm->monitor && !pm->monitorUI) {
508 monitor_unload(pm);
509 SetLastError(ERROR_PROC_NOT_FOUND);
510 pm = NULL;
513 cleanup:
514 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
515 pm->refcount++;
516 pm_localport = pm;
518 LeaveCriticalSection(&monitor_handles_cs);
519 if (driver != dllname) heap_free(driver);
520 heap_free(regroot);
521 TRACE("=> %p\n", pm);
522 return pm;
525 /******************************************************************
526 * monitor_loadall [internal]
528 * Load all registered monitors
531 static DWORD monitor_loadall(void)
533 monitor_t * pm;
534 DWORD registered = 0;
535 DWORD loaded = 0;
536 HKEY hmonitors;
537 WCHAR buffer[MAX_PATH];
538 DWORD id = 0;
540 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
541 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
542 NULL, NULL, NULL, NULL, NULL);
544 TRACE("%d monitors registered\n", registered);
546 while (id < registered) {
547 buffer[0] = '\0';
548 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
549 pm = monitor_load(buffer, NULL);
550 if (pm) loaded++;
551 id++;
553 RegCloseKey(hmonitors);
555 TRACE("%d monitors loaded\n", loaded);
556 return loaded;
559 /******************************************************************
560 * monitor_load_by_port [internal]
562 * load a printmonitor for a given port
564 * On failure, NULL is returned
567 static monitor_t * monitor_load_by_port(LPCWSTR portname)
569 HKEY hroot;
570 HKEY hport;
571 LPWSTR buffer;
572 monitor_t * pm = NULL;
573 DWORD registered = 0;
574 DWORD id = 0;
575 DWORD len;
577 TRACE("(%s)\n", debugstr_w(portname));
579 /* Try the Local Monitor first */
580 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
581 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
582 /* found the portname */
583 RegCloseKey(hroot);
584 return monitor_load(localportW, NULL);
586 RegCloseKey(hroot);
589 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
590 buffer = heap_alloc(len * sizeof(WCHAR));
591 if (buffer == NULL) return NULL;
593 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
594 EnterCriticalSection(&monitor_handles_cs);
595 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
597 while ((pm == NULL) && (id < registered)) {
598 buffer[0] = '\0';
599 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
600 TRACE("testing %s\n", debugstr_w(buffer));
601 len = lstrlenW(buffer);
602 lstrcatW(buffer, bs_ports_bsW);
603 lstrcatW(buffer, portname);
604 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
605 RegCloseKey(hport);
606 buffer[len] = '\0'; /* use only the Monitor-Name */
607 pm = monitor_load(buffer, NULL);
609 id++;
611 LeaveCriticalSection(&monitor_handles_cs);
612 RegCloseKey(hroot);
614 heap_free(buffer);
615 return pm;
618 /******************************************************************
619 * Return the number of bytes for an multi_sz string.
620 * The result includes all \0s
621 * (specifically the extra \0, that is needed as multi_sz terminator).
623 static int multi_sz_lenW(const WCHAR *str)
625 const WCHAR *ptr = str;
626 if (!str) return 0;
629 ptr += lstrlenW(ptr) + 1;
630 } while (*ptr);
632 return (ptr - str + 1) * sizeof(WCHAR);
635 /******************************************************************
636 * validate_envW [internal]
638 * validate the user-supplied printing-environment
640 * PARAMS
641 * env [I] PTR to Environment-String or NULL
643 * RETURNS
644 * Success: PTR to printenv_t
645 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
647 * NOTES
648 * An empty string is handled the same way as NULL.
652 static const printenv_t * validate_envW(LPCWSTR env)
654 const printenv_t *result = NULL;
655 unsigned int i;
657 TRACE("(%s)\n", debugstr_w(env));
658 if (env && env[0])
660 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
662 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
664 result = all_printenv[i];
665 break;
668 if (result == NULL) {
669 FIXME("unsupported Environment: %s\n", debugstr_w(env));
670 SetLastError(ERROR_INVALID_ENVIRONMENT);
672 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
674 else
676 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
679 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
680 return result;
683 /*****************************************************************************
684 * enumerate the local monitors (INTERNAL)
686 * returns the needed size (in bytes) for pMonitors
687 * and *lpreturned is set to number of entries returned in pMonitors
689 * Language-Monitors are also installed in the same Registry-Location but
690 * they are filtered in Windows (not returned by EnumMonitors).
691 * We do no filtering to simplify our Code.
694 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
696 HKEY hroot = NULL;
697 HKEY hentry = NULL;
698 LPWSTR ptr;
699 LPMONITOR_INFO_2W mi;
700 WCHAR buffer[MAX_PATH];
701 WCHAR dllname[MAX_PATH];
702 DWORD dllsize;
703 DWORD len;
704 DWORD index = 0;
705 DWORD needed = 0;
706 DWORD numentries;
707 DWORD entrysize;
709 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
711 numentries = *lpreturned; /* this is 0, when we scan the registry */
712 len = entrysize * numentries;
713 ptr = (LPWSTR) &pMonitors[len];
715 numentries = 0;
716 len = sizeof(buffer)/sizeof(buffer[0]);
717 buffer[0] = '\0';
719 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
720 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
721 /* Scan all Monitor-Registry-Keys */
722 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
723 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
724 dllsize = sizeof(dllname);
725 dllname[0] = '\0';
727 /* The Monitor must have a Driver-DLL */
728 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
729 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
730 /* We found a valid DLL for this Monitor. */
731 TRACE("using Driver: %s\n", debugstr_w(dllname));
733 RegCloseKey(hentry);
736 /* Windows returns only Port-Monitors here, but to simplify our code,
737 we do no filtering for Language-Monitors */
738 if (dllname[0]) {
739 numentries++;
740 needed += entrysize;
741 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
742 if (level > 1) {
743 /* we install and return only monitors for "Windows NT x86" */
744 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
745 needed += dllsize;
748 /* required size is calculated. Now fill the user-buffer */
749 if (pMonitors && (cbBuf >= needed)){
750 mi = (LPMONITOR_INFO_2W) pMonitors;
751 pMonitors += entrysize;
753 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
754 mi->pName = ptr;
755 lstrcpyW(ptr, buffer); /* Name of the Monitor */
756 ptr += (len+1); /* len is lstrlenW(monitorname) */
757 if (level > 1) {
758 mi->pEnvironment = ptr;
759 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
760 ptr += (lstrlenW(x86_envnameW)+1);
762 mi->pDLLName = ptr;
763 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
764 ptr += (dllsize / sizeof(WCHAR));
768 index++;
769 len = sizeof(buffer)/sizeof(buffer[0]);
770 buffer[0] = '\0';
772 RegCloseKey(hroot);
774 *lpreturned = numentries;
775 TRACE("need %d byte for %d entries\n", needed, numentries);
776 return needed;
779 /******************************************************************
780 * enumerate the local Ports from all loaded monitors (internal)
782 * returns the needed size (in bytes) for pPorts
783 * and *lpreturned is set to number of entries returned in pPorts
786 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
788 monitor_t * pm;
789 LPWSTR ptr;
790 LPPORT_INFO_2W cache;
791 LPPORT_INFO_2W out;
792 LPBYTE pi_buffer = NULL;
793 DWORD pi_allocated = 0;
794 DWORD pi_needed;
795 DWORD pi_index;
796 DWORD pi_returned;
797 DWORD res;
798 DWORD outindex = 0;
799 DWORD needed;
800 DWORD numentries;
801 DWORD entrysize;
804 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
805 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
807 numentries = *lpreturned; /* this is 0, when we scan the registry */
808 needed = entrysize * numentries;
809 ptr = (LPWSTR) &pPorts[needed];
811 numentries = 0;
812 needed = 0;
814 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
816 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
817 pi_needed = 0;
818 pi_returned = 0;
819 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
820 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
821 /* Do not use heap_realloc (we do not need the old data in the buffer) */
822 heap_free(pi_buffer);
823 pi_buffer = heap_alloc(pi_needed);
824 pi_allocated = (pi_buffer) ? pi_needed : 0;
825 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
827 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
828 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
830 numentries += pi_returned;
831 needed += pi_needed;
833 /* fill the output-buffer (pPorts), if we have one */
834 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
835 pi_index = 0;
836 while (pi_returned > pi_index) {
837 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
838 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
839 out->pPortName = ptr;
840 lstrcpyW(ptr, cache->pPortName);
841 ptr += (lstrlenW(ptr)+1);
842 if (level > 1) {
843 out->pMonitorName = ptr;
844 lstrcpyW(ptr, cache->pMonitorName);
845 ptr += (lstrlenW(ptr)+1);
847 out->pDescription = ptr;
848 lstrcpyW(ptr, cache->pDescription);
849 ptr += (lstrlenW(ptr)+1);
850 out->fPortType = cache->fPortType;
851 out->Reserved = cache->Reserved;
853 pi_index++;
854 outindex++;
859 /* the temporary portinfo-buffer is no longer needed */
860 heap_free(pi_buffer);
862 *lpreturned = numentries;
863 TRACE("need %d byte for %d entries\n", needed, numentries);
864 return needed;
868 /*****************************************************************************
869 * open_driver_reg [internal]
871 * opens the registry for the printer drivers depending on the given input
872 * variable pEnvironment
874 * RETURNS:
875 * Success: the opened hkey
876 * Failure: NULL
878 static HKEY open_driver_reg(LPCWSTR pEnvironment)
880 HKEY retval = NULL;
881 LPWSTR buffer;
882 const printenv_t * env;
884 TRACE("(%s)\n", debugstr_w(pEnvironment));
886 env = validate_envW(pEnvironment);
887 if (!env) return NULL;
889 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
890 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
892 if (buffer) {
893 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
894 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
895 HeapFree(GetProcessHeap(), 0, buffer);
897 return retval;
900 /*****************************************************************************
901 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
903 * Return the PATH for the Printer-Drivers
905 * PARAMS
906 * pName [I] Servername (NT only) or NULL (local Computer)
907 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
908 * Level [I] Structure-Level (must be 1)
909 * pDriverDirectory [O] PTR to Buffer that receives the Result
910 * cbBuf [I] Size of Buffer at pDriverDirectory
911 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
912 * required for pDriverDirectory
914 * RETURNS
915 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
916 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
917 * if cbBuf is too small
919 * Native Values returned in pDriverDirectory on Success:
920 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
921 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
922 *| win9x(Windows 4.0): "%winsysdir%"
924 * "%winsysdir%" is the Value from GetSystemDirectoryW()
927 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
928 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
930 DWORD needed;
931 const printenv_t * env;
933 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
934 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
936 if (pName != NULL && pName[0]) {
937 FIXME("server %s not supported\n", debugstr_w(pName));
938 SetLastError(ERROR_INVALID_PARAMETER);
939 return FALSE;
942 env = validate_envW(pEnvironment);
943 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
946 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
947 needed = GetSystemDirectoryW(NULL, 0);
948 /* add the Size for the Subdirectories */
949 needed += lstrlenW(spooldriversW);
950 needed += lstrlenW(env->subdir);
951 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
953 *pcbNeeded = needed;
955 if (needed > cbBuf) {
956 SetLastError(ERROR_INSUFFICIENT_BUFFER);
957 return FALSE;
960 if (pDriverDirectory == NULL) {
961 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
962 SetLastError(ERROR_INVALID_USER_BUFFER);
963 return FALSE;
966 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
967 /* add the Subdirectories */
968 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
969 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
971 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
972 return TRUE;
975 /******************************************************************
976 * driver_load [internal]
978 * load a driver user interface dll
980 * On failure, NULL is returned
984 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
986 WCHAR fullname[MAX_PATH];
987 HMODULE hui;
988 DWORD len;
990 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
992 /* build the driverdir */
993 len = sizeof(fullname) -
994 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
996 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
997 (LPBYTE) fullname, len, &len)) {
998 /* Should never Fail */
999 SetLastError(ERROR_BUFFER_OVERFLOW);
1000 return NULL;
1003 lstrcatW(fullname, env->versionsubdir);
1004 lstrcatW(fullname, backslashW);
1005 lstrcatW(fullname, dllname);
1007 hui = LoadLibraryW(fullname);
1008 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1010 return hui;
1013 /******************************************************************
1014 * printer_free
1015 * free the data pointer of an opened printer
1017 static VOID printer_free(printer_t * printer)
1019 if (printer->hXcv)
1020 printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1022 monitor_unload(printer->pm);
1024 heap_free(printer->printername);
1025 heap_free(printer->name);
1026 heap_free(printer);
1029 /******************************************************************
1030 * printer_alloc_handle
1031 * alloc a printer handle and remember the data pointer in the printer handle table
1034 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1036 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1037 printer_t *printer = NULL;
1038 LPCWSTR printername;
1039 HKEY hkeyPrinters;
1040 HKEY hkeyPrinter;
1041 DWORD len;
1043 if (copy_servername_from_name(name, servername)) {
1044 FIXME("server %s not supported\n", debugstr_w(servername));
1045 SetLastError(ERROR_INVALID_PRINTER_NAME);
1046 return NULL;
1049 printername = get_basename_from_name(name);
1050 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1052 /* an empty printername is invalid */
1053 if (printername && (!printername[0])) {
1054 SetLastError(ERROR_INVALID_PARAMETER);
1055 return NULL;
1058 printer = heap_alloc_zero(sizeof(printer_t));
1059 if (!printer) goto end;
1061 /* clone the base name. This is NULL for the printserver */
1062 printer->printername = strdupW(printername);
1064 /* clone the full name */
1065 printer->name = strdupW(name);
1066 if (name && (!printer->name)) {
1067 printer_free(printer);
1068 printer = NULL;
1070 if (printername) {
1071 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1072 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1073 /* OpenPrinter(",XcvMonitor ", ...) detected */
1074 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1075 printer->pm = monitor_load(&printername[len], NULL);
1076 if (printer->pm == NULL) {
1077 printer_free(printer);
1078 SetLastError(ERROR_UNKNOWN_PORT);
1079 printer = NULL;
1080 goto end;
1083 else
1085 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1086 if (strncmpW( printername, XcvPortW, len) == 0) {
1087 /* OpenPrinter(",XcvPort ", ...) detected */
1088 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1089 printer->pm = monitor_load_by_port(&printername[len]);
1090 if (printer->pm == NULL) {
1091 printer_free(printer);
1092 SetLastError(ERROR_UNKNOWN_PORT);
1093 printer = NULL;
1094 goto end;
1099 if (printer->pm) {
1100 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1101 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1102 pDefault ? pDefault->DesiredAccess : 0,
1103 &printer->hXcv);
1105 if (printer->hXcv == NULL) {
1106 printer_free(printer);
1107 SetLastError(ERROR_INVALID_PARAMETER);
1108 printer = NULL;
1109 goto end;
1112 else
1114 /* Does the Printer exist? */
1115 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1116 ERR("Can't create Printers key\n");
1117 printer_free(printer);
1118 SetLastError(ERROR_INVALID_PRINTER_NAME);
1119 printer = NULL;
1120 goto end;
1122 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1123 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1124 RegCloseKey(hkeyPrinters);
1125 printer_free(printer);
1126 SetLastError(ERROR_INVALID_PRINTER_NAME);
1127 printer = NULL;
1128 goto end;
1130 RegCloseKey(hkeyPrinter);
1131 RegCloseKey(hkeyPrinters);
1134 else
1136 TRACE("using the local printserver\n");
1139 end:
1141 TRACE("==> %p\n", printer);
1142 return (HANDLE)printer;
1146 /******************************************************************************
1147 * myAddPrinterDriverEx [internal]
1149 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1150 * and a special mode with lazy error checking.
1153 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1155 static const WCHAR emptyW[1];
1156 const printenv_t *env;
1157 apd_data_t apd;
1158 DRIVER_INFO_8W di;
1159 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1160 HMODULE hui;
1161 LPWSTR ptr;
1162 HKEY hroot;
1163 HKEY hdrv;
1164 DWORD disposition;
1165 DWORD len;
1166 LONG lres;
1167 BOOL res;
1169 /* we need to set all entries in the Registry, independent from the Level of
1170 DRIVER_INFO, that the caller supplied */
1172 ZeroMemory(&di, sizeof(di));
1173 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1174 memcpy(&di, pDriverInfo, di_sizeof[level]);
1177 /* dump the most used infos */
1178 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1179 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1180 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1181 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1182 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1183 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1184 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1185 /* dump only the first of the additional Files */
1186 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1189 /* check environment */
1190 env = validate_envW(di.pEnvironment);
1191 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1193 /* fill the copy-data / get the driverdir */
1194 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1195 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1196 (LPBYTE) apd.src, len, &len)) {
1197 /* Should never Fail */
1198 return FALSE;
1200 memcpy(apd.dst, apd.src, len);
1201 lstrcatW(apd.src, backslashW);
1202 apd.srclen = lstrlenW(apd.src);
1203 lstrcatW(apd.dst, env->versionsubdir);
1204 lstrcatW(apd.dst, backslashW);
1205 apd.dstlen = lstrlenW(apd.dst);
1206 apd.copyflags = dwFileCopyFlags;
1207 apd.lazy = lazy;
1208 CreateDirectoryW(apd.src, NULL);
1209 CreateDirectoryW(apd.dst, NULL);
1211 hroot = open_driver_reg(env->envname);
1212 if (!hroot) {
1213 ERR("Can't create Drivers key\n");
1214 return FALSE;
1217 /* Fill the Registry for the Driver */
1218 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1219 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1220 &hdrv, &disposition)) != ERROR_SUCCESS) {
1222 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1223 RegCloseKey(hroot);
1224 SetLastError(lres);
1225 return FALSE;
1227 RegCloseKey(hroot);
1229 if (disposition == REG_OPENED_EXISTING_KEY) {
1230 TRACE("driver %s already installed\n", debugstr_w(di.pName));
1231 RegCloseKey(hdrv);
1232 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1233 return FALSE;
1236 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1237 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
1238 sizeof(DWORD));
1240 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1241 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1242 apd_copyfile(di.pDriverPath, &apd);
1244 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1245 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1246 apd_copyfile(di.pDataFile, &apd);
1248 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1249 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1250 apd_copyfile(di.pConfigFile, &apd);
1252 /* settings for level 3 */
1253 if (di.pHelpFile)
1254 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1255 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1256 else
1257 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1258 apd_copyfile(di.pHelpFile, &apd);
1261 ptr = di.pDependentFiles;
1262 if (ptr)
1263 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1264 multi_sz_lenW(di.pDependentFiles));
1265 else
1266 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1267 while ((ptr != NULL) && (ptr[0])) {
1268 if (apd_copyfile(ptr, &apd)) {
1269 ptr += lstrlenW(ptr) + 1;
1271 else
1273 WARN("Failed to copy %s\n", debugstr_w(ptr));
1274 ptr = NULL;
1277 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1278 if (di.pMonitorName)
1279 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1280 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1281 else
1282 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1284 if (di.pDefaultDataType)
1285 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1286 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1287 else
1288 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1290 /* settings for level 4 */
1291 if (di.pszzPreviousNames)
1292 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1293 multi_sz_lenW(di.pszzPreviousNames));
1294 else
1295 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1297 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1299 RegCloseKey(hdrv);
1300 hui = driver_load(env, di.pConfigFile);
1301 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1302 if (hui && pDrvDriverEvent) {
1304 /* Support for DrvDriverEvent is optional */
1305 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1306 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1307 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1308 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1310 FreeLibrary(hui);
1312 TRACE("=> TRUE with %u\n", GetLastError());
1313 return TRUE;
1317 /******************************************************************************
1318 * fpAddMonitor [exported through PRINTPROVIDOR]
1320 * Install a Printmonitor
1322 * PARAMS
1323 * pName [I] Servername or NULL (local Computer)
1324 * Level [I] Structure-Level (Must be 2)
1325 * pMonitors [I] PTR to MONITOR_INFO_2
1327 * RETURNS
1328 * Success: TRUE
1329 * Failure: FALSE
1331 * NOTES
1332 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1335 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1337 monitor_t * pm = NULL;
1338 LPMONITOR_INFO_2W mi2w;
1339 HKEY hroot = NULL;
1340 HKEY hentry = NULL;
1341 DWORD disposition;
1342 BOOL res = FALSE;
1344 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1345 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1346 debugstr_w(mi2w ? mi2w->pName : NULL),
1347 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1348 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1350 if (copy_servername_from_name(pName, NULL)) {
1351 FIXME("server %s not supported\n", debugstr_w(pName));
1352 SetLastError(ERROR_ACCESS_DENIED);
1353 return FALSE;
1356 if (!mi2w->pName || (! mi2w->pName[0])) {
1357 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1358 SetLastError(ERROR_INVALID_PARAMETER);
1359 return FALSE;
1361 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1362 WARN("Environment %s requested (we support only %s)\n",
1363 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1364 SetLastError(ERROR_INVALID_ENVIRONMENT);
1365 return FALSE;
1368 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1369 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1370 SetLastError(ERROR_INVALID_PARAMETER);
1371 return FALSE;
1374 /* Load and initialize the monitor. SetLastError() is called on failure */
1375 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1376 return FALSE;
1378 monitor_unload(pm);
1380 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1381 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1382 return FALSE;
1385 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1386 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1387 &disposition) == ERROR_SUCCESS) {
1389 /* Some installers set options for the port before calling AddMonitor.
1390 We query the "Driver" entry to verify that the monitor is installed,
1391 before we return an error.
1392 When a user installs two print monitors at the same time with the
1393 same name, a race condition is possible but silently ignored. */
1395 DWORD namesize = 0;
1397 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1398 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1399 &namesize) == ERROR_SUCCESS)) {
1400 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1401 /* 9x use ERROR_ALREADY_EXISTS */
1402 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1404 else
1406 INT len;
1407 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1408 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1409 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1411 RegCloseKey(hentry);
1414 RegCloseKey(hroot);
1415 return (res);
1418 /******************************************************************************
1419 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1421 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1423 * PARAMS
1424 * pName [I] Servername or NULL (local Computer)
1425 * level [I] Level for the supplied DRIVER_INFO_*W struct
1426 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1427 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1429 * RESULTS
1430 * Success: TRUE
1431 * Failure: FALSE
1434 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1436 LONG lres;
1438 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1439 lres = copy_servername_from_name(pName, NULL);
1440 if (lres) {
1441 FIXME("server %s not supported\n", debugstr_w(pName));
1442 SetLastError(ERROR_ACCESS_DENIED);
1443 return FALSE;
1446 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1447 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1450 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1453 /******************************************************************************
1454 * fpClosePrinter [exported through PRINTPROVIDOR]
1456 * Close a printer handle and free associated resources
1458 * PARAMS
1459 * hPrinter [I] Printerhandle to close
1461 * RESULTS
1462 * Success: TRUE
1463 * Failure: FALSE
1466 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1468 printer_t *printer = (printer_t *) hPrinter;
1470 TRACE("(%p)\n", hPrinter);
1472 if (printer) {
1473 printer_free(printer);
1474 return TRUE;
1476 return FALSE;
1480 /******************************************************************
1481 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1483 * Delete a specific Printmonitor from a Printing-Environment
1485 * PARAMS
1486 * pName [I] Servername or NULL (local Computer)
1487 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1488 * pMonitorName [I] Name of the Monitor, that should be deleted
1490 * RETURNS
1491 * Success: TRUE
1492 * Failure: FALSE
1494 * NOTES
1495 * pEnvironment is ignored in Windows for the local Computer.
1499 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1501 HKEY hroot = NULL;
1502 LONG lres;
1504 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1505 debugstr_w(pMonitorName));
1507 lres = copy_servername_from_name(pName, NULL);
1508 if (lres) {
1509 FIXME("server %s not supported\n", debugstr_w(pName));
1510 SetLastError(ERROR_INVALID_NAME);
1511 return FALSE;
1514 /* pEnvironment is ignored in Windows for the local Computer */
1515 if (!pMonitorName || !pMonitorName[0]) {
1516 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1517 SetLastError(ERROR_INVALID_PARAMETER);
1518 return FALSE;
1521 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1522 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1523 return FALSE;
1526 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1527 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1528 RegCloseKey(hroot);
1529 return TRUE;
1532 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1533 RegCloseKey(hroot);
1535 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1536 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1537 return FALSE;
1540 /*****************************************************************************
1541 * fpEnumMonitors [exported through PRINTPROVIDOR]
1543 * Enumerate available Port-Monitors
1545 * PARAMS
1546 * pName [I] Servername or NULL (local Computer)
1547 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1548 * pMonitors [O] PTR to Buffer that receives the Result
1549 * cbBuf [I] Size of Buffer at pMonitors
1550 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1551 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1553 * RETURNS
1554 * Success: TRUE
1555 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1557 * NOTES
1558 * Windows reads the Registry once and cache the Results.
1561 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1562 LPDWORD pcbNeeded, LPDWORD pcReturned)
1564 DWORD numentries = 0;
1565 DWORD needed = 0;
1566 LONG lres;
1567 BOOL res = FALSE;
1569 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1570 cbBuf, pcbNeeded, pcReturned);
1572 lres = copy_servername_from_name(pName, NULL);
1573 if (lres) {
1574 FIXME("server %s not supported\n", debugstr_w(pName));
1575 SetLastError(ERROR_INVALID_NAME);
1576 goto em_cleanup;
1579 if (!Level || (Level > 2)) {
1580 WARN("level (%d) is ignored in win9x\n", Level);
1581 SetLastError(ERROR_INVALID_LEVEL);
1582 return FALSE;
1585 /* Scan all Monitor-Keys */
1586 numentries = 0;
1587 needed = get_local_monitors(Level, NULL, 0, &numentries);
1589 /* we calculated the needed buffersize. now do more error-checks */
1590 if (cbBuf < needed) {
1591 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1592 goto em_cleanup;
1595 /* fill the Buffer with the Monitor-Keys */
1596 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1597 res = TRUE;
1599 em_cleanup:
1600 if (pcbNeeded) *pcbNeeded = needed;
1601 if (pcReturned) *pcReturned = numentries;
1603 TRACE("returning %d with %d (%d byte for %d entries)\n",
1604 res, GetLastError(), needed, numentries);
1606 return (res);
1609 /******************************************************************************
1610 * fpEnumPorts [exported through PRINTPROVIDOR]
1612 * Enumerate available Ports
1614 * PARAMS
1615 * pName [I] Servername or NULL (local Computer)
1616 * Level [I] Structure-Level (1 or 2)
1617 * pPorts [O] PTR to Buffer that receives the Result
1618 * cbBuf [I] Size of Buffer at pPorts
1619 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1620 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1622 * RETURNS
1623 * Success: TRUE
1624 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1627 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1628 LPDWORD pcbNeeded, LPDWORD pcReturned)
1630 DWORD needed = 0;
1631 DWORD numentries = 0;
1632 LONG lres;
1633 BOOL res = FALSE;
1635 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1636 cbBuf, pcbNeeded, pcReturned);
1638 lres = copy_servername_from_name(pName, NULL);
1639 if (lres) {
1640 FIXME("server %s not supported\n", debugstr_w(pName));
1641 SetLastError(ERROR_INVALID_NAME);
1642 goto emP_cleanup;
1645 if (!Level || (Level > 2)) {
1646 SetLastError(ERROR_INVALID_LEVEL);
1647 goto emP_cleanup;
1650 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1651 SetLastError(RPC_X_NULL_REF_POINTER);
1652 goto emP_cleanup;
1655 EnterCriticalSection(&monitor_handles_cs);
1656 monitor_loadall();
1658 /* Scan all local Ports */
1659 numentries = 0;
1660 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1662 /* we calculated the needed buffersize. now do the error-checks */
1663 if (cbBuf < needed) {
1664 monitor_unloadall();
1665 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1666 goto emP_cleanup_cs;
1668 else if (!pPorts || !pcReturned) {
1669 monitor_unloadall();
1670 SetLastError(RPC_X_NULL_REF_POINTER);
1671 goto emP_cleanup_cs;
1674 /* Fill the Buffer */
1675 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1676 res = TRUE;
1677 monitor_unloadall();
1679 emP_cleanup_cs:
1680 LeaveCriticalSection(&monitor_handles_cs);
1682 emP_cleanup:
1683 if (pcbNeeded) *pcbNeeded = needed;
1684 if (pcReturned) *pcReturned = (res) ? numentries : 0;
1686 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1687 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
1689 return (res);
1692 /******************************************************************************
1693 * fpOpenPrinter [exported through PRINTPROVIDOR]
1695 * Open a Printer / Printserver or a Printer-Object
1697 * PARAMS
1698 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1699 * pPrinter [O] The resulting Handle is stored here
1700 * pDefaults [I] PTR to Default Printer Settings or NULL
1702 * RETURNS
1703 * Success: TRUE
1704 * Failure: FALSE
1706 * NOTES
1707 * lpPrinterName is one of:
1708 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1709 *| Printer: "PrinterName"
1710 *| Printer-Object: "PrinterName,Job xxx"
1711 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1712 *| XcvPort: "Servername,XcvPort PortName"
1716 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
1717 LPPRINTER_DEFAULTSW pDefaults)
1720 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
1722 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
1724 return (*pPrinter != 0);
1727 /******************************************************************************
1728 * fpXcvData [exported through PRINTPROVIDOR]
1730 * Execute commands in the Printmonitor DLL
1732 * PARAMS
1733 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
1734 * pszDataName [i] Name of the command to execute
1735 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
1736 * cbInputData [i] Size in Bytes of Buffer at pInputData
1737 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
1738 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
1739 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
1740 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
1742 * RETURNS
1743 * Success: TRUE
1744 * Failure: FALSE
1746 * NOTES
1747 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
1748 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
1750 * Minimal List of commands, that a Printmonitor DLL should support:
1752 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
1753 *| "AddPort" : Add a Port
1754 *| "DeletePort": Delete a Port
1756 * Many Printmonitors support additional commands. Examples for localspl.dll:
1757 * "GetDefaultCommConfig", "SetDefaultCommConfig",
1758 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
1761 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
1762 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
1763 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
1765 printer_t *printer = (printer_t * ) hXcv;
1767 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
1768 pInputData, cbInputData, pOutputData,
1769 cbOutputData, pcbOutputNeeded, pdwStatus);
1771 if (!printer || (!printer->hXcv)) {
1772 SetLastError(ERROR_INVALID_HANDLE);
1773 return FALSE;
1776 if (!pcbOutputNeeded) {
1777 SetLastError(ERROR_INVALID_PARAMETER);
1778 return FALSE;
1781 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
1782 SetLastError(RPC_X_NULL_REF_POINTER);
1783 return FALSE;
1786 *pcbOutputNeeded = 0;
1788 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
1789 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
1791 return TRUE;
1794 /*****************************************************
1795 * setup_provider [internal]
1797 void setup_provider(void)
1799 static const PRINTPROVIDOR backend = {
1800 fpOpenPrinter,
1801 NULL, /* fpSetJob */
1802 NULL, /* fpGetJob */
1803 NULL, /* fpEnumJobs */
1804 NULL, /* fpAddPrinter */
1805 NULL, /* fpDeletePrinter */
1806 NULL, /* fpSetPrinter */
1807 NULL, /* fpGetPrinter */
1808 NULL, /* fpEnumPrinters */
1809 NULL, /* fpAddPrinterDriver */
1810 NULL, /* fpEnumPrinterDrivers */
1811 NULL, /* fpGetPrinterDriver */
1812 fpGetPrinterDriverDirectory,
1813 NULL, /* fpDeletePrinterDriver */
1814 NULL, /* fpAddPrintProcessor */
1815 NULL, /* fpEnumPrintProcessors */
1816 NULL, /* fpGetPrintProcessorDirectory */
1817 NULL, /* fpDeletePrintProcessor */
1818 NULL, /* fpEnumPrintProcessorDatatypes */
1819 NULL, /* fpStartDocPrinter */
1820 NULL, /* fpStartPagePrinter */
1821 NULL, /* fpWritePrinter */
1822 NULL, /* fpEndPagePrinter */
1823 NULL, /* fpAbortPrinter */
1824 NULL, /* fpReadPrinter */
1825 NULL, /* fpEndDocPrinter */
1826 NULL, /* fpAddJob */
1827 NULL, /* fpScheduleJob */
1828 NULL, /* fpGetPrinterData */
1829 NULL, /* fpSetPrinterData */
1830 NULL, /* fpWaitForPrinterChange */
1831 fpClosePrinter,
1832 NULL, /* fpAddForm */
1833 NULL, /* fpDeleteForm */
1834 NULL, /* fpGetForm */
1835 NULL, /* fpSetForm */
1836 NULL, /* fpEnumForms */
1837 fpEnumMonitors,
1838 fpEnumPorts,
1839 NULL, /* fpAddPort */
1840 NULL, /* fpConfigurePort */
1841 NULL, /* fpDeletePort */
1842 NULL, /* fpCreatePrinterIC */
1843 NULL, /* fpPlayGdiScriptOnPrinterIC */
1844 NULL, /* fpDeletePrinterIC */
1845 NULL, /* fpAddPrinterConnection */
1846 NULL, /* fpDeletePrinterConnection */
1847 NULL, /* fpPrinterMessageBox */
1848 fpAddMonitor,
1849 fpDeleteMonitor,
1850 NULL, /* fpResetPrinter */
1851 NULL, /* fpGetPrinterDriverEx */
1852 NULL, /* fpFindFirstPrinterChangeNotification */
1853 NULL, /* fpFindClosePrinterChangeNotification */
1854 NULL, /* fpAddPortEx */
1855 NULL, /* fpShutDown */
1856 NULL, /* fpRefreshPrinterChangeNotification */
1857 NULL, /* fpOpenPrinterEx */
1858 NULL, /* fpAddPrinterEx */
1859 NULL, /* fpSetPort */
1860 NULL, /* fpEnumPrinterData */
1861 NULL, /* fpDeletePrinterData */
1862 NULL, /* fpClusterSplOpen */
1863 NULL, /* fpClusterSplClose */
1864 NULL, /* fpClusterSplIsAlive */
1865 NULL, /* fpSetPrinterDataEx */
1866 NULL, /* fpGetPrinterDataEx */
1867 NULL, /* fpEnumPrinterDataEx */
1868 NULL, /* fpEnumPrinterKey */
1869 NULL, /* fpDeletePrinterDataEx */
1870 NULL, /* fpDeletePrinterKey */
1871 NULL, /* fpSeekPrinter */
1872 NULL, /* fpDeletePrinterDriverEx */
1873 NULL, /* fpAddPerMachineConnection */
1874 NULL, /* fpDeletePerMachineConnection */
1875 NULL, /* fpEnumPerMachineConnections */
1876 fpXcvData,
1877 fpAddPrinterDriverEx,
1878 NULL, /* fpSplReadPrinter */
1879 NULL, /* fpDriverUnloadComplete */
1880 NULL, /* fpGetSpoolFileInfo */
1881 NULL, /* fpCommitSpoolData */
1882 NULL, /* fpCloseSpoolFileHandle */
1883 NULL, /* fpFlushPrinter */
1884 NULL, /* fpSendRecvBidiData */
1885 NULL /* fpAddDriverCatalog */
1887 pprovider = &backend;
1891 /*****************************************************
1892 * InitializePrintProvidor (localspl.@)
1894 * Initialize the Printprovider
1896 * PARAMS
1897 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
1898 * cbPrintProvidor [I] Size of Buffer in Bytes
1899 * pFullRegistryPath [I] Registry-Path for the Printprovidor
1901 * RETURNS
1902 * Success: TRUE and pPrintProvidor filled
1903 * Failure: FALSE
1905 * NOTES
1906 * The RegistryPath should be:
1907 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
1908 * but this Parameter is ignored in "localspl.dll".
1912 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
1913 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
1916 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
1917 memcpy(pPrintProvidor, pprovider,
1918 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
1920 return TRUE;