comctl32/datetime: Use locale data to compute field widths for day and month.
[wine/hacks.git] / dlls / localspl / provider.c
blob790a1efea3f12f64735827504be290e06dc1b209
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 * fpAddPort [exported through PRINTPROVIDOR]
1463 * Add a Port for a specific Monitor
1465 * PARAMS
1466 * pName [I] Servername or NULL (local Computer)
1467 * hWnd [I] Handle to parent Window for the Dialog-Box
1468 * pMonitorName [I] Name of the Monitor that manage the Port
1470 * RETURNS
1471 * Success: TRUE
1472 * Failure: FALSE
1475 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
1477 monitor_t * pm;
1478 monitor_t * pui;
1479 LONG lres;
1480 DWORD res;
1482 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
1484 lres = copy_servername_from_name(pName, NULL);
1485 if (lres) {
1486 FIXME("server %s not supported\n", debugstr_w(pName));
1487 SetLastError(ERROR_INVALID_PARAMETER);
1488 return FALSE;
1491 /* an empty Monitorname is Invalid */
1492 if (!pMonitorName[0]) {
1493 SetLastError(ERROR_NOT_SUPPORTED);
1494 return FALSE;
1497 pm = monitor_load(pMonitorName, NULL);
1498 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
1499 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
1500 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1502 else
1504 pui = monitor_loadui(pm);
1505 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
1506 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
1507 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
1509 else
1511 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1512 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
1513 pui, debugstr_w(pui ? pui->dllname : NULL));
1515 SetLastError(ERROR_NOT_SUPPORTED);
1516 res = FALSE;
1518 monitor_unload(pui);
1520 monitor_unload(pm);
1522 TRACE("returning %d with %u\n", res, GetLastError());
1523 return res;
1526 /******************************************************************************
1527 * fpAddPortEx [exported through PRINTPROVIDOR]
1529 * Add a Port for a specific Monitor, without presenting a user interface
1531 * PARAMS
1532 * pName [I] Servername or NULL (local Computer)
1533 * level [I] Structure-Level (1 or 2) for pBuffer
1534 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1535 * pMonitorName [I] Name of the Monitor that manage the Port
1537 * RETURNS
1538 * Success: TRUE
1539 * Failure: FALSE
1542 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
1544 PORT_INFO_2W * pi2;
1545 monitor_t * pm;
1546 DWORD lres;
1547 DWORD res;
1549 pi2 = (PORT_INFO_2W *) pBuffer;
1551 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
1552 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
1553 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
1554 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
1556 lres = copy_servername_from_name(pName, NULL);
1557 if (lres) {
1558 FIXME("server %s not supported\n", debugstr_w(pName));
1559 SetLastError(ERROR_INVALID_PARAMETER);
1560 return FALSE;
1563 if ((level < 1) || (level > 2)) {
1564 SetLastError(ERROR_INVALID_LEVEL);
1565 return FALSE;
1568 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
1569 SetLastError(ERROR_INVALID_PARAMETER);
1570 return FALSE;
1573 /* load the Monitor */
1574 pm = monitor_load(pMonitorName, NULL);
1575 if (pm && pm->monitor && pm->monitor->pfnAddPortEx) {
1576 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
1577 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1579 else
1581 FIXME("not implemented for %s (monitor %p: %s)\n",
1582 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : NULL);
1583 SetLastError(ERROR_INVALID_PARAMETER);
1584 res = FALSE;
1586 monitor_unload(pm);
1587 return res;
1590 /******************************************************************************
1591 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1593 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1595 * PARAMS
1596 * pName [I] Servername or NULL (local Computer)
1597 * level [I] Level for the supplied DRIVER_INFO_*W struct
1598 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1599 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1601 * RESULTS
1602 * Success: TRUE
1603 * Failure: FALSE
1606 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1608 LONG lres;
1610 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1611 lres = copy_servername_from_name(pName, NULL);
1612 if (lres) {
1613 FIXME("server %s not supported\n", debugstr_w(pName));
1614 SetLastError(ERROR_ACCESS_DENIED);
1615 return FALSE;
1618 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1619 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1622 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1625 /******************************************************************************
1626 * fpClosePrinter [exported through PRINTPROVIDOR]
1628 * Close a printer handle and free associated resources
1630 * PARAMS
1631 * hPrinter [I] Printerhandle to close
1633 * RESULTS
1634 * Success: TRUE
1635 * Failure: FALSE
1638 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1640 printer_t *printer = (printer_t *) hPrinter;
1642 TRACE("(%p)\n", hPrinter);
1644 if (printer) {
1645 printer_free(printer);
1646 return TRUE;
1648 return FALSE;
1651 /******************************************************************************
1652 * fpConfigurePort [exported through PRINTPROVIDOR]
1654 * Display the Configuration-Dialog for 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 configured
1661 * RETURNS
1662 * Success: TRUE
1663 * Failure: FALSE
1666 static BOOL WINAPI fpConfigurePort(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, but can popup a Dialog */
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->pfnConfigurePort) {
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->pfnConfigurePort(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->pfnConfigurePortUI) {
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->pfnConfigurePortUI(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 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1724 * Delete a specific Printmonitor from a Printing-Environment
1726 * PARAMS
1727 * pName [I] Servername or NULL (local Computer)
1728 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1729 * pMonitorName [I] Name of the Monitor, that should be deleted
1731 * RETURNS
1732 * Success: TRUE
1733 * Failure: FALSE
1735 * NOTES
1736 * pEnvironment is ignored in Windows for the local Computer.
1740 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1742 HKEY hroot = NULL;
1743 LONG lres;
1745 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1746 debugstr_w(pMonitorName));
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 return FALSE;
1755 /* pEnvironment is ignored in Windows for the local Computer */
1756 if (!pMonitorName || !pMonitorName[0]) {
1757 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1758 SetLastError(ERROR_INVALID_PARAMETER);
1759 return FALSE;
1762 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1763 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1764 return FALSE;
1767 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1768 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1769 RegCloseKey(hroot);
1770 return TRUE;
1773 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1774 RegCloseKey(hroot);
1776 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1777 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1778 return FALSE;
1781 /*****************************************************************************
1782 * fpDeletePort [exported through PRINTPROVIDOR]
1784 * Delete a specific Port
1786 * PARAMS
1787 * pName [I] Servername or NULL (local Computer)
1788 * hWnd [I] Handle to parent Window for the Dialog-Box
1789 * pPortName [I] Name of the Port, that should be deleted
1791 * RETURNS
1792 * Success: TRUE
1793 * Failure: FALSE
1796 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1798 monitor_t * pm;
1799 monitor_t * pui;
1800 LONG lres;
1801 DWORD res;
1803 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1805 lres = copy_servername_from_name(pName, NULL);
1806 if (lres) {
1807 FIXME("server %s not supported\n", debugstr_w(pName));
1808 SetLastError(ERROR_INVALID_NAME);
1809 return FALSE;
1812 /* an empty Portname is Invalid */
1813 if (!pPortName[0]) {
1814 SetLastError(ERROR_NOT_SUPPORTED);
1815 return FALSE;
1818 pm = monitor_load_by_port(pPortName);
1819 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
1820 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1821 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1822 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
1823 TRACE("got %d with %u\n", res, GetLastError());
1825 else
1827 pui = monitor_loadui(pm);
1828 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
1829 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1830 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1831 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
1832 TRACE("got %d with %u\n", res, GetLastError());
1834 else
1836 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1837 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1838 pui, debugstr_w(pui ? pui->dllname : NULL));
1840 SetLastError(ERROR_NOT_SUPPORTED);
1841 res = FALSE;
1843 monitor_unload(pui);
1845 monitor_unload(pm);
1847 TRACE("returning %d with %u\n", res, GetLastError());
1848 return res;
1851 /*****************************************************************************
1852 * fpEnumMonitors [exported through PRINTPROVIDOR]
1854 * Enumerate available Port-Monitors
1856 * PARAMS
1857 * pName [I] Servername or NULL (local Computer)
1858 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1859 * pMonitors [O] PTR to Buffer that receives the Result
1860 * cbBuf [I] Size of Buffer at pMonitors
1861 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1862 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1864 * RETURNS
1865 * Success: TRUE
1866 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1868 * NOTES
1869 * Windows reads the Registry once and cache the Results.
1872 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1873 LPDWORD pcbNeeded, LPDWORD pcReturned)
1875 DWORD numentries = 0;
1876 DWORD needed = 0;
1877 LONG lres;
1878 BOOL res = FALSE;
1880 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1881 cbBuf, pcbNeeded, pcReturned);
1883 lres = copy_servername_from_name(pName, NULL);
1884 if (lres) {
1885 FIXME("server %s not supported\n", debugstr_w(pName));
1886 SetLastError(ERROR_INVALID_NAME);
1887 goto em_cleanup;
1890 if (!Level || (Level > 2)) {
1891 WARN("level (%d) is ignored in win9x\n", Level);
1892 SetLastError(ERROR_INVALID_LEVEL);
1893 return FALSE;
1896 /* Scan all Monitor-Keys */
1897 numentries = 0;
1898 needed = get_local_monitors(Level, NULL, 0, &numentries);
1900 /* we calculated the needed buffersize. now do more error-checks */
1901 if (cbBuf < needed) {
1902 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1903 goto em_cleanup;
1906 /* fill the Buffer with the Monitor-Keys */
1907 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
1908 res = TRUE;
1910 em_cleanup:
1911 if (pcbNeeded) *pcbNeeded = needed;
1912 if (pcReturned) *pcReturned = numentries;
1914 TRACE("returning %d with %d (%d byte for %d entries)\n",
1915 res, GetLastError(), needed, numentries);
1917 return (res);
1920 /******************************************************************************
1921 * fpEnumPorts [exported through PRINTPROVIDOR]
1923 * Enumerate available Ports
1925 * PARAMS
1926 * pName [I] Servername or NULL (local Computer)
1927 * Level [I] Structure-Level (1 or 2)
1928 * pPorts [O] PTR to Buffer that receives the Result
1929 * cbBuf [I] Size of Buffer at pPorts
1930 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
1931 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
1933 * RETURNS
1934 * Success: TRUE
1935 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
1938 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
1939 LPDWORD pcbNeeded, LPDWORD pcReturned)
1941 DWORD needed = 0;
1942 DWORD numentries = 0;
1943 LONG lres;
1944 BOOL res = FALSE;
1946 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
1947 cbBuf, pcbNeeded, pcReturned);
1949 lres = copy_servername_from_name(pName, NULL);
1950 if (lres) {
1951 FIXME("server %s not supported\n", debugstr_w(pName));
1952 SetLastError(ERROR_INVALID_NAME);
1953 goto emP_cleanup;
1956 if (!Level || (Level > 2)) {
1957 SetLastError(ERROR_INVALID_LEVEL);
1958 goto emP_cleanup;
1961 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
1962 SetLastError(RPC_X_NULL_REF_POINTER);
1963 goto emP_cleanup;
1966 EnterCriticalSection(&monitor_handles_cs);
1967 monitor_loadall();
1969 /* Scan all local Ports */
1970 numentries = 0;
1971 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
1973 /* we calculated the needed buffersize. now do the error-checks */
1974 if (cbBuf < needed) {
1975 monitor_unloadall();
1976 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1977 goto emP_cleanup_cs;
1979 else if (!pPorts || !pcReturned) {
1980 monitor_unloadall();
1981 SetLastError(RPC_X_NULL_REF_POINTER);
1982 goto emP_cleanup_cs;
1985 /* Fill the Buffer */
1986 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
1987 res = TRUE;
1988 monitor_unloadall();
1990 emP_cleanup_cs:
1991 LeaveCriticalSection(&monitor_handles_cs);
1993 emP_cleanup:
1994 if (pcbNeeded) *pcbNeeded = needed;
1995 if (pcReturned) *pcReturned = (res) ? numentries : 0;
1997 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
1998 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2000 return (res);
2003 /******************************************************************************
2004 * fpOpenPrinter [exported through PRINTPROVIDOR]
2006 * Open a Printer / Printserver or a Printer-Object
2008 * PARAMS
2009 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2010 * pPrinter [O] The resulting Handle is stored here
2011 * pDefaults [I] PTR to Default Printer Settings or NULL
2013 * RETURNS
2014 * Success: TRUE
2015 * Failure: FALSE
2017 * NOTES
2018 * lpPrinterName is one of:
2019 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2020 *| Printer: "PrinterName"
2021 *| Printer-Object: "PrinterName,Job xxx"
2022 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2023 *| XcvPort: "Servername,XcvPort PortName"
2027 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
2028 LPPRINTER_DEFAULTSW pDefaults)
2031 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
2033 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
2035 return (*pPrinter != 0);
2038 /******************************************************************************
2039 * fpXcvData [exported through PRINTPROVIDOR]
2041 * Execute commands in the Printmonitor DLL
2043 * PARAMS
2044 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2045 * pszDataName [i] Name of the command to execute
2046 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2047 * cbInputData [i] Size in Bytes of Buffer at pInputData
2048 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2049 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2050 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2051 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2053 * RETURNS
2054 * Success: TRUE
2055 * Failure: FALSE
2057 * NOTES
2058 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2059 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2061 * Minimal List of commands, that a Printmonitor DLL should support:
2063 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2064 *| "AddPort" : Add a Port
2065 *| "DeletePort": Delete a Port
2067 * Many Printmonitors support additional commands. Examples for localspl.dll:
2068 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2069 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2072 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2073 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2074 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2076 printer_t *printer = (printer_t * ) hXcv;
2078 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2079 pInputData, cbInputData, pOutputData,
2080 cbOutputData, pcbOutputNeeded, pdwStatus);
2082 if (!printer || (!printer->hXcv)) {
2083 SetLastError(ERROR_INVALID_HANDLE);
2084 return FALSE;
2087 if (!pcbOutputNeeded) {
2088 SetLastError(ERROR_INVALID_PARAMETER);
2089 return FALSE;
2092 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2093 SetLastError(RPC_X_NULL_REF_POINTER);
2094 return FALSE;
2097 *pcbOutputNeeded = 0;
2099 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
2100 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
2102 return TRUE;
2105 /*****************************************************
2106 * setup_provider [internal]
2108 void setup_provider(void)
2110 static const PRINTPROVIDOR backend = {
2111 fpOpenPrinter,
2112 NULL, /* fpSetJob */
2113 NULL, /* fpGetJob */
2114 NULL, /* fpEnumJobs */
2115 NULL, /* fpAddPrinter */
2116 NULL, /* fpDeletePrinter */
2117 NULL, /* fpSetPrinter */
2118 NULL, /* fpGetPrinter */
2119 NULL, /* fpEnumPrinters */
2120 NULL, /* fpAddPrinterDriver */
2121 NULL, /* fpEnumPrinterDrivers */
2122 NULL, /* fpGetPrinterDriver */
2123 fpGetPrinterDriverDirectory,
2124 NULL, /* fpDeletePrinterDriver */
2125 NULL, /* fpAddPrintProcessor */
2126 NULL, /* fpEnumPrintProcessors */
2127 NULL, /* fpGetPrintProcessorDirectory */
2128 NULL, /* fpDeletePrintProcessor */
2129 NULL, /* fpEnumPrintProcessorDatatypes */
2130 NULL, /* fpStartDocPrinter */
2131 NULL, /* fpStartPagePrinter */
2132 NULL, /* fpWritePrinter */
2133 NULL, /* fpEndPagePrinter */
2134 NULL, /* fpAbortPrinter */
2135 NULL, /* fpReadPrinter */
2136 NULL, /* fpEndDocPrinter */
2137 NULL, /* fpAddJob */
2138 NULL, /* fpScheduleJob */
2139 NULL, /* fpGetPrinterData */
2140 NULL, /* fpSetPrinterData */
2141 NULL, /* fpWaitForPrinterChange */
2142 fpClosePrinter,
2143 NULL, /* fpAddForm */
2144 NULL, /* fpDeleteForm */
2145 NULL, /* fpGetForm */
2146 NULL, /* fpSetForm */
2147 NULL, /* fpEnumForms */
2148 fpEnumMonitors,
2149 fpEnumPorts,
2150 fpAddPort,
2151 fpConfigurePort,
2152 fpDeletePort,
2153 NULL, /* fpCreatePrinterIC */
2154 NULL, /* fpPlayGdiScriptOnPrinterIC */
2155 NULL, /* fpDeletePrinterIC */
2156 NULL, /* fpAddPrinterConnection */
2157 NULL, /* fpDeletePrinterConnection */
2158 NULL, /* fpPrinterMessageBox */
2159 fpAddMonitor,
2160 fpDeleteMonitor,
2161 NULL, /* fpResetPrinter */
2162 NULL, /* fpGetPrinterDriverEx */
2163 NULL, /* fpFindFirstPrinterChangeNotification */
2164 NULL, /* fpFindClosePrinterChangeNotification */
2165 fpAddPortEx,
2166 NULL, /* fpShutDown */
2167 NULL, /* fpRefreshPrinterChangeNotification */
2168 NULL, /* fpOpenPrinterEx */
2169 NULL, /* fpAddPrinterEx */
2170 NULL, /* fpSetPort */
2171 NULL, /* fpEnumPrinterData */
2172 NULL, /* fpDeletePrinterData */
2173 NULL, /* fpClusterSplOpen */
2174 NULL, /* fpClusterSplClose */
2175 NULL, /* fpClusterSplIsAlive */
2176 NULL, /* fpSetPrinterDataEx */
2177 NULL, /* fpGetPrinterDataEx */
2178 NULL, /* fpEnumPrinterDataEx */
2179 NULL, /* fpEnumPrinterKey */
2180 NULL, /* fpDeletePrinterDataEx */
2181 NULL, /* fpDeletePrinterKey */
2182 NULL, /* fpSeekPrinter */
2183 NULL, /* fpDeletePrinterDriverEx */
2184 NULL, /* fpAddPerMachineConnection */
2185 NULL, /* fpDeletePerMachineConnection */
2186 NULL, /* fpEnumPerMachineConnections */
2187 fpXcvData,
2188 fpAddPrinterDriverEx,
2189 NULL, /* fpSplReadPrinter */
2190 NULL, /* fpDriverUnloadComplete */
2191 NULL, /* fpGetSpoolFileInfo */
2192 NULL, /* fpCommitSpoolData */
2193 NULL, /* fpCloseSpoolFileHandle */
2194 NULL, /* fpFlushPrinter */
2195 NULL, /* fpSendRecvBidiData */
2196 NULL /* fpAddDriverCatalog */
2198 pprovider = &backend;
2202 /*****************************************************
2203 * InitializePrintProvidor (localspl.@)
2205 * Initialize the Printprovider
2207 * PARAMS
2208 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2209 * cbPrintProvidor [I] Size of Buffer in Bytes
2210 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2212 * RETURNS
2213 * Success: TRUE and pPrintProvidor filled
2214 * Failure: FALSE
2216 * NOTES
2217 * The RegistryPath should be:
2218 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2219 * but this Parameter is ignored in "localspl.dll".
2223 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2224 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2227 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2228 memcpy(pPrintProvidor, pprovider,
2229 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2231 return TRUE;