localspl: Implement fpConfigurePort.
[wine/wine-gecko.git] / dlls / localspl / provider.c
blobf3ddb8616aa9f1a36babc546ed6e2e80a1cd77df
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 emptyW[] = {0};
107 static const WCHAR fmt_driversW[] = { 'S','y','s','t','e','m','\\',
108 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
109 'c','o','n','t','r','o','l','\\',
110 'P','r','i','n','t','\\',
111 'E','n','v','i','r','o','n','m','e','n','t','s','\\',
112 '%','s','\\','D','r','i','v','e','r','s','%','s',0 };
113 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
114 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
115 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
116 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
117 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
118 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
119 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
120 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
121 'C','o','n','t','r','o','l','\\',
122 'P','r','i','n','t','\\',
123 'M','o','n','i','t','o','r','s','\\',0};
124 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
125 static const WCHAR nameW[] = {'N','a','m','e',0};
126 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
127 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
128 static const WCHAR portW[] = {'P','o','r','t',0};
129 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
130 static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
131 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
132 'C','o','n','t','r','o','l','\\',
133 'P','r','i','n','t','\\',
134 'P','r','i','n','t','e','r','s',0};
135 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
136 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
137 static const WCHAR version0_subdirW[] = {'\\','0',0};
138 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
139 static const WCHAR version3_subdirW[] = {'\\','3',0};
140 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
141 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
142 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
143 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
144 'M','i','c','r','o','s','o','f','t','\\',
145 'W','i','n','d','o','w','s',' ','N','T','\\',
146 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
147 'P','o','r','t','s',0};
148 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
149 static const WCHAR x64_subdirW[] = {'x','6','4',0};
150 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
151 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
152 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
153 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
156 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
157 version3_regpathW, version3_subdirW};
159 static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
160 version3_regpathW, version3_subdirW};
162 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
163 version0_regpathW, version0_subdirW};
165 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_win40};
168 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
169 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
170 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
171 0, sizeof(DRIVER_INFO_8W)};
174 /******************************************************************
175 * strdupW [internal]
177 * create a copy of a unicode-string
180 static LPWSTR strdupW(LPCWSTR p)
182 LPWSTR ret;
183 DWORD len;
185 if(!p) return NULL;
186 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
187 ret = heap_alloc(len);
188 memcpy(ret, p, len);
189 return ret;
192 /******************************************************************
193 * apd_copyfile [internal]
195 * Copy a file from the driverdirectory to the versioned directory
197 * RETURNS
198 * Success: TRUE
199 * Failure: FALSE
202 static BOOL apd_copyfile(LPWSTR filename, apd_data_t *apd)
204 LPWSTR ptr;
205 LPWSTR srcname;
206 DWORD res;
208 apd->src[apd->srclen] = '\0';
209 apd->dst[apd->dstlen] = '\0';
211 if (!filename || !filename[0]) {
212 /* nothing to copy */
213 return TRUE;
216 ptr = strrchrW(filename, '\\');
217 if (ptr) {
218 ptr++;
220 else
222 ptr = filename;
225 if (apd->copyflags & APD_COPY_FROM_DIRECTORY) {
226 /* we have an absolute Path */
227 srcname = filename;
229 else
231 srcname = apd->src;
232 lstrcatW(srcname, ptr);
234 lstrcatW(apd->dst, ptr);
236 TRACE("%s => %s\n", debugstr_w(filename), debugstr_w(apd->dst));
238 /* FIXME: handle APD_COPY_NEW_FILES */
239 res = CopyFileW(srcname, apd->dst, FALSE);
240 TRACE("got %u with %u\n", res, GetLastError());
242 return (apd->lazy) ? TRUE : res;
245 /******************************************************************
246 * copy_servername_from_name (internal)
248 * for an external server, the serverpart from the name is copied.
250 * RETURNS
251 * the length (in WCHAR) of the serverpart (0 for the local computer)
252 * (-length), when the name is to long
255 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
257 LPCWSTR server;
258 LPWSTR ptr;
259 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
260 DWORD len;
261 DWORD serverlen;
263 if (target) *target = '\0';
265 if (name == NULL) return 0;
266 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
268 server = &name[2];
269 /* skip over both backslash, find separator '\' */
270 ptr = strchrW(server, '\\');
271 serverlen = (ptr) ? ptr - server : lstrlenW(server);
273 /* servername is empty */
274 if (serverlen == 0) return 0;
276 TRACE("found %s\n", debugstr_wn(server, serverlen));
278 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
280 if (target) {
281 memcpy(target, server, serverlen * sizeof(WCHAR));
282 target[serverlen] = '\0';
285 len = sizeof(buffer) / sizeof(buffer[0]);
286 if (GetComputerNameW(buffer, &len)) {
287 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
288 /* The requested Servername is our computername */
289 return 0;
292 return serverlen;
295 /******************************************************************
296 * get_basename_from_name (internal)
298 * skip over the serverpart from the full name
301 static LPCWSTR get_basename_from_name(LPCWSTR name)
303 if (name == NULL) return NULL;
304 if ((name[0] == '\\') && (name[1] == '\\')) {
305 /* skip over the servername and search for the following '\' */
306 name = strchrW(&name[2], '\\');
307 if ((name) && (name[1])) {
308 /* found a separator ('\') followed by a name:
309 skip over the separator and return the rest */
310 name++;
312 else
314 /* no basename present (we found only a servername) */
315 return NULL;
318 return name;
321 /******************************************************************
322 * monitor_unload [internal]
324 * release a printmonitor and unload it from memory, when needed
327 static void monitor_unload(monitor_t * pm)
329 if (pm == NULL) return;
330 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
332 EnterCriticalSection(&monitor_handles_cs);
334 if (pm->refcount) pm->refcount--;
336 if (pm->refcount == 0) {
337 list_remove(&pm->entry);
338 FreeLibrary(pm->hdll);
339 heap_free(pm->name);
340 heap_free(pm->dllname);
341 heap_free(pm);
343 LeaveCriticalSection(&monitor_handles_cs);
346 /******************************************************************
347 * monitor_unloadall [internal]
349 * release all printmonitors and unload them from memory, when needed
353 static void monitor_unloadall(void)
355 monitor_t * pm;
356 monitor_t * next;
358 EnterCriticalSection(&monitor_handles_cs);
359 /* iterate through the list, with safety against removal */
360 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
362 monitor_unload(pm);
364 LeaveCriticalSection(&monitor_handles_cs);
367 /******************************************************************
368 * monitor_load [internal]
370 * load a printmonitor, get the dllname from the registry, when needed
371 * initialize the monitor and dump found function-pointers
373 * On failure, SetLastError() is called and NULL is returned
376 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
378 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
379 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
380 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
381 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
382 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
384 monitor_t * pm = NULL;
385 monitor_t * cursor;
386 LPWSTR regroot = NULL;
387 LPWSTR driver = dllname;
389 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
390 /* Is the Monitor already loaded? */
391 EnterCriticalSection(&monitor_handles_cs);
393 if (name) {
394 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
396 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
397 pm = cursor;
398 break;
403 if (pm == NULL) {
404 pm = heap_alloc_zero(sizeof(monitor_t));
405 if (pm == NULL) goto cleanup;
406 list_add_tail(&monitor_handles, &pm->entry);
408 pm->refcount++;
410 if (pm->name == NULL) {
411 /* Load the monitor */
412 LPMONITOREX pmonitorEx;
413 DWORD len;
415 if (name) {
416 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
417 regroot = heap_alloc(len * sizeof(WCHAR));
420 if (regroot) {
421 lstrcpyW(regroot, monitorsW);
422 lstrcatW(regroot, name);
423 /* Get the Driver from the Registry */
424 if (driver == NULL) {
425 HKEY hroot;
426 DWORD namesize;
427 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
428 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
429 &namesize) == ERROR_SUCCESS) {
430 driver = heap_alloc(namesize);
431 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
433 RegCloseKey(hroot);
438 pm->name = strdupW(name);
439 pm->dllname = strdupW(driver);
441 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
442 monitor_unload(pm);
443 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
444 pm = NULL;
445 goto cleanup;
448 pm->hdll = LoadLibraryW(driver);
449 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
451 if (pm->hdll == NULL) {
452 monitor_unload(pm);
453 SetLastError(ERROR_MOD_NOT_FOUND);
454 pm = NULL;
455 goto cleanup;
458 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
459 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
460 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
461 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
462 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
465 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
466 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
467 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
468 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
469 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
471 if (pInitializePrintMonitorUI != NULL) {
472 pm->monitorUI = pInitializePrintMonitorUI();
473 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
474 if (pm->monitorUI) {
475 TRACE("0x%08x: dwMonitorSize (%d)\n",
476 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
481 if (pInitializePrintMonitor && regroot) {
482 pmonitorEx = pInitializePrintMonitor(regroot);
483 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
484 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
486 if (pmonitorEx) {
487 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
488 pm->monitor = &(pmonitorEx->Monitor);
492 if (pm->monitor) {
493 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
497 if (!pm->monitor && regroot) {
498 if (pInitializePrintMonitor2 != NULL) {
499 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
501 if (pInitializeMonitorEx != NULL) {
502 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
504 if (pInitializeMonitor != NULL) {
505 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
508 if (!pm->monitor && !pm->monitorUI) {
509 monitor_unload(pm);
510 SetLastError(ERROR_PROC_NOT_FOUND);
511 pm = NULL;
514 cleanup:
515 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
516 pm->refcount++;
517 pm_localport = pm;
519 LeaveCriticalSection(&monitor_handles_cs);
520 if (driver != dllname) heap_free(driver);
521 heap_free(regroot);
522 TRACE("=> %p\n", pm);
523 return pm;
526 /******************************************************************
527 * monitor_loadall [internal]
529 * Load all registered monitors
532 static DWORD monitor_loadall(void)
534 monitor_t * pm;
535 DWORD registered = 0;
536 DWORD loaded = 0;
537 HKEY hmonitors;
538 WCHAR buffer[MAX_PATH];
539 DWORD id = 0;
541 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
542 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
543 NULL, NULL, NULL, NULL, NULL);
545 TRACE("%d monitors registered\n", registered);
547 while (id < registered) {
548 buffer[0] = '\0';
549 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
550 pm = monitor_load(buffer, NULL);
551 if (pm) loaded++;
552 id++;
554 RegCloseKey(hmonitors);
556 TRACE("%d monitors loaded\n", loaded);
557 return loaded;
560 /******************************************************************
561 * monitor_loadui [internal]
563 * load the userinterface-dll for a given portmonitor
565 * On failure, NULL is returned
567 static monitor_t * monitor_loadui(monitor_t * pm)
569 monitor_t * pui = NULL;
570 LPWSTR buffer[MAX_PATH];
571 HANDLE hXcv;
572 DWORD len;
573 DWORD res;
575 if (pm == NULL) return NULL;
576 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
578 /* Try the Portmonitor first; works for many monitors */
579 if (pm->monitorUI) {
580 EnterCriticalSection(&monitor_handles_cs);
581 pm->refcount++;
582 LeaveCriticalSection(&monitor_handles_cs);
583 return pm;
586 /* query the userinterface-dllname from the Portmonitor */
587 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
588 /* building (",XcvMonitor %s",pm->name) not needed yet */
589 res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
590 TRACE("got %u with %p\n", res, hXcv);
591 if (res) {
592 res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
593 TRACE("got %u with %s\n", res, debugstr_w((LPWSTR) buffer));
594 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, (LPWSTR) buffer);
595 pm->monitor->pfnXcvClosePort(hXcv);
598 return pui;
601 /******************************************************************
602 * monitor_load_by_port [internal]
604 * load a printmonitor for a given port
606 * On failure, NULL is returned
609 static monitor_t * monitor_load_by_port(LPCWSTR portname)
611 HKEY hroot;
612 HKEY hport;
613 LPWSTR buffer;
614 monitor_t * pm = NULL;
615 DWORD registered = 0;
616 DWORD id = 0;
617 DWORD len;
619 TRACE("(%s)\n", debugstr_w(portname));
621 /* Try the Local Monitor first */
622 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
623 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
624 /* found the portname */
625 RegCloseKey(hroot);
626 return monitor_load(localportW, NULL);
628 RegCloseKey(hroot);
631 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
632 buffer = heap_alloc(len * sizeof(WCHAR));
633 if (buffer == NULL) return NULL;
635 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
636 EnterCriticalSection(&monitor_handles_cs);
637 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
639 while ((pm == NULL) && (id < registered)) {
640 buffer[0] = '\0';
641 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
642 TRACE("testing %s\n", debugstr_w(buffer));
643 len = lstrlenW(buffer);
644 lstrcatW(buffer, bs_ports_bsW);
645 lstrcatW(buffer, portname);
646 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
647 RegCloseKey(hport);
648 buffer[len] = '\0'; /* use only the Monitor-Name */
649 pm = monitor_load(buffer, NULL);
651 id++;
653 LeaveCriticalSection(&monitor_handles_cs);
654 RegCloseKey(hroot);
656 heap_free(buffer);
657 return pm;
660 /******************************************************************
661 * Return the number of bytes for an multi_sz string.
662 * The result includes all \0s
663 * (specifically the extra \0, that is needed as multi_sz terminator).
665 static int multi_sz_lenW(const WCHAR *str)
667 const WCHAR *ptr = str;
668 if (!str) return 0;
671 ptr += lstrlenW(ptr) + 1;
672 } while (*ptr);
674 return (ptr - str + 1) * sizeof(WCHAR);
677 /******************************************************************
678 * validate_envW [internal]
680 * validate the user-supplied printing-environment
682 * PARAMS
683 * env [I] PTR to Environment-String or NULL
685 * RETURNS
686 * Success: PTR to printenv_t
687 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
689 * NOTES
690 * An empty string is handled the same way as NULL.
694 static const printenv_t * validate_envW(LPCWSTR env)
696 const printenv_t *result = NULL;
697 unsigned int i;
699 TRACE("(%s)\n", debugstr_w(env));
700 if (env && env[0])
702 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
704 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
706 result = all_printenv[i];
707 break;
710 if (result == NULL) {
711 FIXME("unsupported Environment: %s\n", debugstr_w(env));
712 SetLastError(ERROR_INVALID_ENVIRONMENT);
714 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
716 else
718 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
721 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
722 return result;
725 /*****************************************************************************
726 * enumerate the local monitors (INTERNAL)
728 * returns the needed size (in bytes) for pMonitors
729 * and *lpreturned is set to number of entries returned in pMonitors
731 * Language-Monitors are also installed in the same Registry-Location but
732 * they are filtered in Windows (not returned by EnumMonitors).
733 * We do no filtering to simplify our Code.
736 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
738 HKEY hroot = NULL;
739 HKEY hentry = NULL;
740 LPWSTR ptr;
741 LPMONITOR_INFO_2W mi;
742 WCHAR buffer[MAX_PATH];
743 WCHAR dllname[MAX_PATH];
744 DWORD dllsize;
745 DWORD len;
746 DWORD index = 0;
747 DWORD needed = 0;
748 DWORD numentries;
749 DWORD entrysize;
751 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
753 numentries = *lpreturned; /* this is 0, when we scan the registry */
754 len = entrysize * numentries;
755 ptr = (LPWSTR) &pMonitors[len];
757 numentries = 0;
758 len = sizeof(buffer)/sizeof(buffer[0]);
759 buffer[0] = '\0';
761 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
762 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
763 /* Scan all Monitor-Registry-Keys */
764 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
765 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
766 dllsize = sizeof(dllname);
767 dllname[0] = '\0';
769 /* The Monitor must have a Driver-DLL */
770 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
771 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
772 /* We found a valid DLL for this Monitor. */
773 TRACE("using Driver: %s\n", debugstr_w(dllname));
775 RegCloseKey(hentry);
778 /* Windows returns only Port-Monitors here, but to simplify our code,
779 we do no filtering for Language-Monitors */
780 if (dllname[0]) {
781 numentries++;
782 needed += entrysize;
783 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
784 if (level > 1) {
785 /* we install and return only monitors for "Windows NT x86" */
786 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
787 needed += dllsize;
790 /* required size is calculated. Now fill the user-buffer */
791 if (pMonitors && (cbBuf >= needed)){
792 mi = (LPMONITOR_INFO_2W) pMonitors;
793 pMonitors += entrysize;
795 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
796 mi->pName = ptr;
797 lstrcpyW(ptr, buffer); /* Name of the Monitor */
798 ptr += (len+1); /* len is lstrlenW(monitorname) */
799 if (level > 1) {
800 mi->pEnvironment = ptr;
801 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
802 ptr += (lstrlenW(x86_envnameW)+1);
804 mi->pDLLName = ptr;
805 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
806 ptr += (dllsize / sizeof(WCHAR));
810 index++;
811 len = sizeof(buffer)/sizeof(buffer[0]);
812 buffer[0] = '\0';
814 RegCloseKey(hroot);
816 *lpreturned = numentries;
817 TRACE("need %d byte for %d entries\n", needed, numentries);
818 return needed;
821 /******************************************************************
822 * enumerate the local Ports from all loaded monitors (internal)
824 * returns the needed size (in bytes) for pPorts
825 * and *lpreturned is set to number of entries returned in pPorts
828 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
830 monitor_t * pm;
831 LPWSTR ptr;
832 LPPORT_INFO_2W cache;
833 LPPORT_INFO_2W out;
834 LPBYTE pi_buffer = NULL;
835 DWORD pi_allocated = 0;
836 DWORD pi_needed;
837 DWORD pi_index;
838 DWORD pi_returned;
839 DWORD res;
840 DWORD outindex = 0;
841 DWORD needed;
842 DWORD numentries;
843 DWORD entrysize;
846 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
847 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
849 numentries = *lpreturned; /* this is 0, when we scan the registry */
850 needed = entrysize * numentries;
851 ptr = (LPWSTR) &pPorts[needed];
853 numentries = 0;
854 needed = 0;
856 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
858 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
859 pi_needed = 0;
860 pi_returned = 0;
861 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
862 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
863 /* Do not use heap_realloc (we do not need the old data in the buffer) */
864 heap_free(pi_buffer);
865 pi_buffer = heap_alloc(pi_needed);
866 pi_allocated = (pi_buffer) ? pi_needed : 0;
867 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
869 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
870 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
872 numentries += pi_returned;
873 needed += pi_needed;
875 /* fill the output-buffer (pPorts), if we have one */
876 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
877 pi_index = 0;
878 while (pi_returned > pi_index) {
879 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
880 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
881 out->pPortName = ptr;
882 lstrcpyW(ptr, cache->pPortName);
883 ptr += (lstrlenW(ptr)+1);
884 if (level > 1) {
885 out->pMonitorName = ptr;
886 lstrcpyW(ptr, cache->pMonitorName);
887 ptr += (lstrlenW(ptr)+1);
889 out->pDescription = ptr;
890 lstrcpyW(ptr, cache->pDescription);
891 ptr += (lstrlenW(ptr)+1);
892 out->fPortType = cache->fPortType;
893 out->Reserved = cache->Reserved;
895 pi_index++;
896 outindex++;
901 /* the temporary portinfo-buffer is no longer needed */
902 heap_free(pi_buffer);
904 *lpreturned = numentries;
905 TRACE("need %d byte for %d entries\n", needed, numentries);
906 return needed;
910 /*****************************************************************************
911 * open_driver_reg [internal]
913 * opens the registry for the printer drivers depending on the given input
914 * variable pEnvironment
916 * RETURNS:
917 * Success: the opened hkey
918 * Failure: NULL
920 static HKEY open_driver_reg(LPCWSTR pEnvironment)
922 HKEY retval = NULL;
923 LPWSTR buffer;
924 const printenv_t * env;
926 TRACE("(%s)\n", debugstr_w(pEnvironment));
928 env = validate_envW(pEnvironment);
929 if (!env) return NULL;
931 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
932 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
934 if (buffer) {
935 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
936 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
937 HeapFree(GetProcessHeap(), 0, buffer);
939 return retval;
942 /*****************************************************************************
943 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
945 * Return the PATH for the Printer-Drivers
947 * PARAMS
948 * pName [I] Servername (NT only) or NULL (local Computer)
949 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
950 * Level [I] Structure-Level (must be 1)
951 * pDriverDirectory [O] PTR to Buffer that receives the Result
952 * cbBuf [I] Size of Buffer at pDriverDirectory
953 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
954 * required for pDriverDirectory
956 * RETURNS
957 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
958 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
959 * if cbBuf is too small
961 * Native Values returned in pDriverDirectory on Success:
962 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
963 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
964 *| win9x(Windows 4.0): "%winsysdir%"
966 * "%winsysdir%" is the Value from GetSystemDirectoryW()
969 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
970 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
972 DWORD needed;
973 const printenv_t * env;
975 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
976 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
978 if (pName != NULL && pName[0]) {
979 FIXME("server %s not supported\n", debugstr_w(pName));
980 SetLastError(ERROR_INVALID_PARAMETER);
981 return FALSE;
984 env = validate_envW(pEnvironment);
985 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
988 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
989 needed = GetSystemDirectoryW(NULL, 0);
990 /* add the Size for the Subdirectories */
991 needed += lstrlenW(spooldriversW);
992 needed += lstrlenW(env->subdir);
993 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
995 *pcbNeeded = needed;
997 if (needed > cbBuf) {
998 SetLastError(ERROR_INSUFFICIENT_BUFFER);
999 return FALSE;
1002 if (pDriverDirectory == NULL) {
1003 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1004 SetLastError(ERROR_INVALID_USER_BUFFER);
1005 return FALSE;
1008 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
1009 /* add the Subdirectories */
1010 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
1011 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
1013 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
1014 return TRUE;
1017 /******************************************************************
1018 * driver_load [internal]
1020 * load a driver user interface dll
1022 * On failure, NULL is returned
1026 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1028 WCHAR fullname[MAX_PATH];
1029 HMODULE hui;
1030 DWORD len;
1032 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1034 /* build the driverdir */
1035 len = sizeof(fullname) -
1036 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1038 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1039 (LPBYTE) fullname, len, &len)) {
1040 /* Should never Fail */
1041 SetLastError(ERROR_BUFFER_OVERFLOW);
1042 return NULL;
1045 lstrcatW(fullname, env->versionsubdir);
1046 lstrcatW(fullname, backslashW);
1047 lstrcatW(fullname, dllname);
1049 hui = LoadLibraryW(fullname);
1050 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1052 return hui;
1055 /******************************************************************
1056 * printer_free
1057 * free the data pointer of an opened printer
1059 static VOID printer_free(printer_t * printer)
1061 if (printer->hXcv)
1062 printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1064 monitor_unload(printer->pm);
1066 heap_free(printer->printername);
1067 heap_free(printer->name);
1068 heap_free(printer);
1071 /******************************************************************
1072 * printer_alloc_handle
1073 * alloc a printer handle and remember the data pointer in the printer handle table
1076 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1078 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1079 printer_t *printer = NULL;
1080 LPCWSTR printername;
1081 HKEY hkeyPrinters;
1082 HKEY hkeyPrinter;
1083 DWORD len;
1085 if (copy_servername_from_name(name, servername)) {
1086 FIXME("server %s not supported\n", debugstr_w(servername));
1087 SetLastError(ERROR_INVALID_PRINTER_NAME);
1088 return NULL;
1091 printername = get_basename_from_name(name);
1092 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1094 /* an empty printername is invalid */
1095 if (printername && (!printername[0])) {
1096 SetLastError(ERROR_INVALID_PARAMETER);
1097 return NULL;
1100 printer = heap_alloc_zero(sizeof(printer_t));
1101 if (!printer) goto end;
1103 /* clone the base name. This is NULL for the printserver */
1104 printer->printername = strdupW(printername);
1106 /* clone the full name */
1107 printer->name = strdupW(name);
1108 if (name && (!printer->name)) {
1109 printer_free(printer);
1110 printer = NULL;
1112 if (printername) {
1113 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1114 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1115 /* OpenPrinter(",XcvMonitor ", ...) detected */
1116 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1117 printer->pm = monitor_load(&printername[len], NULL);
1118 if (printer->pm == NULL) {
1119 printer_free(printer);
1120 SetLastError(ERROR_UNKNOWN_PORT);
1121 printer = NULL;
1122 goto end;
1125 else
1127 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1128 if (strncmpW( printername, XcvPortW, len) == 0) {
1129 /* OpenPrinter(",XcvPort ", ...) detected */
1130 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1131 printer->pm = monitor_load_by_port(&printername[len]);
1132 if (printer->pm == NULL) {
1133 printer_free(printer);
1134 SetLastError(ERROR_UNKNOWN_PORT);
1135 printer = NULL;
1136 goto end;
1141 if (printer->pm) {
1142 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1143 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1144 pDefault ? pDefault->DesiredAccess : 0,
1145 &printer->hXcv);
1147 if (printer->hXcv == NULL) {
1148 printer_free(printer);
1149 SetLastError(ERROR_INVALID_PARAMETER);
1150 printer = NULL;
1151 goto end;
1154 else
1156 /* Does the Printer exist? */
1157 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1158 ERR("Can't create Printers key\n");
1159 printer_free(printer);
1160 SetLastError(ERROR_INVALID_PRINTER_NAME);
1161 printer = NULL;
1162 goto end;
1164 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1165 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1166 RegCloseKey(hkeyPrinters);
1167 printer_free(printer);
1168 SetLastError(ERROR_INVALID_PRINTER_NAME);
1169 printer = NULL;
1170 goto end;
1172 RegCloseKey(hkeyPrinter);
1173 RegCloseKey(hkeyPrinters);
1176 else
1178 TRACE("using the local printserver\n");
1181 end:
1183 TRACE("==> %p\n", printer);
1184 return (HANDLE)printer;
1188 /******************************************************************************
1189 * myAddPrinterDriverEx [internal]
1191 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1192 * and a special mode with lazy error checking.
1195 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1197 const printenv_t *env;
1198 apd_data_t apd;
1199 DRIVER_INFO_8W di;
1200 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1201 HMODULE hui;
1202 LPWSTR ptr;
1203 HKEY hroot;
1204 HKEY hdrv;
1205 DWORD disposition;
1206 DWORD len;
1207 LONG lres;
1208 BOOL res;
1210 /* we need to set all entries in the Registry, independent from the Level of
1211 DRIVER_INFO, that the caller supplied */
1213 ZeroMemory(&di, sizeof(di));
1214 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1215 memcpy(&di, pDriverInfo, di_sizeof[level]);
1218 /* dump the most used infos */
1219 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1220 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1221 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1222 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1223 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1224 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1225 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1226 /* dump only the first of the additional Files */
1227 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1230 /* check environment */
1231 env = validate_envW(di.pEnvironment);
1232 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1234 /* fill the copy-data / get the driverdir */
1235 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1236 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1237 (LPBYTE) apd.src, len, &len)) {
1238 /* Should never Fail */
1239 return FALSE;
1241 memcpy(apd.dst, apd.src, len);
1242 lstrcatW(apd.src, backslashW);
1243 apd.srclen = lstrlenW(apd.src);
1244 lstrcatW(apd.dst, env->versionsubdir);
1245 lstrcatW(apd.dst, backslashW);
1246 apd.dstlen = lstrlenW(apd.dst);
1247 apd.copyflags = dwFileCopyFlags;
1248 apd.lazy = lazy;
1249 CreateDirectoryW(apd.src, NULL);
1250 CreateDirectoryW(apd.dst, NULL);
1252 hroot = open_driver_reg(env->envname);
1253 if (!hroot) {
1254 ERR("Can't create Drivers key\n");
1255 return FALSE;
1258 /* Fill the Registry for the Driver */
1259 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1260 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1261 &hdrv, &disposition)) != ERROR_SUCCESS) {
1263 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1264 RegCloseKey(hroot);
1265 SetLastError(lres);
1266 return FALSE;
1268 RegCloseKey(hroot);
1270 if (disposition == REG_OPENED_EXISTING_KEY) {
1271 TRACE("driver %s already installed\n", debugstr_w(di.pName));
1272 RegCloseKey(hdrv);
1273 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1274 return FALSE;
1277 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1278 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
1279 sizeof(DWORD));
1281 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1282 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1283 apd_copyfile(di.pDriverPath, &apd);
1285 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1286 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1287 apd_copyfile(di.pDataFile, &apd);
1289 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1290 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1291 apd_copyfile(di.pConfigFile, &apd);
1293 /* settings for level 3 */
1294 if (di.pHelpFile)
1295 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1296 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1297 else
1298 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1299 apd_copyfile(di.pHelpFile, &apd);
1302 ptr = di.pDependentFiles;
1303 if (ptr)
1304 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1305 multi_sz_lenW(di.pDependentFiles));
1306 else
1307 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1308 while ((ptr != NULL) && (ptr[0])) {
1309 if (apd_copyfile(ptr, &apd)) {
1310 ptr += lstrlenW(ptr) + 1;
1312 else
1314 WARN("Failed to copy %s\n", debugstr_w(ptr));
1315 ptr = NULL;
1318 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1319 if (di.pMonitorName)
1320 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1321 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1322 else
1323 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1325 if (di.pDefaultDataType)
1326 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1327 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1328 else
1329 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1331 /* settings for level 4 */
1332 if (di.pszzPreviousNames)
1333 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1334 multi_sz_lenW(di.pszzPreviousNames));
1335 else
1336 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1338 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1340 RegCloseKey(hdrv);
1341 hui = driver_load(env, di.pConfigFile);
1342 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1343 if (hui && pDrvDriverEvent) {
1345 /* Support for DrvDriverEvent is optional */
1346 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1347 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1348 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1349 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1351 FreeLibrary(hui);
1353 TRACE("=> TRUE with %u\n", GetLastError());
1354 return TRUE;
1358 /******************************************************************************
1359 * fpAddMonitor [exported through PRINTPROVIDOR]
1361 * Install a Printmonitor
1363 * PARAMS
1364 * pName [I] Servername or NULL (local Computer)
1365 * Level [I] Structure-Level (Must be 2)
1366 * pMonitors [I] PTR to MONITOR_INFO_2
1368 * RETURNS
1369 * Success: TRUE
1370 * Failure: FALSE
1372 * NOTES
1373 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1376 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1378 monitor_t * pm = NULL;
1379 LPMONITOR_INFO_2W mi2w;
1380 HKEY hroot = NULL;
1381 HKEY hentry = NULL;
1382 DWORD disposition;
1383 BOOL res = FALSE;
1385 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1386 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1387 debugstr_w(mi2w ? mi2w->pName : NULL),
1388 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1389 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1391 if (copy_servername_from_name(pName, NULL)) {
1392 FIXME("server %s not supported\n", debugstr_w(pName));
1393 SetLastError(ERROR_ACCESS_DENIED);
1394 return FALSE;
1397 if (!mi2w->pName || (! mi2w->pName[0])) {
1398 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1399 SetLastError(ERROR_INVALID_PARAMETER);
1400 return FALSE;
1402 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1403 WARN("Environment %s requested (we support only %s)\n",
1404 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1405 SetLastError(ERROR_INVALID_ENVIRONMENT);
1406 return FALSE;
1409 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1410 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1411 SetLastError(ERROR_INVALID_PARAMETER);
1412 return FALSE;
1415 /* Load and initialize the monitor. SetLastError() is called on failure */
1416 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1417 return FALSE;
1419 monitor_unload(pm);
1421 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1422 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1423 return FALSE;
1426 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1427 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1428 &disposition) == ERROR_SUCCESS) {
1430 /* Some installers set options for the port before calling AddMonitor.
1431 We query the "Driver" entry to verify that the monitor is installed,
1432 before we return an error.
1433 When a user installs two print monitors at the same time with the
1434 same name, a race condition is possible but silently ignored. */
1436 DWORD namesize = 0;
1438 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1439 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1440 &namesize) == ERROR_SUCCESS)) {
1441 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1442 /* 9x use ERROR_ALREADY_EXISTS */
1443 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1445 else
1447 INT len;
1448 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1449 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1450 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1452 RegCloseKey(hentry);
1455 RegCloseKey(hroot);
1456 return (res);
1459 /******************************************************************************
1460 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1462 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1464 * PARAMS
1465 * pName [I] Servername or NULL (local Computer)
1466 * level [I] Level for the supplied DRIVER_INFO_*W struct
1467 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1468 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1470 * RESULTS
1471 * Success: TRUE
1472 * Failure: FALSE
1475 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1477 LONG lres;
1479 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1480 lres = copy_servername_from_name(pName, NULL);
1481 if (lres) {
1482 FIXME("server %s not supported\n", debugstr_w(pName));
1483 SetLastError(ERROR_ACCESS_DENIED);
1484 return FALSE;
1487 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1488 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1491 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1494 /******************************************************************************
1495 * fpClosePrinter [exported through PRINTPROVIDOR]
1497 * Close a printer handle and free associated resources
1499 * PARAMS
1500 * hPrinter [I] Printerhandle to close
1502 * RESULTS
1503 * Success: TRUE
1504 * Failure: FALSE
1507 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1509 printer_t *printer = (printer_t *) hPrinter;
1511 TRACE("(%p)\n", hPrinter);
1513 if (printer) {
1514 printer_free(printer);
1515 return TRUE;
1517 return FALSE;
1520 /******************************************************************************
1521 * fpConfigurePort [exported through PRINTPROVIDOR]
1523 * Display the Configuration-Dialog for a specific Port
1525 * PARAMS
1526 * pName [I] Servername or NULL (local Computer)
1527 * hWnd [I] Handle to parent Window for the Dialog-Box
1528 * pPortName [I] Name of the Port, that should be configured
1530 * RETURNS
1531 * Success: TRUE
1532 * Failure: FALSE
1535 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1537 monitor_t * pm;
1538 monitor_t * pui;
1539 LONG lres;
1540 DWORD res;
1542 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1544 lres = copy_servername_from_name(pName, NULL);
1545 if (lres) {
1546 FIXME("server %s not supported\n", debugstr_w(pName));
1547 SetLastError(ERROR_INVALID_NAME);
1548 return FALSE;
1551 /* an empty Portname is Invalid, but can popup a Dialog */
1552 if (!pPortName[0]) {
1553 SetLastError(ERROR_NOT_SUPPORTED);
1554 return FALSE;
1557 pm = monitor_load_by_port(pPortName);
1558 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
1559 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1560 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1561 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
1562 TRACE("got %d with %u\n", res, GetLastError());
1564 else
1566 pui = monitor_loadui(pm);
1567 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
1568 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1569 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1570 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
1571 TRACE("got %d with %u\n", res, GetLastError());
1573 else
1575 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1576 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1577 pui, debugstr_w(pui ? pui->dllname : NULL));
1579 SetLastError(ERROR_NOT_SUPPORTED);
1580 res = FALSE;
1582 monitor_unload(pui);
1584 monitor_unload(pm);
1586 TRACE("returning %d with %u\n", res, GetLastError());
1587 return res;
1590 /******************************************************************
1591 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1593 * Delete a specific Printmonitor from a Printing-Environment
1595 * PARAMS
1596 * pName [I] Servername or NULL (local Computer)
1597 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1598 * pMonitorName [I] Name of the Monitor, that should be deleted
1600 * RETURNS
1601 * Success: TRUE
1602 * Failure: FALSE
1604 * NOTES
1605 * pEnvironment is ignored in Windows for the local Computer.
1609 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1611 HKEY hroot = NULL;
1612 LONG lres;
1614 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1615 debugstr_w(pMonitorName));
1617 lres = copy_servername_from_name(pName, NULL);
1618 if (lres) {
1619 FIXME("server %s not supported\n", debugstr_w(pName));
1620 SetLastError(ERROR_INVALID_NAME);
1621 return FALSE;
1624 /* pEnvironment is ignored in Windows for the local Computer */
1625 if (!pMonitorName || !pMonitorName[0]) {
1626 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1627 SetLastError(ERROR_INVALID_PARAMETER);
1628 return FALSE;
1631 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1632 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1633 return FALSE;
1636 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1637 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1638 RegCloseKey(hroot);
1639 return TRUE;
1642 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1643 RegCloseKey(hroot);
1645 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1646 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1647 return FALSE;
1650 /*****************************************************************************
1651 * fpEnumMonitors [exported through PRINTPROVIDOR]
1653 * Enumerate available Port-Monitors
1655 * PARAMS
1656 * pName [I] Servername or NULL (local Computer)
1657 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1658 * pMonitors [O] PTR to Buffer that receives the Result
1659 * cbBuf [I] Size of Buffer at pMonitors
1660 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1661 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1663 * RETURNS
1664 * Success: TRUE
1665 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1667 * NOTES
1668 * Windows reads the Registry once and cache the Results.
1671 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1672 LPDWORD pcbNeeded, LPDWORD pcReturned)
1674 DWORD numentries = 0;
1675 DWORD needed = 0;
1676 LONG lres;
1677 BOOL res = FALSE;
1679 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1680 cbBuf, pcbNeeded, pcReturned);
1682 lres = copy_servername_from_name(pName, NULL);
1683 if (lres) {
1684 FIXME("server %s not supported\n", debugstr_w(pName));
1685 SetLastError(ERROR_INVALID_NAME);
1686 goto em_cleanup;
1689 if (!Level || (Level > 2)) {
1690 WARN("level (%d) is ignored in win9x\n", Level);
1691 SetLastError(ERROR_INVALID_LEVEL);
1692 return FALSE;
1695 /* Scan all Monitor-Keys */
1696 numentries = 0;
1697 needed = get_local_monitors(Level, NULL, 0, &numentries);
1699 /* we calculated the needed buffersize. now do more error-checks */
1700 if (cbBuf < needed) {
1701 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1702 goto em_cleanup;
1705 /* fill the Buffer with the Monitor-Keys */
1706 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1707 res = TRUE;
1709 em_cleanup:
1710 if (pcbNeeded) *pcbNeeded = needed;
1711 if (pcReturned) *pcReturned = numentries;
1713 TRACE("returning %d with %d (%d byte for %d entries)\n",
1714 res, GetLastError(), needed, numentries);
1716 return (res);
1719 /******************************************************************************
1720 * fpEnumPorts [exported through PRINTPROVIDOR]
1722 * Enumerate available Ports
1724 * PARAMS
1725 * pName [I] Servername or NULL (local Computer)
1726 * Level [I] Structure-Level (1 or 2)
1727 * pPorts [O] PTR to Buffer that receives the Result
1728 * cbBuf [I] Size of Buffer at pPorts
1729 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1730 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1732 * RETURNS
1733 * Success: TRUE
1734 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1737 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1738 LPDWORD pcbNeeded, LPDWORD pcReturned)
1740 DWORD needed = 0;
1741 DWORD numentries = 0;
1742 LONG lres;
1743 BOOL res = FALSE;
1745 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1746 cbBuf, pcbNeeded, pcReturned);
1748 lres = copy_servername_from_name(pName, NULL);
1749 if (lres) {
1750 FIXME("server %s not supported\n", debugstr_w(pName));
1751 SetLastError(ERROR_INVALID_NAME);
1752 goto emP_cleanup;
1755 if (!Level || (Level > 2)) {
1756 SetLastError(ERROR_INVALID_LEVEL);
1757 goto emP_cleanup;
1760 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1761 SetLastError(RPC_X_NULL_REF_POINTER);
1762 goto emP_cleanup;
1765 EnterCriticalSection(&monitor_handles_cs);
1766 monitor_loadall();
1768 /* Scan all local Ports */
1769 numentries = 0;
1770 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1772 /* we calculated the needed buffersize. now do the error-checks */
1773 if (cbBuf < needed) {
1774 monitor_unloadall();
1775 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1776 goto emP_cleanup_cs;
1778 else if (!pPorts || !pcReturned) {
1779 monitor_unloadall();
1780 SetLastError(RPC_X_NULL_REF_POINTER);
1781 goto emP_cleanup_cs;
1784 /* Fill the Buffer */
1785 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1786 res = TRUE;
1787 monitor_unloadall();
1789 emP_cleanup_cs:
1790 LeaveCriticalSection(&monitor_handles_cs);
1792 emP_cleanup:
1793 if (pcbNeeded) *pcbNeeded = needed;
1794 if (pcReturned) *pcReturned = (res) ? numentries : 0;
1796 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1797 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
1799 return (res);
1802 /******************************************************************************
1803 * fpOpenPrinter [exported through PRINTPROVIDOR]
1805 * Open a Printer / Printserver or a Printer-Object
1807 * PARAMS
1808 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1809 * pPrinter [O] The resulting Handle is stored here
1810 * pDefaults [I] PTR to Default Printer Settings or NULL
1812 * RETURNS
1813 * Success: TRUE
1814 * Failure: FALSE
1816 * NOTES
1817 * lpPrinterName is one of:
1818 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1819 *| Printer: "PrinterName"
1820 *| Printer-Object: "PrinterName,Job xxx"
1821 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1822 *| XcvPort: "Servername,XcvPort PortName"
1826 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
1827 LPPRINTER_DEFAULTSW pDefaults)
1830 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
1832 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
1834 return (*pPrinter != 0);
1837 /******************************************************************************
1838 * fpXcvData [exported through PRINTPROVIDOR]
1840 * Execute commands in the Printmonitor DLL
1842 * PARAMS
1843 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
1844 * pszDataName [i] Name of the command to execute
1845 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
1846 * cbInputData [i] Size in Bytes of Buffer at pInputData
1847 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
1848 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
1849 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
1850 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
1852 * RETURNS
1853 * Success: TRUE
1854 * Failure: FALSE
1856 * NOTES
1857 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
1858 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
1860 * Minimal List of commands, that a Printmonitor DLL should support:
1862 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
1863 *| "AddPort" : Add a Port
1864 *| "DeletePort": Delete a Port
1866 * Many Printmonitors support additional commands. Examples for localspl.dll:
1867 * "GetDefaultCommConfig", "SetDefaultCommConfig",
1868 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
1871 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
1872 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
1873 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
1875 printer_t *printer = (printer_t * ) hXcv;
1877 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
1878 pInputData, cbInputData, pOutputData,
1879 cbOutputData, pcbOutputNeeded, pdwStatus);
1881 if (!printer || (!printer->hXcv)) {
1882 SetLastError(ERROR_INVALID_HANDLE);
1883 return FALSE;
1886 if (!pcbOutputNeeded) {
1887 SetLastError(ERROR_INVALID_PARAMETER);
1888 return FALSE;
1891 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
1892 SetLastError(RPC_X_NULL_REF_POINTER);
1893 return FALSE;
1896 *pcbOutputNeeded = 0;
1898 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
1899 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
1901 return TRUE;
1904 /*****************************************************
1905 * setup_provider [internal]
1907 void setup_provider(void)
1909 static const PRINTPROVIDOR backend = {
1910 fpOpenPrinter,
1911 NULL, /* fpSetJob */
1912 NULL, /* fpGetJob */
1913 NULL, /* fpEnumJobs */
1914 NULL, /* fpAddPrinter */
1915 NULL, /* fpDeletePrinter */
1916 NULL, /* fpSetPrinter */
1917 NULL, /* fpGetPrinter */
1918 NULL, /* fpEnumPrinters */
1919 NULL, /* fpAddPrinterDriver */
1920 NULL, /* fpEnumPrinterDrivers */
1921 NULL, /* fpGetPrinterDriver */
1922 fpGetPrinterDriverDirectory,
1923 NULL, /* fpDeletePrinterDriver */
1924 NULL, /* fpAddPrintProcessor */
1925 NULL, /* fpEnumPrintProcessors */
1926 NULL, /* fpGetPrintProcessorDirectory */
1927 NULL, /* fpDeletePrintProcessor */
1928 NULL, /* fpEnumPrintProcessorDatatypes */
1929 NULL, /* fpStartDocPrinter */
1930 NULL, /* fpStartPagePrinter */
1931 NULL, /* fpWritePrinter */
1932 NULL, /* fpEndPagePrinter */
1933 NULL, /* fpAbortPrinter */
1934 NULL, /* fpReadPrinter */
1935 NULL, /* fpEndDocPrinter */
1936 NULL, /* fpAddJob */
1937 NULL, /* fpScheduleJob */
1938 NULL, /* fpGetPrinterData */
1939 NULL, /* fpSetPrinterData */
1940 NULL, /* fpWaitForPrinterChange */
1941 fpClosePrinter,
1942 NULL, /* fpAddForm */
1943 NULL, /* fpDeleteForm */
1944 NULL, /* fpGetForm */
1945 NULL, /* fpSetForm */
1946 NULL, /* fpEnumForms */
1947 fpEnumMonitors,
1948 fpEnumPorts,
1949 NULL, /* fpAddPort */
1950 fpConfigurePort,
1951 NULL, /* fpDeletePort */
1952 NULL, /* fpCreatePrinterIC */
1953 NULL, /* fpPlayGdiScriptOnPrinterIC */
1954 NULL, /* fpDeletePrinterIC */
1955 NULL, /* fpAddPrinterConnection */
1956 NULL, /* fpDeletePrinterConnection */
1957 NULL, /* fpPrinterMessageBox */
1958 fpAddMonitor,
1959 fpDeleteMonitor,
1960 NULL, /* fpResetPrinter */
1961 NULL, /* fpGetPrinterDriverEx */
1962 NULL, /* fpFindFirstPrinterChangeNotification */
1963 NULL, /* fpFindClosePrinterChangeNotification */
1964 NULL, /* fpAddPortEx */
1965 NULL, /* fpShutDown */
1966 NULL, /* fpRefreshPrinterChangeNotification */
1967 NULL, /* fpOpenPrinterEx */
1968 NULL, /* fpAddPrinterEx */
1969 NULL, /* fpSetPort */
1970 NULL, /* fpEnumPrinterData */
1971 NULL, /* fpDeletePrinterData */
1972 NULL, /* fpClusterSplOpen */
1973 NULL, /* fpClusterSplClose */
1974 NULL, /* fpClusterSplIsAlive */
1975 NULL, /* fpSetPrinterDataEx */
1976 NULL, /* fpGetPrinterDataEx */
1977 NULL, /* fpEnumPrinterDataEx */
1978 NULL, /* fpEnumPrinterKey */
1979 NULL, /* fpDeletePrinterDataEx */
1980 NULL, /* fpDeletePrinterKey */
1981 NULL, /* fpSeekPrinter */
1982 NULL, /* fpDeletePrinterDriverEx */
1983 NULL, /* fpAddPerMachineConnection */
1984 NULL, /* fpDeletePerMachineConnection */
1985 NULL, /* fpEnumPerMachineConnections */
1986 fpXcvData,
1987 fpAddPrinterDriverEx,
1988 NULL, /* fpSplReadPrinter */
1989 NULL, /* fpDriverUnloadComplete */
1990 NULL, /* fpGetSpoolFileInfo */
1991 NULL, /* fpCommitSpoolData */
1992 NULL, /* fpCloseSpoolFileHandle */
1993 NULL, /* fpFlushPrinter */
1994 NULL, /* fpSendRecvBidiData */
1995 NULL /* fpAddDriverCatalog */
1997 pprovider = &backend;
2001 /*****************************************************
2002 * InitializePrintProvidor (localspl.@)
2004 * Initialize the Printprovider
2006 * PARAMS
2007 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2008 * cbPrintProvidor [I] Size of Buffer in Bytes
2009 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2011 * RETURNS
2012 * Success: TRUE and pPrintProvidor filled
2013 * Failure: FALSE
2015 * NOTES
2016 * The RegistryPath should be:
2017 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2018 * but this Parameter is ignored in "localspl.dll".
2022 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2023 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2026 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2027 memcpy(pPrintProvidor, pprovider,
2028 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2030 return TRUE;