localspl: Fix type of a WCHAR buffer.
[wine/multimedia.git] / dlls / localspl / provider.c
blob2bf9414ad3d358ffda3d69227e1b0ab48a890842
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 registered 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 /* skip monitorui dlls */
363 if (pm->monitor) monitor_unload(pm);
365 LeaveCriticalSection(&monitor_handles_cs);
368 /******************************************************************
369 * monitor_load [internal]
371 * load a printmonitor, get the dllname from the registry, when needed
372 * initialize the monitor and dump found function-pointers
374 * On failure, SetLastError() is called and NULL is returned
377 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
379 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
380 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
381 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
382 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
383 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
385 monitor_t * pm = NULL;
386 monitor_t * cursor;
387 LPWSTR regroot = NULL;
388 LPWSTR driver = dllname;
390 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
391 /* Is the Monitor already loaded? */
392 EnterCriticalSection(&monitor_handles_cs);
394 if (name) {
395 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
397 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
398 pm = cursor;
399 break;
404 if (pm == NULL) {
405 pm = heap_alloc_zero(sizeof(monitor_t));
406 if (pm == NULL) goto cleanup;
407 list_add_tail(&monitor_handles, &pm->entry);
409 pm->refcount++;
411 if (pm->name == NULL) {
412 /* Load the monitor */
413 LPMONITOREX pmonitorEx;
414 DWORD len;
416 if (name) {
417 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
418 regroot = heap_alloc(len * sizeof(WCHAR));
421 if (regroot) {
422 lstrcpyW(regroot, monitorsW);
423 lstrcatW(regroot, name);
424 /* Get the Driver from the Registry */
425 if (driver == NULL) {
426 HKEY hroot;
427 DWORD namesize;
428 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
429 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
430 &namesize) == ERROR_SUCCESS) {
431 driver = heap_alloc(namesize);
432 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
434 RegCloseKey(hroot);
439 pm->name = strdupW(name);
440 pm->dllname = strdupW(driver);
442 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
443 monitor_unload(pm);
444 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
445 pm = NULL;
446 goto cleanup;
449 pm->hdll = LoadLibraryW(driver);
450 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
452 if (pm->hdll == NULL) {
453 monitor_unload(pm);
454 SetLastError(ERROR_MOD_NOT_FOUND);
455 pm = NULL;
456 goto cleanup;
459 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
460 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
461 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
462 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
463 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
466 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
467 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
468 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
469 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
470 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
472 if (pInitializePrintMonitorUI != NULL) {
473 pm->monitorUI = pInitializePrintMonitorUI();
474 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
475 if (pm->monitorUI) {
476 TRACE("0x%08x: dwMonitorSize (%d)\n",
477 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
482 if (pInitializePrintMonitor && regroot) {
483 pmonitorEx = pInitializePrintMonitor(regroot);
484 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
485 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
487 if (pmonitorEx) {
488 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
489 pm->monitor = &(pmonitorEx->Monitor);
493 if (pm->monitor) {
494 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
498 if (!pm->monitor && regroot) {
499 if (pInitializePrintMonitor2 != NULL) {
500 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
502 if (pInitializeMonitorEx != NULL) {
503 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
505 if (pInitializeMonitor != NULL) {
506 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
509 if (!pm->monitor && !pm->monitorUI) {
510 monitor_unload(pm);
511 SetLastError(ERROR_PROC_NOT_FOUND);
512 pm = NULL;
515 cleanup:
516 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
517 pm->refcount++;
518 pm_localport = pm;
520 LeaveCriticalSection(&monitor_handles_cs);
521 if (driver != dllname) heap_free(driver);
522 heap_free(regroot);
523 TRACE("=> %p\n", pm);
524 return pm;
527 /******************************************************************
528 * monitor_loadall [internal]
530 * Load all registered monitors
533 static DWORD monitor_loadall(void)
535 monitor_t * pm;
536 DWORD registered = 0;
537 DWORD loaded = 0;
538 HKEY hmonitors;
539 WCHAR buffer[MAX_PATH];
540 DWORD id = 0;
542 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
543 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
544 NULL, NULL, NULL, NULL, NULL);
546 TRACE("%d monitors registered\n", registered);
548 while (id < registered) {
549 buffer[0] = '\0';
550 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
551 pm = monitor_load(buffer, NULL);
552 if (pm) loaded++;
553 id++;
555 RegCloseKey(hmonitors);
557 TRACE("%d monitors loaded\n", loaded);
558 return loaded;
561 /******************************************************************
562 * monitor_loadui [internal]
564 * load the userinterface-dll for a given portmonitor
566 * On failure, NULL is returned
568 static monitor_t * monitor_loadui(monitor_t * pm)
570 monitor_t * pui = NULL;
571 WCHAR buffer[MAX_PATH];
572 HANDLE hXcv;
573 DWORD len;
574 DWORD res;
576 if (pm == NULL) return NULL;
577 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
579 /* Try the Portmonitor first; works for many monitors */
580 if (pm->monitorUI) {
581 EnterCriticalSection(&monitor_handles_cs);
582 pm->refcount++;
583 LeaveCriticalSection(&monitor_handles_cs);
584 return pm;
587 /* query the userinterface-dllname from the Portmonitor */
588 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
589 /* building (",XcvMonitor %s",pm->name) not needed yet */
590 res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
591 TRACE("got %u with %p\n", res, hXcv);
592 if (res) {
593 res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
594 TRACE("got %u with %s\n", res, debugstr_w(buffer));
595 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
596 pm->monitor->pfnXcvClosePort(hXcv);
599 return pui;
602 /******************************************************************
603 * monitor_load_by_port [internal]
605 * load a printmonitor for a given port
607 * On failure, NULL is returned
610 static monitor_t * monitor_load_by_port(LPCWSTR portname)
612 HKEY hroot;
613 HKEY hport;
614 LPWSTR buffer;
615 monitor_t * pm = NULL;
616 DWORD registered = 0;
617 DWORD id = 0;
618 DWORD len;
620 TRACE("(%s)\n", debugstr_w(portname));
622 /* Try the Local Monitor first */
623 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
624 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
625 /* found the portname */
626 RegCloseKey(hroot);
627 return monitor_load(localportW, NULL);
629 RegCloseKey(hroot);
632 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
633 buffer = heap_alloc(len * sizeof(WCHAR));
634 if (buffer == NULL) return NULL;
636 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
637 EnterCriticalSection(&monitor_handles_cs);
638 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
640 while ((pm == NULL) && (id < registered)) {
641 buffer[0] = '\0';
642 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
643 TRACE("testing %s\n", debugstr_w(buffer));
644 len = lstrlenW(buffer);
645 lstrcatW(buffer, bs_ports_bsW);
646 lstrcatW(buffer, portname);
647 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
648 RegCloseKey(hport);
649 buffer[len] = '\0'; /* use only the Monitor-Name */
650 pm = monitor_load(buffer, NULL);
652 id++;
654 LeaveCriticalSection(&monitor_handles_cs);
655 RegCloseKey(hroot);
657 heap_free(buffer);
658 return pm;
661 /******************************************************************
662 * Return the number of bytes for an multi_sz string.
663 * The result includes all \0s
664 * (specifically the extra \0, that is needed as multi_sz terminator).
666 static int multi_sz_lenW(const WCHAR *str)
668 const WCHAR *ptr = str;
669 if (!str) return 0;
672 ptr += lstrlenW(ptr) + 1;
673 } while (*ptr);
675 return (ptr - str + 1) * sizeof(WCHAR);
678 /******************************************************************
679 * validate_envW [internal]
681 * validate the user-supplied printing-environment
683 * PARAMS
684 * env [I] PTR to Environment-String or NULL
686 * RETURNS
687 * Success: PTR to printenv_t
688 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
690 * NOTES
691 * An empty string is handled the same way as NULL.
695 static const printenv_t * validate_envW(LPCWSTR env)
697 const printenv_t *result = NULL;
698 unsigned int i;
700 TRACE("(%s)\n", debugstr_w(env));
701 if (env && env[0])
703 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
705 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
707 result = all_printenv[i];
708 break;
711 if (result == NULL) {
712 FIXME("unsupported Environment: %s\n", debugstr_w(env));
713 SetLastError(ERROR_INVALID_ENVIRONMENT);
715 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
717 else
719 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
722 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
723 return result;
726 /*****************************************************************************
727 * enumerate the local monitors (INTERNAL)
729 * returns the needed size (in bytes) for pMonitors
730 * and *lpreturned is set to number of entries returned in pMonitors
732 * Language-Monitors are also installed in the same Registry-Location but
733 * they are filtered in Windows (not returned by EnumMonitors).
734 * We do no filtering to simplify our Code.
737 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
739 HKEY hroot = NULL;
740 HKEY hentry = NULL;
741 LPWSTR ptr;
742 LPMONITOR_INFO_2W mi;
743 WCHAR buffer[MAX_PATH];
744 WCHAR dllname[MAX_PATH];
745 DWORD dllsize;
746 DWORD len;
747 DWORD index = 0;
748 DWORD needed = 0;
749 DWORD numentries;
750 DWORD entrysize;
752 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
754 numentries = *lpreturned; /* this is 0, when we scan the registry */
755 len = entrysize * numentries;
756 ptr = (LPWSTR) &pMonitors[len];
758 numentries = 0;
759 len = sizeof(buffer)/sizeof(buffer[0]);
760 buffer[0] = '\0';
762 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
763 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
764 /* Scan all Monitor-Registry-Keys */
765 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
766 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
767 dllsize = sizeof(dllname);
768 dllname[0] = '\0';
770 /* The Monitor must have a Driver-DLL */
771 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
772 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
773 /* We found a valid DLL for this Monitor. */
774 TRACE("using Driver: %s\n", debugstr_w(dllname));
776 RegCloseKey(hentry);
779 /* Windows returns only Port-Monitors here, but to simplify our code,
780 we do no filtering for Language-Monitors */
781 if (dllname[0]) {
782 numentries++;
783 needed += entrysize;
784 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
785 if (level > 1) {
786 /* we install and return only monitors for "Windows NT x86" */
787 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
788 needed += dllsize;
791 /* required size is calculated. Now fill the user-buffer */
792 if (pMonitors && (cbBuf >= needed)){
793 mi = (LPMONITOR_INFO_2W) pMonitors;
794 pMonitors += entrysize;
796 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
797 mi->pName = ptr;
798 lstrcpyW(ptr, buffer); /* Name of the Monitor */
799 ptr += (len+1); /* len is lstrlenW(monitorname) */
800 if (level > 1) {
801 mi->pEnvironment = ptr;
802 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
803 ptr += (lstrlenW(x86_envnameW)+1);
805 mi->pDLLName = ptr;
806 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
807 ptr += (dllsize / sizeof(WCHAR));
811 index++;
812 len = sizeof(buffer)/sizeof(buffer[0]);
813 buffer[0] = '\0';
815 RegCloseKey(hroot);
817 *lpreturned = numentries;
818 TRACE("need %d byte for %d entries\n", needed, numentries);
819 return needed;
822 /******************************************************************
823 * enumerate the local Ports from all loaded monitors (internal)
825 * returns the needed size (in bytes) for pPorts
826 * and *lpreturned is set to number of entries returned in pPorts
829 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
831 monitor_t * pm;
832 LPWSTR ptr;
833 LPPORT_INFO_2W cache;
834 LPPORT_INFO_2W out;
835 LPBYTE pi_buffer = NULL;
836 DWORD pi_allocated = 0;
837 DWORD pi_needed;
838 DWORD pi_index;
839 DWORD pi_returned;
840 DWORD res;
841 DWORD outindex = 0;
842 DWORD needed;
843 DWORD numentries;
844 DWORD entrysize;
847 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
848 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
850 numentries = *lpreturned; /* this is 0, when we scan the registry */
851 needed = entrysize * numentries;
852 ptr = (LPWSTR) &pPorts[needed];
854 numentries = 0;
855 needed = 0;
857 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
859 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
860 pi_needed = 0;
861 pi_returned = 0;
862 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
863 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
864 /* Do not use heap_realloc (we do not need the old data in the buffer) */
865 heap_free(pi_buffer);
866 pi_buffer = heap_alloc(pi_needed);
867 pi_allocated = (pi_buffer) ? pi_needed : 0;
868 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
870 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
871 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
873 numentries += pi_returned;
874 needed += pi_needed;
876 /* fill the output-buffer (pPorts), if we have one */
877 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
878 pi_index = 0;
879 while (pi_returned > pi_index) {
880 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
881 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
882 out->pPortName = ptr;
883 lstrcpyW(ptr, cache->pPortName);
884 ptr += (lstrlenW(ptr)+1);
885 if (level > 1) {
886 out->pMonitorName = ptr;
887 lstrcpyW(ptr, cache->pMonitorName);
888 ptr += (lstrlenW(ptr)+1);
890 out->pDescription = ptr;
891 lstrcpyW(ptr, cache->pDescription);
892 ptr += (lstrlenW(ptr)+1);
893 out->fPortType = cache->fPortType;
894 out->Reserved = cache->Reserved;
896 pi_index++;
897 outindex++;
902 /* the temporary portinfo-buffer is no longer needed */
903 heap_free(pi_buffer);
905 *lpreturned = numentries;
906 TRACE("need %d byte for %d entries\n", needed, numentries);
907 return needed;
911 /*****************************************************************************
912 * open_driver_reg [internal]
914 * opens the registry for the printer drivers depending on the given input
915 * variable pEnvironment
917 * RETURNS:
918 * Success: the opened hkey
919 * Failure: NULL
921 static HKEY open_driver_reg(LPCWSTR pEnvironment)
923 HKEY retval = NULL;
924 LPWSTR buffer;
925 const printenv_t * env;
927 TRACE("(%s)\n", debugstr_w(pEnvironment));
929 env = validate_envW(pEnvironment);
930 if (!env) return NULL;
932 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
933 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
935 if (buffer) {
936 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
937 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
938 HeapFree(GetProcessHeap(), 0, buffer);
940 return retval;
943 /*****************************************************************************
944 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
946 * Return the PATH for the Printer-Drivers
948 * PARAMS
949 * pName [I] Servername (NT only) or NULL (local Computer)
950 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
951 * Level [I] Structure-Level (must be 1)
952 * pDriverDirectory [O] PTR to Buffer that receives the Result
953 * cbBuf [I] Size of Buffer at pDriverDirectory
954 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
955 * required for pDriverDirectory
957 * RETURNS
958 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
959 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
960 * if cbBuf is too small
962 * Native Values returned in pDriverDirectory on Success:
963 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
964 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
965 *| win9x(Windows 4.0): "%winsysdir%"
967 * "%winsysdir%" is the Value from GetSystemDirectoryW()
970 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
971 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
973 DWORD needed;
974 const printenv_t * env;
976 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
977 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
979 if (pName != NULL && pName[0]) {
980 FIXME("server %s not supported\n", debugstr_w(pName));
981 SetLastError(ERROR_INVALID_PARAMETER);
982 return FALSE;
985 env = validate_envW(pEnvironment);
986 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
989 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
990 needed = GetSystemDirectoryW(NULL, 0);
991 /* add the Size for the Subdirectories */
992 needed += lstrlenW(spooldriversW);
993 needed += lstrlenW(env->subdir);
994 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
996 *pcbNeeded = needed;
998 if (needed > cbBuf) {
999 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1000 return FALSE;
1003 if (pDriverDirectory == NULL) {
1004 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1005 SetLastError(ERROR_INVALID_USER_BUFFER);
1006 return FALSE;
1009 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
1010 /* add the Subdirectories */
1011 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
1012 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
1014 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
1015 return TRUE;
1018 /******************************************************************
1019 * driver_load [internal]
1021 * load a driver user interface dll
1023 * On failure, NULL is returned
1027 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1029 WCHAR fullname[MAX_PATH];
1030 HMODULE hui;
1031 DWORD len;
1033 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1035 /* build the driverdir */
1036 len = sizeof(fullname) -
1037 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1039 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1040 (LPBYTE) fullname, len, &len)) {
1041 /* Should never Fail */
1042 SetLastError(ERROR_BUFFER_OVERFLOW);
1043 return NULL;
1046 lstrcatW(fullname, env->versionsubdir);
1047 lstrcatW(fullname, backslashW);
1048 lstrcatW(fullname, dllname);
1050 hui = LoadLibraryW(fullname);
1051 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1053 return hui;
1056 /******************************************************************
1057 * printer_free
1058 * free the data pointer of an opened printer
1060 static VOID printer_free(printer_t * printer)
1062 if (printer->hXcv)
1063 printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1065 monitor_unload(printer->pm);
1067 heap_free(printer->printername);
1068 heap_free(printer->name);
1069 heap_free(printer);
1072 /******************************************************************
1073 * printer_alloc_handle
1074 * alloc a printer handle and remember the data pointer in the printer handle table
1077 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1079 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1080 printer_t *printer = NULL;
1081 LPCWSTR printername;
1082 HKEY hkeyPrinters;
1083 HKEY hkeyPrinter;
1084 DWORD len;
1086 if (copy_servername_from_name(name, servername)) {
1087 FIXME("server %s not supported\n", debugstr_w(servername));
1088 SetLastError(ERROR_INVALID_PRINTER_NAME);
1089 return NULL;
1092 printername = get_basename_from_name(name);
1093 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1095 /* an empty printername is invalid */
1096 if (printername && (!printername[0])) {
1097 SetLastError(ERROR_INVALID_PARAMETER);
1098 return NULL;
1101 printer = heap_alloc_zero(sizeof(printer_t));
1102 if (!printer) goto end;
1104 /* clone the base name. This is NULL for the printserver */
1105 printer->printername = strdupW(printername);
1107 /* clone the full name */
1108 printer->name = strdupW(name);
1109 if (name && (!printer->name)) {
1110 printer_free(printer);
1111 printer = NULL;
1113 if (printername) {
1114 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1115 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1116 /* OpenPrinter(",XcvMonitor ", ...) detected */
1117 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1118 printer->pm = monitor_load(&printername[len], NULL);
1119 if (printer->pm == NULL) {
1120 printer_free(printer);
1121 SetLastError(ERROR_UNKNOWN_PORT);
1122 printer = NULL;
1123 goto end;
1126 else
1128 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1129 if (strncmpW( printername, XcvPortW, len) == 0) {
1130 /* OpenPrinter(",XcvPort ", ...) detected */
1131 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1132 printer->pm = monitor_load_by_port(&printername[len]);
1133 if (printer->pm == NULL) {
1134 printer_free(printer);
1135 SetLastError(ERROR_UNKNOWN_PORT);
1136 printer = NULL;
1137 goto end;
1142 if (printer->pm) {
1143 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1144 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1145 pDefault ? pDefault->DesiredAccess : 0,
1146 &printer->hXcv);
1148 if (printer->hXcv == NULL) {
1149 printer_free(printer);
1150 SetLastError(ERROR_INVALID_PARAMETER);
1151 printer = NULL;
1152 goto end;
1155 else
1157 /* Does the Printer exist? */
1158 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1159 ERR("Can't create Printers key\n");
1160 printer_free(printer);
1161 SetLastError(ERROR_INVALID_PRINTER_NAME);
1162 printer = NULL;
1163 goto end;
1165 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1166 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1167 RegCloseKey(hkeyPrinters);
1168 printer_free(printer);
1169 SetLastError(ERROR_INVALID_PRINTER_NAME);
1170 printer = NULL;
1171 goto end;
1173 RegCloseKey(hkeyPrinter);
1174 RegCloseKey(hkeyPrinters);
1177 else
1179 TRACE("using the local printserver\n");
1182 end:
1184 TRACE("==> %p\n", printer);
1185 return (HANDLE)printer;
1189 /******************************************************************************
1190 * myAddPrinterDriverEx [internal]
1192 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1193 * and a special mode with lazy error checking.
1196 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1198 const printenv_t *env;
1199 apd_data_t apd;
1200 DRIVER_INFO_8W di;
1201 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1202 HMODULE hui;
1203 LPWSTR ptr;
1204 HKEY hroot;
1205 HKEY hdrv;
1206 DWORD disposition;
1207 DWORD len;
1208 LONG lres;
1209 BOOL res;
1211 /* we need to set all entries in the Registry, independent from the Level of
1212 DRIVER_INFO, that the caller supplied */
1214 ZeroMemory(&di, sizeof(di));
1215 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1216 memcpy(&di, pDriverInfo, di_sizeof[level]);
1219 /* dump the most used infos */
1220 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1221 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1222 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1223 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1224 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1225 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1226 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1227 /* dump only the first of the additional Files */
1228 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1231 /* check environment */
1232 env = validate_envW(di.pEnvironment);
1233 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1235 /* fill the copy-data / get the driverdir */
1236 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1237 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1238 (LPBYTE) apd.src, len, &len)) {
1239 /* Should never Fail */
1240 return FALSE;
1242 memcpy(apd.dst, apd.src, len);
1243 lstrcatW(apd.src, backslashW);
1244 apd.srclen = lstrlenW(apd.src);
1245 lstrcatW(apd.dst, env->versionsubdir);
1246 lstrcatW(apd.dst, backslashW);
1247 apd.dstlen = lstrlenW(apd.dst);
1248 apd.copyflags = dwFileCopyFlags;
1249 apd.lazy = lazy;
1250 CreateDirectoryW(apd.src, NULL);
1251 CreateDirectoryW(apd.dst, NULL);
1253 hroot = open_driver_reg(env->envname);
1254 if (!hroot) {
1255 ERR("Can't create Drivers key\n");
1256 return FALSE;
1259 /* Fill the Registry for the Driver */
1260 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1261 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1262 &hdrv, &disposition)) != ERROR_SUCCESS) {
1264 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1265 RegCloseKey(hroot);
1266 SetLastError(lres);
1267 return FALSE;
1269 RegCloseKey(hroot);
1271 if (disposition == REG_OPENED_EXISTING_KEY) {
1272 TRACE("driver %s already installed\n", debugstr_w(di.pName));
1273 RegCloseKey(hdrv);
1274 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
1275 return FALSE;
1278 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1279 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (LPBYTE) &env->driverversion,
1280 sizeof(DWORD));
1282 RegSetValueExW(hdrv, driverW, 0, REG_SZ, (LPBYTE) di.pDriverPath,
1283 (lstrlenW(di.pDriverPath)+1)* sizeof(WCHAR));
1284 apd_copyfile(di.pDriverPath, &apd);
1286 RegSetValueExW(hdrv, data_fileW, 0, REG_SZ, (LPBYTE) di.pDataFile,
1287 (lstrlenW(di.pDataFile)+1)* sizeof(WCHAR));
1288 apd_copyfile(di.pDataFile, &apd);
1290 RegSetValueExW(hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE) di.pConfigFile,
1291 (lstrlenW(di.pConfigFile)+1)* sizeof(WCHAR));
1292 apd_copyfile(di.pConfigFile, &apd);
1294 /* settings for level 3 */
1295 if (di.pHelpFile)
1296 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE) di.pHelpFile,
1297 (lstrlenW(di.pHelpFile)+1)* sizeof(WCHAR));
1298 else
1299 RegSetValueExW(hdrv, help_fileW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1300 apd_copyfile(di.pHelpFile, &apd);
1303 ptr = di.pDependentFiles;
1304 if (ptr)
1305 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE) di.pDependentFiles,
1306 multi_sz_lenW(di.pDependentFiles));
1307 else
1308 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1309 while ((ptr != NULL) && (ptr[0])) {
1310 if (apd_copyfile(ptr, &apd)) {
1311 ptr += lstrlenW(ptr) + 1;
1313 else
1315 WARN("Failed to copy %s\n", debugstr_w(ptr));
1316 ptr = NULL;
1319 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1320 if (di.pMonitorName)
1321 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1322 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1323 else
1324 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1326 if (di.pDefaultDataType)
1327 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1328 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1329 else
1330 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1332 /* settings for level 4 */
1333 if (di.pszzPreviousNames)
1334 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1335 multi_sz_lenW(di.pszzPreviousNames));
1336 else
1337 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE)emptyW, sizeof(emptyW));
1339 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1341 RegCloseKey(hdrv);
1342 hui = driver_load(env, di.pConfigFile);
1343 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1344 if (hui && pDrvDriverEvent) {
1346 /* Support for DrvDriverEvent is optional */
1347 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1348 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1349 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1350 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1352 FreeLibrary(hui);
1354 TRACE("=> TRUE with %u\n", GetLastError());
1355 return TRUE;
1359 /******************************************************************************
1360 * fpAddMonitor [exported through PRINTPROVIDOR]
1362 * Install a Printmonitor
1364 * PARAMS
1365 * pName [I] Servername or NULL (local Computer)
1366 * Level [I] Structure-Level (Must be 2)
1367 * pMonitors [I] PTR to MONITOR_INFO_2
1369 * RETURNS
1370 * Success: TRUE
1371 * Failure: FALSE
1373 * NOTES
1374 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1377 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1379 monitor_t * pm = NULL;
1380 LPMONITOR_INFO_2W mi2w;
1381 HKEY hroot = NULL;
1382 HKEY hentry = NULL;
1383 DWORD disposition;
1384 BOOL res = FALSE;
1386 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1387 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1388 debugstr_w(mi2w ? mi2w->pName : NULL),
1389 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1390 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1392 if (copy_servername_from_name(pName, NULL)) {
1393 FIXME("server %s not supported\n", debugstr_w(pName));
1394 SetLastError(ERROR_ACCESS_DENIED);
1395 return FALSE;
1398 if (!mi2w->pName || (! mi2w->pName[0])) {
1399 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1400 SetLastError(ERROR_INVALID_PARAMETER);
1401 return FALSE;
1403 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1404 WARN("Environment %s requested (we support only %s)\n",
1405 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1406 SetLastError(ERROR_INVALID_ENVIRONMENT);
1407 return FALSE;
1410 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1411 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1412 SetLastError(ERROR_INVALID_PARAMETER);
1413 return FALSE;
1416 /* Load and initialize the monitor. SetLastError() is called on failure */
1417 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1418 return FALSE;
1420 monitor_unload(pm);
1422 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1423 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1424 return FALSE;
1427 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1428 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1429 &disposition) == ERROR_SUCCESS) {
1431 /* Some installers set options for the port before calling AddMonitor.
1432 We query the "Driver" entry to verify that the monitor is installed,
1433 before we return an error.
1434 When a user installs two print monitors at the same time with the
1435 same name, a race condition is possible but silently ignored. */
1437 DWORD namesize = 0;
1439 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1440 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1441 &namesize) == ERROR_SUCCESS)) {
1442 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1443 /* 9x use ERROR_ALREADY_EXISTS */
1444 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1446 else
1448 INT len;
1449 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1450 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1451 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1453 RegCloseKey(hentry);
1456 RegCloseKey(hroot);
1457 return (res);
1460 /******************************************************************************
1461 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1463 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1465 * PARAMS
1466 * pName [I] Servername or NULL (local Computer)
1467 * level [I] Level for the supplied DRIVER_INFO_*W struct
1468 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1469 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1471 * RESULTS
1472 * Success: TRUE
1473 * Failure: FALSE
1476 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1478 LONG lres;
1480 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1481 lres = copy_servername_from_name(pName, NULL);
1482 if (lres) {
1483 FIXME("server %s not supported\n", debugstr_w(pName));
1484 SetLastError(ERROR_ACCESS_DENIED);
1485 return FALSE;
1488 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1489 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1492 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1495 /******************************************************************************
1496 * fpClosePrinter [exported through PRINTPROVIDOR]
1498 * Close a printer handle and free associated resources
1500 * PARAMS
1501 * hPrinter [I] Printerhandle to close
1503 * RESULTS
1504 * Success: TRUE
1505 * Failure: FALSE
1508 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1510 printer_t *printer = (printer_t *) hPrinter;
1512 TRACE("(%p)\n", hPrinter);
1514 if (printer) {
1515 printer_free(printer);
1516 return TRUE;
1518 return FALSE;
1521 /******************************************************************************
1522 * fpConfigurePort [exported through PRINTPROVIDOR]
1524 * Display the Configuration-Dialog for a specific Port
1526 * PARAMS
1527 * pName [I] Servername or NULL (local Computer)
1528 * hWnd [I] Handle to parent Window for the Dialog-Box
1529 * pPortName [I] Name of the Port, that should be configured
1531 * RETURNS
1532 * Success: TRUE
1533 * Failure: FALSE
1536 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1538 monitor_t * pm;
1539 monitor_t * pui;
1540 LONG lres;
1541 DWORD res;
1543 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1545 lres = copy_servername_from_name(pName, NULL);
1546 if (lres) {
1547 FIXME("server %s not supported\n", debugstr_w(pName));
1548 SetLastError(ERROR_INVALID_NAME);
1549 return FALSE;
1552 /* an empty Portname is Invalid, but can popup a Dialog */
1553 if (!pPortName[0]) {
1554 SetLastError(ERROR_NOT_SUPPORTED);
1555 return FALSE;
1558 pm = monitor_load_by_port(pPortName);
1559 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
1560 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1561 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1562 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
1563 TRACE("got %d with %u\n", res, GetLastError());
1565 else
1567 pui = monitor_loadui(pm);
1568 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
1569 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1570 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1571 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
1572 TRACE("got %d with %u\n", res, GetLastError());
1574 else
1576 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1577 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1578 pui, debugstr_w(pui ? pui->dllname : NULL));
1580 SetLastError(ERROR_NOT_SUPPORTED);
1581 res = FALSE;
1583 monitor_unload(pui);
1585 monitor_unload(pm);
1587 TRACE("returning %d with %u\n", res, GetLastError());
1588 return res;
1591 /******************************************************************
1592 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1594 * Delete a specific Printmonitor from a Printing-Environment
1596 * PARAMS
1597 * pName [I] Servername or NULL (local Computer)
1598 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1599 * pMonitorName [I] Name of the Monitor, that should be deleted
1601 * RETURNS
1602 * Success: TRUE
1603 * Failure: FALSE
1605 * NOTES
1606 * pEnvironment is ignored in Windows for the local Computer.
1610 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1612 HKEY hroot = NULL;
1613 LONG lres;
1615 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1616 debugstr_w(pMonitorName));
1618 lres = copy_servername_from_name(pName, NULL);
1619 if (lres) {
1620 FIXME("server %s not supported\n", debugstr_w(pName));
1621 SetLastError(ERROR_INVALID_NAME);
1622 return FALSE;
1625 /* pEnvironment is ignored in Windows for the local Computer */
1626 if (!pMonitorName || !pMonitorName[0]) {
1627 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1628 SetLastError(ERROR_INVALID_PARAMETER);
1629 return FALSE;
1632 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1633 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1634 return FALSE;
1637 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1638 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1639 RegCloseKey(hroot);
1640 return TRUE;
1643 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1644 RegCloseKey(hroot);
1646 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1647 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1648 return FALSE;
1651 /*****************************************************************************
1652 * fpDeletePort [exported through PRINTPROVIDOR]
1654 * Delete a specific Port
1656 * PARAMS
1657 * pName [I] Servername or NULL (local Computer)
1658 * hWnd [I] Handle to parent Window for the Dialog-Box
1659 * pPortName [I] Name of the Port, that should be deleted
1661 * RETURNS
1662 * Success: TRUE
1663 * Failure: FALSE
1666 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1668 monitor_t * pm;
1669 monitor_t * pui;
1670 LONG lres;
1671 DWORD res;
1673 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1675 lres = copy_servername_from_name(pName, NULL);
1676 if (lres) {
1677 FIXME("server %s not supported\n", debugstr_w(pName));
1678 SetLastError(ERROR_INVALID_NAME);
1679 return FALSE;
1682 /* an empty Portname is Invalid */
1683 if (!pPortName[0]) {
1684 SetLastError(ERROR_NOT_SUPPORTED);
1685 return FALSE;
1688 pm = monitor_load_by_port(pPortName);
1689 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
1690 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1691 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1692 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
1693 TRACE("got %d with %u\n", res, GetLastError());
1695 else
1697 pui = monitor_loadui(pm);
1698 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
1699 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1700 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1701 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
1702 TRACE("got %d with %u\n", res, GetLastError());
1704 else
1706 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1707 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1708 pui, debugstr_w(pui ? pui->dllname : NULL));
1710 SetLastError(ERROR_NOT_SUPPORTED);
1711 res = FALSE;
1713 monitor_unload(pui);
1715 monitor_unload(pm);
1717 TRACE("returning %d with %u\n", res, GetLastError());
1718 return res;
1721 /*****************************************************************************
1722 * fpEnumMonitors [exported through PRINTPROVIDOR]
1724 * Enumerate available Port-Monitors
1726 * PARAMS
1727 * pName [I] Servername or NULL (local Computer)
1728 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1729 * pMonitors [O] PTR to Buffer that receives the Result
1730 * cbBuf [I] Size of Buffer at pMonitors
1731 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1732 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1734 * RETURNS
1735 * Success: TRUE
1736 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1738 * NOTES
1739 * Windows reads the Registry once and cache the Results.
1742 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1743 LPDWORD pcbNeeded, LPDWORD pcReturned)
1745 DWORD numentries = 0;
1746 DWORD needed = 0;
1747 LONG lres;
1748 BOOL res = FALSE;
1750 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1751 cbBuf, pcbNeeded, pcReturned);
1753 lres = copy_servername_from_name(pName, NULL);
1754 if (lres) {
1755 FIXME("server %s not supported\n", debugstr_w(pName));
1756 SetLastError(ERROR_INVALID_NAME);
1757 goto em_cleanup;
1760 if (!Level || (Level > 2)) {
1761 WARN("level (%d) is ignored in win9x\n", Level);
1762 SetLastError(ERROR_INVALID_LEVEL);
1763 return FALSE;
1766 /* Scan all Monitor-Keys */
1767 numentries = 0;
1768 needed = get_local_monitors(Level, NULL, 0, &numentries);
1770 /* we calculated the needed buffersize. now do more error-checks */
1771 if (cbBuf < needed) {
1772 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1773 goto em_cleanup;
1776 /* fill the Buffer with the Monitor-Keys */
1777 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1778 res = TRUE;
1780 em_cleanup:
1781 if (pcbNeeded) *pcbNeeded = needed;
1782 if (pcReturned) *pcReturned = numentries;
1784 TRACE("returning %d with %d (%d byte for %d entries)\n",
1785 res, GetLastError(), needed, numentries);
1787 return (res);
1790 /******************************************************************************
1791 * fpEnumPorts [exported through PRINTPROVIDOR]
1793 * Enumerate available Ports
1795 * PARAMS
1796 * pName [I] Servername or NULL (local Computer)
1797 * Level [I] Structure-Level (1 or 2)
1798 * pPorts [O] PTR to Buffer that receives the Result
1799 * cbBuf [I] Size of Buffer at pPorts
1800 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1801 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1803 * RETURNS
1804 * Success: TRUE
1805 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1808 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1809 LPDWORD pcbNeeded, LPDWORD pcReturned)
1811 DWORD needed = 0;
1812 DWORD numentries = 0;
1813 LONG lres;
1814 BOOL res = FALSE;
1816 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1817 cbBuf, pcbNeeded, pcReturned);
1819 lres = copy_servername_from_name(pName, NULL);
1820 if (lres) {
1821 FIXME("server %s not supported\n", debugstr_w(pName));
1822 SetLastError(ERROR_INVALID_NAME);
1823 goto emP_cleanup;
1826 if (!Level || (Level > 2)) {
1827 SetLastError(ERROR_INVALID_LEVEL);
1828 goto emP_cleanup;
1831 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1832 SetLastError(RPC_X_NULL_REF_POINTER);
1833 goto emP_cleanup;
1836 EnterCriticalSection(&monitor_handles_cs);
1837 monitor_loadall();
1839 /* Scan all local Ports */
1840 numentries = 0;
1841 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1843 /* we calculated the needed buffersize. now do the error-checks */
1844 if (cbBuf < needed) {
1845 monitor_unloadall();
1846 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1847 goto emP_cleanup_cs;
1849 else if (!pPorts || !pcReturned) {
1850 monitor_unloadall();
1851 SetLastError(RPC_X_NULL_REF_POINTER);
1852 goto emP_cleanup_cs;
1855 /* Fill the Buffer */
1856 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1857 res = TRUE;
1858 monitor_unloadall();
1860 emP_cleanup_cs:
1861 LeaveCriticalSection(&monitor_handles_cs);
1863 emP_cleanup:
1864 if (pcbNeeded) *pcbNeeded = needed;
1865 if (pcReturned) *pcReturned = (res) ? numentries : 0;
1867 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1868 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
1870 return (res);
1873 /******************************************************************************
1874 * fpOpenPrinter [exported through PRINTPROVIDOR]
1876 * Open a Printer / Printserver or a Printer-Object
1878 * PARAMS
1879 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
1880 * pPrinter [O] The resulting Handle is stored here
1881 * pDefaults [I] PTR to Default Printer Settings or NULL
1883 * RETURNS
1884 * Success: TRUE
1885 * Failure: FALSE
1887 * NOTES
1888 * lpPrinterName is one of:
1889 *| Printserver (NT only): "Servername" or NULL for the local Printserver
1890 *| Printer: "PrinterName"
1891 *| Printer-Object: "PrinterName,Job xxx"
1892 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
1893 *| XcvPort: "Servername,XcvPort PortName"
1897 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
1898 LPPRINTER_DEFAULTSW pDefaults)
1901 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
1903 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
1905 return (*pPrinter != 0);
1908 /******************************************************************************
1909 * fpXcvData [exported through PRINTPROVIDOR]
1911 * Execute commands in the Printmonitor DLL
1913 * PARAMS
1914 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
1915 * pszDataName [i] Name of the command to execute
1916 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
1917 * cbInputData [i] Size in Bytes of Buffer at pInputData
1918 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
1919 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
1920 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
1921 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
1923 * RETURNS
1924 * Success: TRUE
1925 * Failure: FALSE
1927 * NOTES
1928 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
1929 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
1931 * Minimal List of commands, that a Printmonitor DLL should support:
1933 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
1934 *| "AddPort" : Add a Port
1935 *| "DeletePort": Delete a Port
1937 * Many Printmonitors support additional commands. Examples for localspl.dll:
1938 * "GetDefaultCommConfig", "SetDefaultCommConfig",
1939 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
1942 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
1943 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
1944 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
1946 printer_t *printer = (printer_t * ) hXcv;
1948 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
1949 pInputData, cbInputData, pOutputData,
1950 cbOutputData, pcbOutputNeeded, pdwStatus);
1952 if (!printer || (!printer->hXcv)) {
1953 SetLastError(ERROR_INVALID_HANDLE);
1954 return FALSE;
1957 if (!pcbOutputNeeded) {
1958 SetLastError(ERROR_INVALID_PARAMETER);
1959 return FALSE;
1962 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
1963 SetLastError(RPC_X_NULL_REF_POINTER);
1964 return FALSE;
1967 *pcbOutputNeeded = 0;
1969 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
1970 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
1972 return TRUE;
1975 /*****************************************************
1976 * setup_provider [internal]
1978 void setup_provider(void)
1980 static const PRINTPROVIDOR backend = {
1981 fpOpenPrinter,
1982 NULL, /* fpSetJob */
1983 NULL, /* fpGetJob */
1984 NULL, /* fpEnumJobs */
1985 NULL, /* fpAddPrinter */
1986 NULL, /* fpDeletePrinter */
1987 NULL, /* fpSetPrinter */
1988 NULL, /* fpGetPrinter */
1989 NULL, /* fpEnumPrinters */
1990 NULL, /* fpAddPrinterDriver */
1991 NULL, /* fpEnumPrinterDrivers */
1992 NULL, /* fpGetPrinterDriver */
1993 fpGetPrinterDriverDirectory,
1994 NULL, /* fpDeletePrinterDriver */
1995 NULL, /* fpAddPrintProcessor */
1996 NULL, /* fpEnumPrintProcessors */
1997 NULL, /* fpGetPrintProcessorDirectory */
1998 NULL, /* fpDeletePrintProcessor */
1999 NULL, /* fpEnumPrintProcessorDatatypes */
2000 NULL, /* fpStartDocPrinter */
2001 NULL, /* fpStartPagePrinter */
2002 NULL, /* fpWritePrinter */
2003 NULL, /* fpEndPagePrinter */
2004 NULL, /* fpAbortPrinter */
2005 NULL, /* fpReadPrinter */
2006 NULL, /* fpEndDocPrinter */
2007 NULL, /* fpAddJob */
2008 NULL, /* fpScheduleJob */
2009 NULL, /* fpGetPrinterData */
2010 NULL, /* fpSetPrinterData */
2011 NULL, /* fpWaitForPrinterChange */
2012 fpClosePrinter,
2013 NULL, /* fpAddForm */
2014 NULL, /* fpDeleteForm */
2015 NULL, /* fpGetForm */
2016 NULL, /* fpSetForm */
2017 NULL, /* fpEnumForms */
2018 fpEnumMonitors,
2019 fpEnumPorts,
2020 NULL, /* fpAddPort */
2021 fpConfigurePort,
2022 fpDeletePort,
2023 NULL, /* fpCreatePrinterIC */
2024 NULL, /* fpPlayGdiScriptOnPrinterIC */
2025 NULL, /* fpDeletePrinterIC */
2026 NULL, /* fpAddPrinterConnection */
2027 NULL, /* fpDeletePrinterConnection */
2028 NULL, /* fpPrinterMessageBox */
2029 fpAddMonitor,
2030 fpDeleteMonitor,
2031 NULL, /* fpResetPrinter */
2032 NULL, /* fpGetPrinterDriverEx */
2033 NULL, /* fpFindFirstPrinterChangeNotification */
2034 NULL, /* fpFindClosePrinterChangeNotification */
2035 NULL, /* fpAddPortEx */
2036 NULL, /* fpShutDown */
2037 NULL, /* fpRefreshPrinterChangeNotification */
2038 NULL, /* fpOpenPrinterEx */
2039 NULL, /* fpAddPrinterEx */
2040 NULL, /* fpSetPort */
2041 NULL, /* fpEnumPrinterData */
2042 NULL, /* fpDeletePrinterData */
2043 NULL, /* fpClusterSplOpen */
2044 NULL, /* fpClusterSplClose */
2045 NULL, /* fpClusterSplIsAlive */
2046 NULL, /* fpSetPrinterDataEx */
2047 NULL, /* fpGetPrinterDataEx */
2048 NULL, /* fpEnumPrinterDataEx */
2049 NULL, /* fpEnumPrinterKey */
2050 NULL, /* fpDeletePrinterDataEx */
2051 NULL, /* fpDeletePrinterKey */
2052 NULL, /* fpSeekPrinter */
2053 NULL, /* fpDeletePrinterDriverEx */
2054 NULL, /* fpAddPerMachineConnection */
2055 NULL, /* fpDeletePerMachineConnection */
2056 NULL, /* fpEnumPerMachineConnections */
2057 fpXcvData,
2058 fpAddPrinterDriverEx,
2059 NULL, /* fpSplReadPrinter */
2060 NULL, /* fpDriverUnloadComplete */
2061 NULL, /* fpGetSpoolFileInfo */
2062 NULL, /* fpCommitSpoolData */
2063 NULL, /* fpCloseSpoolFileHandle */
2064 NULL, /* fpFlushPrinter */
2065 NULL, /* fpSendRecvBidiData */
2066 NULL /* fpAddDriverCatalog */
2068 pprovider = &backend;
2072 /*****************************************************
2073 * InitializePrintProvidor (localspl.@)
2075 * Initialize the Printprovider
2077 * PARAMS
2078 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2079 * cbPrintProvidor [I] Size of Buffer in Bytes
2080 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2082 * RETURNS
2083 * Success: TRUE and pPrintProvidor filled
2084 * Failure: FALSE
2086 * NOTES
2087 * The RegistryPath should be:
2088 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2089 * but this Parameter is ignored in "localspl.dll".
2093 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2094 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2097 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2098 memcpy(pPrintProvidor, pprovider,
2099 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2101 return TRUE;