gdi32/tests: Add some more tests for monochrome bitmap blits.
[wine/multimedia.git] / dlls / localspl / provider.c
bloba599113eac14605dcee26a67d8ba91e590ef0071
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 fmt_printprocessorsW[] = { 'S','y','s','t','e','m','\\',
114 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
115 'C','o','n','t','r','o','l','\\',
116 'P','r','i','n','t','\\',
117 'E','n','v','i','r','o','n','m','e','n','t','s','\\','%','s','\\',
118 'P','r','i','n','t',' ','P','r','o','c','e','s','s','o','r','s',0 };
119 static const WCHAR hardwareidW[] = {'H','a','r','d','w','a','r','e','I','D',0};
120 static const WCHAR help_fileW[] = {'H','e','l','p',' ','F','i','l','e',0};
121 static const WCHAR ia64_envnameW[] = {'W','i','n','d','o','w','s',' ','I','A','6','4',0};
122 static const WCHAR ia64_subdirW[] = {'i','a','6','4',0};
123 static const WCHAR localportW[] = {'L','o','c','a','l',' ','P','o','r','t',0};
124 static const WCHAR locationW[] = {'L','o','c','a','t','i','o','n',0};
125 static const WCHAR manufacturerW[] = {'M','a','n','u','f','a','c','t','u','r','e','r',0};
126 static const WCHAR monitorW[] = {'M','o','n','i','t','o','r',0};
127 static const WCHAR monitorsW[] = {'S','y','s','t','e','m','\\',
128 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
129 'C','o','n','t','r','o','l','\\',
130 'P','r','i','n','t','\\',
131 'M','o','n','i','t','o','r','s','\\',0};
132 static const WCHAR monitorUIW[] = {'M','o','n','i','t','o','r','U','I',0};
133 static const WCHAR nameW[] = {'N','a','m','e',0};
134 static const WCHAR oem_urlW[] = {'O','E','M',' ','U','r','l',0};
135 static const WCHAR parametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
136 static const WCHAR portW[] = {'P','o','r','t',0};
137 static const WCHAR previous_namesW[] = {'P','r','e','v','i','o','u','s',' ','N','a','m','e','s',0};
138 static const WCHAR printersW[] = {'S','y','s','t','e','m','\\',
139 'C','u', 'r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
140 'C','o','n','t','r','o','l','\\',
141 'P','r','i','n','t','\\',
142 'P','r','i','n','t','e','r','s',0};
143 static const WCHAR spooldriversW[] = {'\\','s','p','o','o','l','\\','d','r','i','v','e','r','s','\\',0};
144 static const WCHAR spoolprtprocsW[] = {'\\','s','p','o','o','l','\\','p','r','t','p','r','o','c','s','\\',0};
145 static const WCHAR version0_regpathW[] = {'\\','V','e','r','s','i','o','n','-','0',0};
146 static const WCHAR version0_subdirW[] = {'\\','0',0};
147 static const WCHAR version3_regpathW[] = {'\\','V','e','r','s','i','o','n','-','3',0};
148 static const WCHAR version3_subdirW[] = {'\\','3',0};
149 static const WCHAR versionW[] = {'V','e','r','s','i','o','n',0};
150 static const WCHAR win40_envnameW[] = {'W','i','n','d','o','w','s',' ','4','.','0',0};
151 static const WCHAR win40_subdirW[] = {'w','i','n','4','0',0};
152 static const WCHAR winnt_cv_portsW[] = {'S','o','f','t','w','a','r','e','\\',
153 'M','i','c','r','o','s','o','f','t','\\',
154 'W','i','n','d','o','w','s',' ','N','T','\\',
155 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
156 'P','o','r','t','s',0};
157 static const WCHAR winprintW[] = {'w','i','n','p','r','i','n','t',0};
158 static const WCHAR x64_envnameW[] = {'W','i','n','d','o','w','s',' ','x','6','4',0};
159 static const WCHAR x64_subdirW[] = {'x','6','4',0};
160 static const WCHAR x86_envnameW[] = {'W','i','n','d','o','w','s',' ','N','T',' ','x','8','6',0};
161 static const WCHAR x86_subdirW[] = {'w','3','2','x','8','6',0};
162 static const WCHAR XcvMonitorW[] = {',','X','c','v','M','o','n','i','t','o','r',' ',0};
163 static const WCHAR XcvPortW[] = {',','X','c','v','P','o','r','t',' ',0};
166 static const printenv_t env_ia64 = {ia64_envnameW, ia64_subdirW, 3,
167 version3_regpathW, version3_subdirW};
169 static const printenv_t env_x86 = {x86_envnameW, x86_subdirW, 3,
170 version3_regpathW, version3_subdirW};
172 static const printenv_t env_x64 = {x64_envnameW, x64_subdirW, 3,
173 version3_regpathW, version3_subdirW};
175 static const printenv_t env_win40 = {win40_envnameW, win40_subdirW, 0,
176 version0_regpathW, version0_subdirW};
178 static const printenv_t * const all_printenv[] = {&env_x86, &env_x64, &env_ia64, &env_win40};
181 static const DWORD di_sizeof[] = {0, sizeof(DRIVER_INFO_1W), sizeof(DRIVER_INFO_2W),
182 sizeof(DRIVER_INFO_3W), sizeof(DRIVER_INFO_4W),
183 sizeof(DRIVER_INFO_5W), sizeof(DRIVER_INFO_6W),
184 0, sizeof(DRIVER_INFO_8W)};
187 /******************************************************************
188 * strdupW [internal]
190 * create a copy of a unicode-string
193 static LPWSTR strdupW(LPCWSTR p)
195 LPWSTR ret;
196 DWORD len;
198 if(!p) return NULL;
199 len = (lstrlenW(p) + 1) * sizeof(WCHAR);
200 ret = heap_alloc(len);
201 if (ret) memcpy(ret, p, len);
202 return ret;
205 /******************************************************************
206 * apd_copyfile [internal]
208 * Copy a file from the driverdirectory to the versioned directory
210 * RETURNS
211 * Success: TRUE
212 * Failure: FALSE
215 static BOOL apd_copyfile( WCHAR *pathname, WCHAR *file_part, apd_data_t *apd )
217 WCHAR *srcname;
218 DWORD res;
220 apd->src[apd->srclen] = '\0';
221 apd->dst[apd->dstlen] = '\0';
223 if (!pathname || !pathname[0]) {
224 /* nothing to copy */
225 return TRUE;
228 if (apd->copyflags & APD_COPY_FROM_DIRECTORY)
229 srcname = pathname;
230 else
232 srcname = apd->src;
233 strcatW( srcname, file_part );
235 strcatW( apd->dst, file_part );
237 TRACE("%s => %s\n", debugstr_w(srcname), debugstr_w(apd->dst));
239 /* FIXME: handle APD_COPY_NEW_FILES */
240 res = CopyFileW(srcname, apd->dst, FALSE);
241 TRACE("got %u with %u\n", res, GetLastError());
243 return (apd->lazy) ? TRUE : res;
246 /******************************************************************
247 * copy_servername_from_name (internal)
249 * for an external server, the serverpart from the name is copied.
251 * RETURNS
252 * the length (in WCHAR) of the serverpart (0 for the local computer)
253 * (-length), when the name is to long
256 static LONG copy_servername_from_name(LPCWSTR name, LPWSTR target)
258 LPCWSTR server;
259 LPWSTR ptr;
260 WCHAR buffer[MAX_COMPUTERNAME_LENGTH +1];
261 DWORD len;
262 DWORD serverlen;
264 if (target) *target = '\0';
266 if (name == NULL) return 0;
267 if ((name[0] != '\\') || (name[1] != '\\')) return 0;
269 server = &name[2];
270 /* skip over both backslash, find separator '\' */
271 ptr = strchrW(server, '\\');
272 serverlen = (ptr) ? ptr - server : lstrlenW(server);
274 /* servername is empty */
275 if (serverlen == 0) return 0;
277 TRACE("found %s\n", debugstr_wn(server, serverlen));
279 if (serverlen > MAX_COMPUTERNAME_LENGTH) return -serverlen;
281 if (target) {
282 memcpy(target, server, serverlen * sizeof(WCHAR));
283 target[serverlen] = '\0';
286 len = sizeof(buffer) / sizeof(buffer[0]);
287 if (GetComputerNameW(buffer, &len)) {
288 if ((serverlen == len) && (strncmpiW(server, buffer, len) == 0)) {
289 /* The requested Servername is our computername */
290 return 0;
293 return serverlen;
296 /******************************************************************
297 * get_basename_from_name (internal)
299 * skip over the serverpart from the full name
302 static LPCWSTR get_basename_from_name(LPCWSTR name)
304 if (name == NULL) return NULL;
305 if ((name[0] == '\\') && (name[1] == '\\')) {
306 /* skip over the servername and search for the following '\' */
307 name = strchrW(&name[2], '\\');
308 if ((name) && (name[1])) {
309 /* found a separator ('\') followed by a name:
310 skip over the separator and return the rest */
311 name++;
313 else
315 /* no basename present (we found only a servername) */
316 return NULL;
319 return name;
322 /******************************************************************
323 * monitor_unload [internal]
325 * release a printmonitor and unload it from memory, when needed
328 static void monitor_unload(monitor_t * pm)
330 if (pm == NULL) return;
331 TRACE("%p (refcount: %d) %s\n", pm, pm->refcount, debugstr_w(pm->name));
333 EnterCriticalSection(&monitor_handles_cs);
335 if (pm->refcount) pm->refcount--;
337 if (pm->refcount == 0) {
338 list_remove(&pm->entry);
339 FreeLibrary(pm->hdll);
340 heap_free(pm->name);
341 heap_free(pm->dllname);
342 heap_free(pm);
344 LeaveCriticalSection(&monitor_handles_cs);
347 /******************************************************************
348 * monitor_unloadall [internal]
350 * release all registered printmonitors and unload them from memory, when needed
354 static void monitor_unloadall(void)
356 monitor_t * pm;
357 monitor_t * next;
359 EnterCriticalSection(&monitor_handles_cs);
360 /* iterate through the list, with safety against removal */
361 LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
363 /* skip monitorui dlls */
364 if (pm->monitor) monitor_unload(pm);
366 LeaveCriticalSection(&monitor_handles_cs);
369 /******************************************************************
370 * monitor_load [internal]
372 * load a printmonitor, get the dllname from the registry, when needed
373 * initialize the monitor and dump found function-pointers
375 * On failure, SetLastError() is called and NULL is returned
378 static monitor_t * monitor_load(LPCWSTR name, LPWSTR dllname)
380 LPMONITOR2 (WINAPI *pInitializePrintMonitor2) (PMONITORINIT, LPHANDLE);
381 PMONITORUI (WINAPI *pInitializePrintMonitorUI)(VOID);
382 LPMONITOREX (WINAPI *pInitializePrintMonitor) (LPWSTR);
383 DWORD (WINAPI *pInitializeMonitorEx)(LPWSTR, LPMONITOR);
384 DWORD (WINAPI *pInitializeMonitor) (LPWSTR);
386 monitor_t * pm = NULL;
387 monitor_t * cursor;
388 LPWSTR regroot = NULL;
389 LPWSTR driver = dllname;
391 TRACE("(%s, %s)\n", debugstr_w(name), debugstr_w(dllname));
392 /* Is the Monitor already loaded? */
393 EnterCriticalSection(&monitor_handles_cs);
395 if (name) {
396 LIST_FOR_EACH_ENTRY(cursor, &monitor_handles, monitor_t, entry)
398 if (cursor->name && (lstrcmpW(name, cursor->name) == 0)) {
399 pm = cursor;
400 break;
405 if (pm == NULL) {
406 pm = heap_alloc_zero(sizeof(monitor_t));
407 if (pm == NULL) goto cleanup;
408 list_add_tail(&monitor_handles, &pm->entry);
410 pm->refcount++;
412 if (pm->name == NULL) {
413 /* Load the monitor */
414 LPMONITOREX pmonitorEx;
415 DWORD len;
417 if (name) {
418 len = lstrlenW(monitorsW) + lstrlenW(name) + 2;
419 regroot = heap_alloc(len * sizeof(WCHAR));
422 if (regroot) {
423 lstrcpyW(regroot, monitorsW);
424 lstrcatW(regroot, name);
425 /* Get the Driver from the Registry */
426 if (driver == NULL) {
427 HKEY hroot;
428 DWORD namesize;
429 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, regroot, &hroot) == ERROR_SUCCESS) {
430 if (RegQueryValueExW(hroot, driverW, NULL, NULL, NULL,
431 &namesize) == ERROR_SUCCESS) {
432 driver = heap_alloc(namesize);
433 RegQueryValueExW(hroot, driverW, NULL, NULL, (LPBYTE) driver, &namesize) ;
435 RegCloseKey(hroot);
440 pm->name = strdupW(name);
441 pm->dllname = strdupW(driver);
443 if ((name && (!regroot || !pm->name)) || !pm->dllname) {
444 monitor_unload(pm);
445 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
446 pm = NULL;
447 goto cleanup;
450 pm->hdll = LoadLibraryW(driver);
451 TRACE("%p: LoadLibrary(%s) => %d\n", pm->hdll, debugstr_w(driver), GetLastError());
453 if (pm->hdll == NULL) {
454 monitor_unload(pm);
455 SetLastError(ERROR_MOD_NOT_FOUND);
456 pm = NULL;
457 goto cleanup;
460 pInitializePrintMonitor2 = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor2");
461 pInitializePrintMonitorUI = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitorUI");
462 pInitializePrintMonitor = (void *)GetProcAddress(pm->hdll, "InitializePrintMonitor");
463 pInitializeMonitorEx = (void *)GetProcAddress(pm->hdll, "InitializeMonitorEx");
464 pInitializeMonitor = (void *)GetProcAddress(pm->hdll, "InitializeMonitor");
467 TRACE("%p: %s,pInitializePrintMonitor2\n", pInitializePrintMonitor2, debugstr_w(driver));
468 TRACE("%p: %s,pInitializePrintMonitorUI\n", pInitializePrintMonitorUI, debugstr_w(driver));
469 TRACE("%p: %s,pInitializePrintMonitor\n", pInitializePrintMonitor, debugstr_w(driver));
470 TRACE("%p: %s,pInitializeMonitorEx\n", pInitializeMonitorEx, debugstr_w(driver));
471 TRACE("%p: %s,pInitializeMonitor\n", pInitializeMonitor, debugstr_w(driver));
473 if (pInitializePrintMonitorUI != NULL) {
474 pm->monitorUI = pInitializePrintMonitorUI();
475 TRACE("%p: MONITORUI from %s,InitializePrintMonitorUI()\n", pm->monitorUI, debugstr_w(driver));
476 if (pm->monitorUI) {
477 TRACE("0x%08x: dwMonitorSize (%d)\n",
478 pm->monitorUI->dwMonitorUISize, pm->monitorUI->dwMonitorUISize);
483 if (pInitializePrintMonitor && regroot) {
484 pmonitorEx = pInitializePrintMonitor(regroot);
485 TRACE("%p: LPMONITOREX from %s,InitializePrintMonitor(%s)\n",
486 pmonitorEx, debugstr_w(driver), debugstr_w(regroot));
488 if (pmonitorEx) {
489 pm->dwMonitorSize = pmonitorEx->dwMonitorSize;
490 pm->monitor = &(pmonitorEx->Monitor);
494 if (pm->monitor) {
495 TRACE("0x%08x: dwMonitorSize (%d)\n", pm->dwMonitorSize, pm->dwMonitorSize);
499 if (!pm->monitor && regroot) {
500 if (pInitializePrintMonitor2 != NULL) {
501 FIXME("%s,InitializePrintMonitor2 not implemented\n", debugstr_w(driver));
503 if (pInitializeMonitorEx != NULL) {
504 FIXME("%s,InitializeMonitorEx not implemented\n", debugstr_w(driver));
506 if (pInitializeMonitor != NULL) {
507 FIXME("%s,InitializeMonitor not implemented\n", debugstr_w(driver));
510 if (!pm->monitor && !pm->monitorUI) {
511 monitor_unload(pm);
512 SetLastError(ERROR_PROC_NOT_FOUND);
513 pm = NULL;
516 cleanup:
517 if ((pm_localport == NULL) && (pm != NULL) && (lstrcmpW(pm->name, localportW) == 0)) {
518 pm->refcount++;
519 pm_localport = pm;
521 LeaveCriticalSection(&monitor_handles_cs);
522 if (driver != dllname) heap_free(driver);
523 heap_free(regroot);
524 TRACE("=> %p\n", pm);
525 return pm;
528 /******************************************************************
529 * monitor_loadall [internal]
531 * Load all registered monitors
534 static DWORD monitor_loadall(void)
536 monitor_t * pm;
537 DWORD registered = 0;
538 DWORD loaded = 0;
539 HKEY hmonitors;
540 WCHAR buffer[MAX_PATH];
541 DWORD id = 0;
543 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hmonitors) == ERROR_SUCCESS) {
544 RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, &registered, NULL, NULL,
545 NULL, NULL, NULL, NULL, NULL);
547 TRACE("%d monitors registered\n", registered);
549 while (id < registered) {
550 buffer[0] = '\0';
551 RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
552 pm = monitor_load(buffer, NULL);
553 if (pm) loaded++;
554 id++;
556 RegCloseKey(hmonitors);
558 TRACE("%d monitors loaded\n", loaded);
559 return loaded;
562 /******************************************************************
563 * monitor_loadui [internal]
565 * load the userinterface-dll for a given portmonitor
567 * On failure, NULL is returned
569 static monitor_t * monitor_loadui(monitor_t * pm)
571 monitor_t * pui = NULL;
572 WCHAR buffer[MAX_PATH];
573 HANDLE hXcv;
574 DWORD len;
575 DWORD res;
577 if (pm == NULL) return NULL;
578 TRACE("(%p) => dllname: %s\n", pm, debugstr_w(pm->dllname));
580 /* Try the Portmonitor first; works for many monitors */
581 if (pm->monitorUI) {
582 EnterCriticalSection(&monitor_handles_cs);
583 pm->refcount++;
584 LeaveCriticalSection(&monitor_handles_cs);
585 return pm;
588 /* query the userinterface-dllname from the Portmonitor */
589 if ((pm->monitor) && (pm->monitor->pfnXcvDataPort)) {
590 /* building (",XcvMonitor %s",pm->name) not needed yet */
591 res = pm->monitor->pfnXcvOpenPort(emptyW, SERVER_ACCESS_ADMINISTER, &hXcv);
592 TRACE("got %u with %p\n", res, hXcv);
593 if (res) {
594 res = pm->monitor->pfnXcvDataPort(hXcv, monitorUIW, NULL, 0, (BYTE *) buffer, sizeof(buffer), &len);
595 TRACE("got %u with %s\n", res, debugstr_w(buffer));
596 if (res == ERROR_SUCCESS) pui = monitor_load(NULL, buffer);
597 pm->monitor->pfnXcvClosePort(hXcv);
600 return pui;
603 /******************************************************************
604 * monitor_load_by_port [internal]
606 * load a printmonitor for a given port
608 * On failure, NULL is returned
611 static monitor_t * monitor_load_by_port(LPCWSTR portname)
613 HKEY hroot;
614 HKEY hport;
615 LPWSTR buffer;
616 monitor_t * pm = NULL;
617 DWORD registered = 0;
618 DWORD id = 0;
619 DWORD len;
621 TRACE("(%s)\n", debugstr_w(portname));
623 /* Try the Local Monitor first */
624 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, winnt_cv_portsW, &hroot) == ERROR_SUCCESS) {
625 if (RegQueryValueExW(hroot, portname, NULL, NULL, NULL, &len) == ERROR_SUCCESS) {
626 /* found the portname */
627 RegCloseKey(hroot);
628 return monitor_load(localportW, NULL);
630 RegCloseKey(hroot);
633 len = MAX_PATH + lstrlenW(bs_ports_bsW) + lstrlenW(portname) + 1;
634 buffer = heap_alloc(len * sizeof(WCHAR));
635 if (buffer == NULL) return NULL;
637 if (RegOpenKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
638 EnterCriticalSection(&monitor_handles_cs);
639 RegQueryInfoKeyW(hroot, NULL, NULL, NULL, &registered, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
641 while ((pm == NULL) && (id < registered)) {
642 buffer[0] = '\0';
643 RegEnumKeyW(hroot, id, buffer, MAX_PATH);
644 TRACE("testing %s\n", debugstr_w(buffer));
645 len = lstrlenW(buffer);
646 lstrcatW(buffer, bs_ports_bsW);
647 lstrcatW(buffer, portname);
648 if (RegOpenKeyW(hroot, buffer, &hport) == ERROR_SUCCESS) {
649 RegCloseKey(hport);
650 buffer[len] = '\0'; /* use only the Monitor-Name */
651 pm = monitor_load(buffer, NULL);
653 id++;
655 LeaveCriticalSection(&monitor_handles_cs);
656 RegCloseKey(hroot);
658 heap_free(buffer);
659 return pm;
662 /******************************************************************
663 * Return the number of bytes for an multi_sz string.
664 * The result includes all \0s
665 * (specifically the extra \0, that is needed as multi_sz terminator).
667 static int multi_sz_lenW(const WCHAR *str)
669 const WCHAR *ptr = str;
670 if (!str) return 0;
673 ptr += lstrlenW(ptr) + 1;
674 } while (*ptr);
676 return (ptr - str + 1) * sizeof(WCHAR);
679 /******************************************************************
680 * validate_envW [internal]
682 * validate the user-supplied printing-environment
684 * PARAMS
685 * env [I] PTR to Environment-String or NULL
687 * RETURNS
688 * Success: PTR to printenv_t
689 * Failure: NULL and ERROR_INVALID_ENVIRONMENT
691 * NOTES
692 * An empty string is handled the same way as NULL.
696 static const printenv_t * validate_envW(LPCWSTR env)
698 const printenv_t *result = NULL;
699 unsigned int i;
701 TRACE("(%s)\n", debugstr_w(env));
702 if (env && env[0])
704 for (i = 0; i < sizeof(all_printenv)/sizeof(all_printenv[0]); i++)
706 if (lstrcmpiW(env, all_printenv[i]->envname) == 0)
708 result = all_printenv[i];
709 break;
712 if (result == NULL) {
713 FIXME("unsupported Environment: %s\n", debugstr_w(env));
714 SetLastError(ERROR_INVALID_ENVIRONMENT);
716 /* on win9x, only "Windows 4.0" is allowed, but we ignore this */
718 else
720 result = (GetVersion() & 0x80000000) ? &env_win40 : &env_x86;
723 TRACE("=> using %p: %s\n", result, debugstr_w(result ? result->envname : NULL));
724 return result;
727 /*****************************************************************************
728 * enumerate the local monitors (INTERNAL)
730 * returns the needed size (in bytes) for pMonitors
731 * and *lpreturned is set to number of entries returned in pMonitors
733 * Language-Monitors are also installed in the same Registry-Location but
734 * they are filtered in Windows (not returned by EnumMonitors).
735 * We do no filtering to simplify our Code.
738 static DWORD get_local_monitors(DWORD level, LPBYTE pMonitors, DWORD cbBuf, LPDWORD lpreturned)
740 HKEY hroot = NULL;
741 HKEY hentry = NULL;
742 LPWSTR ptr;
743 LPMONITOR_INFO_2W mi;
744 WCHAR buffer[MAX_PATH];
745 WCHAR dllname[MAX_PATH];
746 DWORD dllsize;
747 DWORD len;
748 DWORD index = 0;
749 DWORD needed = 0;
750 DWORD numentries;
751 DWORD entrysize;
753 entrysize = (level == 1) ? sizeof(MONITOR_INFO_1W) : sizeof(MONITOR_INFO_2W);
755 numentries = *lpreturned; /* this is 0, when we scan the registry */
756 len = entrysize * numentries;
757 ptr = (LPWSTR) &pMonitors[len];
759 numentries = 0;
760 len = sizeof(buffer)/sizeof(buffer[0]);
761 buffer[0] = '\0';
763 /* Windows creates the "Monitors"-Key on reboot / start "spooler" */
764 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) == ERROR_SUCCESS) {
765 /* Scan all Monitor-Registry-Keys */
766 while (RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
767 TRACE("Monitor_%d: %s\n", numentries, debugstr_w(buffer));
768 dllsize = sizeof(dllname);
769 dllname[0] = '\0';
771 /* The Monitor must have a Driver-DLL */
772 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
773 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
774 /* We found a valid DLL for this Monitor. */
775 TRACE("using Driver: %s\n", debugstr_w(dllname));
777 RegCloseKey(hentry);
780 /* Windows returns only Port-Monitors here, but to simplify our code,
781 we do no filtering for Language-Monitors */
782 if (dllname[0]) {
783 numentries++;
784 needed += entrysize;
785 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(monitorname) */
786 if (level > 1) {
787 /* we install and return only monitors for "Windows NT x86" */
788 needed += (lstrlenW(x86_envnameW) +1) * sizeof(WCHAR);
789 needed += dllsize;
792 /* required size is calculated. Now fill the user-buffer */
793 if (pMonitors && (cbBuf >= needed)){
794 mi = (LPMONITOR_INFO_2W) pMonitors;
795 pMonitors += entrysize;
797 TRACE("%p: writing MONITOR_INFO_%dW #%d\n", mi, level, numentries);
798 mi->pName = ptr;
799 lstrcpyW(ptr, buffer); /* Name of the Monitor */
800 ptr += (len+1); /* len is lstrlenW(monitorname) */
801 if (level > 1) {
802 mi->pEnvironment = ptr;
803 lstrcpyW(ptr, x86_envnameW); /* fixed to "Windows NT x86" */
804 ptr += (lstrlenW(x86_envnameW)+1);
806 mi->pDLLName = ptr;
807 lstrcpyW(ptr, dllname); /* Name of the Driver-DLL */
808 ptr += (dllsize / sizeof(WCHAR));
812 index++;
813 len = sizeof(buffer)/sizeof(buffer[0]);
814 buffer[0] = '\0';
816 RegCloseKey(hroot);
818 *lpreturned = numentries;
819 TRACE("need %d byte for %d entries\n", needed, numentries);
820 return needed;
823 /*****************************************************************************
824 * enumerate the local print processors (INTERNAL)
826 * returns the needed size (in bytes) for pPPInfo
827 * and *lpreturned is set to number of entries returned in pPPInfo
830 static DWORD get_local_printprocessors(LPWSTR regpathW, LPBYTE pPPInfo, DWORD cbBuf, LPDWORD lpreturned)
832 HKEY hroot = NULL;
833 HKEY hentry = NULL;
834 LPWSTR ptr;
835 PPRINTPROCESSOR_INFO_1W ppi;
836 WCHAR buffer[MAX_PATH];
837 WCHAR dllname[MAX_PATH];
838 DWORD dllsize;
839 DWORD len;
840 DWORD index = 0;
841 DWORD needed = 0;
842 DWORD numentries;
844 numentries = *lpreturned; /* this is 0, when we scan the registry */
845 len = numentries * sizeof(PRINTPROCESSOR_INFO_1W);
846 ptr = (LPWSTR) &pPPInfo[len];
848 numentries = 0;
849 len = sizeof(buffer)/sizeof(buffer[0]);
850 buffer[0] = '\0';
852 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, regpathW, &hroot) == ERROR_SUCCESS) {
853 /* add "winprint" first */
854 numentries++;
855 needed = sizeof(PRINTPROCESSOR_INFO_1W) + sizeof(winprintW);
856 if (pPPInfo && (cbBuf >= needed)){
857 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
858 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
860 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
861 ppi->pName = ptr;
862 lstrcpyW(ptr, winprintW); /* Name of the Print Processor */
863 ptr += sizeof(winprintW) / sizeof(WCHAR);
866 /* Scan all Printprocessor Keys */
867 while ((RegEnumKeyExW(hroot, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
868 (lstrcmpiW(buffer, winprintW) != 0)) {
869 TRACE("PrintProcessor_%d: %s\n", numentries, debugstr_w(buffer));
870 dllsize = sizeof(dllname);
871 dllname[0] = '\0';
873 /* The Print Processor must have a Driver-DLL */
874 if (RegOpenKeyExW(hroot, buffer, 0, KEY_READ, &hentry) == ERROR_SUCCESS) {
875 if (RegQueryValueExW(hentry, driverW, NULL, NULL, (LPBYTE) dllname, &dllsize) == ERROR_SUCCESS) {
876 /* We found a valid DLL for this Print Processor */
877 TRACE("using Driver: %s\n", debugstr_w(dllname));
879 RegCloseKey(hentry);
882 if (dllname[0]) {
883 numentries++;
884 needed += sizeof(PRINTPROCESSOR_INFO_1W);
885 needed += (len+1) * sizeof(WCHAR); /* len is lstrlenW(printprocessor name) */
887 /* required size is calculated. Now fill the user-buffer */
888 if (pPPInfo && (cbBuf >= needed)){
889 ppi = (PPRINTPROCESSOR_INFO_1W) pPPInfo;
890 pPPInfo += sizeof(PRINTPROCESSOR_INFO_1W);
892 TRACE("%p: writing PRINTPROCESSOR_INFO_1W #%d\n", ppi, numentries);
893 ppi->pName = ptr;
894 lstrcpyW(ptr, buffer); /* Name of the Print Processor */
895 ptr += (len+1); /* len is lstrlenW(printprosessor name) */
898 index++;
899 len = sizeof(buffer)/sizeof(buffer[0]);
900 buffer[0] = '\0';
902 RegCloseKey(hroot);
904 *lpreturned = numentries;
905 TRACE("need %d byte for %d entries\n", needed, numentries);
906 return needed;
909 /******************************************************************
910 * enumerate the local Ports from all loaded monitors (internal)
912 * returns the needed size (in bytes) for pPorts
913 * and *lpreturned is set to number of entries returned in pPorts
916 static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
918 monitor_t * pm;
919 LPWSTR ptr;
920 LPPORT_INFO_2W cache;
921 LPPORT_INFO_2W out;
922 LPBYTE pi_buffer = NULL;
923 DWORD pi_allocated = 0;
924 DWORD pi_needed;
925 DWORD pi_index;
926 DWORD pi_returned;
927 DWORD res;
928 DWORD outindex = 0;
929 DWORD needed;
930 DWORD numentries;
931 DWORD entrysize;
934 TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
935 entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
937 numentries = *lpreturned; /* this is 0, when we scan the registry */
938 needed = entrysize * numentries;
939 ptr = (LPWSTR) &pPorts[needed];
941 numentries = 0;
942 needed = 0;
944 LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
946 if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
947 pi_needed = 0;
948 pi_returned = 0;
949 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
950 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
951 /* Do not use heap_realloc (we do not need the old data in the buffer) */
952 heap_free(pi_buffer);
953 pi_buffer = heap_alloc(pi_needed);
954 pi_allocated = (pi_buffer) ? pi_needed : 0;
955 res = pm->monitor->pfnEnumPorts(NULL, level, pi_buffer, pi_allocated, &pi_needed, &pi_returned);
957 TRACE("(%s) got %d with %d (need %d byte for %d entries)\n",
958 debugstr_w(pm->name), res, GetLastError(), pi_needed, pi_returned);
960 numentries += pi_returned;
961 needed += pi_needed;
963 /* fill the output-buffer (pPorts), if we have one */
964 if (pPorts && (cbBuf >= needed ) && pi_buffer) {
965 pi_index = 0;
966 while (pi_returned > pi_index) {
967 cache = (LPPORT_INFO_2W) &pi_buffer[pi_index * entrysize];
968 out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
969 out->pPortName = ptr;
970 lstrcpyW(ptr, cache->pPortName);
971 ptr += (lstrlenW(ptr)+1);
972 if (level > 1) {
973 out->pMonitorName = ptr;
974 lstrcpyW(ptr, cache->pMonitorName);
975 ptr += (lstrlenW(ptr)+1);
977 out->pDescription = ptr;
978 lstrcpyW(ptr, cache->pDescription);
979 ptr += (lstrlenW(ptr)+1);
980 out->fPortType = cache->fPortType;
981 out->Reserved = cache->Reserved;
983 pi_index++;
984 outindex++;
989 /* the temporary portinfo-buffer is no longer needed */
990 heap_free(pi_buffer);
992 *lpreturned = numentries;
993 TRACE("need %d byte for %d entries\n", needed, numentries);
994 return needed;
998 /*****************************************************************************
999 * open_driver_reg [internal]
1001 * opens the registry for the printer drivers depending on the given input
1002 * variable pEnvironment
1004 * RETURNS:
1005 * Success: the opened hkey
1006 * Failure: NULL
1008 static HKEY open_driver_reg(LPCWSTR pEnvironment)
1010 HKEY retval = NULL;
1011 LPWSTR buffer;
1012 const printenv_t * env;
1014 TRACE("(%s)\n", debugstr_w(pEnvironment));
1016 env = validate_envW(pEnvironment);
1017 if (!env) return NULL;
1019 buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(fmt_driversW) +
1020 (lstrlenW(env->envname) + lstrlenW(env->versionregpath)) * sizeof(WCHAR));
1022 if (buffer) {
1023 wsprintfW(buffer, fmt_driversW, env->envname, env->versionregpath);
1024 RegCreateKeyW(HKEY_LOCAL_MACHINE, buffer, &retval);
1025 HeapFree(GetProcessHeap(), 0, buffer);
1027 return retval;
1030 /*****************************************************************************
1031 * fpGetPrinterDriverDirectory [exported through PRINTPROVIDOR]
1033 * Return the PATH for the Printer-Drivers
1035 * PARAMS
1036 * pName [I] Servername (NT only) or NULL (local Computer)
1037 * pEnvironment [I] Printing-Environment (see below) or NULL (Default)
1038 * Level [I] Structure-Level (must be 1)
1039 * pDriverDirectory [O] PTR to Buffer that receives the Result
1040 * cbBuf [I] Size of Buffer at pDriverDirectory
1041 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used /
1042 * required for pDriverDirectory
1044 * RETURNS
1045 * Success: TRUE and in pcbNeeded the Bytes used in pDriverDirectory
1046 * Failure: FALSE and in pcbNeeded the Bytes required for pDriverDirectory,
1047 * if cbBuf is too small
1049 * Native Values returned in pDriverDirectory on Success:
1050 *| NT(Windows NT x86): "%winsysdir%\\spool\\DRIVERS\\w32x86"
1051 *| NT(Windows 4.0): "%winsysdir%\\spool\\DRIVERS\\win40"
1052 *| win9x(Windows 4.0): "%winsysdir%"
1054 * "%winsysdir%" is the Value from GetSystemDirectoryW()
1057 static BOOL WINAPI fpGetPrinterDriverDirectory(LPWSTR pName, LPWSTR pEnvironment,
1058 DWORD Level, LPBYTE pDriverDirectory, DWORD cbBuf, LPDWORD pcbNeeded)
1060 DWORD needed;
1061 const printenv_t * env;
1063 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName),
1064 debugstr_w(pEnvironment), Level, pDriverDirectory, cbBuf, pcbNeeded);
1066 if (pName != NULL && pName[0]) {
1067 FIXME("server %s not supported\n", debugstr_w(pName));
1068 SetLastError(ERROR_INVALID_PARAMETER);
1069 return FALSE;
1072 env = validate_envW(pEnvironment);
1073 if (!env) return FALSE; /* pEnvironment invalid or unsupported */
1076 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
1077 needed = GetSystemDirectoryW(NULL, 0);
1078 /* add the Size for the Subdirectories */
1079 needed += lstrlenW(spooldriversW);
1080 needed += lstrlenW(env->subdir);
1081 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
1083 *pcbNeeded = needed;
1085 if (needed > cbBuf) {
1086 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1087 return FALSE;
1090 if (pDriverDirectory == NULL) {
1091 /* ERROR_INVALID_USER_BUFFER is NT, ERROR_INVALID_PARAMETER is win9x */
1092 SetLastError(ERROR_INVALID_USER_BUFFER);
1093 return FALSE;
1096 GetSystemDirectoryW((LPWSTR) pDriverDirectory, cbBuf/sizeof(WCHAR));
1097 /* add the Subdirectories */
1098 lstrcatW((LPWSTR) pDriverDirectory, spooldriversW);
1099 lstrcatW((LPWSTR) pDriverDirectory, env->subdir);
1101 TRACE("=> %s\n", debugstr_w((LPWSTR) pDriverDirectory));
1102 return TRUE;
1105 /******************************************************************
1106 * driver_load [internal]
1108 * load a driver user interface dll
1110 * On failure, NULL is returned
1114 static HMODULE driver_load(const printenv_t * env, LPWSTR dllname)
1116 WCHAR fullname[MAX_PATH];
1117 HMODULE hui;
1118 DWORD len;
1120 TRACE("(%p, %s)\n", env, debugstr_w(dllname));
1122 /* build the driverdir */
1123 len = sizeof(fullname) -
1124 (lstrlenW(env->versionsubdir) + 1 + lstrlenW(dllname) + 1) * sizeof(WCHAR);
1126 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1127 (LPBYTE) fullname, len, &len)) {
1128 /* Should never Fail */
1129 SetLastError(ERROR_BUFFER_OVERFLOW);
1130 return NULL;
1133 lstrcatW(fullname, env->versionsubdir);
1134 lstrcatW(fullname, backslashW);
1135 lstrcatW(fullname, dllname);
1137 hui = LoadLibraryW(fullname);
1138 TRACE("%p: LoadLibrary(%s) %d\n", hui, debugstr_w(fullname), GetLastError());
1140 return hui;
1143 /******************************************************************
1144 * printer_free
1145 * free the data pointer of an opened printer
1147 static VOID printer_free(printer_t * printer)
1149 if (printer->hXcv)
1150 printer->pm->monitor->pfnXcvClosePort(printer->hXcv);
1152 monitor_unload(printer->pm);
1154 heap_free(printer->printername);
1155 heap_free(printer->name);
1156 heap_free(printer);
1159 /******************************************************************
1160 * printer_alloc_handle
1161 * alloc a printer handle and remember the data pointer in the printer handle table
1164 static HANDLE printer_alloc_handle(LPCWSTR name, LPPRINTER_DEFAULTSW pDefault)
1166 WCHAR servername[MAX_COMPUTERNAME_LENGTH + 1];
1167 printer_t *printer = NULL;
1168 LPCWSTR printername;
1169 HKEY hkeyPrinters;
1170 HKEY hkeyPrinter;
1171 DWORD len;
1173 if (copy_servername_from_name(name, servername)) {
1174 FIXME("server %s not supported\n", debugstr_w(servername));
1175 SetLastError(ERROR_INVALID_PRINTER_NAME);
1176 return NULL;
1179 printername = get_basename_from_name(name);
1180 if (name != printername) TRACE("converted %s to %s\n", debugstr_w(name), debugstr_w(printername));
1182 /* an empty printername is invalid */
1183 if (printername && (!printername[0])) {
1184 SetLastError(ERROR_INVALID_PARAMETER);
1185 return NULL;
1188 printer = heap_alloc_zero(sizeof(printer_t));
1189 if (!printer) goto end;
1191 /* clone the base name. This is NULL for the printserver */
1192 printer->printername = strdupW(printername);
1194 /* clone the full name */
1195 printer->name = strdupW(name);
1196 if (name && (!printer->name)) {
1197 printer_free(printer);
1198 printer = NULL;
1200 if (printername) {
1201 len = sizeof(XcvMonitorW)/sizeof(WCHAR) - 1;
1202 if (strncmpW(printername, XcvMonitorW, len) == 0) {
1203 /* OpenPrinter(",XcvMonitor ", ...) detected */
1204 TRACE(",XcvMonitor: %s\n", debugstr_w(&printername[len]));
1205 printer->pm = monitor_load(&printername[len], NULL);
1206 if (printer->pm == NULL) {
1207 printer_free(printer);
1208 SetLastError(ERROR_UNKNOWN_PORT);
1209 printer = NULL;
1210 goto end;
1213 else
1215 len = sizeof(XcvPortW)/sizeof(WCHAR) - 1;
1216 if (strncmpW( printername, XcvPortW, len) == 0) {
1217 /* OpenPrinter(",XcvPort ", ...) detected */
1218 TRACE(",XcvPort: %s\n", debugstr_w(&printername[len]));
1219 printer->pm = monitor_load_by_port(&printername[len]);
1220 if (printer->pm == NULL) {
1221 printer_free(printer);
1222 SetLastError(ERROR_UNKNOWN_PORT);
1223 printer = NULL;
1224 goto end;
1229 if (printer->pm) {
1230 if ((printer->pm->monitor) && (printer->pm->monitor->pfnXcvOpenPort)) {
1231 printer->pm->monitor->pfnXcvOpenPort(&printername[len],
1232 pDefault ? pDefault->DesiredAccess : 0,
1233 &printer->hXcv);
1235 if (printer->hXcv == NULL) {
1236 printer_free(printer);
1237 SetLastError(ERROR_INVALID_PARAMETER);
1238 printer = NULL;
1239 goto end;
1242 else
1244 /* Does the Printer exist? */
1245 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, printersW, &hkeyPrinters) != ERROR_SUCCESS) {
1246 ERR("Can't create Printers key\n");
1247 printer_free(printer);
1248 SetLastError(ERROR_INVALID_PRINTER_NAME);
1249 printer = NULL;
1250 goto end;
1252 if (RegOpenKeyW(hkeyPrinters, printername, &hkeyPrinter) != ERROR_SUCCESS) {
1253 WARN("Printer not found in Registry: %s\n", debugstr_w(printername));
1254 RegCloseKey(hkeyPrinters);
1255 printer_free(printer);
1256 SetLastError(ERROR_INVALID_PRINTER_NAME);
1257 printer = NULL;
1258 goto end;
1260 RegCloseKey(hkeyPrinter);
1261 RegCloseKey(hkeyPrinters);
1264 else
1266 TRACE("using the local printserver\n");
1269 end:
1271 TRACE("==> %p\n", printer);
1272 return (HANDLE)printer;
1275 static inline WCHAR *get_file_part( WCHAR *name )
1277 WCHAR *ptr = strrchrW( name, '\\' );
1278 if (ptr) return ptr + 1;
1279 return name;
1282 /******************************************************************************
1283 * myAddPrinterDriverEx [internal]
1285 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1286 * and a special mode with lazy error checking.
1289 static BOOL myAddPrinterDriverEx(DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags, BOOL lazy)
1291 const printenv_t *env;
1292 apd_data_t apd;
1293 DRIVER_INFO_8W di;
1294 BOOL (WINAPI *pDrvDriverEvent)(DWORD, DWORD, LPBYTE, LPARAM);
1295 HMODULE hui;
1296 WCHAR *file;
1297 HKEY hroot;
1298 HKEY hdrv;
1299 DWORD disposition;
1300 DWORD len;
1301 LONG lres;
1302 BOOL res;
1304 /* we need to set all entries in the Registry, independent from the Level of
1305 DRIVER_INFO, that the caller supplied */
1307 ZeroMemory(&di, sizeof(di));
1308 if (pDriverInfo && (level < (sizeof(di_sizeof) / sizeof(di_sizeof[0])))) {
1309 memcpy(&di, pDriverInfo, di_sizeof[level]);
1312 /* dump the most used infos */
1313 TRACE("%p: .cVersion : 0x%x/%d\n", pDriverInfo, di.cVersion, di.cVersion);
1314 TRACE("%p: .pName : %s\n", di.pName, debugstr_w(di.pName));
1315 TRACE("%p: .pEnvironment: %s\n", di.pEnvironment, debugstr_w(di.pEnvironment));
1316 TRACE("%p: .pDriverPath : %s\n", di.pDriverPath, debugstr_w(di.pDriverPath));
1317 TRACE("%p: .pDataFile : %s\n", di.pDataFile, debugstr_w(di.pDataFile));
1318 TRACE("%p: .pConfigFile : %s\n", di.pConfigFile, debugstr_w(di.pConfigFile));
1319 TRACE("%p: .pHelpFile : %s\n", di.pHelpFile, debugstr_w(di.pHelpFile));
1320 /* dump only the first of the additional Files */
1321 TRACE("%p: .pDependentFiles: %s\n", di.pDependentFiles, debugstr_w(di.pDependentFiles));
1324 /* check environment */
1325 env = validate_envW(di.pEnvironment);
1326 if (env == NULL) return FALSE; /* ERROR_INVALID_ENVIRONMENT */
1328 /* fill the copy-data / get the driverdir */
1329 len = sizeof(apd.src) - sizeof(version3_subdirW) - sizeof(WCHAR);
1330 if (!fpGetPrinterDriverDirectory(NULL, (LPWSTR) env->envname, 1,
1331 (LPBYTE) apd.src, len, &len)) {
1332 /* Should never Fail */
1333 return FALSE;
1335 memcpy(apd.dst, apd.src, len);
1336 lstrcatW(apd.src, backslashW);
1337 apd.srclen = lstrlenW(apd.src);
1338 lstrcatW(apd.dst, env->versionsubdir);
1339 lstrcatW(apd.dst, backslashW);
1340 apd.dstlen = lstrlenW(apd.dst);
1341 apd.copyflags = dwFileCopyFlags;
1342 apd.lazy = lazy;
1343 CreateDirectoryW(apd.src, NULL);
1344 CreateDirectoryW(apd.dst, NULL);
1346 hroot = open_driver_reg(env->envname);
1347 if (!hroot) {
1348 ERR("Can't create Drivers key\n");
1349 return FALSE;
1352 /* Fill the Registry for the Driver */
1353 if ((lres = RegCreateKeyExW(hroot, di.pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1354 KEY_WRITE | KEY_QUERY_VALUE, NULL,
1355 &hdrv, &disposition)) != ERROR_SUCCESS) {
1357 ERR("can't create driver %s: %u\n", debugstr_w(di.pName), lres);
1358 RegCloseKey(hroot);
1359 SetLastError(lres);
1360 return FALSE;
1362 RegCloseKey(hroot);
1364 /* Verified with the Adobe PS Driver, that w2k does not use di.Version */
1365 RegSetValueExW(hdrv, versionW, 0, REG_DWORD, (const BYTE*) &env->driverversion,
1366 sizeof(DWORD));
1368 file = get_file_part( di.pDriverPath );
1369 RegSetValueExW( hdrv, driverW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1370 apd_copyfile( di.pDriverPath, file, &apd );
1372 file = get_file_part( di.pDataFile );
1373 RegSetValueExW( hdrv, data_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1374 apd_copyfile( di.pDataFile, file, &apd );
1376 file = get_file_part( di.pConfigFile );
1377 RegSetValueExW( hdrv, configuration_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1378 apd_copyfile( di.pConfigFile, file, &apd );
1380 /* settings for level 3 */
1381 if (di.pHelpFile)
1383 file = get_file_part( di.pHelpFile );
1384 RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (LPBYTE)file, (strlenW( file ) + 1) * sizeof(WCHAR) );
1385 apd_copyfile( di.pHelpFile, file, &apd );
1387 else
1388 RegSetValueExW( hdrv, help_fileW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW) );
1390 if (di.pDependentFiles && *di.pDependentFiles)
1392 WCHAR *reg, *reg_ptr, *in_ptr;
1393 reg = reg_ptr = HeapAlloc( GetProcessHeap(), 0, multi_sz_lenW( di.pDependentFiles ) );
1395 for (in_ptr = di.pDependentFiles; *in_ptr; in_ptr += strlenW( in_ptr ) + 1)
1397 file = get_file_part( in_ptr );
1398 len = strlenW( file ) + 1;
1399 memcpy( reg_ptr, file, len * sizeof(WCHAR) );
1400 reg_ptr += len;
1401 apd_copyfile( in_ptr, file, &apd );
1403 *reg_ptr = 0;
1405 RegSetValueExW( hdrv, dependent_filesW, 0, REG_MULTI_SZ, (LPBYTE)reg, (reg_ptr - reg + 1) * sizeof(WCHAR) );
1406 HeapFree( GetProcessHeap(), 0, reg );
1408 else
1409 RegSetValueExW(hdrv, dependent_filesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1411 /* The language-Monitor was already copied by the caller to "%SystemRoot%\system32" */
1412 if (di.pMonitorName)
1413 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (LPBYTE) di.pMonitorName,
1414 (lstrlenW(di.pMonitorName)+1)* sizeof(WCHAR));
1415 else
1416 RegSetValueExW(hdrv, monitorW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1418 if (di.pDefaultDataType)
1419 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (LPBYTE) di.pDefaultDataType,
1420 (lstrlenW(di.pDefaultDataType)+1)* sizeof(WCHAR));
1421 else
1422 RegSetValueExW(hdrv, datatypeW, 0, REG_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1424 /* settings for level 4 */
1425 if (di.pszzPreviousNames)
1426 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (LPBYTE) di.pszzPreviousNames,
1427 multi_sz_lenW(di.pszzPreviousNames));
1428 else
1429 RegSetValueExW(hdrv, previous_namesW, 0, REG_MULTI_SZ, (const BYTE*)emptyW, sizeof(emptyW));
1431 if (level > 5) TRACE("level %u for Driver %s is incomplete\n", level, debugstr_w(di.pName));
1433 RegCloseKey(hdrv);
1434 hui = driver_load(env, di.pConfigFile);
1435 pDrvDriverEvent = (void *)GetProcAddress(hui, "DrvDriverEvent");
1436 if (hui && pDrvDriverEvent) {
1438 /* Support for DrvDriverEvent is optional */
1439 TRACE("DRIVER_EVENT_INITIALIZE for %s (%s)\n", debugstr_w(di.pName), debugstr_w(di.pConfigFile));
1440 /* MSDN: level for DRIVER_INFO is 1 to 3 */
1441 res = pDrvDriverEvent(DRIVER_EVENT_INITIALIZE, 3, (LPBYTE) &di, 0);
1442 TRACE("got %d from DRIVER_EVENT_INITIALIZE\n", res);
1444 FreeLibrary(hui);
1446 TRACE("=> TRUE with %u\n", GetLastError());
1447 return TRUE;
1451 /******************************************************************************
1452 * fpAddMonitor [exported through PRINTPROVIDOR]
1454 * Install a Printmonitor
1456 * PARAMS
1457 * pName [I] Servername or NULL (local Computer)
1458 * Level [I] Structure-Level (Must be 2)
1459 * pMonitors [I] PTR to MONITOR_INFO_2
1461 * RETURNS
1462 * Success: TRUE
1463 * Failure: FALSE
1465 * NOTES
1466 * All Files for the Monitor must already be copied to %winsysdir% ("%SystemRoot%\system32")
1469 static BOOL WINAPI fpAddMonitor(LPWSTR pName, DWORD Level, LPBYTE pMonitors)
1471 monitor_t * pm = NULL;
1472 LPMONITOR_INFO_2W mi2w;
1473 HKEY hroot = NULL;
1474 HKEY hentry = NULL;
1475 DWORD disposition;
1476 BOOL res = FALSE;
1478 mi2w = (LPMONITOR_INFO_2W) pMonitors;
1479 TRACE("(%s, %d, %p): %s %s %s\n", debugstr_w(pName), Level, pMonitors,
1480 debugstr_w(mi2w ? mi2w->pName : NULL),
1481 debugstr_w(mi2w ? mi2w->pEnvironment : NULL),
1482 debugstr_w(mi2w ? mi2w->pDLLName : NULL));
1484 if (copy_servername_from_name(pName, NULL)) {
1485 FIXME("server %s not supported\n", debugstr_w(pName));
1486 SetLastError(ERROR_ACCESS_DENIED);
1487 return FALSE;
1490 if (!mi2w->pName || (! mi2w->pName[0])) {
1491 WARN("pName not valid : %s\n", debugstr_w(mi2w->pName));
1492 SetLastError(ERROR_INVALID_PARAMETER);
1493 return FALSE;
1495 if (!mi2w->pEnvironment || lstrcmpW(mi2w->pEnvironment, x86_envnameW)) {
1496 WARN("Environment %s requested (we support only %s)\n",
1497 debugstr_w(mi2w->pEnvironment), debugstr_w(x86_envnameW));
1498 SetLastError(ERROR_INVALID_ENVIRONMENT);
1499 return FALSE;
1502 if (!mi2w->pDLLName || (! mi2w->pDLLName[0])) {
1503 WARN("pDLLName not valid : %s\n", debugstr_w(mi2w->pDLLName));
1504 SetLastError(ERROR_INVALID_PARAMETER);
1505 return FALSE;
1508 /* Load and initialize the monitor. SetLastError() is called on failure */
1509 if ((pm = monitor_load(mi2w->pName, mi2w->pDLLName)) == NULL) {
1510 return FALSE;
1512 monitor_unload(pm);
1514 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1515 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1516 return FALSE;
1519 if (RegCreateKeyExW(hroot, mi2w->pName, 0, NULL, REG_OPTION_NON_VOLATILE,
1520 KEY_WRITE | KEY_QUERY_VALUE, NULL, &hentry,
1521 &disposition) == ERROR_SUCCESS) {
1523 /* Some installers set options for the port before calling AddMonitor.
1524 We query the "Driver" entry to verify that the monitor is installed,
1525 before we return an error.
1526 When a user installs two print monitors at the same time with the
1527 same name, a race condition is possible but silently ignored. */
1529 DWORD namesize = 0;
1531 if ((disposition == REG_OPENED_EXISTING_KEY) &&
1532 (RegQueryValueExW(hentry, driverW, NULL, NULL, NULL,
1533 &namesize) == ERROR_SUCCESS)) {
1534 TRACE("monitor %s already exists\n", debugstr_w(mi2w->pName));
1535 /* 9x use ERROR_ALREADY_EXISTS */
1536 SetLastError(ERROR_PRINT_MONITOR_ALREADY_INSTALLED);
1538 else
1540 INT len;
1541 len = (lstrlenW(mi2w->pDLLName) +1) * sizeof(WCHAR);
1542 res = (RegSetValueExW(hentry, driverW, 0, REG_SZ,
1543 (LPBYTE) mi2w->pDLLName, len) == ERROR_SUCCESS);
1545 RegCloseKey(hentry);
1548 RegCloseKey(hroot);
1549 return (res);
1552 /******************************************************************************
1553 * fpAddPort [exported through PRINTPROVIDOR]
1555 * Add a Port for a specific Monitor
1557 * PARAMS
1558 * pName [I] Servername or NULL (local Computer)
1559 * hWnd [I] Handle to parent Window for the Dialog-Box
1560 * pMonitorName [I] Name of the Monitor that manage the Port
1562 * RETURNS
1563 * Success: TRUE
1564 * Failure: FALSE
1567 static BOOL WINAPI fpAddPort(LPWSTR pName, HWND hWnd, LPWSTR pMonitorName)
1569 monitor_t * pm;
1570 monitor_t * pui;
1571 LONG lres;
1572 DWORD res;
1574 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pMonitorName));
1576 lres = copy_servername_from_name(pName, NULL);
1577 if (lres) {
1578 FIXME("server %s not supported\n", debugstr_w(pName));
1579 SetLastError(ERROR_INVALID_PARAMETER);
1580 return FALSE;
1583 /* an empty Monitorname is Invalid */
1584 if (!pMonitorName[0]) {
1585 SetLastError(ERROR_NOT_SUPPORTED);
1586 return FALSE;
1589 pm = monitor_load(pMonitorName, NULL);
1590 if (pm && pm->monitor && pm->monitor->pfnAddPort) {
1591 res = pm->monitor->pfnAddPort(pName, hWnd, pMonitorName);
1592 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1594 else
1596 pui = monitor_loadui(pm);
1597 if (pui && pui->monitorUI && pui->monitorUI->pfnAddPortUI) {
1598 res = pui->monitorUI->pfnAddPortUI(pName, hWnd, pMonitorName, NULL);
1599 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pui->dllname));
1601 else
1603 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1604 debugstr_w(pMonitorName), pm, debugstr_w(pm ? pm->dllname : NULL),
1605 pui, debugstr_w(pui ? pui->dllname : NULL));
1607 SetLastError(ERROR_NOT_SUPPORTED);
1608 res = FALSE;
1610 monitor_unload(pui);
1612 monitor_unload(pm);
1614 TRACE("returning %d with %u\n", res, GetLastError());
1615 return res;
1618 /******************************************************************************
1619 * fpAddPortEx [exported through PRINTPROVIDOR]
1621 * Add a Port for a specific Monitor, without presenting a user interface
1623 * PARAMS
1624 * pName [I] Servername or NULL (local Computer)
1625 * level [I] Structure-Level (1 or 2) for pBuffer
1626 * pBuffer [I] PTR to: PORT_INFO_1 or PORT_INFO_2
1627 * pMonitorName [I] Name of the Monitor that manage the Port
1629 * RETURNS
1630 * Success: TRUE
1631 * Failure: FALSE
1634 static BOOL WINAPI fpAddPortEx(LPWSTR pName, DWORD level, LPBYTE pBuffer, LPWSTR pMonitorName)
1636 PORT_INFO_2W * pi2;
1637 monitor_t * pm;
1638 DWORD lres;
1639 DWORD res;
1641 pi2 = (PORT_INFO_2W *) pBuffer;
1643 TRACE("(%s, %d, %p, %s): %s %s %s\n", debugstr_w(pName), level, pBuffer,
1644 debugstr_w(pMonitorName), debugstr_w(pi2 ? pi2->pPortName : NULL),
1645 debugstr_w(((level > 1) && pi2) ? pi2->pMonitorName : NULL),
1646 debugstr_w(((level > 1) && pi2) ? pi2->pDescription : NULL));
1648 lres = copy_servername_from_name(pName, NULL);
1649 if (lres) {
1650 FIXME("server %s not supported\n", debugstr_w(pName));
1651 SetLastError(ERROR_INVALID_PARAMETER);
1652 return FALSE;
1655 if ((level < 1) || (level > 2)) {
1656 SetLastError(ERROR_INVALID_LEVEL);
1657 return FALSE;
1660 if ((!pi2) || (!pMonitorName) || (!pMonitorName[0])) {
1661 SetLastError(ERROR_INVALID_PARAMETER);
1662 return FALSE;
1665 /* load the Monitor */
1666 pm = monitor_load(pMonitorName, NULL);
1667 if (pm && pm->monitor && pm->monitor->pfnAddPortEx) {
1668 res = pm->monitor->pfnAddPortEx(pName, level, pBuffer, pMonitorName);
1669 TRACE("got %d with %u (%s)\n", res, GetLastError(), debugstr_w(pm->dllname));
1671 else
1673 FIXME("not implemented for %s (monitor %p: %s)\n",
1674 debugstr_w(pMonitorName), pm, pm ? debugstr_w(pm->dllname) : "(null)");
1675 SetLastError(ERROR_INVALID_PARAMETER);
1676 res = FALSE;
1678 monitor_unload(pm);
1679 return res;
1682 /******************************************************************************
1683 * fpAddPrinterDriverEx [exported through PRINTPROVIDOR]
1685 * Install a Printer Driver with the Option to upgrade / downgrade the Files
1687 * PARAMS
1688 * pName [I] Servername or NULL (local Computer)
1689 * level [I] Level for the supplied DRIVER_INFO_*W struct
1690 * pDriverInfo [I] PTR to DRIVER_INFO_*W struct with the Driver Parameter
1691 * dwFileCopyFlags [I] How to Copy / Upgrade / Downgrade the needed Files
1693 * RESULTS
1694 * Success: TRUE
1695 * Failure: FALSE
1698 static BOOL WINAPI fpAddPrinterDriverEx(LPWSTR pName, DWORD level, LPBYTE pDriverInfo, DWORD dwFileCopyFlags)
1700 LONG lres;
1702 TRACE("(%s, %d, %p, 0x%x)\n", debugstr_w(pName), level, pDriverInfo, dwFileCopyFlags);
1703 lres = copy_servername_from_name(pName, NULL);
1704 if (lres) {
1705 FIXME("server %s not supported\n", debugstr_w(pName));
1706 SetLastError(ERROR_ACCESS_DENIED);
1707 return FALSE;
1710 if ((dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY) != APD_COPY_ALL_FILES) {
1711 TRACE("Flags 0x%x ignored (using APD_COPY_ALL_FILES)\n", dwFileCopyFlags & ~APD_COPY_FROM_DIRECTORY);
1714 return myAddPrinterDriverEx(level, pDriverInfo, dwFileCopyFlags, TRUE);
1717 /******************************************************************************
1718 * fpClosePrinter [exported through PRINTPROVIDOR]
1720 * Close a printer handle and free associated resources
1722 * PARAMS
1723 * hPrinter [I] Printerhandle to close
1725 * RESULTS
1726 * Success: TRUE
1727 * Failure: FALSE
1730 static BOOL WINAPI fpClosePrinter(HANDLE hPrinter)
1732 printer_t *printer = (printer_t *) hPrinter;
1734 TRACE("(%p)\n", hPrinter);
1736 if (printer) {
1737 printer_free(printer);
1738 return TRUE;
1740 return FALSE;
1743 /******************************************************************************
1744 * fpConfigurePort [exported through PRINTPROVIDOR]
1746 * Display the Configuration-Dialog for a specific Port
1748 * PARAMS
1749 * pName [I] Servername or NULL (local Computer)
1750 * hWnd [I] Handle to parent Window for the Dialog-Box
1751 * pPortName [I] Name of the Port, that should be configured
1753 * RETURNS
1754 * Success: TRUE
1755 * Failure: FALSE
1758 static BOOL WINAPI fpConfigurePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1760 monitor_t * pm;
1761 monitor_t * pui;
1762 LONG lres;
1763 DWORD res;
1765 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1767 lres = copy_servername_from_name(pName, NULL);
1768 if (lres) {
1769 FIXME("server %s not supported\n", debugstr_w(pName));
1770 SetLastError(ERROR_INVALID_NAME);
1771 return FALSE;
1774 /* an empty Portname is Invalid, but can popup a Dialog */
1775 if (!pPortName[0]) {
1776 SetLastError(ERROR_NOT_SUPPORTED);
1777 return FALSE;
1780 pm = monitor_load_by_port(pPortName);
1781 if (pm && pm->monitor && pm->monitor->pfnConfigurePort) {
1782 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1783 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1784 res = pm->monitor->pfnConfigurePort(pName, hWnd, pPortName);
1785 TRACE("got %d with %u\n", res, GetLastError());
1787 else
1789 pui = monitor_loadui(pm);
1790 if (pui && pui->monitorUI && pui->monitorUI->pfnConfigurePortUI) {
1791 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1792 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1793 res = pui->monitorUI->pfnConfigurePortUI(pName, hWnd, pPortName);
1794 TRACE("got %d with %u\n", res, GetLastError());
1796 else
1798 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1799 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1800 pui, debugstr_w(pui ? pui->dllname : NULL));
1802 SetLastError(ERROR_NOT_SUPPORTED);
1803 res = FALSE;
1805 monitor_unload(pui);
1807 monitor_unload(pm);
1809 TRACE("returning %d with %u\n", res, GetLastError());
1810 return res;
1813 /******************************************************************
1814 * fpDeleteMonitor [exported through PRINTPROVIDOR]
1816 * Delete a specific Printmonitor from a Printing-Environment
1818 * PARAMS
1819 * pName [I] Servername or NULL (local Computer)
1820 * pEnvironment [I] Printing-Environment of the Monitor or NULL (Default)
1821 * pMonitorName [I] Name of the Monitor, that should be deleted
1823 * RETURNS
1824 * Success: TRUE
1825 * Failure: FALSE
1827 * NOTES
1828 * pEnvironment is ignored in Windows for the local Computer.
1832 static BOOL WINAPI fpDeleteMonitor(LPWSTR pName, LPWSTR pEnvironment, LPWSTR pMonitorName)
1834 HKEY hroot = NULL;
1835 LONG lres;
1837 TRACE("(%s, %s, %s)\n",debugstr_w(pName),debugstr_w(pEnvironment),
1838 debugstr_w(pMonitorName));
1840 lres = copy_servername_from_name(pName, NULL);
1841 if (lres) {
1842 FIXME("server %s not supported\n", debugstr_w(pName));
1843 SetLastError(ERROR_INVALID_NAME);
1844 return FALSE;
1847 /* pEnvironment is ignored in Windows for the local Computer */
1848 if (!pMonitorName || !pMonitorName[0]) {
1849 TRACE("pMonitorName %s is invalid\n", debugstr_w(pMonitorName));
1850 SetLastError(ERROR_INVALID_PARAMETER);
1851 return FALSE;
1854 if(RegCreateKeyW(HKEY_LOCAL_MACHINE, monitorsW, &hroot) != ERROR_SUCCESS) {
1855 ERR("unable to create key %s\n", debugstr_w(monitorsW));
1856 return FALSE;
1859 if(RegDeleteTreeW(hroot, pMonitorName) == ERROR_SUCCESS) {
1860 TRACE("%s deleted\n", debugstr_w(pMonitorName));
1861 RegCloseKey(hroot);
1862 return TRUE;
1865 TRACE("%s does not exist\n", debugstr_w(pMonitorName));
1866 RegCloseKey(hroot);
1868 /* NT: ERROR_UNKNOWN_PRINT_MONITOR (3000), 9x: ERROR_INVALID_PARAMETER (87) */
1869 SetLastError(ERROR_UNKNOWN_PRINT_MONITOR);
1870 return FALSE;
1873 /*****************************************************************************
1874 * fpDeletePort [exported through PRINTPROVIDOR]
1876 * Delete a specific Port
1878 * PARAMS
1879 * pName [I] Servername or NULL (local Computer)
1880 * hWnd [I] Handle to parent Window for the Dialog-Box
1881 * pPortName [I] Name of the Port, that should be deleted
1883 * RETURNS
1884 * Success: TRUE
1885 * Failure: FALSE
1888 static BOOL WINAPI fpDeletePort(LPWSTR pName, HWND hWnd, LPWSTR pPortName)
1890 monitor_t * pm;
1891 monitor_t * pui;
1892 LONG lres;
1893 DWORD res;
1895 TRACE("(%s, %p, %s)\n", debugstr_w(pName), hWnd, debugstr_w(pPortName));
1897 lres = copy_servername_from_name(pName, NULL);
1898 if (lres) {
1899 FIXME("server %s not supported\n", debugstr_w(pName));
1900 SetLastError(ERROR_INVALID_NAME);
1901 return FALSE;
1904 /* an empty Portname is Invalid */
1905 if (!pPortName[0]) {
1906 SetLastError(ERROR_NOT_SUPPORTED);
1907 return FALSE;
1910 pm = monitor_load_by_port(pPortName);
1911 if (pm && pm->monitor && pm->monitor->pfnDeletePort) {
1912 TRACE("use %s for %s (monitor %p: %s)\n", debugstr_w(pm->name),
1913 debugstr_w(pPortName), pm, debugstr_w(pm->dllname));
1914 res = pm->monitor->pfnDeletePort(pName, hWnd, pPortName);
1915 TRACE("got %d with %u\n", res, GetLastError());
1917 else
1919 pui = monitor_loadui(pm);
1920 if (pui && pui->monitorUI && pui->monitorUI->pfnDeletePortUI) {
1921 TRACE("use %s for %s (monitorui %p: %s)\n", debugstr_w(pui->name),
1922 debugstr_w(pPortName), pui, debugstr_w(pui->dllname));
1923 res = pui->monitorUI->pfnDeletePortUI(pName, hWnd, pPortName);
1924 TRACE("got %d with %u\n", res, GetLastError());
1926 else
1928 FIXME("not implemented for %s (monitor %p: %s / monitorui %p: %s)\n",
1929 debugstr_w(pPortName), pm, debugstr_w(pm ? pm->dllname : NULL),
1930 pui, debugstr_w(pui ? pui->dllname : NULL));
1932 SetLastError(ERROR_NOT_SUPPORTED);
1933 res = FALSE;
1935 monitor_unload(pui);
1937 monitor_unload(pm);
1939 TRACE("returning %d with %u\n", res, GetLastError());
1940 return res;
1943 /*****************************************************************************
1944 * fpEnumMonitors [exported through PRINTPROVIDOR]
1946 * Enumerate available Port-Monitors
1948 * PARAMS
1949 * pName [I] Servername or NULL (local Computer)
1950 * Level [I] Structure-Level (1:Win9x+NT or 2:NT only)
1951 * pMonitors [O] PTR to Buffer that receives the Result
1952 * cbBuf [I] Size of Buffer at pMonitors
1953 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pMonitors
1954 * pcReturned [O] PTR to DWORD that receives the number of Monitors in pMonitors
1956 * RETURNS
1957 * Success: TRUE
1958 * Failure: FALSE and in pcbNeeded the Bytes required for pMonitors, if cbBuf is too small
1960 * NOTES
1961 * Windows reads the Registry once and cache the Results.
1964 static BOOL WINAPI fpEnumMonitors(LPWSTR pName, DWORD Level, LPBYTE pMonitors, DWORD cbBuf,
1965 LPDWORD pcbNeeded, LPDWORD pcReturned)
1967 DWORD numentries = 0;
1968 DWORD needed = 0;
1969 LONG lres;
1970 BOOL res = FALSE;
1972 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pMonitors,
1973 cbBuf, pcbNeeded, pcReturned);
1975 lres = copy_servername_from_name(pName, NULL);
1976 if (lres) {
1977 FIXME("server %s not supported\n", debugstr_w(pName));
1978 SetLastError(ERROR_INVALID_NAME);
1979 goto em_cleanup;
1982 if (!Level || (Level > 2)) {
1983 WARN("level (%d) is ignored in win9x\n", Level);
1984 SetLastError(ERROR_INVALID_LEVEL);
1985 return FALSE;
1988 /* Scan all Monitor-Keys */
1989 numentries = 0;
1990 needed = get_local_monitors(Level, NULL, 0, &numentries);
1992 /* we calculated the needed buffersize. now do more error-checks */
1993 if (cbBuf < needed) {
1994 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1995 goto em_cleanup;
1998 /* fill the Buffer with the Monitor-Keys */
1999 needed = get_local_monitors(Level, pMonitors, cbBuf, &numentries);
2000 res = TRUE;
2002 em_cleanup:
2003 if (pcbNeeded) *pcbNeeded = needed;
2004 if (pcReturned) *pcReturned = numentries;
2006 TRACE("returning %d with %d (%d byte for %d entries)\n",
2007 res, GetLastError(), needed, numentries);
2009 return (res);
2012 /******************************************************************************
2013 * fpEnumPorts [exported through PRINTPROVIDOR]
2015 * Enumerate available Ports
2017 * PARAMS
2018 * pName [I] Servername or NULL (local Computer)
2019 * Level [I] Structure-Level (1 or 2)
2020 * pPorts [O] PTR to Buffer that receives the Result
2021 * cbBuf [I] Size of Buffer at pPorts
2022 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPorts
2023 * pcReturned [O] PTR to DWORD that receives the number of Ports in pPorts
2025 * RETURNS
2026 * Success: TRUE
2027 * Failure: FALSE and in pcbNeeded the Bytes required for pPorts, if cbBuf is too small
2030 static BOOL WINAPI fpEnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
2031 LPDWORD pcbNeeded, LPDWORD pcReturned)
2033 DWORD needed = 0;
2034 DWORD numentries = 0;
2035 LONG lres;
2036 BOOL res = FALSE;
2038 TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
2039 cbBuf, pcbNeeded, pcReturned);
2041 lres = copy_servername_from_name(pName, NULL);
2042 if (lres) {
2043 FIXME("server %s not supported\n", debugstr_w(pName));
2044 SetLastError(ERROR_INVALID_NAME);
2045 goto emP_cleanup;
2048 if (!Level || (Level > 2)) {
2049 SetLastError(ERROR_INVALID_LEVEL);
2050 goto emP_cleanup;
2053 if (!pcbNeeded || (!pPorts && (cbBuf > 0))) {
2054 SetLastError(RPC_X_NULL_REF_POINTER);
2055 goto emP_cleanup;
2058 EnterCriticalSection(&monitor_handles_cs);
2059 monitor_loadall();
2061 /* Scan all local Ports */
2062 numentries = 0;
2063 needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
2065 /* we calculated the needed buffersize. now do the error-checks */
2066 if (cbBuf < needed) {
2067 monitor_unloadall();
2068 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2069 goto emP_cleanup_cs;
2071 else if (!pPorts || !pcReturned) {
2072 monitor_unloadall();
2073 SetLastError(RPC_X_NULL_REF_POINTER);
2074 goto emP_cleanup_cs;
2077 /* Fill the Buffer */
2078 needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
2079 res = TRUE;
2080 monitor_unloadall();
2082 emP_cleanup_cs:
2083 LeaveCriticalSection(&monitor_handles_cs);
2085 emP_cleanup:
2086 if (pcbNeeded) *pcbNeeded = needed;
2087 if (pcReturned) *pcReturned = (res) ? numentries : 0;
2089 TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
2090 (res), GetLastError(), needed, (res) ? numentries : 0, numentries);
2092 return (res);
2095 /*****************************************************************************
2096 * fpEnumPrintProcessors [exported through PRINTPROVIDOR]
2098 * Enumerate available Print Processors
2100 * PARAMS
2101 * pName [I] Servername or NULL (local Computer)
2102 * pEnvironment [I] Printing-Environment or NULL (Default)
2103 * Level [I] Structure-Level (Only 1 is allowed)
2104 * pPPInfo [O] PTR to Buffer that receives the Result
2105 * cbBuf [I] Size of Buffer at pMonitors
2106 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2107 * pcReturned [O] PTR to DWORD that receives the number of Print Processors in pPPInfo
2109 * RETURNS
2110 * Success: TRUE
2111 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2114 static BOOL WINAPI fpEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level,
2115 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
2117 const printenv_t * env;
2118 LPWSTR regpathW = NULL;
2119 DWORD numentries = 0;
2120 DWORD needed = 0;
2121 LONG lres;
2122 BOOL res = FALSE;
2124 TRACE("(%s, %s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2125 Level, pPPInfo, cbBuf, pcbNeeded, pcReturned);
2127 lres = copy_servername_from_name(pName, NULL);
2128 if (lres) {
2129 FIXME("server %s not supported\n", debugstr_w(pName));
2130 SetLastError(ERROR_INVALID_NAME);
2131 goto epp_cleanup;
2134 if (Level != 1) {
2135 SetLastError(ERROR_INVALID_LEVEL);
2136 goto epp_cleanup;
2139 env = validate_envW(pEnvironment);
2140 if (!env)
2141 goto epp_cleanup; /* ERROR_INVALID_ENVIRONMENT */
2143 regpathW = heap_alloc(sizeof(fmt_printprocessorsW) +
2144 (lstrlenW(env->envname) * sizeof(WCHAR)));
2146 if (!regpathW)
2147 goto epp_cleanup;
2149 wsprintfW(regpathW, fmt_printprocessorsW, env->envname);
2151 /* Scan all Printprocessor-Keys */
2152 numentries = 0;
2153 needed = get_local_printprocessors(regpathW, NULL, 0, &numentries);
2155 /* we calculated the needed buffersize. now do more error-checks */
2156 if (cbBuf < needed) {
2157 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2158 goto epp_cleanup;
2161 /* fill the Buffer with the Printprocessor Infos */
2162 needed = get_local_printprocessors(regpathW, pPPInfo, cbBuf, &numentries);
2163 res = TRUE;
2165 epp_cleanup:
2166 heap_free(regpathW);
2167 if (pcbNeeded) *pcbNeeded = needed;
2168 if (pcReturned) *pcReturned = numentries;
2170 TRACE("returning %d with %d (%d byte for %d entries)\n",
2171 res, GetLastError(), needed, numentries);
2173 return (res);
2176 /******************************************************************************
2177 * fpGetPrintProcessorDirectory [exported through PRINTPROVIDOR]
2179 * Return the PATH for the Print-Processors
2181 * PARAMS
2182 * pName [I] Servername or NULL (this computer)
2183 * pEnvironment [I] Printing-Environment or NULL (Default)
2184 * level [I] Structure-Level (must be 1)
2185 * pPPInfo [O] PTR to Buffer that receives the Result
2186 * cbBuf [I] Size of Buffer at pPPInfo
2187 * pcbNeeded [O] PTR to DWORD that receives the size in Bytes used / required for pPPInfo
2189 * RETURNS
2190 * Success: TRUE
2191 * Failure: FALSE and in pcbNeeded the Bytes required for pPPInfo, if cbBuf is too small
2193 * Native Values returned in pPPInfo on Success for this computer:
2194 *| NT(Windows x64): "%winsysdir%\\spool\\PRTPROCS\\x64"
2195 *| NT(Windows NT x86): "%winsysdir%\\spool\\PRTPROCS\\w32x86"
2196 *| NT(Windows 4.0): "%winsysdir%\\spool\\PRTPROCS\\win40"
2198 * "%winsysdir%" is the Value from GetSystemDirectoryW()
2201 static BOOL WINAPI fpGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD level,
2202 LPBYTE pPPInfo, DWORD cbBuf, LPDWORD pcbNeeded)
2204 const printenv_t * env;
2205 DWORD needed;
2206 LONG lres;
2208 TRACE("(%s, %s, %d, %p, %d, %p)\n", debugstr_w(pName), debugstr_w(pEnvironment),
2209 level, pPPInfo, cbBuf, pcbNeeded);
2211 *pcbNeeded = 0;
2212 lres = copy_servername_from_name(pName, NULL);
2213 if (lres) {
2214 FIXME("server %s not supported\n", debugstr_w(pName));
2215 SetLastError(RPC_S_SERVER_UNAVAILABLE);
2216 return FALSE;
2219 env = validate_envW(pEnvironment);
2220 if (!env)
2221 return FALSE; /* ERROR_INVALID_ENVIRONMENT */
2223 /* GetSystemDirectoryW returns number of WCHAR including the '\0' */
2224 needed = GetSystemDirectoryW(NULL, 0);
2225 /* add the Size for the Subdirectories */
2226 needed += lstrlenW(spoolprtprocsW);
2227 needed += lstrlenW(env->subdir);
2228 needed *= sizeof(WCHAR); /* return-value is size in Bytes */
2230 *pcbNeeded = needed;
2232 if (needed > cbBuf) {
2233 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2234 return FALSE;
2237 GetSystemDirectoryW((LPWSTR) pPPInfo, cbBuf/sizeof(WCHAR));
2238 /* add the Subdirectories */
2239 lstrcatW((LPWSTR) pPPInfo, spoolprtprocsW);
2240 lstrcatW((LPWSTR) pPPInfo, env->subdir);
2241 TRACE("==> %s\n", debugstr_w((LPWSTR) pPPInfo));
2242 return TRUE;
2245 /******************************************************************************
2246 * fpOpenPrinter [exported through PRINTPROVIDOR]
2248 * Open a Printer / Printserver or a Printer-Object
2250 * PARAMS
2251 * lpPrinterName [I] Name of Printserver, Printer, or Printer-Object
2252 * pPrinter [O] The resulting Handle is stored here
2253 * pDefaults [I] PTR to Default Printer Settings or NULL
2255 * RETURNS
2256 * Success: TRUE
2257 * Failure: FALSE
2259 * NOTES
2260 * lpPrinterName is one of:
2261 *| Printserver (NT only): "Servername" or NULL for the local Printserver
2262 *| Printer: "PrinterName"
2263 *| Printer-Object: "PrinterName,Job xxx"
2264 *| XcvMonitor: "Servername,XcvMonitor MonitorName"
2265 *| XcvPort: "Servername,XcvPort PortName"
2269 static BOOL WINAPI fpOpenPrinter(LPWSTR lpPrinterName, HANDLE *pPrinter,
2270 LPPRINTER_DEFAULTSW pDefaults)
2273 TRACE("(%s, %p, %p)\n", debugstr_w(lpPrinterName), pPrinter, pDefaults);
2275 *pPrinter = printer_alloc_handle(lpPrinterName, pDefaults);
2277 return (*pPrinter != 0);
2280 /******************************************************************************
2281 * fpXcvData [exported through PRINTPROVIDOR]
2283 * Execute commands in the Printmonitor DLL
2285 * PARAMS
2286 * hXcv [i] Handle from fpOpenPrinter (with XcvMonitor or XcvPort)
2287 * pszDataName [i] Name of the command to execute
2288 * pInputData [i] Buffer for extra Input Data (needed only for some commands)
2289 * cbInputData [i] Size in Bytes of Buffer at pInputData
2290 * pOutputData [o] Buffer to receive additional Data (needed only for some commands)
2291 * cbOutputData [i] Size in Bytes of Buffer at pOutputData
2292 * pcbOutputNeeded [o] PTR to receive the minimal Size in Bytes of the Buffer at pOutputData
2293 * pdwStatus [o] PTR to receive the win32 error code from the Printmonitor DLL
2295 * RETURNS
2296 * Success: TRUE
2297 * Failure: FALSE
2299 * NOTES
2300 * Returning "TRUE" does mean, that the Printmonitor DLL was called successful.
2301 * The execution of the command can still fail (check pdwStatus for ERROR_SUCCESS).
2303 * Minimal List of commands, that a Printmonitor DLL should support:
2305 *| "MonitorUI" : Return the Name of the Userinterface-DLL as WSTR in pOutputData
2306 *| "AddPort" : Add a Port
2307 *| "DeletePort": Delete a Port
2309 * Many Printmonitors support additional commands. Examples for localspl.dll:
2310 * "GetDefaultCommConfig", "SetDefaultCommConfig",
2311 * "GetTransmissionRetryTimeout", "ConfigureLPTPortCommandOK"
2314 static BOOL WINAPI fpXcvData(HANDLE hXcv, LPCWSTR pszDataName, PBYTE pInputData,
2315 DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData,
2316 PDWORD pcbOutputNeeded, PDWORD pdwStatus)
2318 printer_t *printer = (printer_t * ) hXcv;
2320 TRACE("(%p, %s, %p, %d, %p, %d, %p, %p)\n", hXcv, debugstr_w(pszDataName),
2321 pInputData, cbInputData, pOutputData,
2322 cbOutputData, pcbOutputNeeded, pdwStatus);
2324 if (!printer || (!printer->hXcv)) {
2325 SetLastError(ERROR_INVALID_HANDLE);
2326 return FALSE;
2329 if (!pcbOutputNeeded) {
2330 SetLastError(ERROR_INVALID_PARAMETER);
2331 return FALSE;
2334 if (!pszDataName || !pdwStatus || (!pOutputData && (cbOutputData > 0))) {
2335 SetLastError(RPC_X_NULL_REF_POINTER);
2336 return FALSE;
2339 *pcbOutputNeeded = 0;
2341 *pdwStatus = printer->pm->monitor->pfnXcvDataPort(printer->hXcv, pszDataName,
2342 pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded);
2344 return TRUE;
2347 /*****************************************************
2348 * setup_provider [internal]
2350 void setup_provider(void)
2352 static const PRINTPROVIDOR backend = {
2353 fpOpenPrinter,
2354 NULL, /* fpSetJob */
2355 NULL, /* fpGetJob */
2356 NULL, /* fpEnumJobs */
2357 NULL, /* fpAddPrinter */
2358 NULL, /* fpDeletePrinter */
2359 NULL, /* fpSetPrinter */
2360 NULL, /* fpGetPrinter */
2361 NULL, /* fpEnumPrinters */
2362 NULL, /* fpAddPrinterDriver */
2363 NULL, /* fpEnumPrinterDrivers */
2364 NULL, /* fpGetPrinterDriver */
2365 fpGetPrinterDriverDirectory,
2366 NULL, /* fpDeletePrinterDriver */
2367 NULL, /* fpAddPrintProcessor */
2368 fpEnumPrintProcessors,
2369 fpGetPrintProcessorDirectory,
2370 NULL, /* fpDeletePrintProcessor */
2371 NULL, /* fpEnumPrintProcessorDatatypes */
2372 NULL, /* fpStartDocPrinter */
2373 NULL, /* fpStartPagePrinter */
2374 NULL, /* fpWritePrinter */
2375 NULL, /* fpEndPagePrinter */
2376 NULL, /* fpAbortPrinter */
2377 NULL, /* fpReadPrinter */
2378 NULL, /* fpEndDocPrinter */
2379 NULL, /* fpAddJob */
2380 NULL, /* fpScheduleJob */
2381 NULL, /* fpGetPrinterData */
2382 NULL, /* fpSetPrinterData */
2383 NULL, /* fpWaitForPrinterChange */
2384 fpClosePrinter,
2385 NULL, /* fpAddForm */
2386 NULL, /* fpDeleteForm */
2387 NULL, /* fpGetForm */
2388 NULL, /* fpSetForm */
2389 NULL, /* fpEnumForms */
2390 fpEnumMonitors,
2391 fpEnumPorts,
2392 fpAddPort,
2393 fpConfigurePort,
2394 fpDeletePort,
2395 NULL, /* fpCreatePrinterIC */
2396 NULL, /* fpPlayGdiScriptOnPrinterIC */
2397 NULL, /* fpDeletePrinterIC */
2398 NULL, /* fpAddPrinterConnection */
2399 NULL, /* fpDeletePrinterConnection */
2400 NULL, /* fpPrinterMessageBox */
2401 fpAddMonitor,
2402 fpDeleteMonitor,
2403 NULL, /* fpResetPrinter */
2404 NULL, /* fpGetPrinterDriverEx */
2405 NULL, /* fpFindFirstPrinterChangeNotification */
2406 NULL, /* fpFindClosePrinterChangeNotification */
2407 fpAddPortEx,
2408 NULL, /* fpShutDown */
2409 NULL, /* fpRefreshPrinterChangeNotification */
2410 NULL, /* fpOpenPrinterEx */
2411 NULL, /* fpAddPrinterEx */
2412 NULL, /* fpSetPort */
2413 NULL, /* fpEnumPrinterData */
2414 NULL, /* fpDeletePrinterData */
2415 NULL, /* fpClusterSplOpen */
2416 NULL, /* fpClusterSplClose */
2417 NULL, /* fpClusterSplIsAlive */
2418 NULL, /* fpSetPrinterDataEx */
2419 NULL, /* fpGetPrinterDataEx */
2420 NULL, /* fpEnumPrinterDataEx */
2421 NULL, /* fpEnumPrinterKey */
2422 NULL, /* fpDeletePrinterDataEx */
2423 NULL, /* fpDeletePrinterKey */
2424 NULL, /* fpSeekPrinter */
2425 NULL, /* fpDeletePrinterDriverEx */
2426 NULL, /* fpAddPerMachineConnection */
2427 NULL, /* fpDeletePerMachineConnection */
2428 NULL, /* fpEnumPerMachineConnections */
2429 fpXcvData,
2430 fpAddPrinterDriverEx,
2431 NULL, /* fpSplReadPrinter */
2432 NULL, /* fpDriverUnloadComplete */
2433 NULL, /* fpGetSpoolFileInfo */
2434 NULL, /* fpCommitSpoolData */
2435 NULL, /* fpCloseSpoolFileHandle */
2436 NULL, /* fpFlushPrinter */
2437 NULL, /* fpSendRecvBidiData */
2438 NULL /* fpAddDriverCatalog */
2440 pprovider = &backend;
2444 /*****************************************************
2445 * InitializePrintProvidor (localspl.@)
2447 * Initialize the Printprovider
2449 * PARAMS
2450 * pPrintProvidor [I] Buffer to fill with a struct PRINTPROVIDOR
2451 * cbPrintProvidor [I] Size of Buffer in Bytes
2452 * pFullRegistryPath [I] Registry-Path for the Printprovidor
2454 * RETURNS
2455 * Success: TRUE and pPrintProvidor filled
2456 * Failure: FALSE
2458 * NOTES
2459 * The RegistryPath should be:
2460 * "System\CurrentControlSet\Control\Print\Providers\<providername>",
2461 * but this Parameter is ignored in "localspl.dll".
2465 BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor,
2466 DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
2469 TRACE("(%p, %u, %s)\n", pPrintProvidor, cbPrintProvidor, debugstr_w(pFullRegistryPath));
2470 memcpy(pPrintProvidor, pprovider,
2471 (cbPrintProvidor < sizeof(PRINTPROVIDOR)) ? cbPrintProvidor : sizeof(PRINTPROVIDOR));
2473 return TRUE;